aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore6
-rw-r--r--INSTALL.md10
-rw-r--r--Makefile.in38
-rw-r--r--bootstrap/bin/start.bootbin5324 -> 5328 bytes
-rw-r--r--bootstrap/bin/start.script8
-rw-r--r--bootstrap/bin/start_clean.bootbin5324 -> 5328 bytes
-rw-r--r--bootstrap/bin/start_clean.script8
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin9028 -> 9028 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin3928 -> 3948 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin31444 -> 31432 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app4
-rw-r--r--bootstrap/lib/compiler/egen/core_parse.erl8
-rw-r--r--bootstrap/lib/kernel/ebin/code.beambin5776 -> 6292 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin23736 -> 23736 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin36428 -> 32824 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin22820 -> 22804 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin24776 -> 24568 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7644 -> 7612 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin11380 -> 11360 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin29332 -> 29308 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin16224 -> 16160 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin11428 -> 11428 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin24716 -> 24664 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin14216 -> 14212 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app12
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin21376 -> 21112 bytes
-rw-r--r--bootstrap/lib/kernel/include/file.hrl2
-rw-r--r--bootstrap/lib/kernel/include/inet.hrl10
-rw-r--r--bootstrap/lib/kernel/include/inet_sctp.hrl10
-rw-r--r--bootstrap/lib/orber/include/Makefile10
-rw-r--r--bootstrap/lib/orber/include/corba.hrl10
-rw-r--r--bootstrap/lib/orber/include/ifr_types.hrl2
-rw-r--r--bootstrap/lib/orber/include/orber_pi.hrl10
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin16608 -> 16584 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin48648 -> 48304 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin26012 -> 25752 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v8.beambin25152 -> 25116 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin46124 -> 45764 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dict.beambin8604 -> 8392 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin21908 -> 21908 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin76928 -> 76924 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin30448 -> 30440 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin14600 -> 14320 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin15284 -> 15268 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin28320 -> 28196 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin12356 -> 12056 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin16896 -> 16892 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin7768 -> 7816 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin65996 -> 65960 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sets.beambin6736 -> 6456 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin39076 -> 37952 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app4
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin15036 -> 14492 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor_bridge.beambin1972 -> 1908 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/timer.beambin4732 -> 4840 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin24568 -> 24552 bytes
-rw-r--r--bootstrap/lib/stdlib/egen/erl_parse.erl180
-rw-r--r--bootstrap/lib/stdlib/include/erl_bits.hrl10
-rw-r--r--bootstrap/lib/stdlib/include/erl_compile.hrl10
-rw-r--r--bootstrap/lib/stdlib/include/ms_transform.hrl10
-rw-r--r--bootstrap/lib/stdlib/include/qlc.hrl10
-rw-r--r--bootstrap/lib/stdlib/include/zip.hrl10
-rw-r--r--configure.in5
-rw-r--r--erts/aclocal.m4219
-rw-r--r--erts/configure.in97
-rw-r--r--erts/doc/src/erl.xml22
-rw-r--r--erts/doc/src/erlang.xml144
-rw-r--r--erts/emulator/Makefile.in65
-rw-r--r--erts/emulator/beam/atom.c10
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/beam_bif_load.c47
-rw-r--r--erts/emulator/beam/beam_bp.h2
-rw-r--r--erts/emulator/beam/beam_emu.c22
-rw-r--r--erts/emulator/beam/bif.c4
-rw-r--r--erts/emulator/beam/big.c8
-rw-r--r--erts/emulator/beam/binary.c18
-rw-r--r--erts/emulator/beam/break.c32
-rw-r--r--erts/emulator/beam/copy.c98
-rw-r--r--erts/emulator/beam/decl.h55
-rw-r--r--erts/emulator/beam/dist.c26
-rw-r--r--erts/emulator/beam/elib_malloc.c2334
-rw-r--r--erts/emulator/beam/elib_stat.h45
-rw-r--r--erts/emulator/beam/erl_alloc.c210
-rw-r--r--erts/emulator/beam/erl_alloc.types8
-rw-r--r--erts/emulator/beam/erl_bif_binary.c4
-rw-r--r--erts/emulator/beam/erl_bif_info.c177
-rw-r--r--erts/emulator/beam/erl_bif_trace.c2
-rw-r--r--erts/emulator/beam/erl_bits.c8
-rw-r--r--erts/emulator/beam/erl_db.c319
-rw-r--r--erts/emulator/beam/erl_db_hash.c12
-rw-r--r--erts/emulator/beam/erl_db_tree.c19
-rw-r--r--erts/emulator/beam/erl_db_util.c13
-rw-r--r--erts/emulator/beam/erl_db_util.h3
-rw-r--r--erts/emulator/beam/erl_drv_thread.c78
-rw-r--r--erts/emulator/beam/erl_fun.c22
-rw-r--r--erts/emulator/beam/erl_fun.h4
-rw-r--r--erts/emulator/beam/erl_gc.c454
-rw-r--r--erts/emulator/beam/erl_init.c116
-rw-r--r--erts/emulator/beam/erl_lock_check.c109
-rw-r--r--erts/emulator/beam/erl_lock_check.h1
-rw-r--r--erts/emulator/beam/erl_lock_count.c18
-rw-r--r--erts/emulator/beam/erl_message.c149
-rw-r--r--erts/emulator/beam/erl_message.h21
-rw-r--r--erts/emulator/beam/erl_mtrace.c2
-rw-r--r--erts/emulator/beam/erl_nif.c10
-rw-r--r--erts/emulator/beam/erl_node_tables.c101
-rw-r--r--erts/emulator/beam/erl_obsolete.c186
-rw-r--r--erts/emulator/beam/erl_port_task.c7
-rw-r--r--erts/emulator/beam/erl_process.c1907
-rw-r--r--erts/emulator/beam/erl_process.h92
-rw-r--r--erts/emulator/beam/erl_process_lock.c350
-rw-r--r--erts/emulator/beam/erl_process_lock.h46
-rw-r--r--erts/emulator/beam/erl_smp.h222
-rw-r--r--erts/emulator/beam/erl_term.h15
-rw-r--r--erts/emulator/beam/erl_threads.h509
-rw-r--r--erts/emulator/beam/export.c8
-rw-r--r--erts/emulator/beam/external.c150
-rw-r--r--erts/emulator/beam/external.h2
-rw-r--r--erts/emulator/beam/global.h30
-rw-r--r--erts/emulator/beam/io.c20
-rw-r--r--erts/emulator/beam/packet_parser.c2
-rw-r--r--erts/emulator/beam/register.c7
-rw-r--r--erts/emulator/beam/sys.h59
-rw-r--r--erts/emulator/beam/utils.c36
-rw-r--r--erts/emulator/drivers/common/efile_drv.c2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c10
-rw-r--r--erts/emulator/drivers/unix/mem_drv.c145
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c6
-rw-r--r--erts/emulator/drivers/win32/mem_drv.c141
-rw-r--r--erts/emulator/hipe/hipe_bif0.c5
-rw-r--r--erts/emulator/hipe/hipe_mkliterals.c4
-rw-r--r--erts/emulator/obsolete/driver.h263
-rw-r--r--erts/emulator/sys/common/erl_poll.c39
-rw-r--r--erts/emulator/sys/unix/sys.c26
-rw-r--r--erts/emulator/sys/unix/sys_float.c17
-rw-r--r--erts/emulator/sys/win32/sys.c34
-rw-r--r--erts/emulator/test/Makefile1
-rw-r--r--erts/emulator/test/decode_packet_SUITE.erl4
-rw-r--r--erts/emulator/test/float_SUITE.erl29
-rw-r--r--erts/emulator/test/hash_SUITE.erl8
-rw-r--r--erts/emulator/test/nif_SUITE.erl168
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c114
-rw-r--r--erts/emulator/test/obsolete_SUITE.erl123
-rw-r--r--erts/emulator/test/obsolete_SUITE_data/Makefile.src33
-rw-r--r--erts/emulator/test/obsolete_SUITE_data/erl_threads.c302
-rw-r--r--erts/emulator/test/obsolete_SUITE_data/testcase_driver.c262
-rw-r--r--erts/emulator/test/obsolete_SUITE_data/testcase_driver.h57
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl361
-rw-r--r--erts/emulator/test/send_term_SUITE.erl67
-rw-r--r--erts/emulator/test/send_term_SUITE_data/send_term_drv.c218
-rw-r--r--erts/epmd/src/epmd.c10
-rw-r--r--erts/epmd/src/epmd_cli.c36
-rw-r--r--erts/epmd/src/epmd_srv.c6
-rw-r--r--erts/etc/common/Makefile.in2
-rw-r--r--erts/etc/common/erlexec.c30
-rw-r--r--erts/include/internal/erl_misc_utils.h9
-rw-r--r--erts/include/internal/ethr_internal.h67
-rw-r--r--erts/include/internal/ethr_mutex.h510
-rw-r--r--erts/include/internal/ethr_optimized_fallbacks.h185
-rw-r--r--erts/include/internal/ethread.h1653
-rw-r--r--erts/include/internal/ethread_header_config.h.in57
-rw-r--r--erts/include/internal/gcc/ethr_atomic.h19
-rw-r--r--erts/include/internal/i386/atomic.h25
-rw-r--r--erts/include/internal/i386/ethread.h3
-rw-r--r--erts/include/internal/i386/rwlock.h12
-rw-r--r--erts/include/internal/i386/spinlock.h14
-rw-r--r--erts/include/internal/libatomic_ops/ethr_atomic.h292
-rw-r--r--erts/include/internal/libatomic_ops/ethread.h30
-rw-r--r--erts/include/internal/ppc32/atomic.h22
-rw-r--r--erts/include/internal/ppc32/ethread.h3
-rw-r--r--erts/include/internal/ppc32/rwlock.h12
-rw-r--r--erts/include/internal/ppc32/spinlock.h12
-rw-r--r--erts/include/internal/pthread/ethr_event.h151
-rw-r--r--erts/include/internal/sparc32/atomic.h39
-rw-r--r--erts/include/internal/sparc32/ethread.h3
-rw-r--r--erts/include/internal/sparc32/rwlock.h12
-rw-r--r--erts/include/internal/sparc32/spinlock.h12
-rw-r--r--erts/include/internal/tile/atomic.h67
-rw-r--r--erts/include/internal/win/ethr_atomic.h244
-rw-r--r--erts/include/internal/win/ethr_event.h62
-rw-r--r--erts/include/internal/win/ethread.h31
-rw-r--r--erts/lib_src/Makefile.in24
-rw-r--r--erts/lib_src/common/erl_misc_utils.c754
-rw-r--r--erts/lib_src/common/ethr_aux.c762
-rw-r--r--erts/lib_src/common/ethr_cbf.c36
-rw-r--r--erts/lib_src/common/ethr_mutex.c2758
-rw-r--r--erts/lib_src/common/ethread.c3369
-rw-r--r--erts/lib_src/pthread/ethr_event.c219
-rw-r--r--erts/lib_src/pthread/ethread.c477
-rw-r--r--erts/lib_src/win/ethr_event.c120
-rw-r--r--erts/lib_src/win/ethread.c625
-rw-r--r--erts/test/ethread_SUITE.erl54
-rw-r--r--erts/test/ethread_SUITE_data/ethread_tests.c1198
-rw-r--r--erts/vsn.mk4
-rw-r--r--lib/.gitignore1
-rw-r--r--lib/appmon/src/appmon_web.erl8
-rw-r--r--lib/asn1/vsn.mk321
-rw-r--r--lib/common_test/Makefile6
-rw-r--r--lib/common_test/doc/src/run_test.xml13
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml118
-rw-r--r--lib/common_test/priv/Makefile.in20
-rw-r--r--lib/common_test/priv/tile1.jpgbin0 -> 34734 bytes
-rw-r--r--lib/common_test/src/ct.erl20
-rw-r--r--lib/common_test/src/ct_framework.erl299
-rw-r--r--lib/common_test/src/ct_logs.erl179
-rw-r--r--lib/common_test/src/ct_run.erl303
-rw-r--r--lib/common_test/src/ct_testspec.erl66
-rw-r--r--lib/common_test/src/ct_util.erl1
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_groups_test_2_SUITE.erl24
-rw-r--r--lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec26
-rw-r--r--lib/common_test/test/ct_test_support.erl7
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE.erl433
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl281
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl344
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl281
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl314
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl146
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl146
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/src/beam_dict.erl30
-rw-r--r--lib/compiler/src/compile.erl36
-rw-r--r--lib/compiler/test/compilation_SUITE.erl13
-rw-r--r--lib/compiler/test/compilation_SUITE_data/string_table.erl8
-rw-r--r--lib/cosEvent/vsn.mk14
-rw-r--r--lib/cosEventDomain/vsn.mk14
-rw-r--r--lib/cosFileTransfer/vsn.mk15
-rw-r--r--lib/cosNotification/vsn.mk17
-rw-r--r--lib/cosProperty/vsn.mk12
-rw-r--r--lib/cosTime/vsn.mk12
-rw-r--r--lib/cosTransactions/vsn.mk13
-rw-r--r--lib/crypto/c_src/crypto.c2
-rw-r--r--lib/crypto/src/crypto.erl8
-rw-r--r--lib/crypto/test/crypto_SUITE.erl19
-rw-r--r--lib/debugger/src/dbg_icmd.erl29
-rw-r--r--lib/debugger/src/dbg_ieval.erl53
-rw-r--r--lib/debugger/src/dbg_iload.erl31
-rw-r--r--lib/debugger/src/dbg_iserver.erl50
-rw-r--r--lib/debugger/src/dbg_ui_break_win.erl7
-rw-r--r--lib/debugger/src/dbg_ui_filedialog_win.erl13
-rw-r--r--lib/debugger/src/dbg_ui_mon.erl21
-rw-r--r--lib/debugger/src/dbg_ui_mon_win.erl28
-rw-r--r--lib/debugger/src/dbg_ui_trace_win.erl205
-rw-r--r--lib/debugger/src/dbg_ui_view.erl6
-rw-r--r--lib/debugger/src/dbg_ui_win.erl8
-rw-r--r--lib/debugger/src/dbg_ui_winman.erl12
-rw-r--r--lib/debugger/src/dbg_wx_break_win.erl6
-rw-r--r--lib/debugger/src/dbg_wx_interpret.erl10
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl19
-rw-r--r--lib/debugger/src/dbg_wx_mon_win.erl11
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl50
-rwxr-xr-xlib/debugger/src/dbg_wx_trace_win.erl24
-rw-r--r--lib/debugger/src/dbg_wx_view.erl39
-rwxr-xr-xlib/debugger/src/dbg_wx_winman.erl12
-rw-r--r--lib/debugger/src/i.erl8
-rw-r--r--lib/debugger/src/int.erl10
-rw-r--r--lib/docbuilder/src/docb_edoc_xml_cb.erl64
-rw-r--r--lib/docbuilder/src/docb_html.erl27
-rw-r--r--lib/docbuilder/src/docb_html_util.erl17
-rw-r--r--lib/docbuilder/src/docb_main.erl27
-rw-r--r--lib/docbuilder/src/docb_pretty_format.erl4
-rw-r--r--lib/docbuilder/src/docb_tr_application2html.erl12
-rw-r--r--lib/docbuilder/src/docb_tr_cite2html.erl22
-rw-r--r--lib/docbuilder/src/docb_tr_index2html.erl4
-rw-r--r--lib/docbuilder/src/docb_tr_part2html.erl15
-rw-r--r--lib/docbuilder/src/docb_tr_term2html.erl22
-rw-r--r--lib/docbuilder/src/docb_transform.erl4
-rw-r--r--lib/docbuilder/src/docb_util.erl8
-rw-r--r--lib/docbuilder/src/docb_xmerl_tree_cb.erl4
-rw-r--r--lib/docbuilder/vsn.mk13
-rw-r--r--lib/edoc/src/edoc_lib.erl4
-rw-r--r--lib/erl_interface/doc/src/ei_connect.xml2
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c93
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.c1
-rw-r--r--lib/erl_interface/src/prog/erl_call.c3
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl34
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c50
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c102
-rw-r--r--lib/et/vsn.mk5
-rw-r--r--lib/eunit/doc/overview.edoc2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl27
-rw-r--r--lib/hipe/rtl/hipe_rtl_primops.erl22
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl4
-rw-r--r--lib/ic/vsn.mk19
-rw-r--r--lib/inets/doc/src/http_client.xml29
-rw-r--r--lib/inets/doc/src/inets.xml22
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl23
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl36
-rw-r--r--lib/inets/src/inets_app/inets.erl18
-rw-r--r--lib/inets/test/ftp_macosx_x86_test.erl6
-rw-r--r--lib/inets/test/ftp_suite_lib.erl26
-rw-r--r--lib/inets/test/httpc_SUITE.erl82
-rw-r--r--lib/inets/vsn.mk95
-rw-r--r--lib/inviso/src/inviso.erl78
-rw-r--r--lib/inviso/src/inviso_c.erl50
-rw-r--r--lib/inviso/src/inviso_lfm.erl14
-rw-r--r--lib/inviso/src/inviso_lfm_tpfreader.erl12
-rw-r--r--lib/inviso/src/inviso_tool.erl72
-rw-r--r--lib/inviso/src/inviso_tool_lib.erl18
-rw-r--r--lib/jinterface/java_src/Makefile16
-rw-r--r--lib/jinterface/java_src/pom.xml.src106
-rw-r--r--lib/jinterface/test/Makefile84
-rw-r--r--lib/jinterface/test/jinterface.dynspec32
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl761
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java46
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/GetNames.java68
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/Makefile.src62
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java201
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/MboxPing.java50
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java229
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/NodePing.java83
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java168
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/Nodename.java54
-rw-r--r--lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java79
-rw-r--r--lib/jinterface/test/jitu.erl156
-rw-r--r--lib/jinterface/test/nc_SUITE.erl736
-rw-r--r--lib/jinterface/test/nc_SUITE_data/Makefile.src53
-rw-r--r--lib/jinterface/test/nc_SUITE_data/connection_server.java96
-rw-r--r--lib/jinterface/test/nc_SUITE_data/echo_server.java261
-rw-r--r--lib/kernel/doc/src/code.xml2
-rw-r--r--lib/kernel/doc/src/erl_ddll.xml38
-rw-r--r--lib/kernel/doc/src/file.xml2
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml2
-rw-r--r--lib/kernel/internal_doc/distribution_handshake.txt40
-rw-r--r--lib/kernel/src/auth.erl6
-rw-r--r--lib/kernel/src/code.erl18
-rw-r--r--lib/kernel/test/code_SUITE.erl32
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl21
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/doc/src/megaco.xml4
-rw-r--r--lib/megaco/doc/src/megaco_flex_scanner.xml2
-rw-r--r--lib/megaco/doc/src/megaco_user.xml2
-rw-r--r--lib/megaco/vsn.mk128
-rw-r--r--lib/mnesia/vsn.mk16
-rw-r--r--lib/odbc/doc/src/databases.xml2
-rw-r--r--lib/odbc/vsn.mk22
-rw-r--r--lib/orber/vsn.mk20
-rw-r--r--lib/parsetools/include/yeccpre.hrl24
-rw-r--r--lib/parsetools/src/yecc.erl18
-rw-r--r--lib/parsetools/src/yeccparser.erl215
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl16
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/doc/src/cert_records.xml37
-rw-r--r--lib/public_key/doc/src/public_key.xml500
-rw-r--r--lib/public_key/include/public_key.hrl9
-rw-r--r--lib/public_key/src/Makefile3
-rw-r--r--lib/public_key/src/pubkey_cert.erl201
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl86
-rw-r--r--lib/public_key/src/pubkey_crypto.erl171
-rw-r--r--lib/public_key/src/pubkey_pem.erl250
-rw-r--r--lib/public_key/src/public_key.app.src1
-rw-r--r--lib/public_key/src/public_key.appup.src18
-rw-r--r--lib/public_key/src/public_key.erl649
-rw-r--r--lib/public_key/test/pkey_test.erl46
-rw-r--r--lib/public_key/test/pkits_SUITE.erl4
-rw-r--r--lib/public_key/test/public_key_SUITE.erl302
-rw-r--r--lib/public_key/vsn.mk12
-rw-r--r--lib/reltool/doc/src/reltool.xml76
-rw-r--r--lib/reltool/doc/src/reltool_usage.xml70
-rw-r--r--lib/reltool/vsn.mk9
-rw-r--r--lib/snmp/doc/src/notes.xml32
-rw-r--r--lib/snmp/doc/src/snmpa.xml4
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl11
-rw-r--r--lib/snmp/src/app/snmp.appup.src24
-rw-r--r--lib/snmp/vsn.mk45
-rw-r--r--lib/ssh/src/ssh_channel.erl14
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl16
-rw-r--r--lib/ssh/vsn.mk80
-rw-r--r--lib/ssl/Makefile16
-rw-r--r--lib/ssl/doc/src/Makefile4
-rw-r--r--lib/ssl/doc/src/book.xml3
-rw-r--r--lib/ssl/doc/src/create_certs.xml148
-rw-r--r--lib/ssl/doc/src/insidecover.xml14
-rw-r--r--lib/ssl/doc/src/licenses.xml156
-rw-r--r--lib/ssl/doc/src/notes.xml2
-rw-r--r--lib/ssl/doc/src/refman.xml3
-rw-r--r--lib/ssl/doc/src/ssl.xml33
-rw-r--r--lib/ssl/doc/src/ssl_app.xml155
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml8
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml431
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml158
-rw-r--r--lib/ssl/doc/src/usersguide.xml20
-rw-r--r--lib/ssl/doc/src/using_ssl.xml149
-rw-r--r--lib/ssl/doc/src/using_ssl.xmlsrc113
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/ssl.erl117
-rw-r--r--lib/ssl/src/ssl_alert.erl25
-rw-r--r--lib/ssl/src/ssl_app.erl12
-rw-r--r--lib/ssl/src/ssl_certificate.erl61
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl51
-rw-r--r--lib/ssl/src/ssl_cipher.erl81
-rw-r--r--lib/ssl/src/ssl_cipher.hrl8
-rw-r--r--lib/ssl/src/ssl_connection.erl361
-rw-r--r--lib/ssl/src/ssl_handshake.erl169
-rw-r--r--lib/ssl/src/ssl_internal.hrl24
-rw-r--r--lib/ssl/src/ssl_manager.erl110
-rw-r--r--lib/ssl/src/ssl_record.erl117
-rw-r--r--lib/ssl/src/ssl_session.erl32
-rw-r--r--lib/ssl/src/ssl_session_cache.erl45
-rw-r--r--lib/ssl/src/ssl_ssl3.erl15
-rw-r--r--lib/ssl/src/ssl_sup.erl7
-rw-r--r--lib/ssl/src/ssl_tls1.erl16
-rw-r--r--lib/ssl/test/erl_make_certs.erl34
-rw-r--r--lib/ssl/test/make_certs.erl16
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl108
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl267
-rw-r--r--lib/ssl/test/ssl_test_lib.erl32
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl4
-rw-r--r--lib/ssl/vsn.mk43
-rw-r--r--lib/stdlib/doc/src/beam_lib.xml1
-rw-r--r--lib/stdlib/doc/src/dets.xml4
-rw-r--r--lib/stdlib/doc/src/ets.xml34
-rw-r--r--lib/stdlib/doc/src/filename.xml2
-rw-r--r--lib/stdlib/doc/src/io_protocol.xml2
-rw-r--r--lib/stdlib/doc/src/lists.xml2
-rw-r--r--lib/stdlib/doc/src/sofs.xml2
-rw-r--r--lib/stdlib/doc/src/timer.xml25
-rw-r--r--lib/stdlib/src/beam_lib.erl1
-rw-r--r--lib/stdlib/src/escript.erl88
-rw-r--r--lib/stdlib/src/ms_transform.erl193
-rw-r--r--lib/stdlib/src/otp_internal.erl6
-rw-r--r--lib/stdlib/src/timer.erl13
-rw-r--r--lib/stdlib/test/ets_SUITE.erl71
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl101
-rw-r--r--lib/stdlib/test/timer_simple_SUITE.erl18
-rw-r--r--lib/stdlib/vsn.mk3
-rw-r--r--lib/test_server/src/test_server_ctrl.erl175
-rw-r--r--lib/test_server/src/ts.erl2
-rw-r--r--lib/test_server/src/ts_erl_config.erl26
-rw-r--r--lib/test_server/src/ts_install.erl21
-rw-r--r--lib/test_server/src/ts_lib.erl20
-rw-r--r--lib/test_server/vsn.mk2
-rw-r--r--lib/tools/c_src/Makefile.in5
-rw-r--r--lib/tools/c_src/erl_memory.c36
-rw-r--r--lib/tools/src/cover.erl2
-rw-r--r--lib/tv/src/tv_pg_gridfcns.erl32
-rw-r--r--lib/wx/.gitignore2
-rw-r--r--lib/wx/api_gen/wxapi.conf9
-rw-r--r--lib/wx/c_src/gen/wxe_derived_dest.h2
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp46
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp41
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h2883
-rw-r--r--lib/wx/c_src/wxe_impl.cpp4
-rw-r--r--lib/wx/src/gen/wxTreeCtrl.erl10
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl2883
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl2883
-rw-r--r--lib/wx/test/wx_class_SUITE.erl3
-rw-r--r--lib/wx/vsn.mk8
-rw-r--r--lib/xmerl/vsn.mk110
-rw-r--r--make/otp.mk.in5
-rwxr-xr-xotp_build252
-rw-r--r--prebuild.delete1
-rwxr-xr-xsystem/doc/reference_manual/typespec.xml2
456 files changed, 28516 insertions, 22365 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..596615322f
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+.gitattributes export-ignore
+.gitignore export-ignore
diff --git a/.gitignore b/.gitignore
index cba7caa074..71c7b9b33d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ a.out.dSYM/
/config.status
/bootstrap/bin/*
+/bootstrap/target
!/bootstrap/bin/*.script
!/bootstrap/bin/*.boot
@@ -142,6 +143,7 @@ a.out.dSYM/
/erts/doc/pdf/*.fo
/erts/doc/pdf/*.pdf
/erts/doc/man[0-9]/*.[0-9]
+/erts/doc/CONF_INFO
# et
@@ -182,6 +184,8 @@ a.out.dSYM/
/lib/jinterface/priv/OtpErlang.jar
/lib/jinterface/priv/com/
/lib/jinterface/doc/html/java
+/lib/jinterface/pom.xml
+/lib/jinterface/target
# kernel
@@ -259,6 +263,8 @@ a.out.dSYM/
/system/doc/tutorial/cnode.xml
/system/doc/tutorial/erl_interface.xml
/system/doc/tutorial/example.xml
+/system/doc/tutorial/nif.xml
+/system/doc/html/installation_guide
/system/doc/installation_guide/INSTALL.xml
/system/doc/installation_guide/INSTALL-CROSS.xml
/system/doc/installation_guide/INSTALL-WIN32.xml
diff --git a/INSTALL.md b/INSTALL.md
index b26c0ce018..2567b791e5 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -273,6 +273,16 @@ Some of the available `configure` options are:
* `--with-ssl=PATH` - Specify location of OpenSSL include and lib
* `--{with,without}-ssl` - OpenSSL (without implies that the `crypto`,
`ssh`, and `ssl` won't be built)
+* `--enable-ethread-pre-pentium4-compatibility` - Enable compatibility with
+ x86 processors before pentium 4 (back to 486) in the ethread library. If
+ not passed the ethread library (part of the runtime system) will use
+ instructions that first appeared on the pentium 4 processor when building
+ for x86.
+* `--with-libatomic_ops=PATH` - Use the `libatomic_ops` library for atomic
+ memory accesses. If `configure` should inform you about no native atomic
+ implementation available, you typically want to try using the
+ `libatomic_ops` library. It can be downloaded from
+ <http://www.hpl.hp.com/research/linux/atomic_ops/>.
If you or your system has special requirements please read the `Makefile` for
additional configuration information.
diff --git a/Makefile.in b/Makefile.in
index 7bdcdcc297..4b6e2e1190 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -485,11 +485,13 @@ dep depend:
# Creates "erl" and "erlc" in bootstrap/bin which uses the precompiled
# libraries in the bootstrap directory
+.PHONY: bootstrap_setup_target
+
# ----------------------------------------------------------------------
# Bootstraps...
# ----------------------------------------------------------------------
ifeq ($(TARGET),win32)
-bootstrap_setup: check_recreate_primary_bootstrap
+bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target
@rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl.exe \
$(BOOTSTRAP_ROOT)/bootstrap/bin/erlc.exe \
$(BOOTSTRAP_ROOT)/bootstrap/bin/erl.ini \
@@ -501,9 +503,9 @@ bootstrap_setup: check_recreate_primary_bootstrap
@cp $(ERL_TOP)/bin/$(TARGET)/erl.exe \
$(BOOTSTRAP_ROOT)/bootstrap/bin/erl.exe
else
-bootstrap_setup: check_recreate_primary_bootstrap $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc
+bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc
-$(BOOTSTRAP_ROOT)/bootstrap/bin/erl: $(ERL_TOP)/erts/etc/unix/erl.src.src
+$(BOOTSTRAP_ROOT)/bootstrap/bin/erl: $(ERL_TOP)/erts/etc/unix/erl.src.src $(BOOTSTRAP_ROOT)/bootstrap/target
@rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl
@sed -e "s;%FINAL_ROOTDIR%;$(BOOTSTRAP_ROOT)/bootstrap;" \
-e "s;\$$ROOTDIR/erts-.*/bin;$(ERL_TOP)/bin/$(TARGET);" \
@@ -512,12 +514,17 @@ $(BOOTSTRAP_ROOT)/bootstrap/bin/erl: $(ERL_TOP)/erts/etc/unix/erl.src.src
$(BOOTSTRAP_ROOT)/bootstrap/bin/erl
@chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/erl
-$(BOOTSTRAP_ROOT)/bootstrap/bin/erlc: $(ERL_TOP)/bin/$(TARGET)/erlc
+$(BOOTSTRAP_ROOT)/bootstrap/bin/erlc: $(ERL_TOP)/bin/$(TARGET)/erlc $(BOOTSTRAP_ROOT)/bootstrap/target
@rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc
@cp $(ERL_TOP)/bin/$(TARGET)/erlc $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc
@chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc
endif
+bootstrap_setup_target:
+ @{ test -r $(BOOTSTRAP_ROOT)/bootstrap/target && \
+ test $(TARGET) = `cat $(BOOTSTRAP_ROOT)/bootstrap/target`; } || \
+ echo $(TARGET) > $(BOOTSTRAP_ROOT)/bootstrap/target
+
secondary_bootstrap_build:
cd lib && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)$${PATH} \
@@ -743,14 +750,16 @@ recreate_primary_bootstrap:
# of the emulator possible
.PHONY: primary_bootstrap \
- primary_bootstrap_check_make \
primary_bootstrap_build \
primary_bootstrap_compiler \
primary_bootstrap_mkdirs \
primary_bootstrap_copy
-primary_bootstrap: primary_bootstrap_check_make
+primary_bootstrap:
@echo "=== Building a bootstrap compiler in $(BOOTSTRAP_ROOT)/bootstrap"
+ $(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) \
+ ERL_TOP=$(ERL_TOP) \
+ bootstrap_clean
cd $(ERL_TOP) && \
$(MAKE) TESTROOT=$(BOOTSTRAP_TOP) \
BOOTSTRAP_TOP=$(BOOTSTRAP_TOP) \
@@ -768,22 +777,6 @@ primary_bootstrap: primary_bootstrap_check_make
$(BOOTSTRAP_TOP) \
$(BOOTSTRAP_ROOT)
-#
-# Dependencies are not complete in all makefiles; therefore, remove bootstrap
-# build result and build from scratch if we are not using clearmake (which
-# tracks dependencies itself).
-#
-primary_bootstrap_check_make:
- @ case "$(MAKE)" in \
- *clearmake*) \
- ;; \
- *) \
- $(MAKE) BOOTSTRAP_ROOT=$(BOOTSTRAP_ROOT) \
- ERL_TOP=$(ERL_TOP) \
- bootstrap_clean \
- ;; \
- esac
-
primary_bootstrap_build: primary_bootstrap_mkdirs primary_bootstrap_compiler \
primary_bootstrap_stdlib
cd lib && $(MAKE) ERLC_FLAGS='-pa $(BOOTSTRAP_COMPILER)/ebin' \
@@ -1023,6 +1016,7 @@ bootstrap_root_clean:
# $(BOOTSTRAP_TOP) for some reason should be empty).
bootstrap_clean:
rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.beam
+ rm -f $(ERL_TOP)/bootstrap/lib/*/ebin/*.app
rm -f $(ERL_TOP)/bootstrap/lib/*/egen/*
rm -f $(ERL_TOP)/bootstrap/lib/*/include/*.hrl
rm -f $(ERL_TOP)/bootstrap/primary_compiler/ebin/*
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index 71d72c4b7d..e09d7405b2 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start.script b/bootstrap/bin/start.script
index 1fce0ecb78..7a62fabed4 100644
--- a/bootstrap/bin/start.script
+++ b/bootstrap/bin/start.script
@@ -1,6 +1,6 @@
-%% script generated at {2010,6,9} {16,21,46}
+%% script generated at {2010,8,3} {17,6,26}
{script,
- {"OTP APN 181 01","R14A"},
+ {"OTP APN 181 01","R14B"},
[{preLoaded,
[erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip,
zlib]},
@@ -43,7 +43,7 @@
{application_controller,start,
[{application,kernel,
[{description,"ERTS CXC 138 10"},
- {vsn,"2.14"},
+ {vsn,"2.14.1"},
{id,[]},
{modules,
[application,application_controller,application_master,
@@ -80,7 +80,7 @@
{application,load,
[{application,stdlib,
[{description,"ERTS CXC 138 10"},
- {vsn,"1.17"},
+ {vsn,"1.17.1"},
{id,[]},
{modules,
[array,base64,beam_lib,binary,c,calendar,dets,
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index 71d72c4b7d..e09d7405b2 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.script b/bootstrap/bin/start_clean.script
index 1fce0ecb78..7a62fabed4 100644
--- a/bootstrap/bin/start_clean.script
+++ b/bootstrap/bin/start_clean.script
@@ -1,6 +1,6 @@
-%% script generated at {2010,6,9} {16,21,46}
+%% script generated at {2010,8,3} {17,6,26}
{script,
- {"OTP APN 181 01","R14A"},
+ {"OTP APN 181 01","R14B"},
[{preLoaded,
[erl_prim_loader,erlang,init,otp_ring0,prim_file,prim_inet,prim_zip,
zlib]},
@@ -43,7 +43,7 @@
{application_controller,start,
[{application,kernel,
[{description,"ERTS CXC 138 10"},
- {vsn,"2.14"},
+ {vsn,"2.14.1"},
{id,[]},
{modules,
[application,application_controller,application_master,
@@ -80,7 +80,7 @@
{application,load,
[{application,stdlib,
[{description,"ERTS CXC 138 10"},
- {vsn,"1.17"},
+ {vsn,"1.17.1"},
{id,[]},
{modules,
[array,base64,beam_lib,binary,c,calendar,dets,
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index 23046bac9f..75c6383ba3 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index e1b39a1799..6e3c32607e 100644
--- a/bootstrap/lib/compiler/ebin/beam_dict.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dict.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index 7bb31cd6e2..b460c83ba0 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.app b/bootstrap/lib/compiler/ebin/compiler.app
index ed0dd7c30e..d201d5fd0d 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,7 @@
{application, compiler,
[{description, "ERTS CXC 138 10"},
- {vsn, "4.6.5"},
+ {vsn, "4.7"},
{modules, [
beam_asm,
beam_block,
diff --git a/bootstrap/lib/compiler/egen/core_parse.erl b/bootstrap/lib/compiler/egen/core_parse.erl
index 05624beb14..b7f5579763 100644
--- a/bootstrap/lib/compiler/egen/core_parse.erl
+++ b/bootstrap/lib/compiler/egen/core_parse.erl
@@ -13,11 +13,11 @@
tok_val(T) -> element(3, T).
tok_line(T) -> element(2, T).
--file("/usr/local/otp/releases/sles10_32_R13B04_patched/lib/parsetools-2.0.2/include/yeccpre.hrl", 0).
+-file("/usr/local/otp_product/releases/sles10_32_R14A_patched/lib/parsetools-2.0.3/include/yeccpre.hrl", 0).
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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
@@ -194,7 +194,7 @@ yecctoken2string(Other) ->
--file("/clearcase/otp/erts/bootstrap/lib/compiler/egen/core_parse.erl", 197).
+-file("/ldisk/bjorn/otp/bootstrap/lib/compiler/egen/core_parse.erl", 197).
yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr);
@@ -852,7 +852,7 @@ yeccpars2_0(S, '(', Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, module, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 3, Ss, Stack, T, Ts, Tzr).
-yeccpars2_1(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
+yeccpars2_1(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
{ok, hd(Stack)}.
yeccpars2_2(S, module, Ss, Stack, T, Ts, Tzr) ->
diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam
index a6fbed812a..dc4cf6cf41 100644
--- a/bootstrap/lib/kernel/ebin/code.beam
+++ b/bootstrap/lib/kernel/ebin/code.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index 8f95f91348..3d66c1c282 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 b432811d6e..f41ed33d9a 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam
index 96f4e1953f..bbc42326cb 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_1.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index 59c75602ec..29be008e0c 100644
--- a/bootstrap/lib/kernel/ebin/dist_ac.beam
+++ b/bootstrap/lib/kernel/ebin/dist_ac.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index 09746d0403..68ef714e17 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/file.beam b/bootstrap/lib/kernel/ebin/file.beam
index 798d1ae8e8..3671dea4f1 100644
--- a/bootstrap/lib/kernel/ebin/file.beam
+++ b/bootstrap/lib/kernel/ebin/file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index 20053eb877..525d4ebdfa 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam
index 00d03a24f5..42be2aad4c 100644
--- a/bootstrap/lib/kernel/ebin/global_group.beam
+++ b/bootstrap/lib/kernel/ebin/global_group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index d06aba7fe9..70e35c2076 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 2bba1e88c9..095d624ea7 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_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam
index 0167a10b36..f1433006b7 100644
--- a/bootstrap/lib/kernel/ebin/inet_res.beam
+++ b/bootstrap/lib/kernel/ebin/inet_res.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 93b0c3d78e..2b2c82d89c 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% This is an -*- erlang -*- file.
@@ -21,7 +21,7 @@
{application, kernel,
[
{description, "ERTS CXC 138 10"},
- {vsn, "2.14"},
+ {vsn, "2.14.1"},
{modules, [application,
application_controller,
application_master,
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index c8346c2a8f..4343fc47aa 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/include/file.hrl b/bootstrap/lib/kernel/include/file.hrl
index b46400ca26..3889bce393 100644
--- a/bootstrap/lib/kernel/include/file.hrl
+++ b/bootstrap/lib/kernel/include/file.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/bootstrap/lib/kernel/include/inet.hrl b/bootstrap/lib/kernel/include/inet.hrl
index 94dd269f7e..929b2ee294 100644
--- a/bootstrap/lib/kernel/include/inet.hrl
+++ b/bootstrap/lib/kernel/include/inet.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% This record is returned by inet:gethostbyaddr/2 and inet:gethostbyname/2.
diff --git a/bootstrap/lib/kernel/include/inet_sctp.hrl b/bootstrap/lib/kernel/include/inet_sctp.hrl
index 83f95e05af..169ba013aa 100644
--- a/bootstrap/lib/kernel/include/inet_sctp.hrl
+++ b/bootstrap/lib/kernel/include/inet_sctp.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% SCTP protocol contribution by Leonid Timochouk and Serge Aleynikov.
diff --git a/bootstrap/lib/orber/include/Makefile b/bootstrap/lib/orber/include/Makefile
index 08745e5727..219b7085e6 100644
--- a/bootstrap/lib/orber/include/Makefile
+++ b/bootstrap/lib/orber/include/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2008-2010. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
#
diff --git a/bootstrap/lib/orber/include/corba.hrl b/bootstrap/lib/orber/include/corba.hrl
index c5d2d50ea0..b9869855bf 100644
--- a/bootstrap/lib/orber/include/corba.hrl
+++ b/bootstrap/lib/orber/include/corba.hrl
@@ -1,20 +1,20 @@
%%--------------------------------------------------------------------
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
diff --git a/bootstrap/lib/orber/include/ifr_types.hrl b/bootstrap/lib/orber/include/ifr_types.hrl
index 798f1c30a1..144ec7f8a1 100644
--- a/bootstrap/lib/orber/include/ifr_types.hrl
+++ b/bootstrap/lib/orber/include/ifr_types.hrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/bootstrap/lib/orber/include/orber_pi.hrl b/bootstrap/lib/orber/include/orber_pi.hrl
index 2b846bc814..84231758fe 100644
--- a/bootstrap/lib/orber/include/orber_pi.hrl
+++ b/bootstrap/lib/orber/include/orber_pi.hrl
@@ -1,20 +1,20 @@
%%----------------------------------------------------------------------
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index 19981adac0..5d4a22d334 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index 260a7e2eb3..3e133f4ff2 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index b0c3e351d2..817ded2d62 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_v8.beam b/bootstrap/lib/stdlib/ebin/dets_v8.beam
index f48768ca53..2ad134d371 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v8.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v8.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index 0694437929..2eabd08ed4 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/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam
index ebf01cb9b5..ee24ed8f47 100644
--- a/bootstrap/lib/stdlib/ebin/dict.beam
+++ b/bootstrap/lib/stdlib/ebin/dict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 083706d1ae..8115d9c474 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_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index ece262c1b0..5ebd228586 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 9e923ae736..1420d376f2 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/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam
index 369e5a8c6d..7cf0571935 100644
--- a/bootstrap/lib/stdlib/ebin/erl_tar.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index 15f1cb8354..5c09e4aa54 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/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam
index c27d4e141f..90627df431 100644
--- a/bootstrap/lib/stdlib/ebin/file_sorter.beam
+++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index 264071fe5f..79a037d8c8 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/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index 918c2537ea..2a0745f786 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 cac4a97ae0..9a031e8eac 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/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index 92b1bc8bee..141891308f 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam
index 9be4e8ab5b..e95a93e5cf 100644
--- a/bootstrap/lib/stdlib/ebin/sets.beam
+++ b/bootstrap/lib/stdlib/ebin/sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam
index 51af30d7e8..aa12f15cdc 100644
--- a/bootstrap/lib/stdlib/ebin/sofs.beam
+++ b/bootstrap/lib/stdlib/ebin/sofs.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index 880e85627e..6ab708e43c 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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,7 +19,7 @@
%%
{application, stdlib,
[{description, "ERTS CXC 138 10"},
- {vsn, "1.17"},
+ {vsn, "1.17.1"},
{modules, [array,
base64,
beam_lib,
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 4511719f95..54811dad66 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 3880293d47..686078826d 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/timer.beam b/bootstrap/lib/stdlib/ebin/timer.beam
index a20cc97935..1020f78632 100644
--- a/bootstrap/lib/stdlib/ebin/timer.beam
+++ b/bootstrap/lib/stdlib/ebin/timer.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index 6c5b31cd1f..6aa0cc32b2 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/egen/erl_parse.erl b/bootstrap/lib/stdlib/egen/erl_parse.erl
index 33c1ad9e95..fd245f386a 100644
--- a/bootstrap/lib/stdlib/egen/erl_parse.erl
+++ b/bootstrap/lib/stdlib/egen/erl_parse.erl
@@ -556,11 +556,11 @@ get_attribute(L, Name) ->
get_attributes(L) ->
erl_scan:attributes_info(L).
--file("/usr/local/otp/releases/sles10_32_R13B04_patched/lib/parsetools-2.0.2/include/yeccpre.hrl", 0).
+-file("/usr/local/otp_product/releases/sles10_32_R14A_patched/lib/parsetools-2.0.3/include/yeccpre.hrl", 0).
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2010. 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
@@ -737,7 +737,7 @@ yecctoken2string(Other) ->
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 740).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 740).
yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr);
@@ -1703,7 +1703,7 @@ yeccpars2_5(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_6(S, dot, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 453, Ss, Stack, T, Ts, Tzr).
-yeccpars2_7(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
+yeccpars2_7(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
{ok, hd(Stack)}.
yeccpars2_8(S, dot, Ss, Stack, T, Ts, Tzr) ->
@@ -7975,7 +7975,7 @@ yeccpars2_39_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7978).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7978).
-compile({inline,yeccpars2_46_/1}).
-file("erl_parse.yrl", 434).
yeccpars2_46_(__Stack0) ->
@@ -7984,7 +7984,7 @@ yeccpars2_46_(__Stack0) ->
{ [ ] , ? line ( __1 ) }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7987).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7987).
-compile({inline,yeccpars2_70_/1}).
-file("erl_parse.yrl", 325).
yeccpars2_70_(__Stack0) ->
@@ -7993,7 +7993,7 @@ yeccpars2_70_(__Stack0) ->
{ tuple , ? line ( __1 ) , [ ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 7996).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 7996).
-compile({inline,yeccpars2_71_/1}).
-file("erl_parse.yrl", 326).
yeccpars2_71_(__Stack0) ->
@@ -8002,7 +8002,7 @@ yeccpars2_71_(__Stack0) ->
{ tuple , ? line ( __1 ) , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8005).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8005).
-compile({inline,yeccpars2_73_/1}).
-file("erl_parse.yrl", 408).
yeccpars2_73_(__Stack0) ->
@@ -8034,7 +8034,7 @@ yeccpars2_81_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8037).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8037).
-compile({inline,yeccpars2_82_/1}).
-file("erl_parse.yrl", 406).
yeccpars2_82_(__Stack0) ->
@@ -8067,7 +8067,7 @@ yeccpars2_88_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8070).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8070).
-compile({inline,yeccpars2_89_/1}).
-file("erl_parse.yrl", 381).
yeccpars2_89_(__Stack0) ->
@@ -8106,7 +8106,7 @@ yeccpars2_98_(__Stack0) ->
[ ]
end | __Stack0].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8109).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8109).
-compile({inline,yeccpars2_100_/1}).
-file("erl_parse.yrl", 427).
yeccpars2_100_(__Stack0) ->
@@ -8123,7 +8123,7 @@ yeccpars2_102_(__Stack0) ->
[ ]
end | __Stack0].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8126).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8126).
-compile({inline,yeccpars2_104_/1}).
-file("erl_parse.yrl", 424).
yeccpars2_104_(__Stack0) ->
@@ -8133,7 +8133,7 @@ yeccpars2_104_(__Stack0) ->
{ clause , L , [ { tuple , L , [ __1 , __3 , { var , L , '_' } ] } ] , __4 , __5 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8136).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8136).
-compile({inline,yeccpars2_106_/1}).
-file("erl_parse.yrl", 421).
yeccpars2_106_(__Stack0) ->
@@ -8175,7 +8175,7 @@ yeccpars2_114_(__Stack0) ->
{ [ ] , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8178).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8178).
-compile({inline,yeccpars2_115_/1}).
-file("erl_parse.yrl", 452).
yeccpars2_115_(__Stack0) ->
@@ -8184,7 +8184,7 @@ yeccpars2_115_(__Stack0) ->
{ string , ? line ( __1 ) , element ( 3 , __1 ) ++ element ( 3 , __2 ) }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8187).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8187).
-compile({inline,yeccpars2_120_/1}).
-file("erl_parse.yrl", 386).
yeccpars2_120_(__Stack0) ->
@@ -8193,7 +8193,7 @@ yeccpars2_120_(__Stack0) ->
{ 'receive' , ? line ( __1 ) , [ ] , __3 , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8196).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8196).
-compile({inline,yeccpars2_122_/1}).
-file("erl_parse.yrl", 384).
yeccpars2_122_(__Stack0) ->
@@ -8202,7 +8202,7 @@ yeccpars2_122_(__Stack0) ->
{ 'receive' , ? line ( __1 ) , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8205).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8205).
-compile({inline,yeccpars2_125_/1}).
-file("erl_parse.yrl", 388).
yeccpars2_125_(__Stack0) ->
@@ -8219,7 +8219,7 @@ yeccpars2_131_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8222).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8222).
-compile({inline,yeccpars2_135_/1}).
-file("erl_parse.yrl", 323).
yeccpars2_135_(__Stack0) ->
@@ -8228,7 +8228,7 @@ yeccpars2_135_(__Stack0) ->
{ b_generate , ? line ( __2 ) , __1 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8231).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8231).
-compile({inline,yeccpars2_137_/1}).
-file("erl_parse.yrl", 322).
yeccpars2_137_(__Stack0) ->
@@ -8245,7 +8245,7 @@ yeccpars2_139_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8248).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8248).
-compile({inline,yeccpars2_140_/1}).
-file("erl_parse.yrl", 315).
yeccpars2_140_(__Stack0) ->
@@ -8254,7 +8254,7 @@ yeccpars2_140_(__Stack0) ->
{ lc , ? line ( __1 ) , __2 , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8257).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8257).
-compile({inline,yeccpars2_141_/1}).
-file("erl_parse.yrl", 431).
yeccpars2_141_(__Stack0) ->
@@ -8271,7 +8271,7 @@ yeccpars2_143_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8274).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8274).
-compile({inline,yeccpars2_145_/1}).
-file("erl_parse.yrl", 371).
yeccpars2_145_(__Stack0) ->
@@ -8288,7 +8288,7 @@ yeccpars2_147_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8291).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8291).
-compile({inline,yeccpars2_148_/1}).
-file("erl_parse.yrl", 365).
yeccpars2_148_(__Stack0) ->
@@ -8312,7 +8312,7 @@ yeccpars2_151_(__Stack0) ->
[ ]
end | __Stack0].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8315).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8315).
-compile({inline,yeccpars2_157_/1}).
-file("erl_parse.yrl", 394).
yeccpars2_157_(__Stack0) ->
@@ -8321,7 +8321,7 @@ yeccpars2_157_(__Stack0) ->
{ 'fun' , ? line ( __1 ) , { function , element ( 3 , __2 ) , element ( 3 , __4 ) , element ( 3 , __6 ) } }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8324).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8324).
-compile({inline,yeccpars2_158_/1}).
-file("erl_parse.yrl", 392).
yeccpars2_158_(__Stack0) ->
@@ -8347,7 +8347,7 @@ yeccpars2_162_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8350).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8350).
-compile({inline,yeccpars2_163_/1}).
-file("erl_parse.yrl", 396).
yeccpars2_163_(__Stack0) ->
@@ -8356,7 +8356,7 @@ yeccpars2_163_(__Stack0) ->
build_fun ( ? line ( __1 ) , __2 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8359).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8359).
-compile({inline,yeccpars2_164_/1}).
-file("erl_parse.yrl", 214).
yeccpars2_164_(__Stack0) ->
@@ -8365,7 +8365,7 @@ yeccpars2_164_(__Stack0) ->
{ 'catch' , ? line ( __1 ) , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8368).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8368).
-compile({inline,yeccpars2_168_/1}).
-file("erl_parse.yrl", 375).
yeccpars2_168_(__Stack0) ->
@@ -8374,7 +8374,7 @@ yeccpars2_168_(__Stack0) ->
{ 'case' , ? line ( __1 ) , __2 , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8377).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8377).
-compile({inline,yeccpars2_170_/1}).
-file("erl_parse.yrl", 270).
yeccpars2_170_(__Stack0) ->
@@ -8383,7 +8383,7 @@ yeccpars2_170_(__Stack0) ->
{ block , ? line ( __1 ) , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8386).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8386).
-compile({inline,yeccpars2_172_/1}).
-file("erl_parse.yrl", 279).
yeccpars2_172_(__Stack0) ->
@@ -8392,7 +8392,7 @@ yeccpars2_172_(__Stack0) ->
{ nil , ? line ( __1 ) }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8395).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8395).
-compile({inline,yeccpars2_173_/1}).
-file("erl_parse.yrl", 280).
yeccpars2_173_(__Stack0) ->
@@ -8401,7 +8401,7 @@ yeccpars2_173_(__Stack0) ->
{ cons , ? line ( __1 ) , __2 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8404).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8404).
-compile({inline,yeccpars2_175_/1}).
-file("erl_parse.yrl", 282).
yeccpars2_175_(__Stack0) ->
@@ -8418,7 +8418,7 @@ yeccpars2_178_(__Stack0) ->
__2
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8421).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8421).
-compile({inline,yeccpars2_180_/1}).
-file("erl_parse.yrl", 284).
yeccpars2_180_(__Stack0) ->
@@ -8442,7 +8442,7 @@ yeccpars2_186_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8445).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8445).
-compile({inline,yeccpars2_187_/1}).
-file("erl_parse.yrl", 287).
yeccpars2_187_(__Stack0) ->
@@ -8459,7 +8459,7 @@ yeccpars2_189_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8462).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8462).
-compile({inline,yeccpars2_190_/1}).
-file("erl_parse.yrl", 288).
yeccpars2_190_(__Stack0) ->
@@ -8468,7 +8468,7 @@ yeccpars2_190_(__Stack0) ->
{ bin , ? line ( __1 ) , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8471).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8471).
-compile({inline,yeccpars2_193_/1}).
-file("erl_parse.yrl", 317).
yeccpars2_193_(__Stack0) ->
@@ -8492,7 +8492,7 @@ yeccpars2_197_(__Stack0) ->
__2
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8495).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8495).
-compile({inline,yeccpars2_198_/1}).
-file("erl_parse.yrl", 294).
yeccpars2_198_(__Stack0) ->
@@ -8541,7 +8541,7 @@ yeccpars2_206_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8544).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8544).
-compile({inline,yeccpars2_207_/1}).
-file("erl_parse.yrl", 296).
yeccpars2_207_(__Stack0) ->
@@ -8550,7 +8550,7 @@ yeccpars2_207_(__Stack0) ->
? mkop1 ( __1 , __2 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8553).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8553).
-compile({inline,yeccpars2_208_/1}).
-file("erl_parse.yrl", 256).
yeccpars2_208_(__Stack0) ->
@@ -8567,7 +8567,7 @@ yeccpars2_210_(__Stack0) ->
__2
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8570).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8570).
-compile({inline,yeccpars2_212_/1}).
-file("erl_parse.yrl", 340).
yeccpars2_212_(__Stack0) ->
@@ -8592,7 +8592,7 @@ yeccpars2_219_(__Stack0) ->
[ ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8595).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8595).
-compile({inline,yeccpars2_221_/1}).
-file("erl_parse.yrl", 356).
yeccpars2_221_(__Stack0) ->
@@ -8601,7 +8601,7 @@ yeccpars2_221_(__Stack0) ->
{ record_field , ? line ( __1 ) , __1 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8604).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8604).
-compile({inline,yeccpars2_223_/1}).
-file("erl_parse.yrl", 357).
yeccpars2_223_(__Stack0) ->
@@ -8626,7 +8626,7 @@ yeccpars2_226_(__Stack0) ->
__2
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8629).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8629).
-compile({inline,yeccpars2_227_/1}).
-file("erl_parse.yrl", 338).
yeccpars2_227_(__Stack0) ->
@@ -8643,7 +8643,7 @@ yeccpars2_229_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8646).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8646).
-compile({inline,yeccpars2_232_/1}).
-file("erl_parse.yrl", 217).
yeccpars2_232_(__Stack0) ->
@@ -8652,7 +8652,7 @@ yeccpars2_232_(__Stack0) ->
{ match , ? line ( __2 ) , __1 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8655).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8655).
-compile({inline,yeccpars2_233_/1}).
-file("erl_parse.yrl", 218).
yeccpars2_233_(__Stack0) ->
@@ -8661,7 +8661,7 @@ yeccpars2_233_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8664).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8664).
-compile({inline,yeccpars2_235_/1}).
-file("erl_parse.yrl", 221).
yeccpars2_235_(__Stack0) ->
@@ -8670,7 +8670,7 @@ yeccpars2_235_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8673).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8673).
-compile({inline,yeccpars2_237_/1}).
-file("erl_parse.yrl", 224).
yeccpars2_237_(__Stack0) ->
@@ -8679,7 +8679,7 @@ yeccpars2_237_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8682).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8682).
-compile({inline,yeccpars2_247_/1}).
-file("erl_parse.yrl", 228).
yeccpars2_247_(__Stack0) ->
@@ -8688,7 +8688,7 @@ yeccpars2_247_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8691).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8691).
-compile({inline,yeccpars2_260_/1}).
-file("erl_parse.yrl", 236).
yeccpars2_260_(__Stack0) ->
@@ -8697,7 +8697,7 @@ yeccpars2_260_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8700).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8700).
-compile({inline,yeccpars2_268_/1}).
-file("erl_parse.yrl", 240).
yeccpars2_268_(__Stack0) ->
@@ -8706,7 +8706,7 @@ yeccpars2_268_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8709).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8709).
-compile({inline,yeccpars2_269_/1}).
-file("erl_parse.yrl", 232).
yeccpars2_269_(__Stack0) ->
@@ -8715,7 +8715,7 @@ yeccpars2_269_(__Stack0) ->
? mkop2 ( __1 , __2 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8718).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8718).
-compile({inline,yeccpars2_270_/1}).
-file("erl_parse.yrl", 362).
yeccpars2_270_(__Stack0) ->
@@ -8724,7 +8724,7 @@ yeccpars2_270_(__Stack0) ->
{ call , ? line ( __1 ) , __1 , element ( 1 , __2 ) }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8727).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8727).
-compile({inline,yeccpars2_273_/1}).
-file("erl_parse.yrl", 252).
yeccpars2_273_(__Stack0) ->
@@ -8733,7 +8733,7 @@ yeccpars2_273_(__Stack0) ->
{ remote , ? line ( __2 ) , __1 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8736).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8736).
-compile({inline,yeccpars2_274_/1}).
-file("erl_parse.yrl", 258).
yeccpars2_274_(__Stack0) ->
@@ -8742,7 +8742,7 @@ yeccpars2_274_(__Stack0) ->
{ record_field , ? line ( __2 ) , __1 , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8745).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8745).
-compile({inline,yeccpars2_277_/1}).
-file("erl_parse.yrl", 344).
yeccpars2_277_(__Stack0) ->
@@ -8751,7 +8751,7 @@ yeccpars2_277_(__Stack0) ->
{ record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8754).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8754).
-compile({inline,yeccpars2_279_/1}).
-file("erl_parse.yrl", 342).
yeccpars2_279_(__Stack0) ->
@@ -8760,7 +8760,7 @@ yeccpars2_279_(__Stack0) ->
{ record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8763).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8763).
-compile({inline,yeccpars2_280_/1}).
-file("erl_parse.yrl", 435).
yeccpars2_280_(__Stack0) ->
@@ -8769,7 +8769,7 @@ yeccpars2_280_(__Stack0) ->
{ __2 , ? line ( __1 ) }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8772).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8772).
-compile({inline,yeccpars2_281_/1}).
-file("erl_parse.yrl", 244).
yeccpars2_281_(__Stack0) ->
@@ -8778,7 +8778,7 @@ yeccpars2_281_(__Stack0) ->
? mkop1 ( __1 , __2 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8781).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8781).
-compile({inline,yeccpars2_284_/1}).
-file("erl_parse.yrl", 348).
yeccpars2_284_(__Stack0) ->
@@ -8787,7 +8787,7 @@ yeccpars2_284_(__Stack0) ->
{ record , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8790).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8790).
-compile({inline,yeccpars2_286_/1}).
-file("erl_parse.yrl", 346).
yeccpars2_286_(__Stack0) ->
@@ -8796,7 +8796,7 @@ yeccpars2_286_(__Stack0) ->
{ record_field , ? line ( __2 ) , __1 , element ( 3 , __3 ) , __5 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8799).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8799).
-compile({inline,yeccpars2_288_/1}).
-file("erl_parse.yrl", 493).
yeccpars2_288_(__Stack0) ->
@@ -8805,7 +8805,7 @@ yeccpars2_288_(__Stack0) ->
{ clause , ? line ( __1 ) , element ( 3 , __1 ) , __2 , __3 , __4 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8808).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8808).
-compile({inline,yeccpars2_289_/1}).
-file("erl_parse.yrl", 203).
yeccpars2_289_(__Stack0) ->
@@ -8870,7 +8870,7 @@ yeccpars2_318_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8873).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8873).
-compile({inline,yeccpars2_332_/1}).
-file("erl_parse.yrl", 152).
yeccpars2_332_(__Stack0) ->
@@ -8879,7 +8879,7 @@ yeccpars2_332_(__Stack0) ->
{ type , ? line ( __1 ) , tuple , [ ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8882).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8882).
-compile({inline,yeccpars2_333_/1}).
-file("erl_parse.yrl", 153).
yeccpars2_333_(__Stack0) ->
@@ -8888,7 +8888,7 @@ yeccpars2_333_(__Stack0) ->
{ type , ? line ( __1 ) , tuple , __2 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8891).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8891).
-compile({inline,yeccpars2_335_/1}).
-file("erl_parse.yrl", 116).
yeccpars2_335_(__Stack0) ->
@@ -8897,7 +8897,7 @@ yeccpars2_335_(__Stack0) ->
{ ann_type , ? line ( __1 ) , [ __1 , __3 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8900).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8900).
-compile({inline,yeccpars2_341_/1}).
-file("erl_parse.yrl", 159).
yeccpars2_341_(__Stack0) ->
@@ -8906,7 +8906,7 @@ yeccpars2_341_(__Stack0) ->
{ type , ? line ( __1 ) , 'fun' , [ ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8909).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8909).
-compile({inline,yeccpars2_345_/1}).
-file("erl_parse.yrl", 163).
yeccpars2_345_(__Stack0) ->
@@ -8924,7 +8924,7 @@ yeccpars2_346_(__Stack0) ->
__3
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8927).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8927).
-compile({inline,yeccpars2_352_/1}).
-file("erl_parse.yrl", 144).
yeccpars2_352_(__Stack0) ->
@@ -8934,7 +8934,7 @@ yeccpars2_352_(__Stack0) ->
[ __1 , __3 , [ ] ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8937).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8937).
-compile({inline,yeccpars2_353_/1}).
-file("erl_parse.yrl", 146).
yeccpars2_353_(__Stack0) ->
@@ -8952,7 +8952,7 @@ yeccpars2_355_(__Stack0) ->
build_gen_type ( __1 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8955).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8955).
-compile({inline,yeccpars2_356_/1}).
-file("erl_parse.yrl", 142).
yeccpars2_356_(__Stack0) ->
@@ -8962,7 +8962,7 @@ yeccpars2_356_(__Stack0) ->
normalise ( __1 ) , __3 }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8965).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8965).
-compile({inline,yeccpars2_358_/1}).
-file("erl_parse.yrl", 148).
yeccpars2_358_(__Stack0) ->
@@ -8971,7 +8971,7 @@ yeccpars2_358_(__Stack0) ->
{ type , ? line ( __1 ) , nil , [ ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8974).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8974).
-compile({inline,yeccpars2_360_/1}).
-file("erl_parse.yrl", 149).
yeccpars2_360_(__Stack0) ->
@@ -8980,7 +8980,7 @@ yeccpars2_360_(__Stack0) ->
{ type , ? line ( __1 ) , list , [ __2 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8983).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8983).
-compile({inline,yeccpars2_362_/1}).
-file("erl_parse.yrl", 150).
yeccpars2_362_(__Stack0) ->
@@ -8990,7 +8990,7 @@ yeccpars2_362_(__Stack0) ->
nonempty_list , [ __2 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 8993).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 8993).
-compile({inline,yeccpars2_365_/1}).
-file("erl_parse.yrl", 179).
yeccpars2_365_(__Stack0) ->
@@ -9017,7 +9017,7 @@ yeccpars2_371_(__Stack0) ->
build_bin_type ( [ __1 , __3 ] , __5 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9020).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9020).
-compile({inline,yeccpars2_373_/1}).
-file("erl_parse.yrl", 182).
yeccpars2_373_(__Stack0) ->
@@ -9027,7 +9027,7 @@ yeccpars2_373_(__Stack0) ->
[ __2 , abstract ( 0 , ? line ( __1 ) ) ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9030).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9030).
-compile({inline,yeccpars2_378_/1}).
-file("erl_parse.yrl", 187).
yeccpars2_378_(__Stack0) ->
@@ -9036,7 +9036,7 @@ yeccpars2_378_(__Stack0) ->
{ type , ? line ( __1 ) , binary , [ __2 , __4 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9039).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9039).
-compile({inline,yeccpars2_379_/1}).
-file("erl_parse.yrl", 184).
yeccpars2_379_(__Stack0) ->
@@ -9046,7 +9046,7 @@ yeccpars2_379_(__Stack0) ->
[ abstract ( 0 , ? line ( __1 ) ) , __2 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9049).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9049).
-compile({inline,yeccpars2_381_/1}).
-file("erl_parse.yrl", 167).
yeccpars2_381_(__Stack0) ->
@@ -9056,7 +9056,7 @@ yeccpars2_381_(__Stack0) ->
[ { type , ? line ( __1 ) , product , [ ] } , __4 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9059).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9059).
-compile({inline,yeccpars2_383_/1}).
-file("erl_parse.yrl", 138).
yeccpars2_383_(__Stack0) ->
@@ -9073,7 +9073,7 @@ yeccpars2_387_(__Stack0) ->
[ __1 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9076).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9076).
-compile({inline,yeccpars2_389_/1}).
-file("erl_parse.yrl", 154).
yeccpars2_389_(__Stack0) ->
@@ -9082,7 +9082,7 @@ yeccpars2_389_(__Stack0) ->
{ type , ? line ( __1 ) , record , [ __2 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9085).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9085).
-compile({inline,yeccpars2_391_/1}).
-file("erl_parse.yrl", 176).
yeccpars2_391_(__Stack0) ->
@@ -9100,7 +9100,7 @@ yeccpars2_393_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9103).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9103).
-compile({inline,yeccpars2_394_/1}).
-file("erl_parse.yrl", 155).
yeccpars2_394_(__Stack0) ->
@@ -9110,7 +9110,7 @@ yeccpars2_394_(__Stack0) ->
record , [ __2 | __4 ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9113).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9113).
-compile({inline,yeccpars2_395_/1}).
-file("erl_parse.yrl", 135).
yeccpars2_395_(__Stack0) ->
@@ -9127,7 +9127,7 @@ yeccpars2_397_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9130).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9130).
-compile({inline,yeccpars2_400_/1}).
-file("erl_parse.yrl", 170).
yeccpars2_400_(__Stack0) ->
@@ -9145,7 +9145,7 @@ yeccpars2_402_(__Stack0) ->
lift_unions ( __1 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9148).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9148).
-compile({inline,yeccpars2_405_/1}).
-file("erl_parse.yrl", 122).
yeccpars2_405_(__Stack0) ->
@@ -9156,7 +9156,7 @@ yeccpars2_405_(__Stack0) ->
skip_paren ( __3 ) ] }
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9159).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9159).
-compile({inline,yeccpars2_406_/1}).
-file("erl_parse.yrl", 127).
yeccpars2_406_(__Stack0) ->
@@ -9166,7 +9166,7 @@ yeccpars2_406_(__Stack0) ->
__2 , skip_paren ( __3 ) )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9169).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9169).
-compile({inline,yeccpars2_408_/1}).
-file("erl_parse.yrl", 131).
yeccpars2_408_(__Stack0) ->
@@ -9176,7 +9176,7 @@ yeccpars2_408_(__Stack0) ->
__2 , skip_paren ( __3 ) )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9179).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9179).
-compile({inline,yeccpars2_410_/1}).
-file("erl_parse.yrl", 103).
yeccpars2_410_(__Stack0) ->
@@ -9202,7 +9202,7 @@ yeccpars2_415_(__Stack0) ->
build_def ( __1 , __3 )
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9205).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9205).
-compile({inline,yeccpars2_418_/1}).
-file("erl_parse.yrl", 109).
yeccpars2_418_(__Stack0) ->
@@ -9332,7 +9332,7 @@ yeccpars2_446_(__Stack0) ->
[ __1 | __3 ]
end | __Stack].
--file("/clearcase/otp/erts/bootstrap/lib/stdlib/egen/erl_parse.erl", 9335).
+-file("/ldisk/bjorn/otp/bootstrap/lib/stdlib/egen/erl_parse.erl", 9335).
-compile({inline,yeccpars2_447_/1}).
-file("erl_parse.yrl", 90).
yeccpars2_447_(__Stack0) ->
diff --git a/bootstrap/lib/stdlib/include/erl_bits.hrl b/bootstrap/lib/stdlib/include/erl_bits.hrl
index 06bc1a75fc..54ebe58585 100644
--- a/bootstrap/lib/stdlib/include/erl_bits.hrl
+++ b/bootstrap/lib/stdlib/include/erl_bits.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%% This is an -*- erlang -*- file.
diff --git a/bootstrap/lib/stdlib/include/erl_compile.hrl b/bootstrap/lib/stdlib/include/erl_compile.hrl
index b49b0c3970..f779c4382c 100644
--- a/bootstrap/lib/stdlib/include/erl_compile.hrl
+++ b/bootstrap/lib/stdlib/include/erl_compile.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
diff --git a/bootstrap/lib/stdlib/include/ms_transform.hrl b/bootstrap/lib/stdlib/include/ms_transform.hrl
index 81a624b075..9937d48fef 100644
--- a/bootstrap/lib/stdlib/include/ms_transform.hrl
+++ b/bootstrap/lib/stdlib/include/ms_transform.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-compile({parse_transform,ms_transform}).
diff --git a/bootstrap/lib/stdlib/include/qlc.hrl b/bootstrap/lib/stdlib/include/qlc.hrl
index 54df6168e4..067fb83060 100644
--- a/bootstrap/lib/stdlib/include/qlc.hrl
+++ b/bootstrap/lib/stdlib/include/qlc.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-compile({parse_transform,qlc}).
diff --git a/bootstrap/lib/stdlib/include/zip.hrl b/bootstrap/lib/stdlib/include/zip.hrl
index 47b06a1cc3..2b5ddc1dfe 100644
--- a/bootstrap/lib/stdlib/include/zip.hrl
+++ b/bootstrap/lib/stdlib/include/zip.hrl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
diff --git a/configure.in b/configure.in
index eb29b13bcc..d0879c6291 100644
--- a/configure.in
+++ b/configure.in
@@ -97,7 +97,7 @@ fi
TARGET=$host
AC_SUBST(TARGET)
-if test X$cross_compiling = Xyes; then
+if test "$cross_compiling" = "yes"; then
CROSS_COMPILING=yes
else
CROSS_COMPILING=no
@@ -368,11 +368,12 @@ if test "$files" != "$pattern"; then
fi
pattern="lib/*/CONF_INFO"
files=`echo $pattern`
-if test "$files" != "$pattern"; then
+if test "$files" != "$pattern" || test -f erts/CONF_INFO; then
echo '*********************************************************************'
echo '********************** APPLICATIONS INFORMATION *******************'
echo '*********************************************************************'
echo
+ test ! -f erts/CONF_INFO || files="$files erts/CONF_INFO"
for infofile in $files; do
app=`dirname $infofile`; app=`basename $app`
printf "%-15s: " $app; cat $infofile
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 61244c7cd3..3b1edd7605 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -521,11 +521,13 @@ if test "X$host_os" = "Xwin32"; then
THR_DEFS="-DWIN32_THREADS"
THR_LIBS=
THR_LIB_NAME=win32_threads
+ THR_LIB_TYPE=win32_threads
else
AC_MSG_RESULT(no)
THR_DEFS=
THR_LIBS=
THR_LIB_NAME=
+ THR_LIB_TYPE=posix_unknown
dnl Try to find POSIX threads
@@ -586,6 +588,7 @@ dnl On ofs1 the '-pthread' switch should be used
AC_MSG_WARN([result yes guessed because of cross compilation])
fi
if test $nptl = yes; then
+ THR_LIB_TYPE=posix_nptl
need_nptl_incldir=no
AC_CHECK_HEADER(nptl/pthread.h,
[need_nptl_incldir=yes
@@ -653,6 +656,19 @@ fi
])
+AC_DEFUN(ERL_INTERNAL_LIBS,
+[
+
+ERTS_INTERNAL_X_LIBS=
+
+AC_CHECK_LIB(kstat, kstat_open,
+[AC_DEFINE(HAVE_KSTAT, 1, [Define if you have kstat])
+ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat"])
+
+AC_SUBST(ERTS_INTERNAL_X_LIBS)
+
+])
+
dnl ----------------------------------------------------------------------
dnl
dnl ERL_FIND_ETHR_LIB
@@ -676,10 +692,14 @@ AC_DEFUN(ERL_FIND_ETHR_LIB,
[
LM_CHECK_THR_LIB
+ERL_INTERNAL_LIBS
+ethr_have_native_atomics=no
+ethr_have_native_spinlock=no
ETHR_THR_LIB_BASE="$THR_LIB_NAME"
+ETHR_THR_LIB_BASE_TYPE="$THR_LIB_TYPE"
ETHR_DEFS="$THR_DEFS"
-ETHR_X_LIBS="$THR_LIBS"
+ETHR_X_LIBS="$THR_LIBS $ERTS_INTERNAL_X_LIBS"
ETHR_LIBS=
ETHR_LIB_NAME=
@@ -691,6 +711,7 @@ ethr_lib_name=ethread
case "$THR_LIB_NAME" in
win32_threads)
+ ETHR_THR_LIB_BASE_DIR=win
# * _WIN32_WINNT >= 0x0400 is needed for
# TryEnterCriticalSection
# * _WIN32_WINNT >= 0x0403 is needed for
@@ -716,10 +737,13 @@ case "$THR_LIB_NAME" in
if test $found_win32_winnt = no; then
AC_MSG_ERROR([-D_WIN32_WINNT missing in CPPFLAGS])
fi
+ ethr_have_native_atomics=yes
+ ethr_have_native_spinlock=yes
AC_DEFINE(ETHR_WIN32_THREADS, 1, [Define if you have win32 threads])
;;
pthread)
+ ETHR_THR_LIB_BASE_DIR=pthread
AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads])
case $host_os in
openbsd*)
@@ -775,9 +799,7 @@ case "$THR_LIB_NAME" in
if test $usable_sigaltstack = no; then
ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK"
fi
-
- AC_DEFINE(ETHR_INIT_MUTEX_IN_CHILD_AT_FORK, 1, \
-[Define if mutexes should be reinitialized (instead of unlocked) in child at fork.]) ;;
+ ;;
*) ;;
esac
@@ -808,6 +830,10 @@ case "$THR_LIB_NAME" in
[Define if you need the <nptl/pthread.h> header file.])
fi
+ AC_CHECK_HEADER(sched.h, \
+ AC_DEFINE(ETHR_HAVE_SCHED_H, 1, \
+[Define if you have the <sched.h> header file.]))
+
AC_CHECK_HEADER(sys/time.h, \
AC_DEFINE(ETHR_HAVE_SYS_TIME_H, 1, \
[Define if you have the <sys/time.h> header file.]))
@@ -823,26 +849,63 @@ case "$THR_LIB_NAME" in
dnl Check for functions
dnl
- AC_CHECK_FUNC(pthread_atfork, \
- AC_DEFINE(ETHR_HAVE_PTHREAD_ATFORK, 1, \
-[Define if you have the pthread_atfork function.]))
- AC_CHECK_FUNC(pthread_mutexattr_settype, \
- AC_DEFINE(ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE, 1, \
-[Define if you have the pthread_mutexattr_settype function.]))
- AC_CHECK_FUNC(pthread_mutexattr_setkind_np, \
- AC_DEFINE(ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP, 1, \
-[Define if you have the pthread_mutexattr_setkind_np function.]))
AC_CHECK_FUNC(pthread_spin_lock, \
- AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \
-[Define if you have the pthread_spin_lock function.]))
+ [ethr_have_native_spinlock=yes \
+ AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \
+[Define if you have the pthread_spin_lock function.])])
+
+ have_sched_yield=no
+ have_librt_sched_yield=no
+ AC_CHECK_FUNC(sched_yield, [have_sched_yield=yes])
+ if test $have_sched_yield = no; then
+ AC_CHECK_LIB(rt, sched_yield,
+ [have_librt_sched_yield=yes
+ ETHR_X_LIBS="$ETHR_X_LIBS -lrt"])
+ fi
+ if test $have_sched_yield = yes || test $have_librt_sched_yield = yes; then
+ AC_DEFINE(ETHR_HAVE_SCHED_YIELD, 1, [Define if you have the sched_yield() function.])
+ AC_MSG_CHECKING([whether sched_yield() returns an int])
+ sched_yield_ret_int=no
+ AC_TRY_COMPILE([
+ #ifdef ETHR_HAVE_SCHED_H
+ #include <sched.h>
+ #endif
+ ],
+ [int sched_yield();],
+ [sched_yield_ret_int=yes])
+ AC_MSG_RESULT([$sched_yield_ret_int])
+ if test $sched_yield_ret_int = yes; then
+ AC_DEFINE(ETHR_SCHED_YIELD_RET_INT, 1, [Define if sched_yield() returns an int.])
+ fi
+ fi
+
+ have_pthread_yield=no
+ AC_CHECK_FUNC(pthread_yield, [have_pthread_yield=yes])
+ if test $have_pthread_yield = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_YIELD, 1, [Define if you have the pthread_yield() function.])
+ AC_MSG_CHECKING([whether pthread_yield() returns an int])
+ pthread_yield_ret_int=no
+ AC_TRY_COMPILE([
+ #if defined(ETHR_NEED_NPTL_PTHREAD_H)
+ #include <nptl/pthread.h>
+ #elif defined(ETHR_HAVE_MIT_PTHREAD_H)
+ #include <pthread/mit/pthread.h>
+ #elif defined(ETHR_HAVE_PTHREAD_H)
+ #include <pthread.h>
+ #endif
+ ],
+ [int pthread_yield();],
+ [pthread_yield_ret_int=yes])
+ AC_MSG_RESULT([$pthread_yield_ret_int])
+ if test $pthread_yield_ret_int = yes; then
+ AC_DEFINE(ETHR_PTHREAD_YIELD_RET_INT, 1, [Define if pthread_yield() returns an int.])
+ fi
+ fi
have_pthread_rwlock_init=no
AC_CHECK_FUNC(pthread_rwlock_init, [have_pthread_rwlock_init=yes])
if test $have_pthread_rwlock_init = yes; then
- AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_INIT, 1, \
-[Define if you have a pthread_rwlock implementation that can be used.])
-
ethr_have_pthread_rwlockattr_setkind_np=no
AC_CHECK_FUNC(pthread_rwlockattr_setkind_np,
[ethr_have_pthread_rwlockattr_setkind_np=yes])
@@ -876,12 +939,42 @@ case "$THR_LIB_NAME" in
fi
fi
+ if test "$force_pthread_rwlocks" = "yes"; then
+ AC_DEFINE(ETHR_FORCE_PTHREAD_RWLOCK, 1, \
+[Define if you want to force usage of pthread rwlocks])
+
+ if test $have_pthread_rwlock_init = yes; then
+ AC_MSG_WARN([Forced usage of pthread rwlocks. Note that this implementation may suffer from starvation issues.])
+ else
+ AC_MSG_ERROR([User forced usage of pthread rwlock, but no such implementation was found])
+ fi
+ fi
AC_CHECK_FUNC(pthread_attr_setguardsize, \
AC_DEFINE(ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE, 1, \
[Define if you have the pthread_attr_setguardsize function.]))
+ linux_futex=no
+ AC_MSG_CHECKING([for Linux futexes])
+ AC_TRY_LINK([
+ #include <sys/syscall.h>
+ #include <unistd.h>
+ #include <linux/futex.h>
+ #include <sys/time.h>
+ ],
+ [
+ int i = 1;
+ syscall(__NR_futex, (void *) &i, FUTEX_WAKE, 1,
+ (void*)0,(void*)0, 0);
+ syscall(__NR_futex, (void *) &i, FUTEX_WAIT, 0,
+ (void*)0,(void*)0, 0);
+ return 0;
+ ],
+ linux_futex=yes)
+ AC_MSG_RESULT([$linux_futex])
+ test $linux_futex = yes && AC_DEFINE(ETHR_HAVE_LINUX_FUTEX, 1, [Define if you have a linux futex implementation.])
+
AC_MSG_CHECKING([for GCC atomic operations])
ethr_have_gcc_atomic_ops=no
AC_TRY_LINK([],
@@ -899,10 +992,69 @@ case "$THR_LIB_NAME" in
AC_MSG_RESULT([$ethr_have_gcc_atomic_ops])
test $ethr_have_gcc_atomic_ops = yes && AC_DEFINE(ETHR_HAVE_GCC_ATOMIC_OPS, 1, [Define if you have gcc atomic operations])
+ case "$host_cpu" in
+ sun4u | sparc64 | sun4v)
+ ethr_have_native_atomics=yes;;
+ i86pc | i386 | i486 | i586 | i686 | x86_64 | amd64)
+ ethr_have_native_atomics=yes;;
+ macppc | ppc | "Power Macintosh")
+ ethr_have_native_atomics=yes;;
+ tile)
+ ethr_have_native_atomics=yes;;
+ *)
+ ;;
+ esac
+
+ AC_MSG_CHECKING([for a usable libatomic_ops implementation])
+ case "x$with_libatomic_ops" in
+ xno | xyes | x)
+ libatomic_ops_include=
+ ;;
+ *)
+ if test -d "${with_libatomic_ops}/include"; then
+ libatomic_ops_include="-I$with_libatomic_ops/include"
+ CPPFLAGS="$CPPFLAGS $libatomic_ops_include"
+ else
+ AC_MSG_ERROR([libatomic_ops include directory $with_libatomic_ops/include not found])
+ fi;;
+ esac
+ ethr_have_libatomic_ops=no
+ AC_TRY_LINK([#include "atomic_ops.h"],
+ [
+ volatile AO_t x;
+ AO_t y;
+ int z;
+
+ AO_nop_full();
+ AO_store(&x, (AO_t) 0);
+ z = AO_load(&x);
+ z = AO_compare_and_swap(&x, (AO_t) 0, (AO_t) 1);
+ ],
+ [ethr_have_native_atomics=yes
+ ethr_have_libatomic_ops=yes])
+ AC_MSG_RESULT([$ethr_have_libatomic_ops])
+ if test $ethr_have_libatomic_ops = yes; then
+ AC_CHECK_SIZEOF(AO_t, ,
+ [
+ #include <stdio.h>
+ #include "atomic_ops.h"
+ ])
+ AC_DEFINE_UNQUOTED(ETHR_SIZEOF_AO_T, $ac_cv_sizeof_AO_t, [Define to the size of AO_t if libatomic_ops is used])
+
+ AC_DEFINE(ETHR_HAVE_LIBATOMIC_OPS, 1, [Define if you have libatomic_ops atomic operations])
+ if test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then
+ AC_DEFINE(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS, 1, [Define if you prefer libatomic_ops native ethread implementations])
+ fi
+ ETHR_DEFS="$ETHR_DEFS $libatomic_ops_include"
+ elif test "x$with_libatomic_ops" != "xno" && test "x$with_libatomic_ops" != "x"; then
+ AC_MSG_ERROR([No usable libatomic_ops implementation found])
+ fi
+
dnl Restore LIBS
LIBS=$saved_libs
dnl restore CPPFLAGS
CPPFLAGS=$saved_cppflags
+
;;
*)
;;
@@ -918,16 +1070,23 @@ fi
if test "x$ETHR_THR_LIB_BASE" != "x"; then
ETHR_DEFS="-DUSE_THREADS $ETHR_DEFS"
- ETHR_LIBS="-l$ethr_lib_name $ETHR_X_LIBS"
+ ETHR_LIBS="-l$ethr_lib_name -lerts_internal_r $ETHR_X_LIBS"
ETHR_LIB_NAME=$ethr_lib_name
fi
AC_CHECK_SIZEOF(void *)
AC_DEFINE_UNQUOTED(ETHR_SIZEOF_PTR, $ac_cv_sizeof_void_p, [Define to the size of pointers])
-if test "X$disable_native_ethr_impls" = "Xyes"; then
- AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations])
-fi
+AC_ARG_ENABLE(native-ethr-impls,
+ AS_HELP_STRING([--disable-native-ethr-impls],
+ [disable native ethread implementations]),
+[ case "$enableval" in
+ no) disable_native_ethr_impls=yes ;;
+ *) disable_native_ethr_impls=no ;;
+ esac ], disable_native_ethr_impls=no)
+
+test "X$disable_native_ethr_impls" = "Xyes" &&
+ AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations])
AC_ARG_ENABLE(prefer-gcc-native-ethr-impls,
AS_HELP_STRING([--enable-prefer-gcc-native-ethr-impls],
@@ -940,6 +1099,21 @@ AC_ARG_ENABLE(prefer-gcc-native-ethr-impls,
test $enable_prefer_gcc_native_ethr_impls = yes &&
AC_DEFINE(ETHR_PREFER_GCC_NATIVE_IMPLS, 1, [Define if you prefer gcc native ethread implementations])
+AC_ARG_ENABLE(ethread-pre-pentium4-compatibility,
+ AS_HELP_STRING([--enable-ethread-pre-pentium4-compatibility],
+ [enable compatibility with x86 processors before pentium 4 (back to 486) in the ethread library]),
+[ case "$enableval" in
+ yes) enable_ethread_pre_pentium4_compatibility=yes ;;
+ *) enable_ethread_pre_pentium4_compatibilit=no ;;
+ esac ], enable_ethread_pre_pentium4_compatibilit=no)
+
+test $enable_ethread_pre_pentium4_compatibilit = yes &&
+ AC_DEFINE(ETHR_PRE_PENTIUM4_COMPAT, 1, [Define if you want compatibilty with x86 processors before pentium4.])
+
+AC_ARG_WITH(libatomic_ops,
+ AS_HELP_STRING([--with-libatomic_ops=PATH],
+ [use libatomic_ops with the ethread library]))
+
AC_DEFINE(ETHR_HAVE_ETHREAD_DEFINES, 1, \
[Define if you have all ethread defines])
@@ -948,6 +1122,7 @@ AC_SUBST(ETHR_LIBS)
AC_SUBST(ETHR_LIB_NAME)
AC_SUBST(ETHR_DEFS)
AC_SUBST(ETHR_THR_LIB_BASE)
+AC_SUBST(ETHR_THR_LIB_BASE_DIR)
])
diff --git a/erts/configure.in b/erts/configure.in
index bfbed302e3..6b494ef127 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -61,6 +61,9 @@ if test x"${ERL_TOP}/erts" != x"$srcdir"; then
fi
erl_top=${ERL_TOP}
+# Remove old configuration information
+/bin/rm -f "$ERL_TOP/erts/CONF_INFO"
+
# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# echo X
# echo "X srcdir = $srcdir"
@@ -87,6 +90,13 @@ else
host_os=$host
fi
+if test "$cross_compiling" = "yes"; then
+ CROSS_COMPILING=yes
+else
+ CROSS_COMPILING=no
+fi
+AC_SUBST(CROSS_COMPILING)
+
ERL_XCOMP_SYSROOT_INIT
AC_ISC_POSIX
@@ -198,9 +208,6 @@ AC_ARG_ENABLE(native-libs,
AC_ARG_ENABLE(tsp,
[ --enable-tsp compile tsp app])
-AC_ARG_ENABLE(elib-malloc,
-[ --enable-elib-malloc use elib_malloc instead of normal malloc])
-
AC_ARG_ENABLE(fp-exceptions,
[ --enable-fp-exceptions Use hardware floating point exceptions (default if hipe enabled)],
[ case "$enableval" in
@@ -277,20 +284,6 @@ AC_ARG_ENABLE(clock-gettime,
*) clock_gettime_correction=yes ;;
esac ], clock_gettime_correction=unknown)
-AC_ARG_ENABLE(native-ethr-impls,
-[ --enable-native-ethr-impls enable native ethread implementations
- --disable-native-ethr-impls disable native ethread implementations],
-[ case "$enableval" in
- no) disable_native_ethr_impls=yes ;;
- *) disable_native_ethr_impls=no ;;
- esac ], disable_native_ethr_impls=no)
-
-dnl Defined in libraries/megaco/configure.in but we need it here
-dnl also in order to show it to the "top user"
-
-AC_ARG_ENABLE(megaco_flex_scanner_lineno,
-[ --disable-megaco-flex-scanner-lineno disable megaco flex scanner lineno])
-
dnl Magic test for clearcase.
OTP_RELEASE=
if test "${ERLANG_COMMERCIAL_BUILD}" != ""; then
@@ -1049,6 +1042,42 @@ if test $ERTS_BUILD_SMP_EMU = yes; then
fi
AC_DEFINE(ERTS_HAVE_SMP_EMU, 1, [Define if the smp emulator is built])
+
+ case "$ethr_have_native_atomics-$ethr_have_native_spinlock" in
+ yes-*)
+ ;;
+
+ no-yes)
+
+ test -f "$ERL_TOP/erts/CONF_INFO" ||
+ echo "" > "$ERL_TOP/erts/CONF_INFO"
+ cat >> $ERL_TOP/erts/CONF_INFO <<EOF
+
+ No native atomic implementation available.
+ Fallbacks implemented using spinlocks will be
+ used. Note that the performance of the SMP
+ runtime system will suffer due to this.
+
+EOF
+ ;;
+
+ no-no)
+
+ test -f "$ERL_TOP/erts/CONF_INFO" ||
+ echo "" > "$ERL_TOP/erts/CONF_INFO"
+ cat >> "$ERL_TOP/erts/CONF_INFO" <<EOF
+
+ No native atomic implementation, nor no native
+ spinlock implementation available. Fallbacks
+ implemented using mutexes will be used. Note
+ that the performance of the SMP runtime system
+ will suffer much due to this.
+
+EOF
+ ;;
+
+ esac
+
enable_threads=force
fi
@@ -1149,17 +1178,15 @@ else
enable_child_waiter_thread=yes
;;
linux*)
- AC_DEFINE(USE_RECURSIVE_MALLOC_MUTEX,[1],
- [Define if malloc should use a recursive mutex])
AC_MSG_CHECKING([whether dlopen() needs to be called before first call to dlerror()])
- if test "x$ETHR_THR_LIB_BASE_NAME" != "xnptl"; then
+ if test "x$ETHR_THR_LIB_BASE_TYPE" != "xposix_nptl"; then
AC_DEFINE(ERTS_NEED_DLOPEN_BEFORE_DLERROR,[1],
[Define if dlopen() needs to be called before first call to dlerror()])
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
- if test "x$ETHR_THR_LIB_BASE_NAME" != "xnptl"; then
+ if test "x$ETHR_THR_LIB_BASE_TYPE" != "xposix_nptl"; then
# Child waiter thread cannot be enabled
disable_child_waiter_thread=yes
enable_child_waiter_thread=no
@@ -1221,13 +1248,7 @@ fi
AC_SUBST(EMU_LOCK_CHECKING)
-ERTS_INTERNAL_X_LIBS=
-
-AC_CHECK_LIB(kstat, kstat_open,
-[AC_DEFINE(HAVE_KSTAT, 1, [Define if you have kstat])
-ERTS_INTERNAL_X_LIBS="$ERTS_INTERNAL_X_LIBS -lkstat"])
-
-AC_SUBST(ERTS_INTERNAL_X_LIBS)
+ERL_INTERNAL_LIBS
dnl THR_LIBS and THR_DEFS are only used by odbc
THR_LIBS=$ETHR_X_LIBS
@@ -2983,17 +3004,6 @@ if test "x$HIPE_ENABLED" = "xyes" ; then
fi
#
-# Check if we should use elib_malloc.
-#
-
-if test X${enable_elib_malloc} = Xyes; then
- AC_DEFINE(ENABLE_ELIB_MALLOC,[],[Define to enable use of elib_malloc (a malloc() replacement)])
- AC_DEFINE(ELIB_HEAP_SBRK,[],[Elib sbrk])
- AC_DEFINE(ELIB_ALLOC_IS_CLIB,[],[Use elib malloc as clib])
- AC_DEFINE(ELIB_SORTED_BLOCKS,[],[Define to enable the use of sorted blocks when using elib_malloc])
-fi
-
-#
# Check for working poll().
#
AC_MSG_CHECKING([for working poll()])
@@ -3605,10 +3615,10 @@ dnl Should one use EXEEXT or ac_exeext?
if test -f "$erl_xcomp_sysroot$SSL_BINDIR/openssl$EXEEXT"; then
if test "$cross_compiling" = "yes"; then
dnl Cannot test it; hope it is working...
- OPENSSL_CMD="$SSL_BINDIR/openssl"
+ OPENSSL_CMD="$erl_xcomp_sysroot$SSL_BINDIR/openssl$EXEEXT"
else
- if "$SSL_BINDIR/openssl" version > /dev/null 2>&1; then
- OPENSSL_CMD="$SSL_BINDIR/openssl"
+ if "$SSL_BINDIR/openssl$EXEEXT" version > /dev/null 2>&1; then
+ OPENSSL_CMD="$SSL_BINDIR/openssl$EXEEXT"
else
is_real_ssl=no
fi
@@ -3617,6 +3627,9 @@ dnl Should one use EXEEXT or ac_exeext?
is_real_ssl=no
fi
if test "x$is_real_ssl" = "xyes" ; then
+ if test "$MIXED_CYGWIN" = "yes"; then
+ OPENSSL_CMD=`cygpath -s -m "$OPENSSL_CMD"` 2> /dev/null
+ fi
SSL_INCLUDE="-I$dir/include"
old_CPPFLAGS=$CPPFLAGS
CPPFLAGS=$SSL_INCLUDE
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index df80142ce1..f477280a6f 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -603,6 +603,24 @@
<item>
<p>Force ets memory block to be moved on realloc.</p>
</item>
+ <tag><marker id="+rg"><c><![CDATA[+rg ReaderGroupsLimit]]></c></marker></tag>
+ <item>
+ <p>Limits the amount of reader groups used by read/write locks
+ optimized for read operations in the Erlang runtime system. By
+ default the reader groups limit equals 8.</p>
+ <p>When the amount of schedulers is less than or equal to the reader
+ groups limit, each scheduler has its own reader group. When the
+ amount of schedulers is larger than the reader groups limit,
+ schedulers share reader groups. Shared reader groups degrades
+ read lock and read unlock performance while a large amount of
+ reader groups degrades write lock performance, so the limit is a
+ tradeoff between performance for read operations and performance
+ for write operations. Each reader group currently consumes 64 byte
+ in each read/write lock. Also note that a runtime system using
+ shared reader groups benefits from <seealso marker="#+sbt">binding
+ schedulers to logical processors</seealso>, since the reader groups
+ are distributed better between schedulers.</p>
+ </item>
<tag><marker id="+S"><c><![CDATA[+S Schedulers:SchedulerOnline]]></c></marker></tag>
<item>
<p>Sets the amount of scheduler threads to create and scheduler
@@ -667,8 +685,8 @@
<seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, default_bind)</seealso>.
</p></item>
</taglist>
- <p>Binding of schedulers are currently only supported on newer
- Linux and Solaris systems.</p>
+ <p>Binding of schedulers is currently only supported on newer
+ Linux, Solaris, and Windows systems.</p>
<p>If no CPU topology is available when the <c>+sbt</c> flag
is processed and <c>BindType</c> is any other type than
<c>u</c>, the runtime system will fail to start. CPU
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 77a628e82b..5d8a96a910 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -499,7 +499,7 @@ iolist() = [char() | binary() | iolist()]
<name>erlang:cancel_timer(TimerRef) -> Time | false</name>
<fsummary>Cancel a timer</fsummary>
<type>
- <v>TimerRef = ref()</v>
+ <v>TimerRef = reference()</v>
<v>Time = int()</v>
</type>
<desc>
@@ -763,7 +763,7 @@ false</pre>
<name>erlang:demonitor(MonitorRef) -> true</name>
<fsummary>Stop monitoring</fsummary>
<type>
- <v>MonitorRef = ref()</v>
+ <v>MonitorRef = reference()</v>
</type>
<desc>
<p>If <c>MonitorRef</c> is a reference which the calling process
@@ -803,7 +803,7 @@ false</pre>
<name>erlang:demonitor(MonitorRef, OptionList) -> true|false</name>
<fsummary>Stop monitoring</fsummary>
<type>
- <v>MonitorRef = ref()</v>
+ <v>MonitorRef = reference()</v>
<v>OptionList = [Option]</v>
<v>Option = flush</v>
<v>Option = info</v>
@@ -2160,7 +2160,7 @@ os_prompt%</pre>
</desc>
</func>
<func>
- <name>make_ref() -> ref()</name>
+ <name>make_ref() -> reference()</name>
<fsummary>Return an almost unique reference</fsummary>
<desc>
<p>Returns an almost unique reference.</p>
@@ -2690,7 +2690,7 @@ os_prompt%</pre>
<name>node(Arg) -> Node</name>
<fsummary>At which node is a pid, port or reference located</fsummary>
<type>
- <v>Arg = pid() | port() | ref()</v>
+ <v>Arg = pid() | port() | reference()</v>
<v>Node = node()</v>
</type>
<desc>
@@ -2767,8 +2767,10 @@ os_prompt%</pre>
Otherwise, some other point in time is chosen. It is also
guaranteed that subsequent calls to this BIF returns
continuously increasing values. Hence, the return value from
- <c>now()</c> can be used to generate unique time-stamps. It
- can only be used to check the local time of day if
+ <c>now()</c> can be used to generate unique time-stamps,
+ and if it is called in a tight loop on a fast machine
+ the time of the node can become skewed.</p>
+ <p>It can only be used to check the local time of day if
the time-zone info of the underlying operating system is
properly configured.</p>
</desc>
@@ -4096,7 +4098,7 @@ os_prompt%</pre>
<name>erlang:read_timer(TimerRef) -> int() | false</name>
<fsummary>Number of milliseconds remaining for a timer</fsummary>
<type>
- <v>TimerRef = ref()</v>
+ <v>TimerRef = reference()</v>
</type>
<desc>
<p><c>TimerRef</c> is a timer reference returned by
@@ -4119,7 +4121,7 @@ os_prompt%</pre>
<name>erlang:ref_to_list(Ref) -> string()</name>
<fsummary>Text representation of a reference</fsummary>
<type>
- <v>Ref = ref()</v>
+ <v>Ref = reference()</v>
</type>
<desc>
<p>Returns a string which corresponds to the text
@@ -4298,7 +4300,7 @@ true</pre>
<v>Dest = pid() | RegName </v>
<v>&nbsp;LocalPid = pid() (of a process, alive or dead, on the local node)</v>
<v>Msg = term()</v>
- <v>TimerRef = ref()</v>
+ <v>TimerRef = reference()</v>
</type>
<desc>
<p>Starts a timer which will send the message <c>Msg</c>
@@ -4827,7 +4829,7 @@ true</pre>
<v>&nbsp;LocalPid = pid() (of a process, alive or dead, on the local node)</v>
<v>&nbsp;RegName = atom()</v>
<v>Msg = term()</v>
- <v>TimerRef = ref()</v>
+ <v>TimerRef = reference()</v>
</type>
<desc>
<p>Starts a timer which will send the message
@@ -5173,9 +5175,9 @@ true</pre>
schedulers actually have bound as requested, call
<seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.
</p>
- <p>Schedulers can currently only be bound on newer Linux
- and Solaris systems, but more systems will be supported
- in the future.
+ <p>Schedulers can currently only be bound on newer Linux,
+ Solaris, and Windows systems, but more systems will be
+ supported in the future.
</p>
<p>In order for the runtime system to be able to bind schedulers,
the CPU topology needs to be known. If the runtime system fails
@@ -5362,7 +5364,7 @@ true</pre>
<p>Returns <c>{Allocator, Version, Features, Settings}.</c></p>
<p>Types:</p>
<list type="bulleted">
- <item><c>Allocator = undefined | elib_malloc | glibc</c></item>
+ <item><c>Allocator = undefined | glibc</c></item>
<item><c>Version = [int()]</c></item>
<item><c>Features = [atom()]</c></item>
<item><c>Settings = [{Subsystem, [{Parameter, Value}]}]</c></item>
@@ -5377,7 +5379,7 @@ true</pre>
implementation used. If <c>Allocator</c> equals
<c>undefined</c>, the <c>malloc()</c> implementation
used could not be identified. Currently
- <c>elib_malloc</c> and <c>glibc</c> can be identified.</p>
+ <c>glibc</c> can be identified.</p>
</item>
<item>
<p><c>Version</c> is a list of integers (but not a
@@ -5531,7 +5533,7 @@ true</pre>
<c>CpuTopology</c> type to change.
</p>
</item>
- <tag><c>{cpu_topology, defined}</c></tag>
+ <tag><marker id="system_info_cpu_topology_defined"><c>{cpu_topology, defined}</c></marker></tag>
<item>
<p>Returns the user defined <c>CpuTopology</c>. For more
information see the documentation of
@@ -5541,12 +5543,14 @@ true</pre>
argument.
</p>
</item>
- <tag><c>{cpu_topology, detected}</c></tag>
+ <tag><marker id="system_info_cpu_topology_detected"><c>{cpu_topology, detected}</c></marker></tag>
<item>
<p>Returns the automatically detected <c>CpuTopology</c>. The
emulator currently only detects the CPU topology on some newer
- linux and solaris systems. For more information see the
- documentation of the
+ Linux, Solaris, and Windows systems. On Windows system with
+ more than 32 logical processors the CPU topology is not detected.
+ </p>
+ <p>For more information see the documentation of the
<seealso marker="#system_info_cpu_topology">cpu_topology</seealso>
argument.
</p>
@@ -5604,52 +5608,9 @@ true</pre>
</item>
<tag><c>elib_malloc</c></tag>
<item>
- <p>If the emulator uses the <c>elib_malloc</c> memory
- allocator, a list of two-element tuples containing status
- information is returned; otherwise, <c>false</c> is
- returned. The list currently contains the following
- two-element tuples (all sizes are presented in bytes):</p>
- <taglist>
- <tag><c>{heap_size, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the current heap size.</p>
- </item>
- <tag><c>{max_alloced_size, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the maximum amount of memory
- allocated on the heap since the emulator started.</p>
- </item>
- <tag><c>{alloced_size, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the current amount of memory
- allocated on the heap.</p>
- </item>
- <tag><c>{free_size, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the current amount of free
- memory on the heap.</p>
- </item>
- <tag><c>{no_alloced_blocks, No}</c></tag>
- <item>
- <p>Where <c>No</c> is the current number of allocated
- blocks on the heap.</p>
- </item>
- <tag><c>{no_free_blocks, No}</c></tag>
- <item>
- <p>Where <c>No</c> is the current number of free blocks
- on the heap.</p>
- </item>
- <tag><c>{smallest_alloced_block, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the size of the smallest
- allocated block on the heap.</p>
- </item>
- <tag><c>{largest_free_block, Size}</c></tag>
- <item>
- <p>Where <c>Size</c> is the size of the largest free
- block on the heap.</p>
- </item>
- </taglist>
+ <p>This option will be removed in a future release.
+ The return value will always be <c>false</c> since
+ the elib_malloc allocator has been removed.</p>
</item>
<tag><c>fullsweep_after</c></tag>
<item>
@@ -5725,11 +5686,34 @@ true</pre>
information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter
in the ERTS User's Guide.</p>
</item>
- <tag><c>logical_processors</c></tag>
+ <tag><marker id="logical_processors"><c>logical_processors</c></marker></tag>
<item>
- <p>Returns the number of logical processors detected on the
- system as an integer or the atom <c>unknown</c> if the
- emulator wasn't able to detect any.
+ <p>Returns the detected number of logical processors configured
+ on the system. The return value is either an integer, or
+ the atom <c>unknown</c> if the emulator wasn't able to
+ detect logical processors configured.
+ </p>
+ </item>
+ <tag><marker id="logical_processors_available"><c>logical_processors_available</c></marker></tag>
+ <item>
+ <p>Returns the detected number of logical processors available to
+ the Erlang runtime system. The return value is either an
+ integer, or the atom <c>unknown</c> if the emulator wasn't
+ able to detect logical processors available. The number
+ of logical processors available is less than or equal to
+ the number of <seealso marker="#logical_processors_online">logical
+ processors online</seealso>.
+ </p>
+ </item>
+ <tag><marker id="logical_processors_online"><c>logical_processors_online</c></marker></tag>
+ <item>
+ <p>Returns the detected number of logical processors online on
+ the system. The return value is either an integer,
+ or the atom <c>unknown</c> if the emulator wasn't able to
+ detect logical processors online. The number of logical
+ processors online is less than or equal to the number of
+ <seealso marker="#logical_processors">logical processors
+ configured</seealso>.
</p>
</item>
<tag><c>machine</c></tag>
@@ -5934,6 +5918,26 @@ true</pre>
<c>get_tcw</c> in "Match Specifications in Erlang",
<seealso marker="erts:match_spec#get_tcw">ERTS User's Guide</seealso>.</p>
</item>
+ <tag><marker id="update_cpu_info"><c>update_cpu_info</c></marker></tag>
+ <item>
+ <p>The runtime system rereads the CPU information available and
+ updates its internally stored information about the
+ <seealso marker="#system_info_cpu_topology_detected">detected CPU
+ topology</seealso> and the amount of logical processors
+ <seealso marker="#logical_processors">configured</seealso>,
+ <seealso marker="#logical_processors_online">online</seealso>, and
+ <seealso marker="#logical_processors_available">available</seealso>.
+ If the CPU information has changed since the last time it was read,
+ the atom <c>changed</c> is returned; otherwise, the atom
+ <c>unchanged</c> is returned. If the CPU information has changed
+ you probably want to
+ <seealso marker="#system_flag_schedulers_online">adjust the amount
+ of schedulers online</seealso>. You typically want to have as
+ many schedulers online as
+ <seealso marker="#logical_processors_available">logical processors
+ available</seealso>.
+ </p>
+ </item>
<tag><marker id="system_info_version"><c>version</c></marker></tag>
<item>
<p>Returns a string containing the version number of the
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index eca6121a1e..ed0d1b3fa6 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -199,6 +199,14 @@ MKDIR = @MKDIR@
USING_MINGW=@MIXED_CYGWIN_MINGW@
+ifeq ($(TARGET),win32)
+LIB_PREFIX=
+LIB_SUFFIX=.lib
+else
+LIB_PREFIX=lib
+LIB_SUFFIX=.a
+endif
+
OMIT_OMIT_FP=no
ifeq (@EMU_LOCK_CHECKING@,yes)
@@ -279,16 +287,11 @@ endif
ifeq ($(TARGET),win32)
LIBS += -L$(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE) -lepcre
-DEPLIBS += $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/epcre.lib
else
-LIBS += $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/libepcre.a
-DEPLIBS += \
- $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/libepcre.a \
- $(ERL_TOP)/erts/lib/internal/$(TARGET)/liberts_internal.a
-# rem liberts_internal.a
+LIBS += $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/$(LIB_PREFIX)epcre$(LIB_SUFFIX)
endif
-ELIB_FLAGS = -DENABLE_ELIB_MALLOC -DELIB_ALLOC_IS_CLIB -DELIB_HEAP_SBRK
+DEPLIBS += $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE)/$(LIB_PREFIX)epcre$(LIB_SUFFIX)
PERFCTR_PATH=@PERFCTR_PATH@
USE_PERFCTR=@USE_PERFCTR@
@@ -305,7 +308,19 @@ LIBSCTP = @LIBSCTP@
ORG_THR_LIBS=@EMU_THR_LIBS@
THR_LIB_NAME=@EMU_THR_LIB_NAME@
-THR_LIBS=$(subst -l$(THR_LIB_NAME),-l$(THR_LIB_NAME)$(TYPEMARKER),$(ORG_THR_LIBS))
+ifneq ($(strip $(THR_LIB_NAME)),)
+DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal_r$(TYPEMARKER)$(LIB_SUFFIX) \
+ $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)ethread$(TYPEMARKER)$(LIB_SUFFIX)
+else
+DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal$(TYPEMARKER)$(LIB_SUFFIX)
+endif
+
+THR_LIBS=$(subst -l$(THR_LIB_NAME),-l$(THR_LIB_NAME)$(TYPEMARKER), \
+ $(subst -lerts_internal_r,-lerts_internal_r$(TYPEMARKER),$(ORG_THR_LIBS)))
+
+LIBS += $(THR_LIBS)
+
+ifneq ($(findstring erts_internal_r, $(THR_LIBS)),erts_internal_r)
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
ERTS_INTERNAL_LIB=erts_internal
@@ -317,7 +332,9 @@ ERTS_INTERNAL_LIB=erts_internal
endif
endif
-LIBS += $(THR_LIBS) -l$(ERTS_INTERNAL_LIB)$(TYPEMARKER)
+LIBS += -l$(ERTS_INTERNAL_LIB)$(TYPEMARKER)
+
+endif # erts_internal_r
LIBS += @LIBRT@
@@ -441,8 +458,6 @@ release_spec: all
ifeq ($(ERLANG_OSTYPE), unix)
$(INSTALL_PROGRAM) $(BINDIR)/$(CS_EXECUTABLE) $(RELSYSDIR)/bin
endif
- $(INSTALL_DIR) $(RELEASE_PATH)/usr/include/obsolete
- $(INSTALL_DATA) obsolete/driver.h $(RELEASE_PATH)/usr/include/obsolete
endif
endif
@@ -636,9 +651,6 @@ $(BINDIR)/$(CS_EXECUTABLE): $(CS_SRC)
$(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \
$(CS_CFLAGS) $(COMMON_INCLUDES) $(CS_SRC) $(CS_LIBS)
-$(OBJDIR)/%.elib.o: beam/%.c
- $(CC) $(ELIB_FLAGS) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
-
$(OBJDIR)/%.kp.o: sys/common/%.c
$(CC) -DERTS_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
@@ -647,9 +659,6 @@ $(OBJDIR)/%.nkp.o: sys/common/%.c
ifeq ($(GCC),yes)
-$(OBJDIR)/erl_obsolete.o: beam/erl_obsolete.c
- $(CC) $(subst -Wstrict-prototypes, , $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS))) $(INCLUDES) -c $< -o $@
-
$(OBJDIR)/erl_goodfit_alloc.o: beam/erl_goodfit_alloc.c
$(CC) $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CFLAGS)) $(INCLUDES) -c $< -o $@
endif
@@ -724,7 +733,7 @@ RUN_OBJS = \
$(OBJDIR)/erl_fun.o $(OBJDIR)/erl_bif_port.o \
$(OBJDIR)/erl_term.o $(OBJDIR)/erl_node_tables.o \
$(OBJDIR)/erl_monitors.o $(OBJDIR)/erl_process_dump.o \
- $(OBJDIR)/erl_obsolete.o $(OBJDIR)/erl_bif_timer.o \
+ $(OBJDIR)/erl_bif_timer.o \
$(OBJDIR)/erl_drv_thread.o $(OBJDIR)/erl_bif_chksum.o \
$(OBJDIR)/erl_bif_re.o $(OBJDIR)/erl_unicode.o \
$(OBJDIR)/packet_parser.o $(OBJDIR)/safe_hash.o \
@@ -748,15 +757,13 @@ OS_OBJS = \
$(OBJDIR)/sys_time.o \
$(OBJDIR)/sys_interrupt.o \
$(OBJDIR)/sys_env.o \
- $(OBJDIR)/dosmap.o \
- $(OBJDIR)/elib_malloc.o
+ $(OBJDIR)/dosmap.o
else
OS_OBJS = \
$(OBJDIR)/sys.o \
$(OBJDIR)/driver_tab.o \
$(OBJDIR)/unix_efile.o \
$(OBJDIR)/gzio.o \
- $(OBJDIR)/elib_malloc.o \
$(OBJDIR)/elib_memmove.o
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
@@ -820,16 +827,6 @@ BASE_OBJS = $(RUN_OBJS) $(EMU_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS)
OBJS = $(BASE_OBJS) $(DRV_OBJS)
-ELIB_C_FILES = beam/elib_malloc.c \
- beam/elib_memmove.c \
- beam/erl_bif_info.c \
- beam/utils.c \
- beam/erl_alloc.c
-
-MOD_OBJS_ELIB = $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(ELIB_C_FILES)))
-OBJS_ELIB = $(patsubst %.o,%.elib.o,$(MOD_OBJS_ELIB)) \
- $(filter-out $(MOD_OBJS_ELIB),$(OBJS))
-
########################################
# HiPE section
@@ -921,10 +918,6 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
$(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS)
-$(BINDIR)/$(EMULATOR_EXECUTABLE_ELIB): $(INIT_OBJS) $(OBJS_ELIB) $(DEPLIBS)
- $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE_ELIB) \
- $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS_ELIB) $(LIBS)
-
endif
#
@@ -1019,7 +1012,7 @@ depend:
$(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \
| $(SED_DEPEND) >> $(TARGET)/depend.mk
ifneq ($(TARGET),win32)
- $(DEP_CC) $(DEP_FLAGS) $(ELIB_FLAGS) $(ELIB_C_FILES) \
+ $(DEP_CC) $(DEP_FLAGS) $(ELIB_C_FILES) \
| $(SED_ELIB_DEPEND) >> $(TARGET)/depend.mk
endif
ifdef HIPE_ENABLED
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index e2a79d6e4f..6b3c106a97 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -41,8 +41,7 @@ static erts_smp_rwmtx_t atom_table_lock;
#define atom_read_unlock() erts_smp_rwmtx_runlock(&atom_table_lock)
#define atom_write_lock() erts_smp_rwmtx_rwlock(&atom_table_lock)
#define atom_write_unlock() erts_smp_rwmtx_rwunlock(&atom_table_lock)
-#define atom_init_lock() erts_smp_rwmtx_init(&atom_table_lock, \
- "atom_tab")
+
#if 0
#define ERTS_ATOM_PUT_OPS_STAT
#endif
@@ -304,12 +303,17 @@ init_atom_table(void)
HashFunctions f;
int i;
Atom a;
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
#ifdef ERTS_ATOM_PUT_OPS_STAT
erts_smp_atomic_init(&atom_put_ops, 0);
#endif
- atom_init_lock();
+ erts_smp_rwmtx_init_opt(&atom_table_lock, &rwmtx_opt, "atom_tab");
+
f.hash = (H_FUN) atom_hash;
f.cmp = (HCMP_FUN) atom_cmp;
f.alloc = (HALLOC_FUN) atom_alloc;
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 28f69b9460..0815cdbc7f 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -432,6 +432,7 @@ atom raw
atom re
atom re_pattern
atom re_run_trap
+atom read_concurrency
atom ready_input
atom ready_output
atom ready_async
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 596ad9a010..4fc271d41c 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -402,7 +402,7 @@ check_process_code(Process* rp, Module* modp)
BeamInstr* end;
Eterm* sp;
#ifndef HYBRID /* FIND ME! */
- ErlFunThing* funp;
+ struct erl_off_heap_header* oh;
int done_gc = 0;
#endif
@@ -470,27 +470,30 @@ check_process_code(Process* rp, Module* modp)
#ifndef HYBRID /* FIND ME! */
rescan:
- for (funp = MSO(rp).funs; funp; funp = funp->next) {
- BeamInstr* fun_code;
-
- fun_code = funp->fe->address;
-
- if (INSIDE((BeamInstr *) funp->fe->address)) {
- if (done_gc) {
- return am_true;
- } else {
- /*
- * Try to get rid of this fun by garbage collecting.
- * Clear both fvalue and ftrace to make sure they
- * don't hold any funs.
- */
- rp->freason = EXC_NULL;
- rp->fvalue = NIL;
- rp->ftrace = NIL;
- done_gc = 1;
- FLAGS(rp) |= F_NEED_FULLSWEEP;
- (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
- goto rescan;
+ for (oh = MSO(rp).first; oh; oh = oh->next) {
+ if (thing_subtag(oh->thing_word) == FUN_SUBTAG) {
+ ErlFunThing* funp = (ErlFunThing*) oh;
+ BeamInstr* fun_code;
+
+ fun_code = funp->fe->address;
+
+ if (INSIDE((BeamInstr *) funp->fe->address)) {
+ if (done_gc) {
+ return am_true;
+ } else {
+ /*
+ * Try to get rid of this fun by garbage collecting.
+ * Clear both fvalue and ftrace to make sure they
+ * don't hold any funs.
+ */
+ rp->freason = EXC_NULL;
+ rp->fvalue = NIL;
+ rp->ftrace = NIL;
+ done_gc = 1;
+ FLAGS(rp) |= F_NEED_FULLSWEEP;
+ (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity);
+ goto rescan;
+ }
}
}
}
diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h
index b5d5b3c203..ebc171078d 100644
--- a/erts/emulator/beam/beam_bp.h
+++ b/erts/emulator/beam/beam_bp.h
@@ -123,7 +123,7 @@ typedef struct {
Uint ms;
Uint s;
Uint us;
- Uint *pc;
+ BeamInstr *pc;
} process_breakpoint_time_t; /* used within psd */
extern erts_smp_spinlock_t erts_bp_lock;
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index c0680086aa..260f349563 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3385,8 +3385,8 @@ apply_bif_or_nif_epilogue:
HTOP += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
pb->size = num_bytes;
- pb->next = MSO(c_p).mso;
- MSO(c_p).mso = pb;
+ pb->next = MSO(c_p).first;
+ MSO(c_p).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
@@ -3486,8 +3486,8 @@ apply_bif_or_nif_epilogue:
HTOP += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
pb->size = tmp_arg1;
- pb->next = MSO(c_p).mso;
- MSO(c_p).mso = pb;
+ pb->next = MSO(c_p).first;
+ MSO(c_p).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
@@ -4463,7 +4463,7 @@ apply_bif_or_nif_epilogue:
E -= 2;
E[0] = make_cp(I);
E[1] = make_cp(c_p->cp); /* original return address */
- c_p->cp = (BeamInstr *) make_cp(beam_return_time_trace);
+ c_p->cp = beam_return_time_trace;
}
}
@@ -4493,20 +4493,20 @@ apply_bif_or_nif_epilogue:
BeamInstr real_I;
Uint32 flags;
Eterm tracer_pid;
- BeamInstr *cpp;
+ Uint* cpp;
int return_to_trace = 0, need = 0;
flags = 0;
SWAPOUT;
reg[0] = r(0);
if (*(c_p->cp) == (BeamInstr) OpCode(return_trace)) {
- cpp = (BeamInstr*)&E[2];
+ cpp = &E[2];
} else if (*(c_p->cp) == (BeamInstr) OpCode(i_return_to_trace)) {
return_to_trace = !0;
- cpp = (BeamInstr*)&E[0];
+ cpp = &E[0];
} else if (*(c_p->cp) == (BeamInstr) OpCode(i_return_time_trace)) {
return_to_trace = !0;
- cpp = (BeamInstr*)&E[0];
+ cpp = &E[0];
} else {
cpp = NULL;
}
@@ -6323,8 +6323,8 @@ new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free)
erts_refc_inc(&fe->refc, 2);
funp->thing_word = HEADER_FUN;
#ifndef HYBRID /* FIND ME! */
- funp->next = MSO(p).funs;
- MSO(p).funs = funp;
+ funp->next = MSO(p).first;
+ MSO(p).first = (struct erl_off_heap_header*) funp;
#endif
funp->fe = fe;
funp->num_free = num_free;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 506bf383ca..6e9755ad48 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -3611,11 +3611,11 @@ BIF_RETTYPE list_to_pid_1(BIF_ALIST_1)
etp = (ExternalThing *) HAlloc(BIF_P, EXTERNAL_THING_HEAD_SIZE + 1);
etp->header = make_external_pid_header(1);
- etp->next = MSO(BIF_P).externals;
+ etp->next = MSO(BIF_P).first;
etp->node = enp;
etp->data.ui[0] = make_pid_data(c, b);
- MSO(BIF_P).externals = etp;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) etp;
erts_deref_dist_entry(dep);
BIF_RET(make_external_pid(etp));
}
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 90d3a0304a..2d250f32cf 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1509,14 +1509,14 @@ Eterm erts_uint64_to_big(Uint64 x, Eterm **hpp)
*hp = make_pos_bignum_header(2);
BIG_DIGIT(hp, 0) = (Uint) (x & ((Uint) 0xffffffff));
BIG_DIGIT(hp, 1) = (Uint) ((x >> 32) & ((Uint) 0xffffffff));
- *hpp += 2;
+ *hpp += 3;
}
else
#endif
{
*hp = make_pos_bignum_header(1);
BIG_DIGIT(hp, 0) = (Uint) x;
- *hpp += 1;
+ *hpp += 2;
}
return make_big(hp);
}
@@ -1539,7 +1539,7 @@ Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp)
*hp = make_pos_bignum_header(2);
BIG_DIGIT(hp, 0) = (Uint) (x & ((Uint) 0xffffffff));
BIG_DIGIT(hp, 1) = (Uint) ((x >> 32) & ((Uint) 0xffffffff));
- *hpp += 2;
+ *hpp += 3;
}
else
#endif
@@ -1549,7 +1549,7 @@ Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp)
else
*hp = make_pos_bignum_header(1);
BIG_DIGIT(hp, 0) = (Uint) x;
- *hpp += 1;
+ *hpp += 2;
}
return make_big(hp);
}
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index c68392fad4..3fd714f9c2 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -88,8 +88,8 @@ new_binary(Process *p, byte *buf, int len)
pb = (ProcBin *) HAlloc(p, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = len;
- pb->next = MSO(p).mso;
- MSO(p).mso = pb;
+ pb->next = MSO(p).first;
+ MSO(p).first = (struct erl_off_heap_header*)pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
@@ -127,8 +127,8 @@ Eterm erts_new_mso_binary(Process *p, byte *buf, int len)
pb = (ProcBin *) HAlloc(p, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = len;
- pb->next = MSO(p).mso;
- MSO(p).mso = pb;
+ pb->next = MSO(p).first;
+ MSO(p).first = (struct erl_off_heap_header*)pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
@@ -487,16 +487,6 @@ BIF_RETTYPE split_binary_2(BIF_ALIST_2)
BIF_ERROR(BIF_P, BADARG);
}
-void
-erts_cleanup_mso(ProcBin* pb)
-{
- while (pb != NULL) {
- ProcBin* next = pb->next;
- if (erts_refc_dectest(&pb->val->refc, 0) == 0)
- erts_bin_free(pb->val);
- pb = next;
- }
-}
/*
* Local functions.
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 857cb177c8..f339e19761 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -611,29 +611,29 @@ static void
bin_check(void)
{
Process *rp;
- ProcBin *bp;
- int i, printed;
+ struct erl_off_heap_header* hdr;
+ int i, printed = 0;
for (i=0; i < erts_max_processes; i++) {
if ((rp = process_tab[i]) == NULL)
continue;
- if (!(bp = rp->off_heap.mso))
- continue;
- printed = 0;
- while (bp) {
- if (printed == 0) {
- erts_printf("Process %T holding binary data \n", rp->id);
- printed = 1;
+ for (hdr = rp->off_heap.first; hdr; hdr = hdr->next) {
+ if (hdr->thing_word == HEADER_PROC_BIN) {
+ ProcBin *bp = (ProcBin*) hdr;
+ if (!printed) {
+ erts_printf("Process %T holding binary data \n", rp->id);
+ printed = 1;
+ }
+ erts_printf("0x%08lx orig_size: %ld, norefs = %ld\n",
+ (unsigned long)bp->val,
+ (long)bp->val->orig_size,
+ erts_smp_atomic_read(&bp->val->refc));
}
- erts_printf("0x%08lx orig_size: %ld, norefs = %ld\n",
- (unsigned long)bp->val,
- (long)bp->val->orig_size,
- erts_smp_atomic_read(&bp->val->refc));
-
- bp = bp->next;
}
- if (printed == 1)
+ if (printed) {
erts_printf("--------------------------------------\n");
+ printed = 0;
+ }
}
/* db_bin_check() has to be rewritten for the AVL trees... */
/*db_bin_check();*/
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index 521a1b1788..57be0169ba 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -314,9 +314,9 @@ copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
*argp = make_binary(hbot);
pb = (ProcBin*) hbot;
erts_refc_inc(&pb->val->refc, 2);
- pb->next = off_heap->mso;
+ pb->next = off_heap->first;
pb->flags = 0;
- off_heap->mso = pb;
+ off_heap->first = (struct erl_off_heap_header*) pb;
off_heap->overhead += pb->size / sizeof(Eterm);
}
break;
@@ -363,9 +363,9 @@ copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
to->val = from->val;
erts_refc_inc(&to->val->refc, 2);
to->bytes = from->bytes + offset;
- to->next = off_heap->mso;
+ to->next = off_heap->first;
to->flags = 0;
- off_heap->mso = to;
+ off_heap->first = (struct erl_off_heap_header*) to;
off_heap->overhead += to->size / sizeof(Eterm);
}
*argp = make_binary(hbot);
@@ -396,8 +396,8 @@ copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
}
#ifndef HYBRID /* FIND ME! */
funp = (ErlFunThing *) tp;
- funp->next = off_heap->funs;
- off_heap->funs = funp;
+ funp->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*) funp;
erts_refc_inc(&funp->fe->refc, 2);
#endif
*argp = make_fun(tp);
@@ -416,8 +416,8 @@ copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
*htop++ = *objp++;
}
- etp->next = off_heap->externals;
- off_heap->externals = etp;
+ etp->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*)etp;
erts_refc_inc(&etp->node->refc, 2);
*argp = make_external(tp);
@@ -650,8 +650,8 @@ Eterm copy_struct_lazy(Process *from, Eterm orig, Uint offs)
*hp++ = *objp++;
}
erts_refc_inc(&pb->val->refc, 2);
- pb->next = erts_global_offheap.mso;
- erts_global_offheap.mso = pb;
+ pb->next = erts_global_offheap.first;
+ erts_global_offheap.first = pb;
erts_global_offheap.overhead += pb->size / sizeof(Eterm);
continue;
}
@@ -672,9 +672,9 @@ Eterm copy_struct_lazy(Process *from, Eterm orig, Uint offs)
while (i--) {
*hp++ = *objp++;
}
-#ifndef HYBRID // FIND ME!
- funp->next = erts_global_offheap.funs;
- erts_global_offheap.funs = funp;
+#ifndef HYBRID /* FIND ME! */
+ funp->next = erts_global_offheap.first;
+ erts_global_offheap.first = funp;
erts_refc_inc(&funp->fe->refc, 2);
#endif
for (i = k; i < j; i++) {
@@ -718,8 +718,8 @@ Eterm copy_struct_lazy(Process *from, Eterm orig, Uint offs)
*hp++ = *objp++;
}
- etp->next = erts_global_offheap.externals;
- erts_global_offheap.externals = etp;
+ etp->next = erts_global_offheap.first;
+ erts_global_offheap.first = etp;
erts_refc_inc(&etp->node->refc, 2);
continue;
}
@@ -775,8 +775,8 @@ Eterm copy_struct_lazy(Process *from, Eterm orig, Uint offs)
to_bin->size = real_size;
to_bin->val = from_bin->val;
to_bin->bytes = from_bin->bytes + sub_offset;
- to_bin->next = erts_global_offheap.mso;
- erts_global_offheap.mso = to_bin;
+ to_bin->next = erts_global_offheap.first;
+ erts_global_offheap.first = to_bin;
erts_global_offheap.overhead += to_bin->size / sizeof(Eterm);
res_binary=make_binary(to_bin);
hp += PROC_BIN_SIZE;
@@ -910,57 +910,43 @@ copy_shallow(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap)
break;
case REFC_BINARY_SUBTAG:
{
- ProcBin* pb = (ProcBin *) (hp-1);
- int tari = thing_arityval(val);
-
- sz -= tari;
- while (tari--) {
- *hp++ = *tp++;
- }
+ ProcBin* pb = (ProcBin *) (tp-1);
erts_refc_inc(&pb->val->refc, 2);
- pb->next = off_heap->mso;
- off_heap->mso = pb;
off_heap->overhead += pb->size / sizeof(Eterm);
}
- break;
+ goto off_heap_common;
+
case FUN_SUBTAG:
{
-#ifndef HYBRID /* FIND ME! */
- ErlFunThing* funp = (ErlFunThing *) (hp-1);
-#endif
- int tari = thing_arityval(val);
-
- sz -= tari;
- while (tari--) {
- *hp++ = *tp++;
- }
-#ifndef HYBRID /* FIND ME! */
- funp->next = off_heap->funs;
- off_heap->funs = funp;
+ ErlFunThing* funp = (ErlFunThing *) (tp-1);
erts_refc_inc(&funp->fe->refc, 2);
-#endif
}
- break;
+ goto off_heap_common;
+
case EXTERNAL_PID_SUBTAG:
case EXTERNAL_PORT_SUBTAG:
case EXTERNAL_REF_SUBTAG:
{
- ExternalThing* etp = (ExternalThing *) (hp-1);
+ ExternalThing* etp = (ExternalThing *) (tp-1);
+ erts_refc_inc(&etp->node->refc, 2);
+ }
+ off_heap_common:
+ {
+ struct erl_off_heap_header* ohh = (struct erl_off_heap_header*)(hp-1);
int tari = thing_arityval(val);
-
+
sz -= tari;
while (tari--) {
*hp++ = *tp++;
}
- etp->next = off_heap->externals;
- off_heap->externals = etp;
- erts_refc_inc(&etp->node->refc, 2);
+ ohh->next = off_heap->first;
+ off_heap->first = ohh;
}
break;
default:
{
int tari = header_arity(val);
-
+
sz -= tari;
while (tari--) {
*hp++ = *tp++;
@@ -1029,12 +1015,6 @@ void move_multi_frags(Eterm** hpp, ErlOffHeap* off_heap, ErlHeapFragment* first,
static void
move_one_frag(Eterm** hpp, Eterm* src, Uint src_sz, ErlOffHeap* off_heap)
{
- union {
- Uint *up;
- ProcBin *pbp;
- ErlFunThing *efp;
- ExternalThing *etp;
- } ohe;
Eterm* ptr = src;
Eterm* end = ptr + src_sz;
Eterm dummy_ref;
@@ -1046,23 +1026,17 @@ move_one_frag(Eterm** hpp, Eterm* src, Uint src_sz, ErlOffHeap* off_heap)
val = *ptr;
ASSERT(val != ERTS_HOLE_MARKER);
if (is_header(val)) {
+ struct erl_off_heap_header* hdr = (struct erl_off_heap_header*)hp;
ASSERT(ptr + header_arity(val) < end);
- ohe.up = hp;
MOVE_BOXED(ptr, val, hp, &dummy_ref);
switch (val & _HEADER_SUBTAG_MASK) {
case REFC_BINARY_SUBTAG:
- ohe.pbp->next = off_heap->mso;
- off_heap->mso = ohe.pbp;
- break;
case FUN_SUBTAG:
- ohe.efp->next = off_heap->funs;
- off_heap->funs = ohe.efp;
- break;
case EXTERNAL_PID_SUBTAG:
case EXTERNAL_PORT_SUBTAG:
case EXTERNAL_REF_SUBTAG:
- ohe.etp->next = off_heap->externals;
- off_heap->externals = ohe.etp;
+ hdr->next = off_heap->first;
+ off_heap->first = hdr;
break;
}
}
diff --git a/erts/emulator/beam/decl.h b/erts/emulator/beam/decl.h
deleted file mode 100644
index da1be29d53..0000000000
--- a/erts/emulator/beam/decl.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-#ifndef __DECL_H__
-#define __DECL_H__
-
-#if defined(__STDC__) || defined(_MSC_VER)
-#define EXTERN_FUNCTION(t, f, x) extern t f x
-#define FUNCTION(t, f, x) t f x
-#define _DOTS_ ...
-#define _VOID_ void
-#elif defined(__cplusplus)
-#define EXTERN_FUNCTION(f, x) extern "C" { f x }
-#define FUNCTION(t, f, x) t f x
-#define _DOTS_ ...
-#define _VOID_ void
-#else
-#define EXTERN_FUNCTION(t, f, x) extern t f (/*x*/)
-#define FUNCTION(t, f, x) t f (/*x*/)
-#define _DOTS_
-#define _VOID_
-#endif
-
-/*
-** Example of declarations
-**
-** EXTERN_FUNCTION(void, foo, (int, int, char));
-** FUNCTION(void, bar, (int, char));
-**
-** struct funcs {
-** FUNCTION(int*, (*f1), (int, int));
-** FUNCTION(void, (*f2), (int, char));
-** FUNCTION(void, (*f3), (_VOID_));
-** FUNCTION(int, (*f4), (char*, _DOTS_));
-** };
-**
-*/
-
-#endif
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index d465017949..16b6aeac3f 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -922,12 +922,8 @@ int erts_net_message(Port *prt,
UseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE);
/* Thanks to Luke Gorrie */
- off_heap.mso = NULL;
-#ifndef HYBRID /* FIND ME! */
- off_heap.funs = NULL;
-#endif
+ off_heap.first = NULL;
off_heap.overhead = 0;
- off_heap.externals = NULL;
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -1434,16 +1430,8 @@ int erts_net_message(Port *prt,
}
}
- if (off_heap.mso) {
- erts_cleanup_mso(off_heap.mso);
- }
- if (off_heap.externals) {
- erts_cleanup_externals(off_heap.externals);
- }
+ erts_cleanup_offheap(&off_heap);
#ifndef HYBRID /* FIND ME! */
- if (off_heap.funs) {
- erts_cleanup_funs(off_heap.funs);
- }
if (ctl != ctl_default) {
erts_free(ERTS_ALC_T_DCTRL_BUF, (void *) ctl);
}
@@ -1453,16 +1441,8 @@ int erts_net_message(Port *prt,
return 0;
data_error:
- if (off_heap.mso) {
- erts_cleanup_mso(off_heap.mso);
- }
- if (off_heap.externals) {
- erts_cleanup_externals(off_heap.externals);
- }
+ erts_cleanup_offheap(&off_heap);
#ifndef HYBRID /* FIND ME! */
- if (off_heap.funs) {
- erts_cleanup_funs(off_heap.funs);
- }
if (ctl != ctl_default) {
erts_free(ERTS_ALC_T_DCTRL_BUF, (void *) ctl);
}
diff --git a/erts/emulator/beam/elib_malloc.c b/erts/emulator/beam/elib_malloc.c
deleted file mode 100644
index b18c48d8d6..0000000000
--- a/erts/emulator/beam/elib_malloc.c
+++ /dev/null
@@ -1,2334 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
-** Description: Faster malloc().
-*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sys.h"
-
-#ifdef ENABLE_ELIB_MALLOC
-
-#undef THREAD_SAFE_ELIB_MALLOC
-#ifdef USE_THREADS
-#define THREAD_SAFE_ELIB_MALLOC 1
-#else
-#define THREAD_SAFE_ELIB_MALLOC 0
-#endif
-
-#include "erl_driver.h"
-#include "erl_threads.h"
-#include "elib_stat.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-/* To avoid clobbering of names becaure of reclaim on VxWorks,
- we undefine all possible malloc, calloc etc. */
-#undef malloc
-#undef calloc
-#undef free
-#undef realloc
-
-#define ELIB_INLINE /* inline all possible functions */
-
-#ifndef ELIB_ALIGN
-#define ELIB_ALIGN sizeof(double)
-#endif
-
-#ifndef ELIB_HEAP_SIZE
-#define ELIB_HEAP_SIZE (64*1024) /* Default 64K */
-#endif
-
-#ifndef ELIB_HEAP_INCREAMENT
-#define ELIB_HEAP_INCREAMENT (32*1024) /* Default 32K */
-#endif
-
-#ifndef ELIB_FAILURE
-#define ELIB_FAILURE abort()
-#endif
-
-#undef ASSERT
-#ifdef DEBUG
-#define ASSERT(B) \
- ((void) ((B) ? 1 : (fprintf(stderr, "%s:%d: Assertion failed: %s\n", \
- __FILE__, __LINE__, #B), abort(), 0)))
-#else
-#define ASSERT(B) ((void) 1)
-#endif
-
-#ifndef USE_RECURSIVE_MALLOC_MUTEX
-#define USE_RECURSIVE_MALLOC_MUTEX 0
-#endif
-
-#if USE_RECURSIVE_MALLOC_MUTEX
-static erts_mtx_t malloc_mutex = ERTS_REC_MTX_INITER;
-#else /* #if USE_RECURSIVE_MALLOC_MUTEX */
-static erts_mtx_t malloc_mutex = ERTS_MTX_INITER;
-#if THREAD_SAFE_ELIB_MALLOC
-static erts_cnd_t malloc_cond = ERTS_CND_INITER;
-#endif
-#endif /* #if USE_RECURSIVE_MALLOC_MUTEX */
-
-typedef unsigned long EWord; /* Assume 32-bit in this implementation */
-typedef unsigned short EHalfWord; /* Assume 16-bit in this implementation */
-typedef unsigned char EByte; /* Assume 8-bit byte */
-
-
-#define elib_printf fprintf
-#define elib_putc fputc
-
-
-#if defined(__STDC__) || defined(__WIN32__)
-#define CONCAT(x,y) x##y
-#else
-#define CONCAT(x,y) x/**/y
-#endif
-
-
-#ifdef ELIB_DEBUG
-#define ELIB_PREFIX(fun, args) CONCAT(elib__,fun) args
-#else
-#define ELIB_PREFIX(fun, args) CONCAT(elib_,fun) args
-#endif
-
-#if defined(__STDC__)
-void *ELIB_PREFIX(malloc, (size_t));
-void *ELIB_PREFIX(calloc, (size_t, size_t));
-void ELIB_PREFIX(cfree, (EWord *));
-void ELIB_PREFIX(free, (EWord *));
-void *ELIB_PREFIX(realloc, (EWord *, size_t));
-void* ELIB_PREFIX(memresize, (EWord *, int));
-void* ELIB_PREFIX(memalign, (int, int));
-void* ELIB_PREFIX(valloc, (int));
-void* ELIB_PREFIX(pvalloc, (int));
-int ELIB_PREFIX(memsize, (EWord *));
-/* Extern interfaces used by VxWorks */
-size_t elib_sizeof(void *);
-void elib_init(EWord *, EWord);
-void elib_force_init(EWord *, EWord);
-#endif
-
-#if defined(__STDC__)
-/* define prototypes for missing */
-void* memalign(size_t a, size_t s);
-void* pvalloc(size_t nb);
-void* memresize(void *p, int nb);
-int memsize(void *p);
-#endif
-
-/* bytes to pages */
-#define PAGES(x) (((x)+page_size-1) / page_size)
-#define PAGE_ALIGN(p) ((char*)((((EWord)(p))+page_size-1)&~(page_size-1)))
-
-/* bytes to words */
-#define WORDS(x) (((x)+sizeof(EWord)-1) / sizeof(EWord))
-
-/* Align an address */
-#define ALIGN(p) ((EWord*)((((EWord)(p)+ELIB_ALIGN-1)&~(ELIB_ALIGN-1))))
-
-/* Calculate the size needed to keep alignment */
-
-#define ALIGN_BSZ(nb) ((nb+sizeof(EWord)+ELIB_ALIGN-1) & ~(ELIB_ALIGN-1))
-
-#define ALIGN_WSZ(nb) WORDS(ALIGN_BSZ(nb))
-
-#define ALIGN_SIZE(nb) (ALIGN_WSZ(nb) - 1)
-
-
-/* PARAMETERS */
-
-#if defined(ELIB_HEAP_SBRK)
-
-#undef PAGE_SIZE
-
-/* Get the system page size (NEED MORE DEFINES HERE) */
-#ifdef _SC_PAGESIZE
-#define PAGE_SIZE sysconf(_SC_PAGESIZE)
-#elif defined(_MSC_VER)
-# ifdef _M_ALPHA
-# define PAGE_SIZE 0x2000
-# else
-# define PAGE_SIZE 0x1000
-# endif
-#else
-#define PAGE_SIZE getpagesize()
-#endif
-
-#define ELIB_EXPAND(need) expand_sbrk(need)
-static FUNCTION(int, expand_sbrk, (EWord));
-
-#elif defined(ELIB_HEAP_FIXED)
-
-#define PAGE_SIZE 1024
-#define ELIB_EXPAND(need) -1
-static EWord fix_heap[WORDS(ELIB_HEAP_SIZE)];
-
-#elif defined(ELIB_HEAP_USER)
-
-#define PAGE_SIZE 1024
-#define ELIB_EXPAND(need) -1
-
-#else
-
-#error "ELIB HEAP TYPE NOT SET"
-
-#endif
-
-
-#define STAT_ALLOCED_BLOCK(SZ) \
-do { \
- tot_allocated += (SZ); \
- if (max_allocated < tot_allocated) \
- max_allocated = tot_allocated; \
-} while (0)
-
-#define STAT_FREED_BLOCK(SZ) \
-do { \
- tot_allocated -= (SZ); \
-} while (0)
-
-static int max_allocated = 0;
-static int tot_allocated = 0;
-static EWord* eheap; /* Align heap start */
-static EWord* eheap_top; /* Point to end of heap */
-EWord page_size = 0; /* Set by elib_init */
-
-#if defined(ELIB_DEBUG) || defined(DEBUG)
-#define ALIGN_CHECK(a, p) \
- do { \
- if ((EWord)(p) & (a-1)) { \
- elib_printf(stderr, \
- "RUNTIME ERROR: bad alignment (0x%lx:%d:%d)\n", \
- (unsigned long) (p), (int) a, __LINE__); \
- ELIB_FAILURE; \
- } \
- } while(0)
-#define ELIB_ALIGN_CHECK(p) ALIGN_CHECK(ELIB_ALIGN, p)
-#else
-#define ALIGN_CHECK(a, p)
-#define ELIB_ALIGN_CHECK(p)
-#endif
-
-#define DYNAMIC 32
-
-/*
-** Free block layout
-** 1 1 30
-** +--------------------------+
-** |F|P| Size |
-** +--------------------------+
-**
-** Where F is the free bit
-** P is the free above bit
-** Size is messured in words and does not include the hdr word
-**
-** If block is on the free list the size is also stored last in the block.
-**
-*/
-typedef struct _free_block FreeBlock;
-struct _free_block {
- EWord hdr;
- Uint flags;
- FreeBlock* parent;
- FreeBlock* left;
- FreeBlock* right;
- EWord v[1];
-};
-
-typedef struct _allocated_block {
- EWord hdr;
- EWord v[5];
-} AllocatedBlock;
-
-
-/*
- * Interface to tree routines.
- */
-typedef Uint Block_t;
-
-static Block_t* get_free_block(Uint);
-static void link_free_block(Block_t *);
-static void unlink_free_block(Block_t *del);
-
-#define FREE_BIT 0x80000000
-#define FREE_ABOVE_BIT 0x40000000
-#define SIZE_MASK 0x3fffffff /* 2^30 words = 2^32 bytes */
-
-/* Work on both FreeBlock and AllocatedBlock */
-#define SIZEOF(p) ((p)->hdr & SIZE_MASK)
-#define IS_FREE(p) (((p)->hdr & FREE_BIT) != 0)
-#define IS_FREE_ABOVE(p) (((p)->hdr & FREE_ABOVE_BIT) != 0)
-
-/* Given that we have a free block above find its size */
-#define SIZEOF_ABOVE(p) *(((EWord*) (p)) - 1)
-
-#define MIN_BLOCK_SIZE (sizeof(FreeBlock)/sizeof(EWord))
-#define MIN_WORD_SIZE (MIN_BLOCK_SIZE-1)
-#define MIN_BYTE_SIZE (sizeof(FreeBlock)-sizeof(EWord))
-
-#define MIN_ALIGN_SIZE ALIGN_SIZE(MIN_BYTE_SIZE)
-
-
-static AllocatedBlock* heap_head = 0;
-static AllocatedBlock* heap_tail = 0;
-static EWord eheap_size = 0;
-
-static int heap_locked;
-
-static int elib_need_init = 1;
-#if THREAD_SAFE_ELIB_MALLOC
-static int elib_is_initing = 0;
-#endif
-
-typedef FreeBlock RBTree_t;
-
-static RBTree_t* root = NULL;
-
-
-static FUNCTION(void, deallocate, (AllocatedBlock*, int));
-
-/*
- * Unlink a free block
- */
-
-#define mark_allocated(p, szp) do { \
- (p)->hdr = ((p)->hdr & FREE_ABOVE_BIT) | (szp); \
- (p)->v[szp] &= ~FREE_ABOVE_BIT; \
- } while(0)
-
-#define mark_free(p, szp) do { \
- (p)->hdr = FREE_BIT | (szp); \
- ((FreeBlock *)p)->v[szp-sizeof(FreeBlock)/sizeof(EWord)+1] = (szp); \
- } while(0)
-
-#if 0
-/* Help macros to log2 */
-#define LOG_1(x) (((x) > 1) ? 1 : 0)
-#define LOG_2(x) (((x) > 3) ? 2+LOG_1((x) >> 2) : LOG_1(x))
-#define LOG_4(x) (((x) > 15) ? 4+LOG_2((x) >> 4) : LOG_2(x))
-#define LOG_8(x) (((x) > 255) ? 8+LOG_4((x)>>8) : LOG_4(x))
-#define LOG_16(x) (((x) > 65535) ? 16+LOG_8((x)>>16) : LOG_8(x))
-
-#define log2(x) LOG_16(x)
-#endif
-
-/*
- * Split a block to be allocated.
- * Mark block as ALLOCATED and clear
- * FREE_ABOVE_BIT on next block
- *
- * nw is SIZE aligned and szp is SIZE aligned + 1
- */
-static void
-split_block(FreeBlock* p, EWord nw, EWord szp)
-{
- EWord szq;
- FreeBlock* q;
-
- szq = szp - nw;
- /* Preserve FREE_ABOVE bit in p->hdr !!! */
-
- if (szq >= MIN_ALIGN_SIZE+1) {
- szq--;
- p->hdr = (p->hdr & FREE_ABOVE_BIT) | nw;
-
- q = (FreeBlock*) (((EWord*) p) + nw + 1);
- mark_free(q, szq);
- link_free_block((Block_t *) q);
-
- q = (FreeBlock*) (((EWord*) q) + szq + 1);
- q->hdr |= FREE_ABOVE_BIT;
- }
- else {
- mark_allocated((AllocatedBlock*)p, szp);
- }
-}
-
-/*
- * Find a free block
- */
-static FreeBlock*
-alloc_block(EWord nw)
-{
- for (;;) {
- FreeBlock* p = (FreeBlock *) get_free_block(nw);
-
- if (p != NULL) {
- return p;
- } else if (ELIB_EXPAND(nw+MIN_WORD_SIZE)) {
- return 0;
- }
- }
-}
-
-
-size_t elib_sizeof(void *p)
-{
- AllocatedBlock* pp;
-
- if (p != 0) {
- pp = (AllocatedBlock*) (((char *)p)-1);
- return SIZEOF(pp);
- }
- return 0;
-}
-
-static void locked_elib_init(EWord*, EWord);
-static void init_elib_malloc(EWord*, EWord);
-
-/*
-** Initialize the elib
-** The addr and sz is only used when compiled with EXPAND_ADDR
-*/
-/* Not static, this is used by VxWorks */
-void elib_init(EWord* addr, EWord sz)
-{
- if (!elib_need_init)
- return;
- erts_mtx_lock(&malloc_mutex);
- locked_elib_init(addr, sz);
- erts_mtx_unlock(&malloc_mutex);
-}
-
-static void locked_elib_init(EWord* addr, EWord sz)
-{
- if (!elib_need_init)
- return;
-
-#if THREAD_SAFE_ELIB_MALLOC
-
-#if !USE_RECURSIVE_MALLOC_MUTEX
- {
- static erts_tid_t initer_tid;
-
- if(elib_is_initing) {
-
- if(erts_equal_tids(initer_tid, erts_thr_self()))
- return;
-
- /* Wait until initializing thread is done with initialization */
-
- while(elib_need_init)
- erts_cnd_wait(&malloc_cond, &malloc_mutex);
-
- return;
- }
- else {
- initer_tid = erts_thr_self();
- elib_is_initing = 1;
- }
- }
-#else
- if(elib_is_initing)
- return;
- elib_is_initing = 1;
-#endif
-
-#endif /* #if THREAD_SAFE_ELIB_MALLOC */
-
- /* Do the actual initialization of the malloc implementation */
- init_elib_malloc(addr, sz);
-
-#if THREAD_SAFE_ELIB_MALLOC
-
-#if !USE_RECURSIVE_MALLOC_MUTEX
- erts_mtx_unlock(&malloc_mutex);
-#endif
-
- /* Recursive calls to malloc are allowed here... */
- erts_mtx_set_forksafe(&malloc_mutex);
-
-#if !USE_RECURSIVE_MALLOC_MUTEX
- erts_mtx_lock(&malloc_mutex);
- elib_is_initing = 0;
-#endif
-
-#endif /* #if THREAD_SAFE_ELIB_MALLOC */
-
- elib_need_init = 0;
-
-#if THREAD_SAFE_ELIB_MALLOC && !USE_RECURSIVE_MALLOC_MUTEX
- erts_cnd_broadcast(&malloc_cond);
-#endif
-
-}
-
-static void init_elib_malloc(EWord* addr, EWord sz)
-{
- int i;
- FreeBlock* freep;
- EWord tmp_sz;
-#ifdef ELIB_HEAP_SBRK
- char* top;
- EWord n;
-#endif
-
- max_allocated = 0;
- tot_allocated = 0;
- root = NULL;
-
- /* Get the page size (may involve system call!!!) */
- page_size = PAGE_SIZE;
-
-#if defined(ELIB_HEAP_SBRK)
- sz = PAGES(ELIB_HEAP_SIZE)*page_size;
-
- if ((top = (char*) sbrk(0)) == (char*)-1) {
- elib_printf(stderr, "could not initialize elib, sbrk(0)");
- ELIB_FAILURE;
- }
- n = PAGE_ALIGN(top) - top;
- if ((top = (char*) sbrk(n)) == (char*)-1) {
- elib_printf(stderr, "could not initialize elib, sbrk(n)");
- ELIB_FAILURE;
- }
- if ((eheap = (EWord*) sbrk(sz)) == (EWord*)-1) {
- elib_printf(stderr, "could not initialize elib, sbrk(SIZE)");
- ELIB_FAILURE;
- }
- sz = WORDS(ELIB_HEAP_SIZE);
-#elif defined(ELIB_HEAP_FIXED)
- eheap = fix_heap;
- sz = WORDS(ELIB_HEAP_SIZE);
-#elif defined(ELIB_HEAP_USER)
- eheap = addr;
- sz = WORDS(sz);
-#else
- return -1;
-#endif
- eheap_size = 0;
-
- /* Make sure that the first word of the heap_head is aligned */
- addr = ALIGN(eheap+1);
- sz -= ((addr - 1) - eheap); /* Subtract unusable size */
- eheap_top = eheap = addr - 1; /* Set new aligned heap start */
-
- eheap_top[sz-1] = 0; /* Heap stop mark */
-
- addr = eheap;
- heap_head = (AllocatedBlock*) addr;
- heap_head->hdr = MIN_ALIGN_SIZE;
- for (i = 0; i < MIN_ALIGN_SIZE; i++)
- heap_head->v[i] = 0;
-
- addr += (MIN_ALIGN_SIZE+1);
- freep = (FreeBlock*) addr;
- tmp_sz = sz - (((MIN_ALIGN_SIZE+1) + MIN_BLOCK_SIZE) + 1 + 1);
- mark_free(freep, tmp_sz);
- link_free_block((Block_t *) freep);
-
- /* No need to align heap tail */
- heap_tail = (AllocatedBlock*) &eheap_top[sz-MIN_BLOCK_SIZE-1];
- heap_tail->hdr = FREE_ABOVE_BIT | MIN_WORD_SIZE;
- heap_tail->v[0] = 0;
- heap_tail->v[1] = 0;
- heap_tail->v[2] = 0;
-
- eheap_top += sz;
- eheap_size += sz;
-
- heap_locked = 0;
-}
-
-#ifdef ELIB_HEAP_USER
-void elib_force_init(EWord* addr, EWord sz)
-{
- elib_need_init = 1;
- elib_init(addr,sz);
-}
-#endif
-
-#ifdef ELIB_HEAP_SBRK
-
-/*
-** need in number of words (should include head and tail words)
-*/
-static int expand_sbrk(EWord sz)
-{
- EWord* p;
- EWord bytes = sz * sizeof(EWord);
- EWord size;
- AllocatedBlock* tail;
-
- if (bytes < ELIB_HEAP_SIZE)
- size = PAGES(ELIB_HEAP_INCREAMENT)*page_size;
- else
- size = PAGES(bytes)*page_size;
-
- if ((p = (EWord*) sbrk(size)) == ((EWord*) -1))
- return -1;
-
- if (p != eheap_top) {
- elib_printf(stderr, "panic: sbrk moved\n");
- ELIB_FAILURE;
- }
-
- sz = WORDS(size);
-
- /* Set new endof heap marker and a new heap tail */
- eheap_top[sz-1] = 0;
-
- tail = (AllocatedBlock*) &eheap_top[sz-MIN_BLOCK_SIZE-1];
- tail->hdr = FREE_ABOVE_BIT | MIN_WORD_SIZE;
- tail->v[0] = 0;
- tail->v[1] = 0;
- tail->v[2] = 0;
-
- /* Patch old tail with new appended size */
- heap_tail->hdr = (heap_tail->hdr & FREE_ABOVE_BIT) |
- (MIN_WORD_SIZE+1+(sz-MIN_BLOCK_SIZE-1));
- deallocate(heap_tail, 0);
-
- heap_tail = tail;
-
- eheap_size += sz;
- eheap_top += sz;
-
- return 0;
-}
-
-#endif /* ELIB_HEAP_SBRK */
-
-
-/*
-** Scan heap and check for corrupted heap
-*/
-int elib_check_heap(void)
-{
- AllocatedBlock* p = heap_head;
- EWord sz;
-
- if (heap_locked) {
- elib_printf(stderr, "heap is locked no info avaiable\n");
- return 0;
- }
-
- while((sz = SIZEOF(p)) != 0) {
- if (IS_FREE(p)) {
- if (p->v[sz-1] != sz) {
- elib_printf(stderr, "panic: heap corrupted\r\n");
- ELIB_FAILURE;
- }
- p = (AllocatedBlock*) (p->v + sz);
- if (!IS_FREE_ABOVE(p)) {
- elib_printf(stderr, "panic: heap corrupted\r\n");
- ELIB_FAILURE;
- }
- }
- else
- p = (AllocatedBlock*) (p->v + sz);
- }
- return 1;
-}
-
-/*
-** Load the byte vector pointed to by v of length vsz
-** with a heap image
-** The scale is defined by vsz and the current heap size
-** free = 0, full = 255
-**
-**
-*/
-int elib_heap_map(EByte* v, int vsz)
-{
- AllocatedBlock* p = heap_head;
- EWord sz;
- int gsz = eheap_size / vsz; /* The granuality used */
- int fsz = 0;
- int usz = 0;
-
- if (gsz == 0)
- return -1; /* too good reolution */
-
- while((sz = SIZEOF(p)) != 0) {
- if (IS_FREE(p)) {
- fsz += sz;
- if ((fsz + usz) > gsz) {
- *v++ = (255*usz)/gsz;
- fsz -= (gsz - usz);
- usz = 0;
- while(fsz >= gsz) {
- *v++ = 0;
- fsz -= gsz;
- }
- }
- }
- else {
- usz += sz;
- if ((fsz + usz) > gsz) {
- *v++ = 255 - (255*fsz)/gsz;
- usz -= (gsz - fsz);
- fsz = 0;
- while(usz >= gsz) {
- *v++ = 255;
- usz -= gsz;
- }
- }
- }
- p = (AllocatedBlock*) (p->v + sz);
- }
- return 0;
-}
-
-/*
-** Generate a histogram of free/allocated blocks
-** Count granuality of 10 gives
-** (0-10],(10-100],(100-1000],(1000-10000] ...
-** (0-2], (2-4], (4-8], (8-16], ....
-*/
-static int i_logb(EWord size, int base)
-{
- int lg = 0;
- while(size >= base) {
- size /= base;
- lg++;
- }
- return lg;
-}
-
-int elib_histo(EWord* vf, EWord* va, int vsz, int base)
-{
- AllocatedBlock* p = heap_head;
- EWord sz;
- int i;
- int linear;
-
- if ((vsz <= 1) || (vf == 0 && va == 0))
- return -1;
-
- if (base < 0) {
- linear = 1;
- base = -base;
- }
- else
- linear = 0;
-
- if (base <= 1)
- return -1;
-
- if (vf != 0) {
- for (i = 0; i < vsz; i++)
- vf[i] = 0;
- }
- if (va != 0) {
- for (i = 0; i < vsz; i++)
- va[i] = 0;
- }
-
- while((sz = SIZEOF(p)) != 0) {
- if (IS_FREE(p)) {
- if (vf != 0) {
- int val;
- if (linear)
- val = sz / base;
- else
- val = i_logb(sz, base);
- if (val >= vsz)
- vf[vsz-1]++;
- else
- vf[val]++;
- }
- }
- else {
- if (va != 0) {
- int val;
- if (linear)
- val = sz / base;
- else
- val = i_logb(sz, base);
- if (val >= vsz)
- va[vsz-1]++;
- else
- va[val]++;
- }
- }
- p = (AllocatedBlock*) (p->v + sz);
- }
- return 0;
-}
-
-/*
-** Fill the info structure with actual values
-** Total
-** Allocated
-** Free
-** maxMaxFree
-*/
-void elib_stat(struct elib_stat* info)
-{
- EWord blks = 0;
- EWord sz_free = 0;
- EWord sz_alloc = 0;
- EWord sz_max_free = 0;
- EWord sz_min_used = 0x7fffffff;
- EWord sz;
- EWord num_free = 0;
- AllocatedBlock* p = heap_head;
-
- info->mem_total = eheap_size;
-
- p = (AllocatedBlock*) (p->v + SIZEOF(p));
-
- while((sz = SIZEOF(p)) != 0) {
- blks++;
- if (IS_FREE(p)) {
- if (sz > sz_max_free)
- sz_max_free = sz;
- sz_free += sz;
- ++num_free;
- }
- else {
- if (sz < sz_min_used)
- sz_min_used = sz;
- sz_alloc += sz;
- }
- p = (AllocatedBlock*) (p->v + sz);
- }
- info->mem_blocks = blks;
- info->free_blocks = num_free;
- info->mem_alloc = sz_alloc;
- info->mem_free = sz_free;
- info->min_used = sz_min_used;
- info->max_free = sz_max_free;
- info->mem_max_alloc = max_allocated;
- ASSERT(sz_alloc == tot_allocated);
-}
-
-/*
-** Dump the heap
-*/
-void elib_heap_dump(char* label)
-{
- AllocatedBlock* p = heap_head;
- EWord sz;
-
- elib_printf(stderr, "HEAP DUMP (%s)\n", label);
- if (!elib_check_heap())
- return;
-
- while((sz = SIZEOF(p)) != 0) {
- if (IS_FREE(p)) {
- elib_printf(stderr, "%p: FREE, size = %d\n", p, (int) sz);
- }
- else {
- elib_printf(stderr, "%p: USED, size = %d %s\n", p, (int) sz,
- IS_FREE_ABOVE(p)?"(FREE ABOVE)":"");
- }
- p = (AllocatedBlock*) (p->v + sz);
- }
-}
-
-/*
-** Scan heaps and count:
-** free_size, allocated_size, max_free_block
-*/
-void elib_statistics(void* to)
-{
- struct elib_stat info;
- EWord frag;
-
- if (!elib_check_heap())
- return;
-
- elib_stat(&info);
-
- frag = 1000 - ((1000 * info.max_free) / info.mem_free);
-
- elib_printf(to, "Heap Statistics: total(%d), blocks(%d), frag(%d.%d%%)\n",
- info.mem_total, info.mem_blocks,
- (int) frag/10, (int) frag % 10);
-
- elib_printf(to, " allocated(%d), free(%d), "
- "free_blocks(%d)\n",
- info.mem_alloc, info.mem_free,info.free_blocks);
- elib_printf(to, " max_free(%d), min_used(%d)\n",
- info.max_free, info.min_used);
-}
-
-/*
-** Allocate a least nb bytes with alignment a
-** Algorithm:
-** 1) Try locate a block which match exacly among the by direct index.
-** 2) Try using a fix block of greater size
-** 3) Try locate a block by searching in lists where block sizes
-** X may vary between 2^i < X <= 2^(i+1)
-**
-** Reset memory to zero if clear is true
-*/
-static AllocatedBlock* allocate(EWord nb, EWord a, int clear)
-{
- FreeBlock* p;
- EWord nw;
-
- if (a == ELIB_ALIGN) {
- /*
- * Common case: Called by malloc(), realloc(), calloc().
- */
- nw = nb < MIN_BYTE_SIZE ? MIN_ALIGN_SIZE : ALIGN_SIZE(nb);
-
- if ((p = alloc_block(nw)) == 0)
- return NULL;
- } else {
- /*
- * Special case: Called by memalign().
- */
- EWord asz, szp, szq, tmpsz;
- FreeBlock *q;
-
- if ((p = alloc_block((1+MIN_ALIGN_SIZE)*sizeof(EWord)+a-1+nb)) == 0)
- return NULL;
-
- asz = a - ((EWord) ((AllocatedBlock *)p)->v) % a;
-
- if (asz != a) {
- /* Enforce the alignment requirement by cutting of a free
- block at the beginning of the block. */
-
- if (asz < (1+MIN_ALIGN_SIZE)*sizeof(EWord) && !IS_FREE_ABOVE(p)) {
- /* Not enough room to cut of a free block;
- increase align size */
- asz += (((1+MIN_ALIGN_SIZE)*sizeof(EWord) + a - 1)/a)*a;
- }
-
- szq = ALIGN_SIZE(asz - sizeof(EWord));
- szp = SIZEOF(p) - szq - 1;
-
- q = p;
- p = (FreeBlock*) (((EWord*) q) + szq + 1);
- p->hdr = FREE_ABOVE_BIT | FREE_BIT | szp;
-
- if (IS_FREE_ABOVE(q)) { /* This should not be possible I think,
- but just in case... */
- tmpsz = SIZEOF_ABOVE(q) + 1;
- szq += tmpsz;
- q = (FreeBlock*) (((EWord*) q) - tmpsz);
- unlink_free_block((Block_t *) q);
- q->hdr = (q->hdr & FREE_ABOVE_BIT) | FREE_BIT | szq;
- }
- mark_free(q, szq);
- link_free_block((Block_t *) q);
-
- } /* else already had the correct alignment */
-
- nw = nb < MIN_BYTE_SIZE ? MIN_ALIGN_SIZE : ALIGN_SIZE(nb);
- }
-
- split_block(p, nw, SIZEOF(p));
-
- STAT_ALLOCED_BLOCK(SIZEOF(p));
-
- if (clear) {
- EWord* pp = ((AllocatedBlock*)p)->v;
-
- while(nw--)
- *pp++ = 0;
- }
-
- return (AllocatedBlock*) p;
-}
-
-
-/*
-** Deallocate memory pointed to by p
-** 1. Merge with block above if this block is free
-** 2. Merge with block below if this block is free
-** Link the block to the correct free list
-**
-** p points to the block header!
-**
-*/
-static void deallocate(AllocatedBlock* p, int stat_count)
-{
- FreeBlock* q;
- EWord szq;
- EWord szp;
-
- szp = SIZEOF(p);
-
- if (stat_count)
- STAT_FREED_BLOCK(SIZEOF(p));
-
- if (IS_FREE_ABOVE(p)) {
- szq = SIZEOF_ABOVE(p);
- q = (FreeBlock*) ( ((EWord*) p) - szq - 1);
- unlink_free_block((Block_t *) q);
-
- p = (AllocatedBlock*) q;
- szp += (szq + 1);
- }
- q = (FreeBlock*) (p->v + szp);
- if (IS_FREE(q)) {
- szq = SIZEOF(q);
- unlink_free_block((Block_t *) q);
- szp += (szq + 1);
- }
- else
- q->hdr |= FREE_ABOVE_BIT;
-
- /* The block above p can NEVER be free !!! */
- p->hdr = FREE_BIT | szp;
- p->v[szp-1] = szp;
-
- link_free_block((Block_t *) p);
-}
-
-/*
-** Reallocate memory
-** If preserve is true then data is moved if neccesary
-*/
-static AllocatedBlock* reallocate(AllocatedBlock* p, EWord nb, int preserve)
-{
- EWord szp;
- EWord szq;
- EWord sz;
- EWord nw;
- FreeBlock* q;
-
- if (nb < MIN_BYTE_SIZE)
- nw = MIN_ALIGN_SIZE;
- else
- nw = ALIGN_SIZE(nb);
-
- sz = szp = SIZEOF(p);
-
- STAT_FREED_BLOCK(szp);
-
- /* Merge with block below */
- q = (FreeBlock*) (p->v + szp);
- if (IS_FREE(q)) {
- szq = SIZEOF(q);
- unlink_free_block((Block_t *) q);
- szp += (szq + 1);
- }
-
- if (nw <= szp) {
- split_block((FreeBlock *) p, nw, szp);
- STAT_ALLOCED_BLOCK(SIZEOF(p));
- return p;
- }
- else {
- EWord* dp = p->v;
- AllocatedBlock* npp;
-
- if (IS_FREE_ABOVE(p)) {
- szq = SIZEOF_ABOVE(p);
- if (szq + szp + 1 >= nw) {
- q = (FreeBlock*) (((EWord*) p) - szq - 1);
- unlink_free_block((Block_t * )q);
- szp += (szq + 1);
- p = (AllocatedBlock*) q;
-
- if (preserve) {
- EWord* pp = p->v;
- while(sz--)
- *pp++ = *dp++;
- }
- split_block((FreeBlock *) p, nw, szp);
- STAT_ALLOCED_BLOCK(SIZEOF(p));
- return p;
- }
- }
-
- /*
- * Update p so that allocate() and deallocate() works.
- * (Note that allocate() may call expand_sbrk(), which in
- * in turn calls deallocate().)
- */
-
- p->hdr = (p->hdr & FREE_ABOVE_BIT) | szp;
- p->v[szp] &= ~FREE_ABOVE_BIT;
-
- npp = allocate(nb, ELIB_ALIGN, 0);
- if(npp == NULL)
- return NULL;
- if (preserve) {
- EWord* pp = npp->v;
- while(sz--)
- *pp++ = *dp++;
- }
- deallocate(p, 0);
- return npp;
- }
-}
-
-/*
-** What malloc() and friends should do (and return) when the heap is
-** exhausted. [sverkerw]
-*/
-static void* heap_exhausted(void)
-{
- /* Choose behaviour */
-#if 0
- /* Crash-and-burn --- leave a usable corpse (hopefully) */
- abort();
-#endif
- /* The usual ANSI-compliant behaviour */
- return NULL;
-}
-
-/*
-** Allocate size bytes of memory
-*/
-void* ELIB_PREFIX(malloc, (size_t nb))
-{
- void *res;
- AllocatedBlock* p;
-
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if (nb == 0)
- res = NULL;
- else if ((p = allocate(nb, ELIB_ALIGN, 0)) != 0) {
- ELIB_ALIGN_CHECK(p->v);
- res = p->v;
- }
- else
- res = heap_exhausted();
-
- erts_mtx_unlock(&malloc_mutex);
-
- return res;
-}
-
-
-void* ELIB_PREFIX(calloc, (size_t nelem, size_t size))
-{
- void *res;
- int nb;
- AllocatedBlock* p;
-
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if ((nb = nelem * size) == 0)
- res = NULL;
- else if ((p = allocate(nb, ELIB_ALIGN, 1)) != 0) {
- ELIB_ALIGN_CHECK(p->v);
- res = p->v;
- }
- else
- res = heap_exhausted();
-
- erts_mtx_unlock(&malloc_mutex);
-
- return res;
-}
-
-/*
-** Free memory allocated by malloc
-*/
-
-void ELIB_PREFIX(free, (EWord* p))
-{
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if (p != 0)
- deallocate((AllocatedBlock*)(p-1), 1);
-
- erts_mtx_unlock(&malloc_mutex);
-}
-
-void ELIB_PREFIX(cfree, (EWord* p))
-{
- ELIB_PREFIX(free, (p));
-}
-
-
-/*
-** Realloc the memory allocated in p to nb number of bytes
-**
-*/
-
-void* ELIB_PREFIX(realloc, (EWord* p, size_t nb))
-{
- void *res = NULL;
- AllocatedBlock* pp;
-
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if (p != 0) {
- pp = (AllocatedBlock*) (p-1);
- if (nb > 0) {
- if ((pp = reallocate(pp, nb, 1)) != 0) {
- ELIB_ALIGN_CHECK(pp->v);
- res = pp->v;
- }
- }
- else
- deallocate(pp, 1);
- }
- else if (nb > 0) {
- if ((pp = allocate(nb, ELIB_ALIGN, 0)) != 0) {
- ELIB_ALIGN_CHECK(pp->v);
- res = pp->v;
- }
- else
- res = heap_exhausted();
- }
-
- erts_mtx_unlock(&malloc_mutex);
-
- return res;
-}
-
-/*
-** Resize the memory area pointed to by p with nb number of bytes
-*/
-void* ELIB_PREFIX(memresize, (EWord* p, int nb))
-{
- void *res = NULL;
- AllocatedBlock* pp;
-
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if (p != 0) {
- pp = (AllocatedBlock*) (p-1);
- if (nb > 0) {
- if ((pp = reallocate(pp, nb, 0)) != 0) {
- ELIB_ALIGN_CHECK(pp->v);
- res = pp->v;
- }
- }
- else
- deallocate(pp, 1);
- }
- else if (nb > 0) {
- if ((pp = allocate(nb, ELIB_ALIGN, 0)) != 0) {
- ELIB_ALIGN_CHECK(pp->v);
- res = pp->v;
- }
- else
- res = heap_exhausted();
- }
-
- erts_mtx_unlock(&malloc_mutex);
-
- return res;
-}
-
-
-/* Create aligned memory a must be a power of 2 !!! */
-
-void* ELIB_PREFIX(memalign, (int a, int nb))
-{
- void *res;
- AllocatedBlock* p;
-
- erts_mtx_lock(&malloc_mutex);
- if (elib_need_init)
- locked_elib_init(NULL,(EWord)0);
-
- if (nb == 0 || a <= 0)
- res = NULL;
- else if ((p = allocate(nb, a, 0)) != 0) {
- ALIGN_CHECK(a, p->v);
- res = p->v;
- }
- else
- res = heap_exhausted();
-
- erts_mtx_unlock(&malloc_mutex);
-
- return res;
-}
-
-void* ELIB_PREFIX(valloc, (int nb))
-{
- return ELIB_PREFIX(memalign, (page_size, nb));
-}
-
-
-void* ELIB_PREFIX(pvalloc, (int nb))
-{
- return ELIB_PREFIX(memalign, (page_size, PAGES(nb)*page_size));
-}
-/* Return memory size for pointer p in bytes */
-
-int ELIB_PREFIX(memsize, (p))
-EWord* p;
-{
- return SIZEOF((AllocatedBlock*)(p-1))*4;
-}
-
-
-/*
-** --------------------------------------------------------------------------
-** DEBUG LIBRARY
-** --------------------------------------------------------------------------
-*/
-
-#ifdef ELIB_DEBUG
-
-#define IN_HEAP(p) (((p) >= (char*) eheap) && (p) < (char*) eheap_top)
-/*
-** ptr_to_block: return the pointer to heap block pointed into by ptr
-** Returns 0 if not pointing into a block
-*/
-
-static EWord* ptr_to_block(char* ptr)
-{
- AllocatedBlock* p = heap_head;
- EWord sz;
-
- while((sz = SIZEOF(p)) != 0) {
- if ((ptr >= (char*) p->v) && (ptr < (char*)(p->v+sz)))
- return p->v;
- p = (AllocatedBlock*) (p->v + sz);
- }
- return 0;
-}
-
-/*
-** Validate a pointer
-** returns:
-** 0 - if points to start of a block
-** 1 - if points outsize heap
-** -1 - if points inside block
-**
-*/
-static int check_pointer(char* ptr)
-{
- if (IN_HEAP(ptr)) {
- if (ptr_to_block(ptr) == 0)
- return 1;
- return 0;
- }
- return -1;
-}
-
-/*
-** Validate a memory area
-** returns:
-** 0 - if area is included in a block
-** -1 - if area overlap a heap block
-** 1 - if area is outside heap
-*/
-static int check_area(char* ptr, int n)
-{
- if (IN_HEAP(ptr)) {
- if (IN_HEAP(ptr+n-1)) {
- EWord* p1 = ptr_to_block(ptr);
- EWord* p2 = ptr_to_block(ptr+n-1);
-
- if (p1 == p2)
- return (p1 == 0) ? -1 : 0;
- return -1;
- }
- }
- else if (IN_HEAP(ptr+n-1))
- return -1;
- return 1;
-}
-
-/*
-** Check if a block write will overwrite heap block
-*/
-static void check_write(char* ptr, int n, char* file, int line, char* fun)
-{
- if (check_area(ptr, n) == -1) {
- elib_printf(stderr, "RUNTIME ERROR: %s heap overwrite\n", fun);
- elib_printf(stderr, "File: %s Line: %d\n", file, line);
- ELIB_FAILURE;
- }
-}
-
-/*
-** Check if a pointer is an allocated object
-*/
-static void check_allocated_block(char* ptr, char* file, int line, char* fun)
-{
- EWord* q;
-
- if (!IN_HEAP(ptr) || ((q=ptr_to_block(ptr)) == 0) || (ptr != (char*) q)) {
- elib_printf(stderr, "RUNTIME ERROR: %s non heap pointer\n", fun);
- elib_printf(stderr, "File: %s Line: %d\n", file, line);
- ELIB_FAILURE;
- }
-
- if (IS_FREE((AllocatedBlock*)(q-1))) {
- elib_printf(stderr, "RUNTIME ERROR: %s free pointer\n", fun);
- elib_printf(stderr, "File: %s Line: %d\n", file, line);
- ELIB_FAILURE;
- }
-
-}
-
-/*
-** --------------------------------------------------------------------------
-** DEBUG VERSIONS (COMPILED WITH THE ELIB.H)
-** --------------------------------------------------------------------------
-*/
-
-void* elib_dbg_malloc(int n, char* file, int line)
-{
- return elib__malloc(n);
-}
-
-void* elib_dbg_calloc(int n, int s, char* file, int line)
-{
- return elib__calloc(n, s);
-}
-
-void* elib_dbg_realloc(EWord* p, int n, char* file, int line)
-{
- if (p == 0)
- return elib__malloc(n);
- check_allocated_block(p, file, line, "elib_realloc");
- return elib__realloc(p, n);
-}
-
-void elib_dbg_free(EWord* p, char* file, int line)
-{
- if (p == 0)
- return;
- check_allocated_block(p, file, line, "elib_free");
- elib__free(p);
-}
-
-void elib_dbg_cfree(EWord* p, char* file, int line)
-{
- if (p == 0)
- return;
- check_allocated_block(p, file, line, "elib_free");
- elib__cfree(p);
-}
-
-void* elib_dbg_memalign(int a, int n, char* file, int line)
-{
- return elib__memalign(a, n);
-}
-
-void* elib_dbg_valloc(int n, char* file, int line)
-{
- return elib__valloc(n);
-}
-
-void* elib_dbg_pvalloc(int n, char* file, int line)
-{
- return elib__pvalloc(n);
-}
-
-void* elib_dbg_memresize(EWord* p, int n, char* file, int line)
-{
- if (p == 0)
- return elib__malloc(n);
- check_allocated_block(p, file, line, "elib_memresize");
- return elib__memresize(p, n);
-}
-
-int elib_dbg_memsize(void* p, char* file, int line)
-{
- check_allocated_block(p, file, line, "elib_memsize");
- return elib__memsize(p);
-}
-
-/*
-** --------------------------------------------------------------------------
-** LINK TIME FUNCTIONS (NOT COMPILED CALLS)
-** --------------------------------------------------------------------------
-*/
-
-void* elib_malloc(int n)
-{
- return elib_dbg_malloc(n, "", -1);
-}
-
-void* elib_calloc(int n, int s)
-{
- return elib_dbg_calloc(n, s, "", -1);
-}
-
-void* elib_realloc(EWord* p, int n)
-{
- return elib_dbg_realloc(p, n, "", -1);
-}
-
-void elib_free(EWord* p)
-{
- elib_dbg_free(p, "", -1);
-}
-
-void elib_cfree(EWord* p)
-{
- elib_dbg_cfree(p, "", -1);
-}
-
-void* elib_memalign(int a, int n)
-{
- return elib_dbg_memalign(a, n, "", -1);
-}
-
-void* elib_valloc(int n)
-{
- return elib_dbg_valloc(n, "", -1);
-}
-
-void* elib_pvalloc(int n)
-{
- return elib_dbg_pvalloc(n, "", -1);
-}
-
-void* elib_memresize(EWord* p, int n)
-{
- return elib_dbg_memresize(p, n, "", -1);
-}
-
-
-int elib_memsize(EWord* p)
-{
- return elib_dbg_memsize(p, "", -1);
-}
-
-#endif /* ELIB_DEBUG */
-
-/*
-** --------------------------------------------------------------------------
-** Map c library functions to elib
-** --------------------------------------------------------------------------
-*/
-
-#if defined(ELIB_ALLOC_IS_CLIB)
-void* malloc(size_t nb)
-{
- return elib_malloc(nb);
-}
-
-void* calloc(size_t nelem, size_t size)
-{
- return elib_calloc(nelem, size);
-}
-
-
-void free(void *p)
-{
- elib_free(p);
-}
-
-void cfree(void *p)
-{
- elib_cfree(p);
-}
-
-void* realloc(void* p, size_t nb)
-{
- return elib_realloc(p, nb);
-}
-
-
-void* memalign(size_t a, size_t s)
-{
- return elib_memalign(a, s);
-}
-
-void* valloc(size_t nb)
-{
- return elib_valloc(nb);
-}
-
-void* pvalloc(size_t nb)
-{
- return elib_pvalloc(nb);
-}
-
-#if 0
-void* memresize(void* p, int nb)
-{
- return elib_memresize(p, nb);
-}
-
-int memsize(void* p)
-{
- return elib_memsize(p);
-}
-#endif
-#endif /* ELIB_ALLOC_IS_CLIB */
-
-#endif /* ENABLE_ELIB_MALLOC */
-
-void elib_ensure_initialized(void)
-{
-#ifdef ENABLE_ELIB_MALLOC
-#ifndef ELIB_DONT_INITIALIZE
- elib_init(NULL, 0);
-#endif
-#endif
-}
-
-#ifdef ENABLE_ELIB_MALLOC
-/**
- ** A Slightly modified version of the "address order best fit" algorithm
- ** used in erl_bestfit_alloc.c. Comments refer to that implementation.
- **/
-
-/*
- * Description: A combined "address order best fit"/"best fit" allocator
- * based on a Red-Black (binary search) Tree. The search,
- * insert, and delete operations are all O(log n) operations
- * on a Red-Black Tree. In the "address order best fit" case
- * n equals number of free blocks, and in the "best fit" case
- * n equals number of distinct sizes of free blocks. Red-Black
- * Trees are described in "Introduction to Algorithms", by
- * Thomas H. Cormen, Charles E. Leiserson, and
- * Ronald L. Riverest.
- *
- * This module is a callback-module for erl_alloc_util.c
- *
- * Author: Rickard Green
- */
-
-#ifdef DEBUG
-#if 0
-#define HARD_DEBUG
-#endif
-#else
-#undef HARD_DEBUG
-#endif
-
-#define SZ_MASK SIZE_MASK
-#define FLG_MASK (~(SZ_MASK))
-
-#define BLK_SZ(B) (*((Block_t *) (B)) & SZ_MASK)
-
-#define TREE_NODE_FLG (((Uint) 1) << 0)
-#define RED_FLG (((Uint) 1) << 1)
-#ifdef HARD_DEBUG
-# define LEFT_VISITED_FLG (((Uint) 1) << 2)
-# define RIGHT_VISITED_FLG (((Uint) 1) << 3)
-#endif
-
-#define IS_TREE_NODE(N) (((RBTree_t *) (N))->flags & TREE_NODE_FLG)
-#define IS_LIST_ELEM(N) (!IS_TREE_NODE(((RBTree_t *) (N))))
-
-#define SET_TREE_NODE(N) (((RBTree_t *) (N))->flags |= TREE_NODE_FLG)
-#define SET_LIST_ELEM(N) (((RBTree_t *) (N))->flags &= ~TREE_NODE_FLG)
-
-#define IS_RED(N) (((RBTree_t *) (N)) \
- && ((RBTree_t *) (N))->flags & RED_FLG)
-#define IS_BLACK(N) (!IS_RED(((RBTree_t *) (N))))
-
-#define SET_RED(N) (((RBTree_t *) (N))->flags |= RED_FLG)
-#define SET_BLACK(N) (((RBTree_t *) (N))->flags &= ~RED_FLG)
-
-#undef ASSERT
-#define ASSERT ASSERT_EXPR
-
-#if 1
-#define RBT_ASSERT ASSERT
-#else
-#define RBT_ASSERT(x)
-#endif
-
-
-#ifdef HARD_DEBUG
-static RBTree_t * check_tree(Uint);
-#endif
-
-#ifdef ERTS_INLINE
-# ifndef ERTS_CAN_INLINE
-# define ERTS_CAN_INLINE 1
-# endif
-#else
-# if defined(__GNUC__)
-# define ERTS_CAN_INLINE 1
-# define ERTS_INLINE __inline__
-# elif defined(__WIN32__)
-# define ERTS_CAN_INLINE 1
-# define ERTS_INLINE __inline
-# else
-# define ERTS_CAN_INLINE 0
-# define ERTS_INLINE
-# endif
-#endif
-
-/* Types... */
-#if 0
-typedef struct RBTree_t_ RBTree_t;
-
-struct RBTree_t_ {
- Block_t hdr;
- Uint flags;
- RBTree_t *parent;
- RBTree_t *left;
- RBTree_t *right;
-};
-#endif
-
-#if 0
-typedef struct {
- RBTree_t t;
- RBTree_t *next;
-} RBTreeList_t;
-
-#define LIST_NEXT(N) (((RBTreeList_t *) (N))->next)
-#define LIST_PREV(N) (((RBTreeList_t *) (N))->t.parent)
-#endif
-
-#ifdef DEBUG
-
-/* Destroy all tree fields */
-#define DESTROY_TREE_NODE(N) \
- sys_memset((void *) (((Block_t *) (N)) + 1), \
- 0xff, \
- (sizeof(RBTree_t) - sizeof(Block_t)))
-
-/* Destroy all tree and list fields */
-#define DESTROY_LIST_ELEM(N) \
- sys_memset((void *) (((Block_t *) (N)) + 1), \
- 0xff, \
- (sizeof(RBTreeList_t) - sizeof(Block_t)))
-
-#else
-
-#define DESTROY_TREE_NODE(N)
-#define DESTROY_LIST_ELEM(N)
-
-#endif
-
-
-/*
- * Red-Black Tree operations needed
- */
-
-static ERTS_INLINE void
-left_rotate(RBTree_t **root, RBTree_t *x)
-{
- RBTree_t *y = x->right;
- x->right = y->left;
- if (y->left)
- y->left->parent = x;
- y->parent = x->parent;
- if (!y->parent) {
- RBT_ASSERT(*root == x);
- *root = y;
- }
- else if (x == x->parent->left)
- x->parent->left = y;
- else {
- RBT_ASSERT(x == x->parent->right);
- x->parent->right = y;
- }
- y->left = x;
- x->parent = y;
-}
-
-static ERTS_INLINE void
-right_rotate(RBTree_t **root, RBTree_t *x)
-{
- RBTree_t *y = x->left;
- x->left = y->right;
- if (y->right)
- y->right->parent = x;
- y->parent = x->parent;
- if (!y->parent) {
- RBT_ASSERT(*root == x);
- *root = y;
- }
- else if (x == x->parent->right)
- x->parent->right = y;
- else {
- RBT_ASSERT(x == x->parent->left);
- x->parent->left = y;
- }
- y->right = x;
- x->parent = y;
-}
-
-
-/*
- * Replace node x with node y
- * NOTE: block header of y is not changed
- */
-static ERTS_INLINE void
-replace(RBTree_t **root, RBTree_t *x, RBTree_t *y)
-{
-
- if (!x->parent) {
- RBT_ASSERT(*root == x);
- *root = y;
- }
- else if (x == x->parent->left)
- x->parent->left = y;
- else {
- RBT_ASSERT(x == x->parent->right);
- x->parent->right = y;
- }
- if (x->left) {
- RBT_ASSERT(x->left->parent == x);
- x->left->parent = y;
- }
- if (x->right) {
- RBT_ASSERT(x->right->parent == x);
- x->right->parent = y;
- }
-
- y->flags = x->flags;
- y->parent = x->parent;
- y->right = x->right;
- y->left = x->left;
-
- DESTROY_TREE_NODE(x);
-
-}
-
-static void
-tree_insert_fixup(RBTree_t *blk)
-{
- RBTree_t *x = blk, *y;
-
- /*
- * Rearrange the tree so that it satisfies the Red-Black Tree properties
- */
-
- RBT_ASSERT(x != root && IS_RED(x->parent));
- do {
-
- /*
- * x and its parent are both red. Move the red pair up the tree
- * until we get to the root or until we can separate them.
- */
-
- RBT_ASSERT(IS_RED(x));
- RBT_ASSERT(IS_BLACK(x->parent->parent));
- RBT_ASSERT(x->parent->parent);
-
- if (x->parent == x->parent->parent->left) {
- y = x->parent->parent->right;
- if (IS_RED(y)) {
- SET_BLACK(y);
- x = x->parent;
- SET_BLACK(x);
- x = x->parent;
- SET_RED(x);
- }
- else {
-
- if (x == x->parent->right) {
- x = x->parent;
- left_rotate(&root, x);
- }
-
- RBT_ASSERT(x == x->parent->parent->left->left);
- RBT_ASSERT(IS_RED(x));
- RBT_ASSERT(IS_RED(x->parent));
- RBT_ASSERT(IS_BLACK(x->parent->parent));
- RBT_ASSERT(IS_BLACK(y));
-
- SET_BLACK(x->parent);
- SET_RED(x->parent->parent);
- right_rotate(&root, x->parent->parent);
-
- RBT_ASSERT(x == x->parent->left);
- RBT_ASSERT(IS_RED(x));
- RBT_ASSERT(IS_RED(x->parent->right));
- RBT_ASSERT(IS_BLACK(x->parent));
- break;
- }
- }
- else {
- RBT_ASSERT(x->parent == x->parent->parent->right);
- y = x->parent->parent->left;
- if (IS_RED(y)) {
- SET_BLACK(y);
- x = x->parent;
- SET_BLACK(x);
- x = x->parent;
- SET_RED(x);
- }
- else {
-
- if (x == x->parent->left) {
- x = x->parent;
- right_rotate(&root, x);
- }
-
- RBT_ASSERT(x == x->parent->parent->right->right);
- RBT_ASSERT(IS_RED(x));
- RBT_ASSERT(IS_RED(x->parent));
- RBT_ASSERT(IS_BLACK(x->parent->parent));
- RBT_ASSERT(IS_BLACK(y));
-
- SET_BLACK(x->parent);
- SET_RED(x->parent->parent);
- left_rotate(&root, x->parent->parent);
-
- RBT_ASSERT(x == x->parent->right);
- RBT_ASSERT(IS_RED(x));
- RBT_ASSERT(IS_RED(x->parent->left));
- RBT_ASSERT(IS_BLACK(x->parent));
- break;
- }
- }
- } while (x != root && IS_RED(x->parent));
-
- SET_BLACK(root);
-}
-
-static void
-unlink_free_block(Block_t *del)
-{
- Uint spliced_is_black;
- RBTree_t *x, *y, *z = (RBTree_t *) del;
- RBTree_t null_x; /* null_x is used to get the fixup started when we
- splice out a node without children. */
-
- null_x.parent = NULL;
-
-#ifdef HARD_DEBUG
- check_tree(0);
-#endif
-
- /* Remove node from tree... */
-
- /* Find node to splice out */
- if (!z->left || !z->right)
- y = z;
- else
- /* Set y to z:s successor */
- for(y = z->right; y->left; y = y->left);
- /* splice out y */
- x = y->left ? y->left : y->right;
- spliced_is_black = IS_BLACK(y);
- if (x) {
- x->parent = y->parent;
- }
- else if (!x && spliced_is_black) {
- x = &null_x;
- x->flags = 0;
- SET_BLACK(x);
- x->right = x->left = NULL;
- x->parent = y->parent;
- y->left = x;
- }
-
- if (!y->parent) {
- RBT_ASSERT(root == y);
- root = x;
- }
- else if (y == y->parent->left)
- y->parent->left = x;
- else {
- RBT_ASSERT(y == y->parent->right);
- y->parent->right = x;
- }
- if (y != z) {
- /* We spliced out the successor of z; replace z by the successor */
- replace(&root, z, y);
- }
-
- if (spliced_is_black) {
- /* We removed a black node which makes the resulting tree
- violate the Red-Black Tree properties. Fixup tree... */
-
- while (IS_BLACK(x) && x->parent) {
-
- /*
- * x has an "extra black" which we move up the tree
- * until we reach the root or until we can get rid of it.
- *
- * y is the sibbling of x
- */
-
- if (x == x->parent->left) {
- y = x->parent->right;
- RBT_ASSERT(y);
- if (IS_RED(y)) {
- RBT_ASSERT(y->right);
- RBT_ASSERT(y->left);
- SET_BLACK(y);
- RBT_ASSERT(IS_BLACK(x->parent));
- SET_RED(x->parent);
- left_rotate(&root, x->parent);
- y = x->parent->right;
- }
- RBT_ASSERT(y);
- RBT_ASSERT(IS_BLACK(y));
- if (IS_BLACK(y->left) && IS_BLACK(y->right)) {
- SET_RED(y);
- x = x->parent;
- }
- else {
- if (IS_BLACK(y->right)) {
- SET_BLACK(y->left);
- SET_RED(y);
- right_rotate(&root, y);
- y = x->parent->right;
- }
- RBT_ASSERT(y);
- if (IS_RED(x->parent)) {
-
- SET_BLACK(x->parent);
- SET_RED(y);
- }
- RBT_ASSERT(y->right);
- SET_BLACK(y->right);
- left_rotate(&root, x->parent);
- x = root;
- break;
- }
- }
- else {
- RBT_ASSERT(x == x->parent->right);
- y = x->parent->left;
- RBT_ASSERT(y);
- if (IS_RED(y)) {
- RBT_ASSERT(y->right);
- RBT_ASSERT(y->left);
- SET_BLACK(y);
- RBT_ASSERT(IS_BLACK(x->parent));
- SET_RED(x->parent);
- right_rotate(&root, x->parent);
- y = x->parent->left;
- }
- RBT_ASSERT(y);
- RBT_ASSERT(IS_BLACK(y));
- if (IS_BLACK(y->right) && IS_BLACK(y->left)) {
- SET_RED(y);
- x = x->parent;
- }
- else {
- if (IS_BLACK(y->left)) {
- SET_BLACK(y->right);
- SET_RED(y);
- left_rotate(&root, y);
- y = x->parent->left;
- }
- RBT_ASSERT(y);
- if (IS_RED(x->parent)) {
- SET_BLACK(x->parent);
- SET_RED(y);
- }
- RBT_ASSERT(y->left);
- SET_BLACK(y->left);
- right_rotate(&root, x->parent);
- x = root;
- break;
- }
- }
- }
- SET_BLACK(x);
-
- if (null_x.parent) {
- if (null_x.parent->left == &null_x)
- null_x.parent->left = NULL;
- else {
- RBT_ASSERT(null_x.parent->right == &null_x);
- null_x.parent->right = NULL;
- }
- RBT_ASSERT(!null_x.left);
- RBT_ASSERT(!null_x.right);
- }
- else if (root == &null_x) {
- root = NULL;
- RBT_ASSERT(!null_x.left);
- RBT_ASSERT(!null_x.right);
- }
- }
-
-
- DESTROY_TREE_NODE(del);
-
-#ifdef HARD_DEBUG
- check_tree(0);
-#endif
-
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * "Address order best fit" specific callbacks. *
-\* */
-
-static void
-link_free_block(Block_t *block)
-{
- RBTree_t *blk = (RBTree_t *) block;
- Uint blk_sz = BLK_SZ(blk);
-
- blk->flags = 0;
- blk->left = NULL;
- blk->right = NULL;
-
- if (!root) {
- blk->parent = NULL;
- SET_BLACK(blk);
- root = blk;
- } else {
- RBTree_t *x = root;
- while (1) {
- Uint size;
-
- size = BLK_SZ(x);
-
- if (blk_sz < size || (blk_sz == size && blk < x)) {
- if (!x->left) {
- blk->parent = x;
- x->left = blk;
- break;
- }
- x = x->left;
- }
- else {
- if (!x->right) {
- blk->parent = x;
- x->right = blk;
- break;
- }
- x = x->right;
- }
-
- }
-
- /* Insert block into size tree */
- RBT_ASSERT(blk->parent);
-
- SET_RED(blk);
- if (IS_RED(blk->parent)) {
- tree_insert_fixup(blk);
- }
- }
-
-#ifdef HARD_DEBUG
- check_tree(0);
-#endif
-}
-
-
-static Block_t *
-get_free_block(Uint size)
-{
- RBTree_t *x = root;
- RBTree_t *blk = NULL;
- Uint blk_sz;
-
- while (x) {
- blk_sz = BLK_SZ(x);
- if (blk_sz < size) {
- x = x->right;
- }
- else {
- blk = x;
- x = x->left;
- }
- }
-
- if (!blk)
- return NULL;
-
-#ifdef HARD_DEBUG
- ASSERT(blk == check_tree(size));
-#endif
-
- unlink_free_block((Block_t *) blk);
-
- return (Block_t *) blk;
-}
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * Debug functions *
-\* */
-
-
-#ifdef HARD_DEBUG
-
-#define IS_LEFT_VISITED(FB) ((FB)->flags & LEFT_VISITED_FLG)
-#define IS_RIGHT_VISITED(FB) ((FB)->flags & RIGHT_VISITED_FLG)
-
-#define SET_LEFT_VISITED(FB) ((FB)->flags |= LEFT_VISITED_FLG)
-#define SET_RIGHT_VISITED(FB) ((FB)->flags |= RIGHT_VISITED_FLG)
-
-#define UNSET_LEFT_VISITED(FB) ((FB)->flags &= ~LEFT_VISITED_FLG)
-#define UNSET_RIGHT_VISITED(FB) ((FB)->flags &= ~RIGHT_VISITED_FLG)
-
-
-#if 0
-# define PRINT_TREE
-#else
-# undef PRINT_TREE
-#endif
-
-#ifdef PRINT_TREE
-static void print_tree(void);
-#endif
-
-/*
- * Checks that the order between parent and children are correct,
- * and that the Red-Black Tree properies are satisfied. if size > 0,
- * check_tree() returns a node that satisfies "best fit" resp.
- * "address order best fit".
- *
- * The Red-Black Tree properies are:
- * 1. Every node is either red or black.
- * 2. Every leaf (NIL) is black.
- * 3. If a node is red, then both its children are black.
- * 4. Every simple path from a node to a descendant leaf
- * contains the same number of black nodes.
- */
-
-static RBTree_t *
-check_tree(Uint size)
-{
- RBTree_t *res = NULL;
- Sint blacks;
- Sint curr_blacks;
- RBTree_t *x;
-
-#ifdef PRINT_TREE
- print_tree();
-#endif
-
- if (!root)
- return res;
-
- x = root;
- ASSERT(IS_BLACK(x));
- ASSERT(!x->parent);
- curr_blacks = 1;
- blacks = -1;
-
- while (x) {
- if (!IS_LEFT_VISITED(x)) {
- SET_LEFT_VISITED(x);
- if (x->left) {
- x = x->left;
- if (IS_BLACK(x))
- curr_blacks++;
- continue;
- }
- else {
- if (blacks < 0)
- blacks = curr_blacks;
- ASSERT(blacks == curr_blacks);
- }
- }
-
- if (!IS_RIGHT_VISITED(x)) {
- SET_RIGHT_VISITED(x);
- if (x->right) {
- x = x->right;
- if (IS_BLACK(x))
- curr_blacks++;
- continue;
- }
- else {
- if (blacks < 0)
- blacks = curr_blacks;
- ASSERT(blacks == curr_blacks);
- }
- }
-
-
- if (IS_RED(x)) {
- ASSERT(IS_BLACK(x->right));
- ASSERT(IS_BLACK(x->left));
- }
-
- ASSERT(x->parent || x == root);
-
- if (x->left) {
- ASSERT(x->left->parent == x);
- ASSERT(BLK_SZ(x->left) < BLK_SZ(x)
- || (BLK_SZ(x->left) == BLK_SZ(x) && x->left < x));
- }
-
- if (x->right) {
- ASSERT(x->right->parent == x);
- ASSERT(BLK_SZ(x->right) > BLK_SZ(x)
- || (BLK_SZ(x->right) == BLK_SZ(x) && x->right > x));
- }
-
- if (size && BLK_SZ(x) >= size) {
- if (!res
- || BLK_SZ(x) < BLK_SZ(res)
- || (BLK_SZ(x) == BLK_SZ(res) && x < res))
- res = x;
- }
-
- UNSET_LEFT_VISITED(x);
- UNSET_RIGHT_VISITED(x);
- if (IS_BLACK(x))
- curr_blacks--;
- x = x->parent;
-
- }
-
- ASSERT(curr_blacks == 0);
-
- UNSET_LEFT_VISITED(root);
- UNSET_RIGHT_VISITED(root);
-
- return res;
-
-}
-
-
-#ifdef PRINT_TREE
-#define INDENT_STEP 2
-
-#include <stdio.h>
-
-static void
-print_tree_aux(RBTree_t *x, int indent)
-{
- int i;
-
- if (!x) {
- for (i = 0; i < indent; i++) {
- putc(' ', stderr);
- }
- fprintf(stderr, "BLACK: nil\r\n");
- }
- else {
- print_tree_aux(x->right, indent + INDENT_STEP);
- for (i = 0; i < indent; i++) {
- putc(' ', stderr);
- }
- fprintf(stderr, "%s: sz=%lu addr=0x%lx\r\n",
- IS_BLACK(x) ? "BLACK" : "RED",
- BLK_SZ(x),
- (Uint) x);
- print_tree_aux(x->left, indent + INDENT_STEP);
- }
-}
-
-
-static void
-print_tree(void)
-{
- fprintf(stderr, " --- Size-Adress tree begin ---\r\n");
- print_tree_aux(root, 0);
- fprintf(stderr, " --- Size-Adress tree end ---\r\n");
-}
-
-#endif
-
-#endif
-
-#endif /* ENABLE_ELIB_MALLOC */
diff --git a/erts/emulator/beam/elib_stat.h b/erts/emulator/beam/elib_stat.h
deleted file mode 100644
index d8c7f31737..0000000000
--- a/erts/emulator/beam/elib_stat.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
-** Interface to elib statistics
-**
-*/
-#ifndef __ELIB_STAT_H__
-#define __ELIB_STAT_H__
-
-struct elib_stat {
- int mem_total; /* Number of heap words */
- int mem_blocks; /* Number of block */
- int mem_alloc; /* Number of words in use */
- int mem_free; /* Number of words free */
- int min_used; /* Size of the smallest block used */
- int max_free; /* Size of the largest free block */
- int free_blocks; /* Number of fragments in free list */
- int mem_max_alloc;/* Max number of words in use */
-};
-
-EXTERN_FUNCTION(void, elib_statistics, (void*));
-EXTERN_FUNCTION(int, elib_check_heap, (_VOID_));
-EXTERN_FUNCTION(void, elib_heap_dump, (char*));
-EXTERN_FUNCTION(void, elib_stat, (struct elib_stat*));
-EXTERN_FUNCTION(int, elib_heap_map, (unsigned char*, int));
-EXTERN_FUNCTION(int, elib_histo, (unsigned long*, unsigned long*, int, int));
-
-#endif
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 16ae643ed9..07b4167b27 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -38,9 +38,6 @@
#include "erl_bits.h"
#include "erl_instrument.h"
#include "erl_mseg.h"
-#ifdef ELIB_ALLOC_IS_CLIB
-#include "erl_version.h"
-#endif
#include "erl_monitors.h"
#include "erl_bif_timer.h"
#if defined(ERTS_ALC_T_DRV_SEL_D_STATE) || defined(ERTS_ALC_T_DRV_EV_D_STATE)
@@ -64,8 +61,15 @@
#ifdef DEBUG
static Uint install_debug_functions(void);
+#if 0
+#define HARD_DEBUG
+#ifdef __GNUC__
+#warning "* * * * * * * * * * * * * *"
+#warning "* HARD DEBUG IS ENABLED! *"
+#warning "* * * * * * * * * * * * * *"
+#endif
+#endif
#endif
-extern void elib_ensure_initialized(void);
ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
@@ -391,6 +395,10 @@ refuse_af_strategy(struct au_init *init)
static void init_thr_ix(int static_ixs);
+#ifdef HARD_DEBUG
+static void hdbg_init(void);
+#endif
+
void
erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
{
@@ -406,6 +414,10 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
ERTS_DEFAULT_ALCU_INIT
};
+#ifdef HARD_DEBUG
+ hdbg_init();
+#endif
+
erts_sys_alloc_init();
init_thr_ix(erts_no_schedulers);
erts_init_utils_mem();
@@ -2305,13 +2317,8 @@ erts_allocator_info_term(void *proc, Eterm which_alloc, int only_sz)
l = 0;
as[l] = am_atom_put("e", 1);
ts[l++] = am_true;
-#ifdef ELIB_ALLOC_IS_CLIB
- as[l] = am_atom_put("m", 1);
- ts[l++] = am_atom_put("elib", 4);
-#else
as[l] = am_atom_put("m", 1);
ts[l++] = am_atom_put("libc", 4);
-#endif
if(sas.trim_threshold >= 0) {
as[l] = am_atom_put("tt", 2);
ts[l++] = erts_bld_uint(hpp, szp,
@@ -2465,11 +2472,7 @@ erts_allocator_info(int to, void *arg)
case ERTS_ALC_A_SYSTEM: {
SysAllocStat sas;
erts_print(to, arg, "option e: true\n");
-#ifdef ELIB_ALLOC_IS_CLIB
- erts_print(to, arg, "option m: elib\n");
-#else
erts_print(to, arg, "option m: libc\n");
-#endif
sys_alloc_stat(&sas);
if(sas.trim_threshold >= 0)
erts_print(to, arg, "option tt: %d\n", sas.trim_threshold);
@@ -2573,13 +2576,8 @@ erts_allocator_options(void *proc)
switch (a) {
case ERTS_ALC_A_SYSTEM:
-#ifdef ELIB_ALLOC_IS_CLIB
- as[l] = am_atom_put("m", 1);
- ts[l++] = am_atom_put("elib", 4);
-#else
as[l] = am_atom_put("m", 1);
ts[l++] = am_atom_put("libc", 4);
-#endif
if(sas.trim_threshold >= 0) {
as[l] = am_atom_put("tt", 2);
ts[l++] = erts_bld_uint(hpp, szp,
@@ -2650,23 +2648,7 @@ erts_allocator_options(void *proc)
features = length ? erts_bld_list(hpp, szp, length, terms) : NIL;
-#if defined(ELIB_ALLOC_IS_CLIB)
- {
- Eterm version;
- int i;
- int ver[5];
- i = sscanf(ERLANG_VERSION,
- "%d.%d.%d.%d.%d",
- &ver[0], &ver[1], &ver[2], &ver[3], &ver[4]);
-
- version = NIL;
- for(i--; i >= 0; i--)
- version = erts_bld_cons(hpp, szp, make_small(ver[i]), version);
-
- res = erts_bld_tuple(hpp, szp, 4,
- am_elib_malloc, version, features, settings);
- }
-#elif defined(__GLIBC__)
+#if defined(__GLIBC__)
{
Eterm AM_glibc = am_atom_put("glibc", 5);
Eterm version;
@@ -2862,12 +2844,10 @@ unsigned long erts_alc_test(unsigned long op,
break;
}
case 0xf0a:
- if (ethr_mutex_lock((ethr_mutex *) a1) != 0)
- ERTS_ALC_TEST_ABORT;
+ ethr_mutex_lock((ethr_mutex *) a1);
break;
case 0xf0b:
- if (ethr_mutex_unlock((ethr_mutex *) a1) != 0)
- ERTS_ALC_TEST_ABORT;
+ ethr_mutex_unlock((ethr_mutex *) a1);
break;
case 0xf0c: {
ethr_cond *cnd = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_cond));
@@ -2883,16 +2863,13 @@ unsigned long erts_alc_test(unsigned long op,
break;
}
case 0xf0e:
- if (ethr_cond_broadcast((ethr_cond *) a1) != 0)
- ERTS_ALC_TEST_ABORT;
+ ethr_cond_broadcast((ethr_cond *) a1);
break;
case 0xf0f: {
int res;
do {
res = ethr_cond_wait((ethr_cond *) a1, (ethr_mutex *) a2);
} while (res == EINTR);
- if (res != 0)
- ERTS_ALC_TEST_ABORT;
break;
}
case 0xf10: {
@@ -2939,8 +2916,11 @@ unsigned long erts_alc_test(unsigned long op,
#undef PRINT_OPS
#endif
-
+#ifdef HARD_DEBUG
+#define FENCE_SZ (4*sizeof(UWord))
+#else
#define FENCE_SZ (3*sizeof(UWord))
+#endif
#if defined(ARCH_64)
#define FENCE_PATTERN 0xABCDEF97ABCDEF97
@@ -2962,6 +2942,104 @@ unsigned long erts_alc_test(unsigned long op,
#define GET_TYPE_OF_PATTERN(P) \
(((P) >> TYPE_PATTERN_SHIFT) & TYPE_PATTERN_MASK)
+#ifdef HARD_DEBUG
+
+#define ERL_ALC_HDBG_MAX_MBLK 100000
+#define ERTS_ALC_O_CHECK -1
+
+typedef struct hdbg_mblk_ hdbg_mblk;
+struct hdbg_mblk_ {
+ hdbg_mblk *next;
+ hdbg_mblk *prev;
+ void *p;
+ Uint s;
+ ErtsAlcType_t n;
+};
+
+static hdbg_mblk hdbg_mblks[ERL_ALC_HDBG_MAX_MBLK];
+
+static hdbg_mblk *free_hdbg_mblks;
+static hdbg_mblk *used_hdbg_mblks;
+static erts_mtx_t hdbg_mblk_mtx;
+
+static void
+hdbg_init(void)
+{
+ int i;
+ for (i = 0; i < ERL_ALC_HDBG_MAX_MBLK-1; i++)
+ hdbg_mblks[i].next = &hdbg_mblks[i+1];
+ hdbg_mblks[ERL_ALC_HDBG_MAX_MBLK-1].next = NULL;
+ free_hdbg_mblks = &hdbg_mblks[0];
+ used_hdbg_mblks = NULL;
+ erts_mtx_init(&hdbg_mblk_mtx, "erts_alloc_hard_debug");
+}
+
+static void *check_memory_fence(void *ptr,
+ Uint *size,
+ ErtsAlcType_t n,
+ int func);
+void erts_hdbg_chk_blks(void);
+
+void
+erts_hdbg_chk_blks(void)
+{
+ hdbg_mblk *mblk;
+
+ erts_mtx_lock(&hdbg_mblk_mtx);
+ for (mblk = used_hdbg_mblks; mblk; mblk = mblk->next) {
+ Uint sz;
+ check_memory_fence(mblk->p, &sz, mblk->n, ERTS_ALC_O_CHECK);
+ ASSERT(sz == mblk->s);
+ }
+ erts_mtx_unlock(&hdbg_mblk_mtx);
+}
+
+static hdbg_mblk *
+hdbg_alloc(void *p, Uint s, ErtsAlcType_t n)
+{
+ hdbg_mblk *mblk;
+
+ erts_mtx_lock(&hdbg_mblk_mtx);
+ mblk = free_hdbg_mblks;
+ if (!mblk) {
+ erts_fprintf(stderr,
+ "Ran out of debug blocks; please increase "
+ "ERL_ALC_HDBG_MAX_MBLK=%d and recompile!\n",
+ ERL_ALC_HDBG_MAX_MBLK);
+ abort();
+ }
+ free_hdbg_mblks = mblk->next;
+
+ mblk->p = p;
+ mblk->s = s;
+ mblk->n = n;
+
+ mblk->next = used_hdbg_mblks;
+ mblk->prev = NULL;
+ if (used_hdbg_mblks)
+ used_hdbg_mblks->prev = mblk;
+ used_hdbg_mblks = mblk;
+ erts_mtx_unlock(&hdbg_mblk_mtx);
+ return (void *) mblk;
+}
+
+static void
+hdbg_free(hdbg_mblk *mblk)
+{
+ erts_mtx_lock(&hdbg_mblk_mtx);
+ if (mblk->next)
+ mblk->next->prev = mblk->prev;
+ if (mblk->prev)
+ mblk->prev->next = mblk->next;
+ else
+ used_hdbg_mblks = mblk->next;
+
+ mblk->next = free_hdbg_mblks;
+ free_hdbg_mblks = mblk;
+ erts_mtx_unlock(&hdbg_mblk_mtx);
+}
+
+#endif
#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
static void *check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func);
@@ -3007,17 +3085,28 @@ set_memory_fence(void *ptr, Uint sz, ErtsAlcType_t n)
{
UWord *ui_ptr;
UWord pattern;
+#ifdef HARD_DEBUG
+ hdbg_mblk **mblkpp;
+#endif
if (!ptr)
return NULL;
ui_ptr = (UWord *) ptr;
pattern = MK_PATTERN(n);
-
+
+#ifdef HARD_DEBUG
+ mblkpp = (hdbg_mblk **) ui_ptr++;
+#endif
+
*(ui_ptr++) = sz;
*(ui_ptr++) = pattern;
memcpy((void *) (((char *) ui_ptr)+sz), (void *) &pattern, sizeof(UWord));
+#ifdef HARD_DEBUG
+ *mblkpp = hdbg_alloc((void *) ui_ptr, sz, n);
+#endif
+
return (void *) ui_ptr;
}
@@ -3029,6 +3118,9 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func)
UWord pre_pattern;
UWord post_pattern;
UWord *ui_ptr;
+#ifdef HARD_DEBUG
+ hdbg_mblk *mblk;
+#endif
if (!ptr)
return NULL;
@@ -3036,6 +3128,9 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func)
ui_ptr = (UWord *) ptr;
pre_pattern = *(--ui_ptr);
*size = sz = *(--ui_ptr);
+#ifdef HARD_DEBUG
+ mblk = (hdbg_mblk *) *(--ui_ptr);
+#endif
found_type = GET_TYPE_OF_PATTERN(pre_pattern);
if (pre_pattern != MK_PATTERN(n)) {
@@ -3091,6 +3186,17 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func)
(unsigned long) ptr, (unsigned long) sz, ftype, op_str, otype);
}
+#ifdef HARD_DEBUG
+ switch (func) {
+ case ERTS_ALC_O_REALLOC:
+ case ERTS_ALC_O_FREE:
+ hdbg_free(mblk);
+ break;
+ default:
+ break;
+ }
+#endif
+
return (void *) ui_ptr;
}
@@ -3103,6 +3209,10 @@ debug_alloc(ErtsAlcType_t n, void *extra, Uint size)
Uint dsize;
void *res;
+#ifdef HARD_DEBUG
+ erts_hdbg_chk_blks();
+#endif
+
ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
dsize = size + FENCE_SZ;
res = (*real_af->alloc)(n, real_af->extra, dsize);
@@ -3132,13 +3242,17 @@ debug_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
dsize = size + FENCE_SZ;
dptr = check_memory_fence(ptr, &old_size, n, ERTS_ALC_O_REALLOC);
+#ifdef HARD_DEBUG
+ erts_hdbg_chk_blks();
+#endif
+
if (old_size > size)
sys_memset((void *) (((char *) ptr) + size),
0xf,
sizeof(Uint) + old_size - size);
res = (*real_af->realloc)(n, real_af->extra, dptr, dsize);
-
+
res = set_memory_fence(res, size, n);
#ifdef PRINT_OPS
@@ -3168,6 +3282,10 @@ debug_free(ErtsAlcType_t n, void *extra, void *ptr)
fprintf(stderr, "free(%s, 0x%lx)\r\n", ERTS_ALC_N2TD(n), (Uint) ptr);
#endif
+#ifdef HARD_DEBUG
+ erts_hdbg_chk_blks();
+#endif
+
}
static Uint
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 6f88bbe5b8..7df9f19af0 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -212,7 +212,8 @@ type LOGGER_DSBUF TEMPORARY SYSTEM logger_dsbuf
type TMP_DSBUF TEMPORARY SYSTEM tmp_dsbuf
type INFO_DSBUF SYSTEM SYSTEM info_dsbuf
# INFO_DSBUF have to use the SYSTEM allocator; otherwise, a deadlock might occur
-type SCHDLR_DATA LONG_LIVED PROCESSES scheduler_data
+type SCHDLR_DATA LONG_LIVED SYSTEM scheduler_data
+type SCHDLR_SLP_INFO LONG_LIVED SYSTEM scheduler_sleep_info
type RUNQS LONG_LIVED SYSTEM run_queues
type DDLL_PROCESS STANDARD SYSTEM ddll_processes
type DDLL_HANDLE STANDARD SYSTEM ddll_handle
@@ -246,6 +247,7 @@ type CPUDATA LONG_LIVED SYSTEM cpu_data
type TMP_CPU_IDS SHORT_LIVED SYSTEM tmp_cpu_ids
type EXT_TERM_DATA SHORT_LIVED PROCESSES external_term_data
type ZLIB STANDARD SYSTEM zlib
+type RDR_GRPS_MAP LONG_LIVED SYSTEM reader_groups_map
+if smp
type ASYNC SHORT_LIVED SYSTEM async
@@ -269,7 +271,9 @@ type RUNQ_BLNS LONG_LIVED SYSTEM run_queue_balancing
+if threads
-type ETHR_INTERNAL SYSTEM SYSTEM ethread_internal
+type ETHR_STD STANDARD SYSTEM ethread_standard
+type ETHR_SL SHORT_LIVED SYSTEM ethread_short_lived
+type ETHR_LL LONG_LIVED SYSTEM ethread_long_lived
+ifnot smp
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index 82f1e06e8e..1d8fd11b7b 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -2511,8 +2511,8 @@ BIF_RETTYPE binary_copy_trap(BIF_ALIST_2)
pb = (ProcBin *) HAlloc(BIF_P, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = target_size;
- pb->next = MSO(BIF_P).mso;
- MSO(BIF_P).mso = pb;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
pb->val = save;
pb->bytes = t;
pb->flags = 0;
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 48cda52612..dace5b9297 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -38,9 +38,6 @@
#include "erl_instrument.h"
#include "dist.h"
#include "erl_gc.h"
-#ifdef ELIB_ALLOC_IS_CLIB
-#include "elib_stat.h"
-#endif
#ifdef HIPE
#include "hipe_arch.h"
#endif
@@ -122,22 +119,26 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
#endif
static Eterm
-bld_bin_list(Uint **hpp, Uint *szp, ProcBin* pb)
+bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
{
+ struct erl_off_heap_header* ohh;
Eterm res = NIL;
Eterm tuple;
- for (; pb; pb = pb->next) {
- Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val);
- Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size);
-
- if (szp)
- *szp += 4+2;
- if (hpp) {
- Uint refc = (Uint) erts_smp_atomic_read(&pb->val->refc);
- tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
- res = CONS(*hpp + 4, tuple, res);
- *hpp += 4+2;
+ for (ohh = oh->first; ohh; ohh = ohh->next) {
+ if (ohh->thing_word == HEADER_PROC_BIN) {
+ ProcBin* pb = (ProcBin*) ohh;
+ Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val);
+ Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size);
+
+ if (szp)
+ *szp += 4+2;
+ if (hpp) {
+ Uint refc = (Uint) erts_smp_atomic_read(&pb->val->refc);
+ tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
+ res = CONS(*hpp + 4, tuple, res);
+ *hpp += 4+2;
+ }
}
}
return res;
@@ -176,10 +177,10 @@ static void do_make_one_mon_element(ErtsMonitor *mon, void * vpmlc)
Eterm tup;
Eterm r = (IS_CONST(mon->ref)
? mon->ref
- : STORE_NC(&(pmlc->hp), &MSO(pmlc->p).externals, mon->ref));
+ : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->ref));
Eterm p = (IS_CONST(mon->pid)
? mon->pid
- : STORE_NC(&(pmlc->hp), &MSO(pmlc->p).externals, mon->pid));
+ : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->pid));
tup = TUPLE5(pmlc->hp, pmlc->tag, make_small(mon->type), r, p, mon->name);
pmlc->hp += 6;
pmlc->res = CONS(pmlc->hp, tup, pmlc->res);
@@ -240,7 +241,7 @@ static void do_make_one_lnk_element(ErtsLink *lnk, void * vpllc)
Eterm old_res, targets = NIL;
Eterm p = (IS_CONST(lnk->pid)
? lnk->pid
- : STORE_NC(&(pllc->hp), &MSO(pllc->p).externals, lnk->pid));
+ : STORE_NC(&(pllc->hp), &MSO(pllc->p), lnk->pid));
if (lnk->type == LINK_NODE) {
targets = make_small(ERTS_LINK_REFC(lnk));
} else if (ERTS_LINK_ROOT(lnk) != NULL) {
@@ -1225,7 +1226,7 @@ process_info_aux(Process *BIF_P,
hp = HAlloc(BIF_P, 3 + mic.sz);
res = NIL;
for (i = 0; i < mic.mi_i; i++) {
- item = STORE_NC(&hp, &MSO(BIF_P).externals, mic.mi[i].entity);
+ item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity);
res = CONS(hp, item, res);
hp += 2;
}
@@ -1258,9 +1259,7 @@ process_info_aux(Process *BIF_P,
else {
/* Monitor by pid. Build {process, Pid} and cons it. */
Eterm t;
- Eterm pid = STORE_NC(&hp,
- &MSO(BIF_P).externals,
- mic.mi[i].entity);
+ Eterm pid = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity);
t = TUPLE2(hp, am_process, pid);
hp += 3;
res = CONS(hp, t, res);
@@ -1282,7 +1281,7 @@ process_info_aux(Process *BIF_P,
res = NIL;
for (i = 0; i < mic.mi_i; ++i) {
- item = STORE_NC(&hp, &MSO(BIF_P).externals, mic.mi[i].entity);
+ item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity);
res = CONS(hp, item, res);
hp += 2;
}
@@ -1491,7 +1490,7 @@ process_info_aux(Process *BIF_P,
case am_group_leader: {
int sz = NC_HEAP_SIZE(rp->group_leader);
hp = HAlloc(BIF_P, 3 + sz);
- res = STORE_NC(&hp, &MSO(BIF_P).externals, rp->group_leader);
+ res = STORE_NC(&hp, &MSO(BIF_P), rp->group_leader);
break;
}
@@ -1516,9 +1515,9 @@ process_info_aux(Process *BIF_P,
case am_binary: {
Uint sz = 3;
- (void) bld_bin_list(NULL, &sz, MSO(rp).mso);
+ (void) bld_bin_list(NULL, &sz, &MSO(rp));
hp = HAlloc(BIF_P, sz);
- res = bld_bin_list(&hp, NULL, MSO(rp).mso);
+ res = bld_bin_list(&hp, NULL, &MSO(rp));
break;
}
@@ -2124,86 +2123,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
BIF_RET(erts_alloc_util_allocators((void *) BIF_P));
}
else if (BIF_ARG_1 == am_elib_malloc) {
-#ifdef ELIB_ALLOC_IS_CLIB
- struct elib_stat stat;
- DECL_AM(heap_size);
- DECL_AM(max_alloced_size);
- DECL_AM(alloced_size);
- DECL_AM(free_size);
- DECL_AM(no_alloced_blocks);
- DECL_AM(no_free_blocks);
- DECL_AM(smallest_alloced_block);
- DECL_AM(largest_free_block);
- Eterm atoms[8];
- Eterm ints[8];
- Uint **hpp;
- Uint sz;
- Uint *szp;
- int length;
-#ifdef DEBUG
- Uint *endp;
-#endif
-
- elib_stat(&stat);
-
- /* First find out the heap size needed ... */
- hpp = NULL;
- szp = &sz;
- sz = 0;
-
- build_elib_malloc_term:
- length = 0;
- atoms[length] = AM_heap_size;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.mem_total*sizeof(Uint));
- atoms[length] = AM_max_alloced_size;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.mem_max_alloc*sizeof(Uint));
- atoms[length] = AM_alloced_size;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.mem_alloc*sizeof(Uint));
- atoms[length] = AM_free_size;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.mem_free*sizeof(Uint));
- atoms[length] = AM_no_alloced_blocks;
- ints[length++] = erts_bld_uint(hpp, szp, (Uint) stat.mem_blocks);
- atoms[length] = AM_no_free_blocks;
- ints[length++] = erts_bld_uint(hpp, szp, (Uint) stat.free_blocks);
- atoms[length] = AM_smallest_alloced_block;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.min_used*sizeof(Uint));
- atoms[length] = AM_largest_free_block;
- ints[length++] = erts_bld_uint(hpp, szp,
- (Uint) stat.max_free*sizeof(Uint));
-
-
-
- ASSERT(length <= sizeof(atoms)/sizeof(Eterm));
- ASSERT(length <= sizeof(ints)/sizeof(Eterm));
-
- res = erts_bld_2tup_list(hpp, szp, length, atoms, ints);
-
- if (szp) {
- /* ... and then build the term */
- hp = HAlloc(BIF_P, sz);
-#ifdef DEBUG
- endp = hp + sz;
-#endif
-
- szp = NULL;
- hpp = &hp;
- goto build_elib_malloc_term;
- }
-
-#ifdef DEBUG
- ASSERT(endp == hp);
-#endif
-
-#else /* #ifdef ELIB_ALLOC_IS_CLIB */
- res = am_false;
-#endif /* #ifdef ELIB_ALLOC_IS_CLIB */
-
- BIF_RET(res);
+ /* To be removed in R15 */
+ BIF_RET(am_false);
}
else if (BIF_ARG_1 == am_os_version) {
int major, minor, build;
@@ -2314,6 +2235,15 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
} else if (ERTS_IS_ATOM_STR("cpu_topology", BIF_ARG_1)) {
res = erts_get_cpu_topology_term(BIF_P, am_used);
BIF_TRAP1(erts_format_cpu_topology_trap, BIF_P, res);
+ } else if (ERTS_IS_ATOM_STR("update_cpu_info", BIF_ARG_1)) {
+ if (erts_update_cpu_info()) {
+ ERTS_DECL_AM(changed);
+ BIF_RET(AM_changed);
+ }
+ else {
+ ERTS_DECL_AM(unchanged);
+ BIF_RET(AM_unchanged);
+ }
#if defined(__GNUC__) && defined(HAVE_SOLARIS_SPARC_PERFMON)
} else if (ERTS_IS_ATOM_STR("ultrasparc_read_tick1", BIF_ARG_1)) {
register unsigned high asm("%l0");
@@ -2385,7 +2315,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
}
/* Arguments that are unusual follow ... */
else if (ERTS_IS_ATOM_STR("logical_processors", BIF_ARG_1)) {
- int no = erts_get_cpu_configured(erts_cpuinfo);
+ int no;
+ erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
+ no = erts_get_cpu_configured(erts_cpuinfo);
+ erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
if (no > 0)
BIF_RET(make_small((Uint) no));
else {
@@ -2394,7 +2327,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
}
}
else if (ERTS_IS_ATOM_STR("logical_processors_online", BIF_ARG_1)) {
- int no = erts_get_cpu_online(erts_cpuinfo);
+ int no;
+ erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
+ no = erts_get_cpu_online(erts_cpuinfo);
+ erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
if (no > 0)
BIF_RET(make_small((Uint) no));
else {
@@ -2403,7 +2339,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
}
}
else if (ERTS_IS_ATOM_STR("logical_processors_available", BIF_ARG_1)) {
- int no = erts_get_cpu_available(erts_cpuinfo);
+ int no;
+ erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
+ no = erts_get_cpu_available(erts_cpuinfo);
+ erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
if (no > 0)
BIF_RET(make_small((Uint) no));
else {
@@ -2563,6 +2502,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
BIF_RET(erts_sched_stat_term(BIF_P, 1));
} else if (ERTS_IS_ATOM_STR("taints", BIF_ARG_1)) {
BIF_RET(erts_nif_taints(BIF_P));
+ } else if (ERTS_IS_ATOM_STR("reader_groups_map", BIF_ARG_1)) {
+ BIF_RET(erts_get_reader_groups_map(BIF_P));
}
BIF_ERROR(BIF_P, BADARG);
@@ -2678,7 +2619,7 @@ BIF_RETTYPE port_info_2(BIF_ALIST_2)
hp = HAlloc(BIF_P, 3 + mic.sz);
res = NIL;
for (i = 0; i < mic.mi_i; i++) {
- item = STORE_NC(&hp, &MSO(BIF_P).externals, mic.mi[i].entity);
+ item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity);
res = CONS(hp, item, res);
hp += 2;
}
@@ -2698,7 +2639,7 @@ BIF_RETTYPE port_info_2(BIF_ALIST_2)
res = NIL;
for (i = 0; i < mic.mi_i; i++) {
Eterm t;
- item = STORE_NC(&hp, &MSO(BIF_P).externals, mic.mi[i].entity);
+ item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity);
t = TUPLE2(hp, am_process, item);
hp += 3;
res = CONS(hp, t, res);
@@ -3426,6 +3367,16 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
else if (ERTS_IS_ATOM_STR("fake_scheduler_bindings", tp[1])) {
return erts_fake_scheduler_bindings(BIF_P, tp[2]);
}
+ else if (ERTS_IS_ATOM_STR("reader_groups_map", tp[1])) {
+ Sint groups;
+ if (is_not_small(tp[2]))
+ BIF_ERROR(BIF_P, BADARG);
+ groups = signed_val(tp[2]);
+ if (groups < (Sint) 1 || groups > (Sint) INT_MAX)
+ BIF_ERROR(BIF_P, BADARG);
+
+ BIF_RET(erts_debug_reader_groups_map(BIF_P, (int) groups));
+ }
break;
}
default:
@@ -3730,8 +3681,8 @@ static Eterm lcnt_build_lock_stats_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_s
* [{{file, line}, {tries, colls, {seconds, nanoseconds, n_blocks}}}]
*/
- ethr_atomic_read(&stats->tries, (long *)&tries);
- ethr_atomic_read(&stats->colls, (long *)&colls);
+ tries = (unsigned long) ethr_atomic_read(&stats->tries);
+ colls = (unsigned long) ethr_atomic_read(&stats->colls);
line = stats->line;
timer_s = stats->timer.s;
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 443cac9033..0509e51a6f 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -2161,7 +2161,7 @@ trace_delivered_1(BIF_ALIST_1)
#ifdef ERTS_SMP
bp = new_message_buffer(REF_THING_SIZE + 4);
hp = &bp->mem[0];
- msg_ref = STORE_NC(&hp, &bp->off_heap.externals, ref);
+ msg_ref = STORE_NC(&hp, &bp->off_heap, ref);
#else
hp = HAlloc(BIF_P, 4);
msg_ref = ref;
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index defe18c92b..96faa673f6 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1335,8 +1335,8 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term,
hp += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
pb->size = used_size_in_bytes;
- pb->next = MSO(c_p).mso;
- MSO(c_p).mso = pb;
+ pb->next = MSO(c_p).first;
+ MSO(c_p).first = (struct erl_off_heap_header*)pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = PB_IS_WRITABLE | PB_ACTIVE_WRITER;
@@ -1506,8 +1506,8 @@ erts_bs_init_writable(Process* p, Eterm sz)
hp += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
pb->size = 0;
- pb->next = MSO(p).mso;
- MSO(p).mso = pb;
+ pb->next = MSO(p).first;
+ MSO(p).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = PB_IS_WRITABLE | PB_ACTIVE_WRITER;
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index cbdaa459de..b0369a402b 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -78,11 +78,19 @@ enum DbIterSafety {
** The main meta table, containing all ets tables.
*/
#ifdef ERTS_SMP
-# define META_MAIN_TAB_LOCK_CNT 16
-static union {
- erts_smp_spinlock_t lck;
- byte _cache_line_alignment[64];
-}meta_main_tab_locks[META_MAIN_TAB_LOCK_CNT];
+
+#define ERTS_META_MAIN_TAB_LOCK_TAB_BITS 8
+#define ERTS_META_MAIN_TAB_LOCK_TAB_SIZE (1 << ERTS_META_MAIN_TAB_LOCK_TAB_BITS)
+#define ERTS_META_MAIN_TAB_LOCK_TAB_MASK (ERTS_META_MAIN_TAB_LOCK_TAB_SIZE - 1)
+
+typedef union {
+ erts_smp_rwmtx_t rwmtx;
+ byte cache_line_align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(
+ sizeof(erts_smp_rwmtx_t))];
+} erts_meta_main_tab_lock_t;
+
+static erts_meta_main_tab_lock_t *meta_main_tab_locks;
+
#endif
static struct {
union {
@@ -104,17 +112,13 @@ static struct {
#define MARK_SLOT_DEAD(i) (meta_main_tab[(i)].u.next_free |= 2)
#define GET_ANY_SLOT_TAB(i) ((DbTable*)(meta_main_tab[(i)].u.next_free & ~(1|2))) /* dead or alive */
-static ERTS_INLINE void meta_main_tab_lock(unsigned slot)
+static ERTS_INLINE erts_smp_rwmtx_t *
+get_meta_main_tab_lock(unsigned slot)
{
#ifdef ERTS_SMP
- erts_smp_spin_lock(&meta_main_tab_locks[slot % META_MAIN_TAB_LOCK_CNT].lck);
-#endif
-}
-
-static ERTS_INLINE void meta_main_tab_unlock(unsigned slot)
-{
-#ifdef ERTS_SMP
- erts_smp_spin_unlock(&meta_main_tab_locks[slot % META_MAIN_TAB_LOCK_CNT].lck);
+ return &meta_main_tab_locks[slot & ERTS_META_MAIN_TAB_LOCK_TAB_MASK].rwmtx;
+#else
+ return NULL;
#endif
}
@@ -166,7 +170,8 @@ 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_WRITE_REC=3, /* record write access */
+ LCK_NONE=4
} db_lock_kind_t;
extern DbTableMethod db_hash;
@@ -214,17 +219,17 @@ Export ets_select_continue_exp;
*/
static Export ets_delete_continue_exp;
-static ERTS_INLINE DbTable* db_ref(DbTable* tb)
+static ERTS_INLINE DbTable* db_ref(DbTable* tb, db_lock_kind_t kind)
{
- if (tb != NULL) {
+ if (tb != NULL && kind != LCK_READ) {
erts_refc_inc(&tb->common.ref, 2);
}
return tb;
}
-static ERTS_INLINE DbTable* db_unref(DbTable* tb)
+static ERTS_INLINE DbTable* db_unref(DbTable* tb, db_lock_kind_t kind)
{
- if (!erts_refc_dectest(&tb->common.ref, 0)) {
+ if (kind != LCK_READ && !erts_refc_dectest(&tb->common.ref, 0)) {
#ifdef HARDDEBUG
if (erts_smp_atomic_read(&tb->common.memory_size) != sizeof(DbTable)) {
erts_fprintf(stderr, "ets: db_unref memory remain=%ld fix=%x\n",
@@ -256,12 +261,19 @@ static ERTS_INLINE DbTable* db_unref(DbTable* tb)
return tb;
}
-static ERTS_INLINE void db_init_lock(DbTable* tb, char *rwname, char* fixname)
+static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock,
+ char *rwname, char* fixname)
{
+#ifdef ERTS_SMP
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ if (use_frequent_read_lock)
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+#endif
erts_refc_init(&tb->common.ref, 1);
erts_refc_init(&tb->common.fixref, 0);
#ifdef ERTS_SMP
- erts_smp_rwmtx_init_x(&tb->common.rwlock, rwname, tb->common.the_name);
+ erts_smp_rwmtx_init_opt_x(&tb->common.rwlock, &rwmtx_opt,
+ rwname, tb->common.the_name);
erts_smp_mtx_init_x(&tb->common.fixlock, fixname, tb->common.the_name);
tb->common.is_thread_safe = !(tb->common.status & DB_FINE_LOCKED);
#endif
@@ -297,7 +309,7 @@ static ERTS_INLINE void db_lock_take_over_ref(DbTable* tb, db_lock_kind_t kind)
static ERTS_INLINE void db_lock(DbTable* tb, db_lock_kind_t kind)
{
- (void) db_ref(tb);
+ (void) db_ref(tb, kind);
#ifdef ERTS_SMP
db_lock_take_over_ref(tb, kind);
#endif
@@ -331,7 +343,7 @@ static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind)
}
}
#endif
- (void) db_unref(tb); /* May delete table... */
+ (void) db_unref(tb, kind); /* May delete table... */
}
@@ -349,32 +361,49 @@ static ERTS_INLINE void db_meta_unlock(DbTable* tb, db_lock_kind_t kind)
}
static ERTS_INLINE
-DbTable* db_get_table(Process *p,
- Eterm id,
- int what,
- db_lock_kind_t kind)
+DbTable* db_get_table_aux(Process *p,
+ Eterm id,
+ int what,
+ db_lock_kind_t kind,
+ int meta_already_locked)
{
DbTable *tb = NULL;
+ erts_smp_rwmtx_t *mtl = NULL;
if (is_small(id)) {
Uint slot = unsigned_val(id) & meta_main_tab_slot_mask;
- meta_main_tab_lock(slot);
+ if (!meta_already_locked) {
+ mtl = get_meta_main_tab_lock(slot);
+ erts_smp_rwmtx_rlock(mtl);
+ }
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ else {
+ erts_smp_rwmtx_t *test_mtl = get_meta_main_tab_lock(slot);
+ ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rlocked(test_mtl)
+ || erts_lc_rwmtx_is_rwlocked(test_mtl));
+ }
+#endif
if (slot < db_max_tabs && IS_SLOT_ALIVE(slot)) {
/* SMP: inc to prevent race, between unlock of meta_main_tab_lock
* and the table locking outside the meta_main_tab_lock
*/
- tb = db_ref(meta_main_tab[slot].u.tb);
+ tb = db_ref(meta_main_tab[slot].u.tb, kind);
}
- meta_main_tab_unlock(slot);
}
else if (is_atom(id)) {
- erts_smp_rwmtx_t* rwlock;
- struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&rwlock);
- erts_smp_rwmtx_rlock(rwlock);
+ struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&mtl);
+ if (!meta_already_locked)
+ erts_smp_rwmtx_rlock(mtl);
+ else{
+ ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rlocked(mtl)
+ || erts_lc_rwmtx_is_rwlocked(mtl));
+ mtl = NULL;
+ }
+
if (bucket->pu.tb != NULL) {
if (is_atom(bucket->u.name_atom)) { /* single */
if (bucket->u.name_atom == id) {
- tb = db_ref(bucket->pu.tb);
+ tb = db_ref(bucket->pu.tb, kind);
}
}
else { /* multi */
@@ -382,23 +411,33 @@ DbTable* db_get_table(Process *p,
Uint i;
for (i=0; i<cnt; i++) {
if (bucket->pu.mvec[i].u.name_atom == id) {
- tb = db_ref(bucket->pu.mvec[i].pu.tb);
+ tb = db_ref(bucket->pu.mvec[i].pu.tb, kind);
break;
}
}
}
}
- erts_smp_rwmtx_runlock(rwlock);
}
if (tb) {
db_lock_take_over_ref(tb, kind);
- if (tb->common.id == id && ((tb->common.status & what) != 0 ||
- p->id == tb->common.owner)) {
- return tb;
+ if (tb->common.id != id
+ || ((tb->common.status & what) == 0 && p->id != tb->common.owner)) {
+ db_unlock(tb, kind);
+ tb = NULL;
}
- db_unlock(tb, kind);
}
- return NULL;
+ if (mtl)
+ erts_smp_rwmtx_runlock(mtl);
+ return tb;
+}
+
+static ERTS_INLINE
+DbTable* db_get_table(Process *p,
+ Eterm id,
+ int what,
+ db_lock_kind_t kind)
+{
+ return db_get_table_aux(p, id, what, kind, 0);
}
/* Requires meta_main_tab_locks[slot] locked.
@@ -413,15 +452,15 @@ static ERTS_INLINE void free_slot(int slot)
erts_smp_spin_unlock(&meta_main_tab_main_lock);
}
-static int insert_named_tab(Eterm name_atom, DbTable* tb)
+static int insert_named_tab(Eterm name_atom, DbTable* tb, int have_lock)
{
int ret = 0;
erts_smp_rwmtx_t* rwlock;
struct meta_name_tab_entry* new_entry;
struct meta_name_tab_entry* bucket = meta_name_tab_bucket(name_atom,
&rwlock);
-
- erts_smp_rwmtx_rwlock(rwlock);
+ if (!have_lock)
+ erts_smp_rwmtx_rwlock(rwlock);
if (bucket->pu.tb == NULL) { /* empty */
new_entry = bucket;
@@ -468,17 +507,32 @@ static int insert_named_tab(Eterm name_atom, DbTable* tb)
ret = 1; /* Ok */
done:
- erts_smp_rwmtx_rwunlock(rwlock);
+ if (!have_lock)
+ erts_smp_rwmtx_rwunlock(rwlock);
return ret;
}
-static int remove_named_tab(Eterm name_atom)
+static int remove_named_tab(DbTable *tb, int have_lock)
{
int ret = 0;
erts_smp_rwmtx_t* rwlock;
+ Eterm name_atom = tb->common.id;
struct meta_name_tab_entry* bucket = meta_name_tab_bucket(name_atom,
&rwlock);
- erts_smp_rwmtx_rwlock(rwlock);
+#ifdef ERTS_SMP
+ if (!have_lock && erts_smp_rwmtx_tryrwlock(rwlock) == EBUSY) {
+ /*
+ * We keep our increased refc over this op in order to
+ * prevent the table from disapearing.
+ */
+ erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
+ erts_smp_rwmtx_rwlock(rwlock);
+ erts_smp_rwmtx_rwlock(&tb->common.rwlock);
+ }
+#endif
+
+ ERTS_SMP_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(rwlock));
+
if (bucket->pu.tb == NULL) {
goto done;
}
@@ -529,7 +583,8 @@ static int remove_named_tab(Eterm name_atom)
ret = 1; /* Ok */
done:
- erts_smp_rwmtx_rwunlock(rwlock);
+ if (!have_lock)
+ erts_smp_rwmtx_rwunlock(rwlock);
return ret;
}
@@ -1133,6 +1188,7 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
{
DbTable* tb;
Eterm ret;
+ erts_smp_rwmtx_t *lck1, *lck2;
#ifdef HARDDEBUG
erts_fprintf(stderr,
@@ -1141,34 +1197,65 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
BIF_P->initial[0], BIF_P->initial[1], BIF_P->initial[2]);
#endif
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
+
+ if (is_not_atom(BIF_ARG_2)) {
BIF_ERROR(BIF_P, BADARG);
}
- if (is_not_atom(BIF_ARG_2)) {
- goto badarg;
+ (void) meta_name_tab_bucket(BIF_ARG_2, &lck1);
+
+ if (is_small(BIF_ARG_1)) {
+ Uint slot = unsigned_val(BIF_ARG_1) & meta_main_tab_slot_mask;
+ lck2 = get_meta_main_tab_lock(slot);
+ }
+ else if (is_atom(BIF_ARG_1)) {
+ (void) meta_name_tab_bucket(BIF_ARG_1, &lck2);
+ if (lck1 == lck2)
+ lck2 = NULL;
+ else if (lck1 > lck2) {
+ erts_smp_rwmtx_t *tmp = lck1;
+ lck1 = lck2;
+ lck2 = tmp;
+ }
+ }
+ else {
+ BIF_ERROR(BIF_P, BADARG);
}
+ erts_smp_rwmtx_rwlock(lck1);
+ if (lck2)
+ erts_smp_rwmtx_rwlock(lck2);
+
+ tb = db_get_table_aux(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE, 1);
+ if (!tb)
+ goto badarg;
+
if (is_not_atom(tb->common.id)) { /* Not a named table */
tb->common.the_name = BIF_ARG_2;
goto done;
}
- if (!insert_named_tab(BIF_ARG_2,tb)) {
+ if (!insert_named_tab(BIF_ARG_2, tb, 1))
goto badarg;
- }
- if (!remove_named_tab(tb->common.id)) {
+
+ if (!remove_named_tab(tb, 1))
erl_exit(1,"Could not find named tab %s", tb->common.id);
- }
tb->common.id = tb->common.the_name = BIF_ARG_2;
done:
ret = tb->common.id;
db_unlock(tb, LCK_WRITE);
+ erts_smp_rwmtx_rwunlock(lck1);
+ if (lck2)
+ erts_smp_rwmtx_rwunlock(lck2);
BIF_RET(ret);
badarg:
- db_unlock(tb, LCK_WRITE);
+ if (tb)
+ db_unlock(tb, LCK_WRITE);
+ erts_smp_rwmtx_rwunlock(lck1);
+ if (lck2)
+ erts_smp_rwmtx_rwunlock(lck2);
BIF_ERROR(BIF_P, BADARG);
}
@@ -1189,10 +1276,11 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
UWord heir_data;
Uint32 status;
Sint keypos;
- int is_named, is_fine_locked;
+ int is_named, is_fine_locked, frequent_read;
int cret;
DeclareTmpHeap(meta_tuple,3,BIF_P);
DbTableMethod* meth;
+ erts_smp_rwmtx_t *mmtl;
if (is_not_atom(BIF_ARG_1)) {
BIF_ERROR(BIF_P, BADARG);
@@ -1205,6 +1293,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
keypos = 1;
is_named = 0;
is_fine_locked = 0;
+ frequent_read = 0;
heir = am_none;
heir_data = (UWord) am_undefined;
@@ -1238,6 +1327,13 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
is_fine_locked = 0;
} else break;
}
+ else if (tp[1] == am_read_concurrency) {
+ if (tp[2] == am_true) {
+ frequent_read = 1;
+ } else if (tp[2] == am_false) {
+ frequent_read = 0;
+ } else break;
+ }
else if (tp[1] == am_heir && tp[2] == am_none) {
heir = am_none;
heir_data = am_undefined;
@@ -1286,6 +1382,11 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
BIF_ERROR(BIF_P, BADARG);
}
+#ifdef ERTS_SMP
+ if (frequent_read && !(status & DB_PRIVATE))
+ status |= DB_FREQ_READ;
+#endif
+
/* we create table outside any table lock
* and take the unusal cost of destroy table if it
* fails to find a slot
@@ -1308,7 +1409,8 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
tb->common.type = status & ERTS_ETS_TABLE_TYPES;
/* Note, 'type' is *read only* from now on... */
#endif
- db_init_lock(tb, "db_tab", "db_tab_fix");
+ db_init_lock(tb, status & (DB_FINE_LOCKED|DB_FREQ_READ),
+ "db_tab", "db_tab_fix");
tb->common.keypos = keypos;
tb->common.owner = BIF_P->id;
set_heir(BIF_P, tb, heir, heir_data);
@@ -1351,15 +1453,17 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
tb->common.id = ret;
tb->common.slot = slot; /* store slot for erase */
- meta_main_tab_lock(slot);
+ mmtl = get_meta_main_tab_lock(slot);
+ erts_smp_rwmtx_rwlock(mmtl);
meta_main_tab[slot].u.tb = tb;
ASSERT(IS_SLOT_ALIVE(slot));
- meta_main_tab_unlock(slot);
+ erts_smp_rwmtx_rwunlock(mmtl);
- if (is_named && !insert_named_tab(BIF_ARG_1, tb)) {
- meta_main_tab_lock(slot);
+ if (is_named && !insert_named_tab(BIF_ARG_1, tb, 0)) {
+ mmtl = get_meta_main_tab_lock(slot);
+ erts_smp_rwmtx_rwlock(mmtl);
free_slot(slot);
- meta_main_tab_unlock(slot);
+ erts_smp_rwmtx_rwunlock(mmtl);
db_lock_take_over_ref(tb,LCK_WRITE);
free_heir_data(tb);
@@ -1499,6 +1603,7 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
{
int trap;
DbTable* tb;
+ erts_smp_rwmtx_t *mmtl;
#ifdef HARDDEBUG
erts_fprintf(stderr,
@@ -1520,13 +1625,23 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
tb->common.status &= ~(DB_PROTECTED|DB_PUBLIC|DB_PRIVATE);
tb->common.status |= DB_DELETE;
- meta_main_tab_lock(tb->common.slot);
+ mmtl = get_meta_main_tab_lock(tb->common.slot);
+#ifdef ERTS_SMP
+ if (erts_smp_rwmtx_tryrwlock(mmtl) == EBUSY) {
+ /*
+ * We keep our increased refc over this op in order to
+ * prevent the table from disapearing.
+ */
+ erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
+ erts_smp_rwmtx_rwlock(mmtl);
+ erts_smp_rwmtx_rwlock(&tb->common.rwlock);
+ }
+#endif
/* We must keep the slot, to be found by db_proc_dead() if process dies */
MARK_SLOT_DEAD(tb->common.slot);
- meta_main_tab_unlock(tb->common.slot);
- if (is_atom(tb->common.id)) {
- remove_named_tab(tb->common.id);
- }
+ erts_smp_rwmtx_rwunlock(mmtl);
+ if (is_atom(tb->common.id))
+ remove_named_tab(tb, 0);
if (tb->common.owner != BIF_P->id) {
DeclareTmpHeap(meta_tuple,3,BIF_P);
@@ -1919,14 +2034,15 @@ BIF_RETTYPE ets_all_0(BIF_ALIST_0)
previous = NIL;
j = 0;
for(i = 0; (i < t_max_tabs && j < t_tabs_cnt); i++) {
- meta_main_tab_lock(i);
+ erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(i);
+ erts_smp_rwmtx_rlock(mmtl);
if (IS_SLOT_ALIVE(i)) {
j++;
tb = meta_main_tab[i].u.tb;
previous = CONS(hp, tb->common.id, previous);
hp += 2;
}
- meta_main_tab_unlock(i);
+ erts_smp_rwmtx_runlock(mmtl);
}
HRelease(BIF_P, hendp, hp);
BIF_RET(previous);
@@ -2630,12 +2746,30 @@ void init_db(void)
size_t size;
#ifdef ERTS_SMP
- for (i=0; i<META_MAIN_TAB_LOCK_CNT; i++) {
- erts_smp_spinlock_init_x(&meta_main_tab_locks[i].lck, "meta_main_tab_slot", make_small(i));
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+
+ meta_main_tab_locks = erts_alloc(ERTS_ALC_T_DB_TABLES,
+ (sizeof(erts_meta_main_tab_lock_t)
+ * (ERTS_META_MAIN_TAB_LOCK_TAB_SIZE+1)));
+
+ if ((((Uint) meta_main_tab_locks) & ERTS_CACHE_LINE_MASK) != 0)
+ meta_main_tab_locks = ((erts_meta_main_tab_lock_t *)
+ ((((Uint) meta_main_tab_locks)
+ & ~ERTS_CACHE_LINE_MASK)
+ + ERTS_CACHE_LINE_SIZE));
+
+ ASSERT((((Uint) meta_main_tab_locks) & ERTS_CACHE_LINE_MASK) == 0);
+
+ for (i = 0; i < ERTS_META_MAIN_TAB_LOCK_TAB_SIZE; i++) {
+ erts_smp_rwmtx_init_opt_x(&meta_main_tab_locks[i].rwmtx, &rwmtx_opt,
+ "meta_main_tab_slot", make_small(i));
}
erts_smp_spinlock_init(&meta_main_tab_main_lock, "meta_main_tab_main");
for (i=0; i<META_NAME_TAB_LOCK_CNT; i++) {
- erts_smp_rwmtx_init_x(&meta_name_tab_rwlocks[i].lck, "meta_name_tab", make_small(i));
+ erts_smp_rwmtx_init_opt_x(&meta_name_tab_rwlocks[i].lck, &rwmtx_opt,
+ "meta_name_tab", make_small(i));
}
#endif
@@ -2895,12 +3029,12 @@ retry:
to_pid, to_locks,
ERTS_P2P_FLG_TRY_LOCK);
if (to_proc == ERTS_PROC_LOCK_BUSY) {
- db_ref(tb); /* while unlocked */
+ db_ref(tb, LCK_NONE); /* while unlocked */
db_unlock(tb,LCK_WRITE);
to_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
to_pid, to_locks);
db_lock(tb,LCK_WRITE);
- tb = db_unref(tb);
+ tb = db_unref(tb, LCK_NONE);
ASSERT(tb != NULL);
if (tb->common.owner != p->id) {
@@ -3008,12 +3142,13 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
while (state->slots.ix < state->slots.size) {
DbTable *tb = NULL;
Sint ix = unsigned_val(state->slots.arr[state->slots.ix]);
- meta_main_tab_lock(ix);
+ erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(ix);
+ erts_smp_rwmtx_rlock(mmtl);
if (!IS_SLOT_FREE(ix)) {
- tb = db_ref(GET_ANY_SLOT_TAB(ix));
+ tb = db_ref(GET_ANY_SLOT_TAB(ix), LCK_WRITE);
ASSERT(tb);
}
- meta_main_tab_unlock(ix);
+ erts_smp_rwmtx_runlock(mmtl);
if (tb) {
int do_yield;
db_lock_take_over_ref(tb, LCK_WRITE);
@@ -3045,7 +3180,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
tb->common.status |= DB_DELETE;
if (is_atom(tb->common.id))
- remove_named_tab(tb->common.id);
+ remove_named_tab(tb, 0);
free_heir_data(tb);
free_fixations_locked(tb);
@@ -3095,12 +3230,13 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
while (state->slots.ix < state->slots.size) {
DbTable *tb = NULL;
Sint ix = unsigned_val(state->slots.arr[state->slots.ix]);
- meta_main_tab_lock(ix);
+ erts_smp_rwmtx_t *mmtl = get_meta_main_tab_lock(ix);
+ erts_smp_rwmtx_rlock(mmtl);
if (IS_SLOT_ALIVE(ix)) {
- tb = db_ref(meta_main_tab[ix].u.tb);
+ tb = db_ref(meta_main_tab[ix].u.tb, LCK_WRITE_REC);
ASSERT(tb);
}
- meta_main_tab_unlock(ix);
+ erts_smp_rwmtx_runlock(mmtl);
if (tb) {
int reds;
DbFixation** pp;
@@ -3274,6 +3410,7 @@ unlocked:
#ifdef ERTS_SMP
if (*kind_p == LCK_READ && tb->common.is_thread_safe) {
/* Must have write lock while purging pseudo-deleted (OTP-8166) */
+ db_ref(tb, LCK_WRITE); /* LCK_WRITE need it, but not LCK_READ */
erts_smp_rwmtx_runlock(&tb->common.rwlock);
erts_smp_rwmtx_rwlock(&tb->common.rwlock);
*kind_p = LCK_WRITE;
@@ -3386,6 +3523,7 @@ static int free_table_cont(Process *p,
int clean_meta_tab)
{
Eterm result;
+ erts_smp_rwmtx_t *mmtl;
#ifdef HARDDEBUG
if (!first) {
@@ -3411,9 +3549,20 @@ static int free_table_cont(Process *p,
tb->common.id);
#endif
/* Completely done - we will not get called again. */
- meta_main_tab_lock(tb->common.slot);
+ mmtl = get_meta_main_tab_lock(tb->common.slot);
+#ifdef ERTS_SMP
+ if (erts_smp_rwmtx_tryrwlock(mmtl) == EBUSY) {
+ /*
+ * We keep our increased refc over this op in order to
+ * prevent the table from disapearing.
+ */
+ erts_smp_rwmtx_rwunlock(&tb->common.rwlock);
+ erts_smp_rwmtx_rwlock(mmtl);
+ erts_smp_rwmtx_rwlock(&tb->common.rwlock);
+ }
+#endif
free_slot(tb->common.slot);
- meta_main_tab_unlock(tb->common.slot);
+ erts_smp_rwmtx_rwunlock(mmtl);
if (clean_meta_tab) {
db_meta_lock(meta_pid_to_tab, LCK_WRITE_REC);
@@ -3421,7 +3570,7 @@ static int free_table_cont(Process *p,
make_small(tb->common.slot));
db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC);
}
- db_unref(tb);
+ db_unref(tb, LCK_NONE);
BUMP_REDS(p, 100);
return 0;
}
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 124129a371..08117bb6e5 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -623,12 +623,16 @@ int db_create_hash(Process *p, DbTable *tbl)
erts_smp_atomic_init(&tb->is_resizing, 0);
#ifdef ERTS_SMP
if (tb->common.type & DB_FINE_LOCKED) {
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
int i;
+ if (tb->common.type & DB_FREQ_READ)
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
tb->locks = (DbTableHashFineLocks*) erts_db_alloc_fnf(ERTS_ALC_T_DB_SEG, /* Other type maybe? */
(DbTable *) tb,
sizeof(DbTableHashFineLocks));
for (i=0; i<DB_HASH_LOCK_CNT; ++i) {
- erts_rwmtx_init_x(&tb->locks->lck_vec[i].lck, "db_hash_slot", make_small(i));
+ erts_smp_rwmtx_init_opt_x(&tb->locks->lck_vec[i].lck, &rwmtx_opt,
+ "db_hash_slot", make_small(i));
}
/* This important property is needed to guarantee that the buckets
* involved in a grow/shrink operation it protected by the same lock:
@@ -2751,11 +2755,7 @@ static void db_finalize_dbterm_hash(DbUpdateHandle* handle)
newDbTerm = &newp->dbterm;
newDbTerm->size = handle->new_size;
- newDbTerm->off_heap.mso = NULL;
- newDbTerm->off_heap.externals = NULL;
- #ifndef HYBRID /* FIND ME! */
- newDbTerm->off_heap.funs = NULL;
- #endif
+ newDbTerm->off_heap.first = NULL;
newDbTerm->off_heap.overhead = 0;
/* make a flat copy */
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index b6b3cabafe..da2696163a 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -1081,11 +1081,12 @@ static int db_select_continue_tree(Process *p,
static int db_select_tree(Process *p, DbTable *tbl,
Eterm pattern, int reverse, Eterm *ret)
{
+ /* Strategy: Traverse backwards to build resulting list from tail to head */
DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_context sc;
struct mp_info mpi;
- Eterm lastkey = NIL;
+ Eterm lastkey = THE_NON_VALUE;
Eterm key;
Eterm continuation;
unsigned sz;
@@ -1293,7 +1294,7 @@ static int db_select_count_tree(Process *p, DbTable *tbl,
DbTreeStack* stack;
struct select_count_context sc;
struct mp_info mpi;
- Eterm lastkey = NIL;
+ Eterm lastkey = THE_NON_VALUE;
Eterm key;
Eterm continuation;
unsigned sz;
@@ -1395,7 +1396,7 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl,
DbTreeStack* stack;
struct select_context sc;
struct mp_info mpi;
- Eterm lastkey = NIL;
+ Eterm lastkey = THE_NON_VALUE;
Eterm key;
Eterm continuation;
unsigned sz;
@@ -1636,7 +1637,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl,
DbTableTree *tb = &tbl->tree;
struct select_delete_context sc;
struct mp_info mpi;
- Eterm lastkey = NIL;
+ Eterm lastkey = THE_NON_VALUE;
Eterm key;
Eterm continuation;
unsigned sz;
@@ -2588,11 +2589,7 @@ static void db_finalize_dbterm_tree(DbUpdateHandle* handle)
newDbTerm = &newp->dbterm;
newDbTerm->size = handle->new_size;
- newDbTerm->off_heap.mso = NULL;
- newDbTerm->off_heap.externals = NULL;
- #ifndef HYBRID /* FIND ME! */
- newDbTerm->off_heap.funs = NULL;
- #endif
+ newDbTerm->off_heap.first = NULL;
newDbTerm->off_heap.overhead = 0;
/* make a flat copy */
@@ -2628,7 +2625,7 @@ static void traverse_backwards(DbTableTree *tb,
{
TreeDbTerm *this, *next;
- if (lastkey == NIL) {
+ if (lastkey == THE_NON_VALUE) {
stack->pos = stack->slot = 0;
if (( this = tb->root ) == NULL) {
return;
@@ -2666,7 +2663,7 @@ static void traverse_forward(DbTableTree *tb,
{
TreeDbTerm *this, *next;
- if (lastkey == NIL) {
+ if (lastkey == THE_NON_VALUE) {
stack->pos = stack->slot = 0;
if (( this = tb->root ) == NULL) {
return;
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 93a47eb76f..48e0080525 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -363,12 +363,7 @@ static ErtsMatchPseudoProcess *match_pseudo_process;
static ERTS_INLINE void
cleanup_match_pseudo_process(ErtsMatchPseudoProcess *mpsp, int keep_heap)
{
- if (mpsp->process.mbuf
- || mpsp->process.off_heap.mso
-#ifndef HYBRID /* FIND ME! */
- || mpsp->process.off_heap.funs
-#endif
- || mpsp->process.off_heap.externals) {
+ if (mpsp->process.mbuf || mpsp->process.off_heap.first) {
erts_cleanup_empty_process(&mpsp->process);
}
#ifdef DEBUG
@@ -2495,11 +2490,7 @@ void* db_get_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
p = (DbTerm*) ((void *)(((char *) structp) + offset));
}
p->size = size;
- p->off_heap.mso = NULL;
- p->off_heap.externals = NULL;
-#ifndef HYBRID /* FIND ME! */
- p->off_heap.funs = NULL;
-#endif
+ p->off_heap.first = NULL;
p->off_heap.overhead = 0;
top = DBTERM_BUF(p);
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 382e5dceb5..672c5f2cd1 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -240,8 +240,9 @@ typedef struct db_table_common {
#define DB_DUPLICATE_BAG (1 << 8)
#define DB_ORDERED_SET (1 << 9)
#define DB_DELETE (1 << 10) /* table is being deleted */
+#define DB_FREQ_READ (1 << 11)
-#define ERTS_ETS_TABLE_TYPES (DB_BAG|DB_SET|DB_DUPLICATE_BAG|DB_ORDERED_SET|DB_FINE_LOCKED)
+#define ERTS_ETS_TABLE_TYPES (DB_BAG|DB_SET|DB_DUPLICATE_BAG|DB_ORDERED_SET|DB_FINE_LOCKED|DB_FREQ_READ)
#define IS_HASH_TABLE(Status) (!!((Status) & \
(DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c
index aa37edafd1..d42820ddf3 100644
--- a/erts/emulator/beam/erl_drv_thread.c
+++ b/erts/emulator/beam/erl_drv_thread.c
@@ -186,10 +186,9 @@ int
erl_drv_mutex_trylock(ErlDrvMutex *dmtx)
{
#ifdef USE_THREADS
- int res = dmtx ? ethr_mutex_trylock(&dmtx->mtx) : EINVAL;
- if (res != 0 && res != EBUSY)
- fatal_error(res, "erl_drv_mutex_trylock()");
- return res;
+ if (!dmtx)
+ fatal_error(EINVAL, "erl_drv_mutex_trylock()");
+ return ethr_mutex_trylock(&dmtx->mtx);
#else
return 0;
#endif
@@ -199,9 +198,9 @@ void
erl_drv_mutex_lock(ErlDrvMutex *dmtx)
{
#ifdef USE_THREADS
- int res = dmtx ? ethr_mutex_lock(&dmtx->mtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_mutex_lock()");
+ if (!dmtx)
+ fatal_error(EINVAL, "erl_drv_mutex_lock()");
+ ethr_mutex_lock(&dmtx->mtx);
#endif
}
@@ -209,9 +208,9 @@ void
erl_drv_mutex_unlock(ErlDrvMutex *dmtx)
{
#ifdef USE_THREADS
- int res = dmtx ? ethr_mutex_unlock(&dmtx->mtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_mutex_unlock()");
+ if (!dmtx)
+ fatal_error(EINVAL, "erl_drv_mutex_unlock()");
+ ethr_mutex_unlock(&dmtx->mtx);
#endif
}
@@ -256,9 +255,9 @@ void
erl_drv_cond_signal(ErlDrvCond *dcnd)
{
#ifdef USE_THREADS
- int res = dcnd ? ethr_cond_signal(&dcnd->cnd) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_cond_signal()");
+ if (!dcnd)
+ fatal_error(EINVAL, "erl_drv_cond_signal()");
+ ethr_cond_signal(&dcnd->cnd);
#endif
}
@@ -266,9 +265,9 @@ void
erl_drv_cond_broadcast(ErlDrvCond *dcnd)
{
#ifdef USE_THREADS
- int res = dcnd ? ethr_cond_broadcast(&dcnd->cnd) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_cond_broadcast()");
+ if (!dcnd)
+ fatal_error(EINVAL, "erl_drv_cond_broadcast()");
+ ethr_cond_broadcast(&dcnd->cnd);
#endif
}
@@ -277,18 +276,13 @@ void
erl_drv_cond_wait(ErlDrvCond *dcnd, ErlDrvMutex *dmtx)
{
#ifdef USE_THREADS
- int res;
if (!dcnd || !dmtx) {
- res = EINVAL;
- error:
- fatal_error(res, "erl_drv_cond_wait()");
+ fatal_error(EINVAL, "erl_drv_cond_wait()");
}
while (1) {
- res = ethr_cond_wait(&dcnd->cnd, &dmtx->mtx);
+ int res = ethr_cond_wait(&dcnd->cnd, &dmtx->mtx);
if (res == 0)
break;
- if (res != EINTR)
- goto error;
}
#endif
}
@@ -333,10 +327,9 @@ int
erl_drv_rwlock_tryrlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_tryrlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0 && res != EBUSY)
- fatal_error(res, "erl_drv_rwlock_tryrlock()");
- return res;
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_tryrlock()");
+ return ethr_rwmutex_tryrlock(&drwlck->rwmtx);
#else
return 0;
#endif
@@ -346,9 +339,9 @@ void
erl_drv_rwlock_rlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_rlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_rwlock_rlock()");
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_rlock()");
+ ethr_rwmutex_rlock(&drwlck->rwmtx);
#endif
}
@@ -356,9 +349,9 @@ void
erl_drv_rwlock_runlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_runlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_rwlock_runlock()");
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_runlock()");
+ ethr_rwmutex_runlock(&drwlck->rwmtx);
#endif
}
@@ -366,10 +359,9 @@ int
erl_drv_rwlock_tryrwlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_tryrwlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0 && res != EBUSY)
- fatal_error(res, "erl_drv_rwlock_tryrwlock()");
- return res;
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_tryrwlock()");
+ return ethr_rwmutex_tryrwlock(&drwlck->rwmtx);
#else
return 0;
#endif
@@ -379,9 +371,9 @@ void
erl_drv_rwlock_rwlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_rwlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_rwlock_rwlock()");
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_rwlock()");
+ ethr_rwmutex_rwlock(&drwlck->rwmtx);
#endif
}
@@ -389,9 +381,9 @@ void
erl_drv_rwlock_rwunlock(ErlDrvRWLock *drwlck)
{
#ifdef USE_THREADS
- int res = drwlck ? ethr_rwmutex_rwunlock(&drwlck->rwmtx) : EINVAL;
- if (res != 0)
- fatal_error(res, "erl_drv_rwlock_rwunlock()");
+ if (!drwlck)
+ fatal_error(EINVAL, "erl_drv_rwlock_rwunlock()");
+ ethr_rwmutex_rwunlock(&drwlck->rwmtx);
#endif
}
diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c
index 15d9538301..5dce5ad262 100644
--- a/erts/emulator/beam/erl_fun.c
+++ b/erts/emulator/beam/erl_fun.c
@@ -37,8 +37,6 @@ static erts_smp_rwmtx_t erts_fun_table_lock;
#define erts_fun_read_unlock() erts_smp_rwmtx_runlock(&erts_fun_table_lock)
#define erts_fun_write_lock() erts_smp_rwmtx_rwlock(&erts_fun_table_lock)
#define erts_fun_write_unlock() erts_smp_rwmtx_rwunlock(&erts_fun_table_lock)
-#define erts_fun_init_lock() erts_smp_rwmtx_init(&erts_fun_table_lock, \
- "fun_tab")
static HashValue fun_hash(ErlFunEntry* obj);
static int fun_cmp(ErlFunEntry* obj1, ErlFunEntry* obj2);
@@ -57,8 +55,12 @@ void
erts_init_fun_table(void)
{
HashFunctions f;
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+
+ erts_smp_rwmtx_init_opt(&erts_fun_table_lock, &rwmtx_opt, "fun_tab");
- erts_fun_init_lock();
f.hash = (H_FUN) fun_hash;
f.cmp = (HCMP_FUN) fun_cmp;
f.alloc = (HALLOC_FUN) fun_alloc;
@@ -192,20 +194,6 @@ erts_erase_fun_entry(ErlFunEntry* fe)
erts_fun_write_unlock();
}
-#ifndef HYBRID /* FIND ME! */
-void
-erts_cleanup_funs(ErlFunThing* funp)
-{
- while (funp) {
- ErlFunEntry* fe = funp->fe;
- if (erts_refc_dectest(&fe->refc, 0) == 0) {
- erts_erase_fun_entry(fe);
- }
- funp = funp->next;
- }
-}
-#endif
-
void
erts_cleanup_funs_on_purge(BeamInstr* start, BeamInstr* end)
{
diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h
index 944d4b3df5..2f165afa06 100644
--- a/erts/emulator/beam/erl_fun.h
+++ b/erts/emulator/beam/erl_fun.h
@@ -53,10 +53,10 @@ typedef struct erl_fun_entry {
typedef struct erl_fun_thing {
Eterm thing_word; /* Subtag FUN_SUBTAG. */
+ ErlFunEntry* fe; /* Pointer to fun entry. */
#ifndef HYBRID /* FIND ME! */
- struct erl_fun_thing* next; /* Next fun in mso list. */
+ struct erl_off_heap_header* next;
#endif
- ErlFunEntry* fe; /* Pointer to fun entry. */
#ifdef HIPE
UWord* native_address; /* Native code for the fun. */
#endif
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index a19e090f1e..adc50675bf 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -110,9 +110,7 @@ static Uint adjust_after_fullsweep(Process *p, int size_before,
int need, Eterm *objv, int nobj);
static void shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj);
static void grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj);
-static void sweep_proc_bins(Process *p, int fullsweep);
-static void sweep_proc_funs(Process *p, int fullsweep);
-static void sweep_proc_externals(Process *p, int fullsweep);
+static void sweep_off_heap(Process *p, int fullsweep);
static void offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
static void offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size);
static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
@@ -145,6 +143,16 @@ erts_init_gc(void)
{
int i = 0;
+ ASSERT(offsetof(ProcBin,thing_word) == offsetof(struct erl_off_heap_header,thing_word));
+ ASSERT(offsetof(ProcBin,thing_word) == offsetof(ErlFunThing,thing_word));
+ ASSERT(offsetof(ProcBin,thing_word) == offsetof(ExternalThing,header));
+ ASSERT(offsetof(ProcBin,size) == offsetof(struct erl_off_heap_header,size));
+ ASSERT(offsetof(ProcBin,size) == offsetof(ErlSubBin,size));
+ ASSERT(offsetof(ProcBin,size) == offsetof(ErlHeapBin,size));
+ ASSERT(offsetof(ProcBin,next) == offsetof(struct erl_off_heap_header,next));
+ ASSERT(offsetof(ProcBin,next) == offsetof(ErlFunThing,next));
+ ASSERT(offsetof(ProcBin,next) == offsetof(ExternalThing,next));
+
erts_smp_spinlock_init(&info_lck, "gc_info");
garbage_cols = 0;
reclaimed = 0;
@@ -286,25 +294,14 @@ erts_offset_heap_ptr(Eterm* hp, Uint sz, Sint offs,
offset_heap_ptr(hp, sz, offs, (char *) low, ((char *)high)-((char *)low));
}
+
#define ptr_within(ptr, low, high) ((ptr) < (high) && (ptr) >= (low))
void
erts_offset_off_heap(ErlOffHeap *ohp, Sint offs, Eterm* low, Eterm* high)
{
- if (ohp->mso && ptr_within((Eterm *)ohp->mso, low, high)) {
- Eterm** uptr = (Eterm**) (void *) &ohp->mso;
- *uptr += offs;
- }
-
-#ifndef HYBRID /* FIND ME! */
- if (ohp->funs && ptr_within((Eterm *)ohp->funs, low, high)) {
- Eterm** uptr = (Eterm**) (void *) &ohp->funs;
- *uptr += offs;
- }
-#endif
-
- if (ohp->externals && ptr_within((Eterm *)ohp->externals, low, high)) {
- Eterm** uptr = (Eterm**) (void *) &ohp->externals;
+ if (ohp->first && ptr_within((Eterm *)ohp->first, low, high)) {
+ Eterm** uptr = (Eterm**) (void *) &ohp->first;
*uptr += offs;
}
}
@@ -504,14 +501,8 @@ erts_garbage_collect_hibernate(Process* p)
cleanup_rootset(&rootset);
- if (MSO(p).mso) {
- sweep_proc_bins(p, 1);
- }
- if (MSO(p).funs) {
- sweep_proc_funs(p, 1);
- }
- if (MSO(p).externals) {
- sweep_proc_externals(p, 1);
+ if (MSO(p).first) {
+ sweep_off_heap(p, 1);
}
/*
@@ -1041,15 +1032,8 @@ do_minor(Process *p, int new_sz, Eterm* objv, int nobj)
OLD_HTOP(p) = old_htop;
HIGH_WATER(p) = (HEAP_START(p) != HIGH_WATER(p)) ? n_heap : n_htop;
- if (MSO(p).mso) {
- sweep_proc_bins(p, 0);
- }
-
- if (MSO(p).funs) {
- sweep_proc_funs(p, 0);
- }
- if (MSO(p).externals) {
- sweep_proc_externals(p, 0);
+ if (MSO(p).first) {
+ sweep_off_heap(p, 0);
}
#ifdef HARDDEBUG
@@ -1271,17 +1255,11 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
}
}
- if (MSO(p).mso) {
- sweep_proc_bins(p, 1);
- }
- if (MSO(p).funs) {
- sweep_proc_funs(p, 1);
- }
- if (MSO(p).externals) {
- sweep_proc_externals(p, 1);
+ if (MSO(p).first) {
+ sweep_off_heap(p, 1);
}
- if (OLD_HEAP(p) != NULL) {
+ if (OLD_HEAP(p) != NULL) {
ERTS_HEAP_FREE(ERTS_ALC_T_OLD_HEAP,
OLD_HEAP(p),
(OLD_HEND(p) - OLD_HEAP(p)) * sizeof(Eterm));
@@ -1305,6 +1283,7 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl)
HIGH_WATER(p) = HEAP_TOP(p);
ErtsGcQuickSanityCheck(p);
+
/*
* Copy newly received message onto the end of the new heap.
*/
@@ -2044,108 +2023,24 @@ next_vheap_size(Process* p, Uint vheap, Uint vheap_sz) {
return vheap_sz < p->min_vheap_size ? p->min_vheap_size : vheap_sz;
}
-static void
-sweep_proc_externals(Process *p, int fullsweep)
-{
- ExternalThing** prev;
- ExternalThing* ptr;
- char* oh = 0;
- Uint oh_size = 0;
-
- if (fullsweep == 0) {
- oh = (char *) OLD_HEAP(p);
- oh_size = (char *) OLD_HEND(p) - oh;
- }
-
- prev = &MSO(p).externals;
- ptr = MSO(p).externals;
-
- while (ptr) {
- Eterm* ppt = (Eterm *) ptr;
-
- if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
- ExternalThing* ro = external_thing_ptr(*ppt);
-
- *prev = ro; /* Patch to moved pos */
- prev = &ro->next;
- ptr = ro->next;
- } else if (in_area(ppt, oh, oh_size)) {
- /*
- * Object resides on old heap, and we just did a
- * generational collection - keep object in list.
- */
- prev = &ptr->next;
- ptr = ptr->next;
- } else { /* Object has not been moved - deref it */
- erts_deref_node_entry(ptr->node);
- *prev = ptr = ptr->next;
- }
- }
- ASSERT(*prev == NULL);
-}
-
-static void
-sweep_proc_funs(Process *p, int fullsweep)
-{
- ErlFunThing** prev;
- ErlFunThing* ptr;
- char* oh = 0;
- Uint oh_size = 0;
-
- if (fullsweep == 0) {
- oh = (char *) OLD_HEAP(p);
- oh_size = (char *) OLD_HEND(p) - oh;
- }
-
- prev = &MSO(p).funs;
- ptr = MSO(p).funs;
-
- while (ptr) {
- Eterm* ppt = (Eterm *) ptr;
-
- if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
- ErlFunThing* ro = (ErlFunThing *) fun_val(*ppt);
-
- *prev = ro; /* Patch to moved pos */
- prev = &ro->next;
- ptr = ro->next;
- } else if (in_area(ppt, oh, oh_size)) {
- /*
- * Object resides on old heap, and we just did a
- * generational collection - keep object in list.
- */
- prev = &ptr->next;
- ptr = ptr->next;
- } else { /* Object has not been moved - deref it */
- ErlFunEntry* fe = ptr->fe;
-
- *prev = ptr = ptr->next;
- if (erts_refc_dectest(&fe->refc, 0) == 0) {
- erts_erase_fun_entry(fe);
- }
- }
- }
- ASSERT(*prev == NULL);
-}
-
struct shrink_cand_data {
- ProcBin* new_candidates;
- ProcBin* new_candidates_end;
- ProcBin* old_candidates;
+ struct erl_off_heap_header* new_candidates;
+ struct erl_off_heap_header* new_candidates_end;
+ struct erl_off_heap_header* old_candidates;
Uint no_of_candidates;
Uint no_of_active;
};
static ERTS_INLINE void
link_live_proc_bin(struct shrink_cand_data *shrink,
- ProcBin ***prevppp,
- ProcBin **pbpp,
+ struct erl_off_heap_header*** prevppp,
+ struct erl_off_heap_header** currpp,
int new_heap)
{
- ProcBin *pbp = *pbpp;
-
- *pbpp = pbp->next;
+ ProcBin *pbp = (ProcBin*) *currpp;
+ ASSERT(**prevppp == *currpp);
+ *currpp = pbp->next;
if (pbp->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE)) {
ASSERT(((pbp->flags & (PB_ACTIVE_WRITER|PB_IS_WRITABLE))
== (PB_ACTIVE_WRITER|PB_IS_WRITABLE))
@@ -2162,15 +2057,16 @@ link_live_proc_bin(struct shrink_cand_data *shrink,
/* Our allocators are 8 byte aligned, i.e., shrinking with
less than 8 bytes will have no real effect */
if (unused >= 8) { /* A shrink candidate; save in candidate list */
+ **prevppp = pbp->next;
if (new_heap) {
if (!shrink->new_candidates)
- shrink->new_candidates_end = pbp;
+ shrink->new_candidates_end = (struct erl_off_heap_header*)pbp;
pbp->next = shrink->new_candidates;
- shrink->new_candidates = pbp;
+ shrink->new_candidates = (struct erl_off_heap_header*)pbp;
}
else {
pbp->next = shrink->old_candidates;
- shrink->old_candidates = pbp;
+ shrink->old_candidates = (struct erl_off_heap_header*)pbp;
}
shrink->no_of_candidates++;
return;
@@ -2178,67 +2074,101 @@ link_live_proc_bin(struct shrink_cand_data *shrink,
}
}
- /* Not a shrink candidate; keep in original mso list */
- **prevppp = pbp;
+ /* Not a shrink candidate; keep in original mso list */
*prevppp = &pbp->next;
-
}
static void
-sweep_proc_bins(Process *p, int fullsweep)
+sweep_off_heap(Process *p, int fullsweep)
{
struct shrink_cand_data shrink = {0};
- ProcBin** prev;
- ProcBin* ptr;
- Binary* bptr;
- char* oh = NULL;
- Uint oh_size = 0;
+ struct erl_off_heap_header* ptr;
+ struct erl_off_heap_header** prev;
+ char* oheap = NULL;
+ Uint oheap_sz = 0;
Uint bin_vheap = 0;
+#ifdef DEBUG
+ int seen_mature = 0;
+#endif
if (fullsweep == 0) {
- oh = (char *) OLD_HEAP(p);
- oh_size = (char *) OLD_HEND(p) - oh;
+ oheap = (char *) OLD_HEAP(p);
+ oheap_sz = (char *) OLD_HEND(p) - oheap;
}
BIN_OLD_VHEAP(p) = 0;
- prev = &MSO(p).mso;
- ptr = MSO(p).mso;
+ prev = &MSO(p).first;
+ ptr = MSO(p).first;
- /*
- * Note: In R7 we no longer force a fullsweep when we find binaries
- * on the old heap. The reason is that with the introduction of the
- * bit syntax we can expect binaries to be used a lot more. Note that
- * in earlier releases a brand new binary (or any other term) could
- * be put on the old heap during a gen-gc fullsweep, but this is
- * no longer the case in R7.
+ /* Firts part of the list will reside on the (old) new-heap.
+ * Keep if moved, otherwise deref.
*/
while (ptr) {
- Eterm* ppt = (Eterm *) ptr;
-
- if (IS_MOVED_BOXED(*ppt)) { /* Object is alive */
- bin_vheap += ptr->size / sizeof(Eterm);
- ptr = (ProcBin*) binary_val(*ppt);
- link_live_proc_bin(&shrink,
- &prev,
- &ptr,
- !in_area(ptr, oh, oh_size));
- } else if (in_area(ppt, oh, oh_size)) {
- /*
- * Object resides on old heap, and we just did a
- * generational collection - keep object in list.
- */
- BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
- link_live_proc_bin(&shrink, &prev, &ptr, 0);
- } else { /* Object has not been moved - deref it */
-
- *prev = ptr->next;
- bptr = ptr->val;
- if (erts_refc_dectest(&bptr->refc, 0) == 0)
- erts_bin_free(bptr);
- ptr = *prev;
- }
+ if (IS_MOVED_BOXED(ptr->thing_word)) {
+ ASSERT(!in_area(ptr, oheap, oheap_sz));
+ *prev = ptr = (struct erl_off_heap_header*) boxed_val(ptr->thing_word);
+ ASSERT(!IS_MOVED_BOXED(ptr->thing_word));
+ if (ptr->thing_word == HEADER_PROC_BIN) {
+ int to_new_heap = !in_area(ptr, oheap, oheap_sz);
+ ASSERT(to_new_heap == !seen_mature || (!to_new_heap && (seen_mature=1)));
+ if (to_new_heap) {
+ bin_vheap += ptr->size / sizeof(Eterm);
+ } else {
+ BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
+ }
+ link_live_proc_bin(&shrink, &prev, &ptr, to_new_heap);
+ }
+ else {
+ prev = &ptr->next;
+ ptr = ptr->next;
+ }
+ }
+ else if (!in_area(ptr, oheap, oheap_sz)) {
+ /* garbage */
+ switch (thing_subtag(ptr->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ {
+ Binary* bptr = ((ProcBin*)ptr)->val;
+ if (erts_refc_dectest(&bptr->refc, 0) == 0) {
+ erts_bin_free(bptr);
+ }
+ break;
+ }
+ case FUN_SUBTAG:
+ {
+ ErlFunEntry* fe = ((ErlFunThing*)ptr)->fe;
+ if (erts_refc_dectest(&fe->refc, 0) == 0) {
+ erts_erase_fun_entry(fe);
+ }
+ break;
+ }
+ default:
+ ASSERT(is_external_header(ptr->thing_word));
+ erts_deref_node_entry(((ExternalThing*)ptr)->node);
+ }
+ *prev = ptr = ptr->next;
+ }
+ else break; /* and let old-heap loop continue */
+ }
+
+ /* The rest of the list resides on old-heap, and we just did a
+ * generational collection - keep objects in list.
+ */
+ while (ptr) {
+ ASSERT(in_area(ptr, oheap, oheap_sz));
+ ASSERT(!IS_MOVED_BOXED(ptr->thing_word));
+ if (ptr->thing_word == HEADER_PROC_BIN) {
+ BIN_OLD_VHEAP(p) += ptr->size / sizeof(Eterm); /* for binary gc (words)*/
+ link_live_proc_bin(&shrink, &prev, &ptr, 0);
+ }
+ else {
+ ASSERT(is_fun_header(ptr->thing_word) ||
+ is_external_header(ptr->thing_word));
+ prev = &ptr->next;
+ ptr = ptr->next;
+ }
}
if (BIN_OLD_VHEAP(p) >= BIN_OLD_VHEAP_SZ(p)) {
@@ -2254,7 +2184,8 @@ sweep_proc_bins(Process *p, int fullsweep)
*/
if (shrink.no_of_candidates) {
- ProcBin *candlist[] = {shrink.new_candidates, shrink.old_candidates};
+ ProcBin *candlist[] = { (ProcBin*)shrink.new_candidates,
+ (ProcBin*)shrink.old_candidates };
Uint leave_unused = 0;
int i;
@@ -2266,21 +2197,21 @@ sweep_proc_bins(Process *p, int fullsweep)
}
for (i = 0; i < sizeof(candlist)/sizeof(candlist[0]); i++) {
-
- for (ptr = candlist[i]; ptr; ptr = ptr->next) {
- Uint new_size = ptr->size;
+ ProcBin* pb;
+ for (pb = candlist[i]; pb; pb = (ProcBin*)pb->next) {
+ Uint new_size = pb->size;
if (leave_unused) {
new_size += (new_size * 100) / leave_unused;
/* Our allocators are 8 byte aligned, i.e., shrinking with
less than 8 bytes will have no real effect */
- if (new_size + 8 >= ptr->val->orig_size)
+ if (new_size + 8 >= pb->val->orig_size)
continue;
}
- ptr->val = erts_bin_realloc(ptr->val, new_size);
- ptr->val->orig_size = new_size;
- ptr->bytes = (byte *) ptr->val->orig_bytes;
+ pb->val = erts_bin_realloc(pb->val, new_size);
+ pb->val->orig_size = new_size;
+ pb->bytes = (byte *) pb->val->orig_bytes;
}
}
@@ -2289,21 +2220,20 @@ sweep_proc_bins(Process *p, int fullsweep)
* We now potentially have the mso list divided into three lists:
* - shrink candidates on new heap (inactive writable with unused data)
* - shrink candidates on old heap (inactive writable with unused data)
- * - other binaries (read only + active writable ...)
+ * - other binaries (read only + active writable ...) + funs and externals
*
* Put them back together: new candidates -> other -> old candidates
* This order will ensure that the list only refers from new
* generation to old and never from old to new *which is important*.
*/
if (shrink.new_candidates) {
- if (prev == &MSO(p).mso) /* empty other binaries list */
+ if (prev == &MSO(p).first) /* empty other binaries list */
prev = &shrink.new_candidates_end->next;
else
- shrink.new_candidates_end->next = MSO(p).mso;
- MSO(p).mso = shrink.new_candidates;
+ shrink.new_candidates_end->next = MSO(p).first;
+ MSO(p).first = shrink.new_candidates;
}
}
-
*prev = shrink.old_candidates;
}
@@ -2334,15 +2264,17 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
tari = thing_arityval(val);
switch (thing_subtag(val)) {
case REFC_BINARY_SUBTAG:
+ case FUN_SUBTAG:
+ case EXTERNAL_PID_SUBTAG:
+ case EXTERNAL_PORT_SUBTAG:
+ case EXTERNAL_REF_SUBTAG:
{
- ProcBin* pb = (ProcBin*) hp;
- Eterm** uptr = (Eterm **) (void *) &pb->next;
+ struct erl_off_heap_header* oh = (struct erl_off_heap_header*) hp;
- if (*uptr && in_area((Eterm *)pb->next, area, area_size)) {
+ if (in_area(oh->next, area, area_size)) {
+ Eterm** uptr = (Eterm **) (void *) &oh->next;
*uptr += offs; /* Patch the mso chain */
}
- sz -= tari;
- hp += tari + 1;
}
break;
case BIN_MATCHSTATE_SUBTAG:
@@ -2353,40 +2285,11 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
mb->orig = offset_ptr(mb->orig, offs);
mb->base = binary_bytes(mb->orig);
}
- sz -= tari;
- hp += tari + 1;
}
break;
- case FUN_SUBTAG:
- {
- ErlFunThing* funp = (ErlFunThing *) hp;
- Eterm** uptr = (Eterm **) (void *) &funp->next;
-
- if (*uptr && in_area((Eterm *)funp->next, area, area_size)) {
- *uptr += offs;
- }
- sz -= tari;
- hp += tari + 1;
- }
- break;
- case EXTERNAL_PID_SUBTAG:
- case EXTERNAL_PORT_SUBTAG:
- case EXTERNAL_REF_SUBTAG:
- {
- ExternalThing* etp = (ExternalThing *) hp;
- Eterm** uptr = (Eterm **) (void *) &etp->next;
-
- if (*uptr && in_area((Eterm *)etp->next, area, area_size)) {
- *uptr += offs;
- }
- sz -= tari;
- hp += tari + 1;
- }
- break;
- default:
- sz -= tari;
- hp += tari + 1;
}
+ sz -= tari;
+ hp += tari + 1;
break;
}
default:
@@ -2423,18 +2326,8 @@ offset_heap_ptr(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
static void
offset_off_heap(Process* p, Sint offs, char* area, Uint area_size)
{
- if (MSO(p).mso && in_area((Eterm *)MSO(p).mso, area, area_size)) {
- Eterm** uptr = (Eterm**) (void *) &MSO(p).mso;
- *uptr += offs;
- }
-
- if (MSO(p).funs && in_area((Eterm *)MSO(p).funs, area, area_size)) {
- Eterm** uptr = (Eterm**) (void *) &MSO(p).funs;
- *uptr += offs;
- }
-
- if (MSO(p).externals && in_area((Eterm *)MSO(p).externals, area, area_size)) {
- Eterm** uptr = (Eterm**) (void *) &MSO(p).externals;
+ if (MSO(p).first && in_area((Eterm *)MSO(p).first, area, area_size)) {
+ Eterm** uptr = (Eterm**) (void *) &MSO(p).first;
*uptr += offs;
}
}
@@ -2555,8 +2448,8 @@ do { \
__FILE__, __LINE__, #EXP); \
} while (0)
-#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
-# define ERTS_EXTERNAL_VISITED_BIT ((Eterm) 1 << 31)
+#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST
+# define ERTS_OFFHEAP_VISITED_BIT ((Eterm) 1 << 31)
#endif
@@ -2566,62 +2459,45 @@ erts_check_off_heap2(Process *p, Eterm *htop)
Eterm *oheap = (Eterm *) OLD_HEAP(p);
Eterm *ohtop = (Eterm *) OLD_HTOP(p);
int old;
- ProcBin *pb;
- ErlFunThing *eft;
- ExternalThing *et;
+ union erl_off_heap_ptr u;
old = 0;
- for (pb = MSO(p).mso; pb; pb = pb->next) {
- Eterm *ptr = (Eterm *) pb;
- long refc = erts_refc_read(&pb->val->refc, 1);
+ for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next) {
+ long refc;
+ switch (thing_subtag(u.hdr->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ refc = erts_refc_read(&u.pb->val->refc, 1);
+ break;
+ case FUN_SUBTAG:
+ refc = erts_refc_read(&u.fun->fe->refc, 1);
+ break;
+ case EXTERNAL_PID_SUBTAG:
+ case EXTERNAL_PORT_SUBTAG:
+ case EXTERNAL_REF_SUBTAG:
+ refc = erts_refc_read(&u.ext->node->refc, 1);
+ break;
+ default:
+ ASSERT(!!"erts_check_off_heap2: Invalid thing_word");
+ }
ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
+#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_LIST
+ ERTS_CHK_OFFHEAP_ASSERT(!(u.hdr->thing_word & ERTS_EXTERNAL_VISITED_BIT));
+ u.hdr->thing_word |= ERTS_OFFHEAP_VISITED_BIT;
+#endif
if (old) {
- ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
+ ERTS_CHK_OFFHEAP_ASSERT(oheap <= u.ep && u.ep < ohtop);
}
- else if (oheap <= ptr && ptr < ohtop)
+ else if (oheap <= u.ep && u.ep < ohtop)
old = 1;
else {
- ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
+ ERTS_CHK_OFFHEAP_ASSERT(within2(u.ep, p, htop));
}
}
- old = 0;
- for (eft = MSO(p).funs; eft; eft = eft->next) {
- Eterm *ptr = (Eterm *) eft;
- long refc = erts_refc_read(&eft->fe->refc, 1);
- ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
- if (old)
- ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
- else if (oheap <= ptr && ptr < ohtop)
- old = 1;
- else
- ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
- }
-
- old = 0;
- for (et = MSO(p).externals; et; et = et->next) {
- Eterm *ptr = (Eterm *) et;
- long refc = erts_refc_read(&et->node->refc, 1);
- ERTS_CHK_OFFHEAP_ASSERT(refc >= 1);
-#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
- ERTS_CHK_OFFHEAP_ASSERT(!(et->header & ERTS_EXTERNAL_VISITED_BIT));
-#endif
- if (old)
- ERTS_CHK_OFFHEAP_ASSERT(oheap <= ptr && ptr < ohtop);
- else if (oheap <= ptr && ptr < ohtop)
- old = 1;
- else
- ERTS_CHK_OFFHEAP_ASSERT(within2(ptr, p, htop));
-#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
- et->header |= ERTS_EXTERNAL_VISITED_BIT;
-#endif
- }
-
#ifdef ERTS_OFFHEAP_DEBUG_CHK_CIRCULAR_EXTERNAL_LIST
- for (et = MSO(p).externals; et; et = et->next)
- et->header &= ~ERTS_EXTERNAL_VISITED_BIT;
+ for (u.hdr = MSO(p).first; u.hdr; u.hdr = u.hdr->next)
+ u.hdr->thing_word &= ~ERTS_OFFHEAP_VISITED_BIT;
#endif
-
}
void
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 4a4507b212..14bd10b42c 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -78,6 +78,7 @@ static erts_tid_t main_thread;
erts_cpu_info_t *erts_cpuinfo;
+int erts_reader_groups;
int erts_use_sender_punish;
/*
@@ -110,6 +111,7 @@ int erts_compat_rel;
static int use_multi_run_queue;
static int no_schedulers;
static int no_schedulers_online;
+static int max_reader_groups;
#ifdef DEBUG
Uint32 verbose; /* See erl_debug.h for information about verbose */
@@ -505,6 +507,7 @@ void erts_usage(void)
ERTS_MIN_COMPAT_REL, this_rel_num());
erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n");
+ erts_fprintf(stderr, "-rg amount set reader groups limit\n");
erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n");
erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n");
erts_fprintf(stderr, "-sct cput set cpu topology,\n");
@@ -538,6 +541,50 @@ void erts_usage(void)
erl_exit(-1, "");
}
+#ifdef USE_THREADS
+/*
+ * allocators for thread lib
+ */
+
+static void *ethr_std_alloc(size_t size)
+{
+ return erts_alloc_fnf(ERTS_ALC_T_ETHR_STD, (Uint) size);
+}
+static void *ethr_std_realloc(void *ptr, size_t size)
+{
+ return erts_realloc_fnf(ERTS_ALC_T_ETHR_STD, ptr, (Uint) size);
+}
+static void ethr_std_free(void *ptr)
+{
+ erts_free(ERTS_ALC_T_ETHR_STD, ptr);
+}
+static void *ethr_sl_alloc(size_t size)
+{
+ return erts_alloc_fnf(ERTS_ALC_T_ETHR_SL, (Uint) size);
+}
+static void *ethr_sl_realloc(void *ptr, size_t size)
+{
+ return erts_realloc_fnf(ERTS_ALC_T_ETHR_SL, ptr, (Uint) size);
+}
+static void ethr_sl_free(void *ptr)
+{
+ erts_free(ERTS_ALC_T_ETHR_SL, ptr);
+}
+static void *ethr_ll_alloc(size_t size)
+{
+ return erts_alloc_fnf(ERTS_ALC_T_ETHR_LL, (Uint) size);
+}
+static void *ethr_ll_realloc(void *ptr, size_t size)
+{
+ return erts_realloc_fnf(ERTS_ALC_T_ETHR_LL, ptr, (Uint) size);
+}
+static void ethr_ll_free(void *ptr)
+{
+ erts_free(ERTS_ALC_T_ETHR_LL, ptr);
+}
+
+#endif
+
static void
early_init(int *argc, char **argv) /*
* Only put things here which are
@@ -615,9 +662,15 @@ early_init(int *argc, char **argv) /*
? ncpuavail
: (ncpuonln > 0 ? ncpuonln : no_schedulers));
+#ifdef ERTS_SMP
+ erts_max_main_threads = no_schedulers_online;
+#endif
+
schdlrs = no_schedulers;
schdlrs_onln = no_schedulers_online;
+ max_reader_groups = ERTS_MAX_READER_GROUPS;
+
if (argc && argv) {
int i = 1;
while (i < *argc) {
@@ -627,6 +680,24 @@ early_init(int *argc, char **argv) /*
}
if (argv[i][0] == '-') {
switch (argv[i][1]) {
+ case 'r': {
+ char *sub_param = argv[i]+2;
+ if (has_prefix("g", sub_param)) {
+ char *arg = get_arg(sub_param+1, argv[i+1], &i);
+ if (sscanf(arg, "%d", &max_reader_groups) != 1) {
+ erts_fprintf(stderr,
+ "bad reader groups limit: %s\n", arg);
+ erts_usage();
+ }
+ if (max_reader_groups < 0) {
+ erts_fprintf(stderr,
+ "bad reader groups limit: %d\n",
+ max_reader_groups);
+ erts_usage();
+ }
+ }
+ break;
+ }
case 'S' : {
int tot, onln;
char *arg = get_arg(argv[i]+2, argv[i+1], &i);
@@ -699,6 +770,36 @@ early_init(int *argc, char **argv) /*
erts_early_init_scheduling(); /* Require allocators */
erts_init_utils(); /* Require allocators */
+#ifdef USE_THREADS
+ {
+ erts_thr_late_init_data_t elid = ERTS_THR_LATE_INIT_DATA_DEF_INITER;
+ elid.mem.std.alloc = ethr_std_alloc;
+ elid.mem.std.realloc = ethr_std_realloc;
+ elid.mem.std.free = ethr_std_free;
+ elid.mem.sl.alloc = ethr_sl_alloc;
+ elid.mem.sl.realloc = ethr_sl_realloc;
+ elid.mem.sl.free = ethr_sl_free;
+ elid.mem.ll.alloc = ethr_ll_alloc;
+ elid.mem.ll.realloc = ethr_ll_realloc;
+ elid.mem.ll.free = ethr_ll_free;
+
+#ifdef ERTS_SMP
+ elid.main_threads = erts_max_main_threads;
+#else
+ elid.main_threads = 1;
+#endif
+ elid.reader_groups = (elid.main_threads > 1
+ ? elid.main_threads
+ : 0);
+ if (max_reader_groups <= 1)
+ elid.reader_groups = 0;
+ if (elid.reader_groups > max_reader_groups)
+ elid.reader_groups = max_reader_groups;
+ erts_reader_groups = elid.reader_groups;
+
+ erts_thr_late_init(&elid);
+ }
+#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_late_init();
#endif
@@ -1193,9 +1294,17 @@ erl_start(int argc, char **argv)
erts_async_thread_suggested_stack_size));
break;
- case 'r':
- erts_ets_realloc_always_moves = 1;
+ case 'r': {
+ char *sub_param = argv[i]+2;
+ if (has_prefix("g", sub_param)) {
+ get_arg(sub_param+1, argv[i+1], &i);
+ /* already handled */
+ }
+ else {
+ erts_ets_realloc_always_moves = 1;
+ }
break;
+ }
case 'n': /* XXX obsolete */
break;
case 'c':
@@ -1280,6 +1389,7 @@ erl_start(int argc, char **argv)
erts_sys_main_thread(); /* May or may not return! */
#else
+ erts_thr_set_main_status(1, 1);
set_main_stack_size();
process_main();
#endif
@@ -1353,7 +1463,7 @@ system_cleanup(int exit_code)
erts_cleanup_incgc();
#endif
-#if defined(USE_THREADS) && !defined(ERTS_SMP)
+#if defined(USE_THREADS)
exit_async();
#endif
#if HAVE_ERTS_MSEG
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index cee470ae37..99cc80e259 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -96,10 +96,10 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "proc_status", "pid" },
{ "proc_tab", NULL },
{ "ports_snapshot", NULL },
- { "db_tab", "address" },
- { "db_tab_fix", "address" },
{ "meta_name_tab", "address" },
{ "meta_main_tab_slot", "address" },
+ { "db_tab", "address" },
+ { "db_tab_fix", "address" },
{ "meta_main_tab_main", NULL },
{ "db_hash_slot", "address" },
{ "node_table", NULL },
@@ -119,9 +119,9 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "child_status", NULL },
#endif
#ifdef __WIN32__
- { "sys_driver_data_lock", NULL },
+ { "sys_driver_data_lock", NULL },
#endif
- { "drv_ev_state_grow", NULL, },
+ { "drv_ev_state_grow", NULL, },
{ "drv_ev_state", "address" },
{ "safe_hash", "address" },
{ "pollset_rm_list", NULL },
@@ -153,6 +153,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "instr", NULL },
{ "fix_alloc", "index" },
{ "alcu_allocator", "index" },
+ { "alcu_delayed_free", "index" },
{ "mseg", NULL },
#ifdef HALFWORD_HEAP
{ "pmmap", NULL },
@@ -177,17 +178,19 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "pix_lock", "address" },
{ "run_queues_lists", NULL },
{ "sched_stat", NULL },
+ { "run_queue_sleep_list", "address" },
#endif
{ "alloc_thr_ix_lock", NULL },
#ifdef ERTS_SMP
- { "proc_lck_wtr_alloc", NULL },
+ { "proc_lck_qs_alloc", NULL },
#endif
#ifdef __WIN32__
#ifdef DEBUG
{ "save_ops_lock", NULL },
#endif
#endif
- { "mtrace_buf", NULL }
+ { "mtrace_buf", NULL },
+ { "erts_alloc_hard_debug", NULL }
};
#define ERTS_LOCK_ORDER_SIZE \
@@ -199,6 +202,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
& ERTS_LC_FLG_LT_ALL \
& ~(ERTS_LC_FLG_LT_SPINLOCK|ERTS_LC_FLG_LT_RWSPINLOCK)))
+static __decl_noreturn void __noreturn lc_abort(void);
+
static char *
lock_type(Uint16 flags)
{
@@ -222,7 +227,7 @@ rw_op_str(Uint16 flags)
return " (r)";
case ERTS_LC_FLG_LO_WRITE:
erts_fprintf(stderr, "\nInternal error\n");
- abort();
+ lc_abort();
default:
break;
}
@@ -271,28 +276,18 @@ static erts_lc_free_block_t *free_blocks;
#define ERTS_LC_FB_CHUNK_SIZE 10
#endif
-#ifdef ETHR_HAVE_NATIVE_LOCKS
static ethr_spinlock_t free_blocks_lock;
-#define ERTS_LC_LOCK ethr_spin_lock
-#define ERTS_LC_UNLOCK ethr_spin_unlock
-#else
-static ethr_mutex free_blocks_lock;
-#define ERTS_LC_LOCK ethr_mutex_lock
-#define ERTS_LC_UNLOCK ethr_mutex_unlock
-#endif
static ERTS_INLINE void
lc_lock(void)
{
- if (ERTS_LC_LOCK(&free_blocks_lock) != 0)
- abort();
+ ethr_spin_lock(&free_blocks_lock);
}
static ERTS_INLINE void
lc_unlock(void)
{
- if (ERTS_LC_UNLOCK(&free_blocks_lock) != 0)
- abort();
+ ethr_spin_unlock(&free_blocks_lock);
}
static ERTS_INLINE void lc_free(void *p)
@@ -313,7 +308,7 @@ static void *lc_core_alloc(void)
{
lc_unlock();
erts_fprintf(stderr, "Lock checker out of memory!\n");
- abort();
+ lc_abort();
}
#else
@@ -327,7 +322,7 @@ static void *lc_core_alloc(void)
* ERTS_LC_FB_CHUNK_SIZE);
if (!fbs) {
erts_fprintf(stderr, "Lock checker failed to allocate memory!\n");
- abort();
+ lc_abort();
}
for (i = 1; i < ERTS_LC_FB_CHUNK_SIZE - 1; i++) {
#ifdef DEBUG
@@ -367,11 +362,11 @@ create_locked_locks(char *thread_name)
{
erts_lc_locked_locks_t *l_lcks = malloc(sizeof(erts_lc_locked_locks_t));
if (!l_lcks)
- abort();
+ lc_abort();
l_lcks->thread_name = strdup(thread_name ? thread_name : "unknown");
if (!l_lcks->thread_name)
- abort();
+ lc_abort();
l_lcks->tid = erts_thr_self();
l_lcks->required.first = NULL;
@@ -513,7 +508,7 @@ uninitialized_lock(void)
{
erts_fprintf(stderr, "Performing operations on uninitialized lock!\n");
print_curr_locks(get_my_locked_locks());
- abort();
+ lc_abort();
}
static void
@@ -523,7 +518,7 @@ lock_twice(char *prefix, erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck,
erts_fprintf(stderr, "%s%s", prefix, rw_op_str(op_flags));
print_lock(" ", lck, " lock which is already locked by thread!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -533,7 +528,7 @@ unlock_op_mismatch(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck,
erts_fprintf(stderr, "Unlocking%s ", rw_op_str(op_flags));
print_lock("", lck, " lock which mismatch previous lock operation!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -541,7 +536,7 @@ unlock_of_not_locked(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck)
{
print_lock("Unlocking ", lck, " lock which is not locked by thread!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -550,7 +545,7 @@ lock_order_violation(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck)
print_lock("Lock order violation occured when locking ", lck, "!\n");
print_curr_locks(l_lcks);
print_lock_order();
- abort();
+ lc_abort();
}
static void
@@ -561,7 +556,7 @@ type_order_violation(char *op, erts_lc_locked_locks_t *l_lcks,
print_lock(op, lck, "!\n");
ASSERT(l_lcks);
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -613,7 +608,7 @@ lock_mismatch(erts_lc_locked_locks_t *l_lcks, int exact,
}
}
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -621,7 +616,7 @@ unlock_of_required_lock(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck)
{
print_lock("Unlocking required ", lck, " lock!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -629,7 +624,7 @@ unrequire_of_not_required_lock(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *l
{
print_lock("Unrequire on ", lck, " lock not required!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -637,7 +632,7 @@ require_twice(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck)
{
print_lock("Require on ", lck, " lock already required!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
static void
@@ -645,7 +640,7 @@ required_not_locked(erts_lc_locked_locks_t *l_lcks, erts_lc_lock_t *lck)
{
print_lock("Required ", lck, " lock not locked!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
@@ -658,13 +653,23 @@ thread_exit_handler(void)
erts_fprintf(stderr,
"Thread exiting while having locked locks!\n");
print_curr_locks(l_lcks);
- abort();
+ lc_abort();
}
destroy_locked_locks(l_lcks);
/* erts_tsd_set(locks_key, NULL); */
}
}
+static __decl_noreturn void
+lc_abort(void)
+{
+#ifdef __WIN32__
+ DebugBreak();
+#else
+ abort();
+#endif
+}
+
void
erts_lc_set_thread_name(char *thread_name)
{
@@ -676,7 +681,7 @@ erts_lc_set_thread_name(char *thread_name)
free((void *) l_lcks->thread_name);
l_lcks->thread_name = strdup(thread_name ? thread_name : "unknown");
if (!l_lcks->thread_name)
- abort();
+ lc_abort();
}
}
@@ -686,7 +691,7 @@ erts_lc_assert_failed(char *file, int line, char *assertion)
erts_fprintf(stderr, "%s:%d: Lock check assertion \"%s\" failed!\n",
file, line, assertion);
print_curr_locks(get_my_locked_locks());
- abort();
+ lc_abort();
return 0;
}
@@ -699,7 +704,7 @@ void erts_lc_fail(char *fmt, ...)
va_end(args);
erts_fprintf(stderr, "\n");
print_curr_locks(get_my_locked_locks());
- abort();
+ lc_abort();
}
@@ -719,7 +724,7 @@ erts_lc_get_lock_order_id(char *name)
"(update erl_lock_check.c)\n",
name);
}
- abort();
+ lc_abort();
return (Sint16) -1;
}
@@ -895,6 +900,25 @@ erts_lc_check_exact(erts_lc_lock_t *have, int have_len)
}
}
+void
+erts_lc_check_no_locked_of_type(Uint16 flags)
+{
+ erts_lc_locked_locks_t *l_lcks = get_my_locked_locks();
+ if (l_lcks) {
+ erts_lc_locked_lock_t *l_lck = l_lcks->locked.first;
+ for (l_lck = l_lcks->locked.first; l_lck; l_lck = l_lck->next) {
+ if (l_lck->flags & flags) {
+ erts_fprintf(stderr,
+ "Locked lock of type %s found which isn't "
+ "allowed here!\n",
+ lock_type(l_lck->flags));
+ print_curr_locks(l_lcks);
+ lc_abort();
+ }
+ }
+ }
+}
+
int
erts_lc_trylock_force_busy_flg(erts_lc_lock_t *lck, Uint16 op_flags)
{
@@ -1283,13 +1307,8 @@ erts_lc_init(void)
free_blocks = NULL;
#endif /* #ifdef ERTS_LC_STATIC_ALLOC */
-#ifdef ETHR_HAVE_NATIVE_LOCKS
if (ethr_spinlock_init(&free_blocks_lock) != 0)
- abort();
-#else
- if (ethr_mutex_init(&free_blocks_lock) != 0)
- abort();
-#endif
+ lc_abort();
erts_tsd_key_create(&locks_key);
}
diff --git a/erts/emulator/beam/erl_lock_check.h b/erts/emulator/beam/erl_lock_check.h
index d5e2ede9ac..0372e6850d 100644
--- a/erts/emulator/beam/erl_lock_check.h
+++ b/erts/emulator/beam/erl_lock_check.h
@@ -77,6 +77,7 @@ void erts_lc_check(erts_lc_lock_t *have, int have_len,
void erts_lc_check_exact(erts_lc_lock_t *have, int have_len);
void erts_lc_have_locks(int *resv, erts_lc_lock_t *lcks, int len);
void erts_lc_have_lock_ids(int *resv, int *ids, int len);
+void erts_lc_check_no_locked_of_type(Uint16 flags);
int erts_lc_trylock_force_busy_flg(erts_lc_lock_t *lck, Uint16 op_flags);
void erts_lc_trylock_flg(int locked, erts_lc_lock_t *lck, Uint16 op_flags);
void erts_lc_lock_flg(erts_lc_lock_t *lck, Uint16 op_flags);
diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c
index 26028aeefc..239773f366 100644
--- a/erts/emulator/beam/erl_lock_count.c
+++ b/erts/emulator/beam/erl_lock_count.c
@@ -166,8 +166,8 @@ static void print_lock_x(erts_lcnt_lock_t *lock, Uint16 flag, char *action, char
int i;
type = lcnt_lock_type(lock->flag);
- ethr_atomic_read(&lock->r_state, &r_state);
- ethr_atomic_read(&lock->w_state, &w_state);
+ r_state = ethr_atomic_read(&lock->r_state);
+ w_state = ethr_atomic_read(&lock->w_state);
if (lock->flag & flag) {
@@ -394,10 +394,10 @@ void erts_lcnt_lock_opt(erts_lcnt_lock_t *lock, Uint16 option) {
ASSERT(eltd);
- ethr_atomic_read(&lock->w_state, &w_state);
+ w_state = ethr_atomic_read(&lock->w_state);
if (option & ERTS_LCNT_LO_WRITE) {
- ethr_atomic_read(&lock->r_state, &r_state);
+ r_state = ethr_atomic_read(&lock->r_state);
ethr_atomic_inc( &lock->w_state);
}
if (option & ERTS_LCNT_LO_READ) {
@@ -423,7 +423,7 @@ void erts_lcnt_lock(erts_lcnt_lock_t *lock) {
if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return;
- ethr_atomic_read(&lock->w_state, &w_state);
+ w_state = ethr_atomic_read(&lock->w_state);
ethr_atomic_inc( &lock->w_state);
eltd = lcnt_get_thread_data();
@@ -478,7 +478,7 @@ void erts_lcnt_lock_post_x(erts_lcnt_lock_t *lock, char *file, unsigned int line
#ifdef DEBUG
if (!(lock->flag & (ERTS_LCNT_LT_RWMUTEX | ERTS_LCNT_LT_RWSPINLOCK))) {
- ethr_atomic_read(&lock->flowstate, &flowstate);
+ flowstate = ethr_atomic_read(&lock->flowstate);
ASSERT(flowstate == 0);
ethr_atomic_inc( &lock->flowstate);
}
@@ -522,12 +522,12 @@ void erts_lcnt_unlock(erts_lcnt_lock_t *lock) {
if (erts_lcnt_rt_options & ERTS_LCNT_OPT_SUSPEND) return;
#ifdef DEBUG
/* flowstate */
- ethr_atomic_read(&lock->flowstate, &flowstate);
+ flowstate = ethr_atomic_read(&lock->flowstate);
ASSERT(flowstate == 1);
ethr_atomic_dec( &lock->flowstate);
/* write state */
- ethr_atomic_read(&lock->w_state, &w_state);
+ w_state = ethr_atomic_read(&lock->w_state);
ASSERT(w_state > 0)
#endif
ethr_atomic_dec(&lock->w_state);
@@ -558,7 +558,7 @@ void erts_lcnt_trylock(erts_lcnt_lock_t *lock, int res) {
if (res != EBUSY) {
#ifdef DEBUG
- ethr_atomic_read(&lock->flowstate, &flowstate);
+ flowstate = ethr_atomic_read(&lock->flowstate);
ASSERT(flowstate == 0);
ethr_atomic_inc( &lock->flowstate);
#endif
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index b63f3df7df..1f61dca230 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -30,6 +30,7 @@
#include "erl_message.h"
#include "erl_process.h"
#include "erl_nmgc.h"
+#include "erl_binary.h"
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message,
ErlMessage,
@@ -164,16 +165,25 @@ erts_resize_message_buffer(ErlHeapFragment *bp, Uint size,
void
erts_cleanup_offheap(ErlOffHeap *offheap)
{
- if (offheap->mso) {
- erts_cleanup_mso(offheap->mso);
- }
-#ifndef HYBRID /* FIND ME! */
- if (offheap->funs) {
- erts_cleanup_funs(offheap->funs);
- }
-#endif
- if (offheap->externals) {
- erts_cleanup_externals(offheap->externals);
+ union erl_off_heap_ptr u;
+
+ for (u.hdr = offheap->first; u.hdr; u.hdr = u.hdr->next) {
+ switch (thing_subtag(u.hdr->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ if (erts_refc_dectest(&u.pb->val->refc, 0) == 0) {
+ erts_bin_free(u.pb->val);
+ }
+ break;
+ case FUN_SUBTAG:
+ if (erts_refc_dectest(&u.fun->fe->refc, 0) == 0) {
+ erts_erase_fun_entry(u.fun->fe);
+ }
+ break;
+ default:
+ ASSERT(is_external_header(u.hdr->thing_word));
+ erts_deref_node_entry(u.ext->node);
+ break;
+ }
}
}
@@ -201,41 +211,17 @@ link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp)
MBUF_SIZE(proc) += bp->used_size;
FLAGS(proc) |= F_FORCE_GC;
- /* Move any binaries into the process */
- if (bp->off_heap.mso != NULL) {
- ProcBin** next_p = &bp->off_heap.mso;
+ /* Move any off_heap's into the process */
+ if (bp->off_heap.first != NULL) {
+ struct erl_off_heap_header** next_p = &bp->off_heap.first;
while (*next_p != NULL) {
next_p = &((*next_p)->next);
}
- *next_p = MSO(proc).mso;
- MSO(proc).mso = bp->off_heap.mso;
- bp->off_heap.mso = NULL;
+ *next_p = MSO(proc).first;
+ MSO(proc).first = bp->off_heap.first;
+ bp->off_heap.first = NULL;
MSO(proc).overhead += bp->off_heap.overhead;
}
-
- /* Move any funs into the process */
-#ifndef HYBRID
- if (bp->off_heap.funs != NULL) {
- ErlFunThing** next_p = &bp->off_heap.funs;
- while (*next_p != NULL) {
- next_p = &((*next_p)->next);
- }
- *next_p = MSO(proc).funs;
- MSO(proc).funs = bp->off_heap.funs;
- bp->off_heap.funs = NULL;
- }
-#endif
-
- /* Move any external things into the process */
- if (bp->off_heap.externals != NULL) {
- ExternalThing** next_p = &bp->off_heap.externals;
- while (*next_p != NULL) {
- next_p = &((*next_p)->next);
- }
- *next_p = MSO(proc).externals;
- MSO(proc).externals = bp->off_heap.externals;
- bp->off_heap.externals = NULL;
- }
}
}
@@ -506,19 +492,7 @@ erts_link_mbuf_to_proc(struct process *proc, ErlHeapFragment *bp)
void
erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
{
- /* Unions for typecasts avoids warnings about type-punned pointers and aliasing */
- union {
- Uint** upp;
- ProcBin **pbpp;
- ErlFunThing **efpp;
- ExternalThing **etpp;
- } oh_list_pp, oh_el_next_pp;
- union {
- Uint *up;
- ProcBin *pbp;
- ErlFunThing *efp;
- ExternalThing *etp;
- } oh_el_p;
+ struct erl_off_heap_header* oh;
Eterm term, token, *fhp, *hp;
Sint offs;
Uint sz;
@@ -571,9 +545,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
hp = *hpp;
offs = hp - fhp;
- oh_list_pp.upp = NULL;
- oh_el_next_pp.upp = NULL; /* Shut up compiler warning */
- oh_el_p.up = NULL; /* Shut up compiler warning */
+ oh = NULL;
while (sz--) {
Uint cpy_sz;
Eterm val = *fhp++;
@@ -593,25 +565,11 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
case ARITYVAL_SUBTAG:
break;
case REFC_BINARY_SUBTAG:
- oh_list_pp.pbpp = &off_heap->mso;
- oh_el_p.up = (hp-1);
- oh_el_next_pp.pbpp = &(oh_el_p.pbp)->next;
- cpy_sz = thing_arityval(val);
- goto cpy_words;
case FUN_SUBTAG:
-#ifndef HYBRID
- oh_list_pp.efpp = &off_heap->funs;
- oh_el_p.up = (hp-1);
- oh_el_next_pp.efpp = &(oh_el_p.efp)->next;
-#endif
- cpy_sz = thing_arityval(val);
- goto cpy_words;
case EXTERNAL_PID_SUBTAG:
case EXTERNAL_PORT_SUBTAG:
case EXTERNAL_REF_SUBTAG:
- oh_list_pp.etpp = &off_heap->externals;
- oh_el_p.up = (hp-1);
- oh_el_next_pp.etpp = &(oh_el_p.etp)->next;
+ oh = (struct erl_off_heap_header*) (hp-1);
cpy_sz = thing_arityval(val);
goto cpy_words;
default:
@@ -641,44 +599,13 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg)
case 1: *hp++ = *fhp++;
default: break;
}
- if (oh_list_pp.upp) {
-#ifdef HARD_DEBUG
- Uint *dbg_old_oh_list_p = *oh_list_pp.upp;
-#endif
+ if (oh) {
/* Add to offheap list */
- *oh_el_next_pp.upp = *oh_list_pp.upp;
- *oh_list_pp.upp = oh_el_p.up;
- ASSERT(*hpp <= oh_el_p.up);
- ASSERT(hp > oh_el_p.up);
-#ifdef HARD_DEBUG
- switch (val & _HEADER_SUBTAG_MASK) {
- case REFC_BINARY_SUBTAG:
- ASSERT(off_heap->mso == *oh_list_pp.pbpp);
- ASSERT(off_heap->mso->next
- == (ProcBin *) dbg_old_oh_list_p);
- break;
-#ifndef HYBRID
- case FUN_SUBTAG:
- ASSERT(off_heap->funs == *oh_list_pp.efpp);
- ASSERT(off_heap->funs->next
- == (ErlFunThing *) dbg_old_oh_list_p);
- break;
-#endif
- case EXTERNAL_PID_SUBTAG:
- case EXTERNAL_PORT_SUBTAG:
- case EXTERNAL_REF_SUBTAG:
- ASSERT(off_heap->externals
- == *oh_list_pp.etpp);
- ASSERT(off_heap->externals->next
- == (ExternalThing *) dbg_old_oh_list_p);
- break;
- default:
- ASSERT(0);
- }
-#endif
- oh_list_pp.upp = NULL;
-
-
+ oh->next = off_heap->first;
+ off_heap->first = oh;
+ ASSERT(*hpp <= (Eterm*)oh);
+ ASSERT(hp > (Eterm*)oh);
+ oh = NULL;
}
break;
}
@@ -765,11 +692,7 @@ copy_done:
#endif
- bp->off_heap.mso = NULL;
-#ifndef HYBRID
- bp->off_heap.funs = NULL;
-#endif
- bp->off_heap.externals = NULL;
+ bp->off_heap.first = NULL;
free_message_buffer(bp);
msg->data.heap_frag = NULL;
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index f478572ac2..55ea92860a 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -28,13 +28,18 @@ struct external_thing_;
* but is stored outside of any heap.
*/
-typedef struct erl_off_heap {
- struct proc_bin* mso; /* List of associated binaries. */
-#ifndef HYBRID /* FIND ME! */
- struct erl_fun_thing* funs; /* List of funs. */
+struct erl_off_heap_header {
+ Eterm thing_word;
+ Uint size;
+#if HALFWORD_HEAP
+ void* dummy_ptr_padding__;
#endif
- struct external_thing_* externals; /* List of external things. */
- int overhead; /* Administrative overhead (used to force GC). */
+ struct erl_off_heap_header* next;
+};
+
+typedef struct erl_off_heap {
+ struct erl_off_heap_header* first;
+ int overhead; /* Administrative overhead (used to force GC). */
} ErlOffHeap;
#include "external.h"
@@ -201,9 +206,7 @@ do { \
(HEAP_FRAG_P)->next = NULL; \
(HEAP_FRAG_P)->alloc_size = (DATA_WORDS); \
(HEAP_FRAG_P)->used_size = (DATA_WORDS); \
- (HEAP_FRAG_P)->off_heap.mso = NULL; \
- (HEAP_FRAG_P)->off_heap.funs = NULL; \
- (HEAP_FRAG_P)->off_heap.externals = NULL; \
+ (HEAP_FRAG_P)->off_heap.first = NULL; \
(HEAP_FRAG_P)->off_heap.overhead = 0; \
} while (0)
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index 9cf55ee319..b1478758a1 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -585,9 +585,7 @@ void erts_mtrace_init(char *receiver, char *nodename)
Uint16 port;
erts_mtx_init(&mtrace_buf_mutex, "mtrace_buf");
- erts_mtx_set_forksafe(&mtrace_buf_mutex);
erts_mtx_init(&mtrace_op_mutex, "mtrace_op");
- erts_mtx_set_forksafe(&mtrace_op_mutex);
socket_desc = erts_sock_open();
if (socket_desc == ERTS_SOCK_INVALID_SOCKET) {
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 3d63fa1caf..e95d9c4f75 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -258,9 +258,7 @@ void enif_free_env(ErlNifEnv* env)
static ERTS_INLINE void clear_offheap(ErlOffHeap* oh)
{
- oh->mso = NULL;
- oh->externals = NULL;
- oh->funs = NULL;
+ oh->first = NULL;
oh->overhead = 0;
}
@@ -364,7 +362,7 @@ ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
#ifdef DEBUG
static int is_offheap(const ErlOffHeap* oh)
{
- return oh->mso != NULL || oh->funs != NULL || oh->externals != NULL;
+ return oh->first != NULL;
}
#endif
@@ -627,8 +625,8 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
pb = (ProcBin *) alloc_heap(env, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = bptr->orig_size;
- pb->next = MSO(env->proc).mso;
- MSO(env->proc).mso = pb;
+ pb->next = MSO(env->proc).first;
+ MSO(env->proc).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 5865d33138..e430b4ad77 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -80,6 +80,8 @@ dist_table_alloc(void *dep_tmpl)
Eterm chnl_nr;
Eterm sysname;
DistEntry *dep;
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
if(((DistEntry *) dep_tmpl) == erts_this_dist_entry)
return dep_tmpl;
@@ -92,7 +94,7 @@ dist_table_alloc(void *dep_tmpl)
dep->prev = NULL;
erts_refc_init(&dep->refc, -1);
- erts_smp_rwmtx_init_x(&dep->rwmtx, "dist_entry", chnl_nr);
+ erts_smp_rwmtx_init_opt_x(&dep->rwmtx, &rwmtx_opt, "dist_entry", chnl_nr);
dep->sysname = sysname;
dep->cid = NIL;
dep->connection_id = 0;
@@ -580,6 +582,18 @@ ErlNode *erts_find_or_insert_node(Eterm sysname, Uint creation)
ErlNode ne;
ne.sysname = sysname;
ne.creation = creation;
+
+ erts_smp_rwmtx_rlock(&erts_node_table_rwmtx);
+ res = hash_get(&erts_node_table, (void *) &ne);
+ if (res && res != erts_this_node) {
+ long refc = erts_refc_inctest(&res->refc, 0);
+ if (refc < 2) /* New or pending delete */
+ erts_refc_inc(&res->refc, 1);
+ }
+ erts_smp_rwmtx_runlock(&erts_node_table_rwmtx);
+ if (res)
+ return res;
+
erts_smp_rwmtx_rwlock(&erts_node_table_rwmtx);
res = hash_put(&erts_node_table, (void *) &ne);
ASSERT(res);
@@ -696,8 +710,12 @@ erts_set_this_node(Eterm sysname, Uint creation)
void erts_init_node_tables(void)
{
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
HashFunctions f;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+
f.hash = (H_FUN) dist_table_hash;
f.cmp = (HCMP_FUN) dist_table_cmp;
f.alloc = (HALLOC_FUN) dist_table_alloc;
@@ -719,9 +737,10 @@ void erts_init_node_tables(void)
erts_this_dist_entry->prev = NULL;
erts_refc_init(&erts_this_dist_entry->refc, 1); /* erts_this_node */
- erts_smp_rwmtx_init_x(&erts_this_dist_entry->rwmtx,
- "dist_entry",
- make_small(ERST_INTERNAL_CHANNEL_NO));
+ erts_smp_rwmtx_init_opt_x(&erts_this_dist_entry->rwmtx,
+ &rwmtx_opt,
+ "dist_entry",
+ make_small(ERST_INTERNAL_CHANNEL_NO));
erts_this_dist_entry->sysname = am_Noname;
erts_this_dist_entry->cid = NIL;
erts_this_dist_entry->connection_id = 0;
@@ -772,8 +791,8 @@ void erts_init_node_tables(void)
(void) hash_put(&erts_node_table, (void *) erts_this_node);
- erts_smp_rwmtx_init(&erts_node_table_rwmtx, "node_table");
- erts_smp_rwmtx_init(&erts_dist_table_rwmtx, "dist_table");
+ erts_smp_rwmtx_init_opt(&erts_node_table_rwmtx, &rwmtx_opt, "node_table");
+ erts_smp_rwmtx_init_opt(&erts_dist_table_rwmtx, &rwmtx_opt, "dist_table");
references_atoms_need_init = 1;
}
@@ -1087,30 +1106,24 @@ insert_offheap2(ErlOffHeap *oh, void *arg)
static void
insert_offheap(ErlOffHeap *oh, int type, Eterm id)
{
- if(oh->externals) {
- ExternalThing *etp = oh->externals;
- while (etp) {
- insert_node(etp->node, type, id);
- etp = etp->next;
- }
- }
+ union erl_off_heap_ptr u;
+ struct insert_offheap2_arg a;
+ a.type = BIN_REF;
- if(oh->mso) {
- ProcBin *pb;
- struct insert_offheap2_arg a;
- a.type = BIN_REF;
- for(pb = oh->mso; pb; pb = pb->next) {
- if(IsMatchProgBinary(pb->val)) {
+ for (u.hdr = oh->first; u.hdr; u.hdr = u.hdr->next) {
+ switch (thing_subtag(u.hdr->thing_word)) {
+ case REFC_BINARY_SUBTAG:
+ if(IsMatchProgBinary(u.pb->val)) {
InsertedBin *ib;
int insert_bin = 1;
for (ib = inserted_bins; ib; ib = ib->next)
- if(ib->bin_val == pb->val) {
+ if(ib->bin_val == u.pb->val) {
insert_bin = 0;
break;
}
if (insert_bin) {
#if HALFWORD_HEAP
- UWord val = (UWord) pb->val;
+ UWord val = (UWord) u.pb->val;
DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE*2); /* extra place allocated */
#else
DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE);
@@ -1124,13 +1137,13 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id)
a.id = erts_bld_uword(&hp, NULL, (UWord) val);
#else
UseTmpHeapNoproc(BIG_UINT_HEAP_SIZE);
- a.id = erts_bld_uint(&hp, NULL, (Uint) pb->val);
+ a.id = erts_bld_uint(&hp, NULL, (Uint) u.pb->val);
#endif
- erts_match_prog_foreach_offheap(pb->val,
+ erts_match_prog_foreach_offheap(u.pb->val,
insert_offheap2,
(void *) &a);
nib = erts_alloc(ERTS_ALC_T_NC_TMP, sizeof(InsertedBin));
- nib->bin_val = pb->val;
+ nib->bin_val = u.pb->val;
nib->next = inserted_bins;
inserted_bins = nib;
#if HALFWORD_HEAP
@@ -1139,15 +1152,16 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id)
UnUseTmpHeapNoproc(BIG_UINT_HEAP_SIZE);
#endif
}
- }
+ }
+ break;
+ case FUN_SUBTAG:
+ break; /* No need to */
+ default:
+ ASSERT(is_external_header(u.hdr->thing_word));
+ insert_node(u.ext->node, type, id);
+ break;
}
}
-
-#if 0
- if(oh->funs) {
- /* No need to */
- }
-#endif
}
static void doit_insert_monitor(ErtsMonitor *monitor, void *p)
@@ -1289,6 +1303,7 @@ setup_reference_table(void)
for (i = 0; i < erts_max_processes; i++)
if (process_tab[i]) {
ErlMessage *msg;
+
/* Insert Heap */
insert_offheap(&(process_tab[i]->off_heap),
HEAP_REF,
@@ -1375,21 +1390,22 @@ setup_reference_table(void)
{ /* Add binaries stored elsewhere ... */
ErlOffHeap oh;
- ProcBin pb[2] = {{0},{0}};
- ProcBin *mso = NULL;
+ ProcBin pb[2];
int i = 0;
Binary *default_match_spec;
Binary *default_meta_match_spec;
- /* Only the ProcBin members val and next will be inspected
+ oh.first = NULL;
+ /* Only the ProcBin members thing_word, val and next will be inspected
(by insert_offheap()) */
#undef ADD_BINARY
-#define ADD_BINARY(Bin) \
- if ((Bin)) { \
- pb[i].val = (Bin); \
- pb[i].next = mso; \
- mso = &pb[i]; \
- i++; \
+#define ADD_BINARY(Bin) \
+ if ((Bin)) { \
+ pb[i].thing_word = REFC_BINARY_SUBTAG; \
+ pb[i].val = (Bin); \
+ pb[i].next = oh.first; \
+ oh.first = (struct erl_off_heap_header*) &pb[i]; \
+ i++; \
}
erts_get_default_trace_pattern(NULL,
@@ -1401,11 +1417,6 @@ setup_reference_table(void)
ADD_BINARY(default_match_spec);
ADD_BINARY(default_meta_match_spec);
- oh.mso = mso;
- oh.externals = NULL;
-#ifndef HYBRID /* FIND ME! */
- oh.funs = NULL;
-#endif
insert_offheap(&oh, BIN_REF, AM_match_spec);
#undef ADD_BINARY
}
diff --git a/erts/emulator/beam/erl_obsolete.c b/erts/emulator/beam/erl_obsolete.c
deleted file mode 100644
index 9c5a7c7ff9..0000000000
--- a/erts/emulator/beam/erl_obsolete.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sys.h"
-#include "erl_driver.h"
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * *
- * ------------------------- OBSOLETE! DO NOT USE! ------------------------- *
- * *
-\* */
-
-/* cut from ../obsolete/driver.h (since it doesn't mix well with other
- * headers from the emulator).
- */
-#ifdef __WIN32__
-#ifdef CONST
-# undef CONST
-#endif
-#endif
-
-#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE)
-# define _USING_PROTOTYPES_ 1
-# define _ANSI_ARGS_(x) x
-# define CONST const
-#else
-# define _ANSI_ARGS_(x) ()
-# define CONST
-#endif
-
-typedef void* erl_mutex_t;
-typedef void* erl_cond_t;
-typedef void* erl_thread_t;
-
-EXTERN erl_mutex_t erts_mutex_create _ANSI_ARGS_((void));
-EXTERN int erts_mutex_destroy _ANSI_ARGS_((erl_mutex_t));
-EXTERN int erts_mutex_lock _ANSI_ARGS_((erl_mutex_t));
-EXTERN int erts_mutex_unlock _ANSI_ARGS_((erl_mutex_t));
-
-EXTERN erl_cond_t erts_cond_create _ANSI_ARGS_((void));
-EXTERN int erts_cond_destroy _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_signal _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_broadcast _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_wait _ANSI_ARGS_((erl_cond_t, erl_mutex_t));
-EXTERN int erts_cond_timedwait _ANSI_ARGS_((erl_cond_t, erl_mutex_t, long));
-
-EXTERN int erts_thread_create _ANSI_ARGS_((erl_thread_t*,
- void* (*func)(void*),
- void* arg,
- int detached));
-EXTERN erl_thread_t erts_thread_self _ANSI_ARGS_((void));
-EXTERN void erts_thread_exit _ANSI_ARGS_((void*));
-EXTERN int erts_thread_join _ANSI_ARGS_((erl_thread_t, void**));
-EXTERN int erts_thread_kill _ANSI_ARGS_((erl_thread_t));
-
-/*
- * These functions implement the thread interface in ../obsolete/driver.h.
- * Do *not* use this interface! Within the emulator, use the erl_threads.h,
- * erl_smp.h, or ethread.h interface. From a driver use the thread interface
- * in erl_driver.h.
- */
-
-erl_mutex_t
-erts_mutex_create(void)
-{
- return (erl_mutex_t) erl_drv_mutex_create(NULL);
-}
-
-int
-erts_mutex_destroy(erl_mutex_t mtx)
-{
- erl_drv_mutex_destroy((ErlDrvMutex *) mtx);
- return 0;
-}
-
-int
-erts_mutex_lock(erl_mutex_t mtx)
-{
- erl_drv_mutex_lock((ErlDrvMutex *) mtx);
- return 0;
-}
-
-int
-erts_mutex_unlock(erl_mutex_t mtx)
-{
- erl_drv_mutex_unlock((ErlDrvMutex *) mtx);
- return 0;
-}
-
-erl_cond_t
-erts_cond_create(void)
-{
- return (erl_cond_t) erl_drv_cond_create(NULL);
-}
-
-int
-erts_cond_destroy(erl_cond_t cnd)
-{
- erl_drv_cond_destroy((ErlDrvCond *) cnd);
- return 0;
-}
-
-
-int
-erts_cond_signal(erl_cond_t cnd)
-{
- erl_drv_cond_signal((ErlDrvCond *) cnd);
- return 0;
-}
-
-int
-erts_cond_broadcast(erl_cond_t cnd)
-{
- erl_drv_cond_broadcast((ErlDrvCond *) cnd);
- return 0;
-}
-
-
-int
-erts_cond_wait(erl_cond_t cnd, erl_mutex_t mtx)
-{
- erl_drv_cond_wait((ErlDrvCond *) cnd, (ErlDrvMutex *) mtx);
- return 0;
-}
-
-int
-erts_cond_timedwait(erl_cond_t cnd, erl_mutex_t mtx, long ms)
-{
- return ENOTSUP;
-}
-
-int
-erts_thread_create(erl_thread_t *tid,
- void* (*func)(void*),
- void* arg,
- int detached)
-{
- if (detached)
- return ENOTSUP;
- return erl_drv_thread_create(NULL, (ErlDrvTid *) tid, func, arg, NULL);
-}
-
-erl_thread_t
-erts_thread_self(void)
-{
- return (erl_thread_t) erl_drv_thread_self();
-}
-
-void
-erts_thread_exit(void *res)
-{
- erl_drv_thread_exit(res);
-}
-
-int
-erts_thread_join(erl_thread_t tid, void **respp)
-{
- return erl_drv_thread_join((ErlDrvTid) tid, respp);
-}
-
-int
-erts_thread_kill(erl_thread_t tid)
-{
- return ENOTSUP;
-}
-
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 967a14f0d1..c10724b951 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -625,6 +625,7 @@ erts_port_task_schedule(Eterm id,
if (!enq_port) {
ERTS_PT_CHK_PRES_PORTQ(runq, pp);
+ erts_smp_runq_unlock(runq);
}
else {
enqueue_port(runq, pp);
@@ -634,9 +635,10 @@ erts_port_task_schedule(Eterm id,
profile_runnable_port(pp, am_active);
}
+ erts_smp_runq_unlock(runq);
+
erts_smp_notify_inc_runq(runq);
}
- erts_smp_runq_unlock(runq);
return 0;
}
@@ -944,8 +946,8 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
enqueue_port(xrunq, pp);
ASSERT(pp->sched.exe_taskq);
pp->sched.exe_taskq = NULL;
- erts_smp_notify_inc_runq(xrunq);
erts_smp_runq_unlock(xrunq);
+ erts_smp_notify_inc_runq(xrunq);
}
#endif
port_was_enqueued = 1;
@@ -1112,7 +1114,6 @@ erts_port_migrate(Port *prt, int *prt_locked,
dequeue_port(from_rq, prt);
erts_smp_atomic_set(&prt->run_queue, (long) to_rq);
enqueue_port(to_rq, prt);
- erts_smp_notify_inc_runq(to_rq);
return ERTS_MIGRATE_SUCCESS;
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 41031f5468..0e78727316 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -46,7 +46,13 @@
#define ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST (CONTEXT_REDS/10)
-#define ERTS_SCHED_SLEEP_SPINCOUNT 10000
+#define ERTS_SCHED_SPIN_UNTIL_YIELD 100
+
+#define ERTS_SCHED_SYS_SLEEP_SPINCOUNT 10
+#define ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT 1000
+#define ERTS_SCHED_TSE_SLEEP_SPINCOUNT \
+ (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT)
+#define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0
#define ERTS_WAKEUP_OTHER_LIMIT (100*CONTEXT_REDS/2)
#define ERTS_WAKEUP_OTHER_DEC 10
@@ -106,6 +112,10 @@ Uint erts_no_schedulers;
Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES;
Uint erts_process_tab_index_mask;
+#ifdef ERTS_SMP
+Uint erts_max_main_threads;
+#endif
+
int erts_sched_thread_suggested_stack_size = -1;
#ifdef ERTS_ENABLE_LOCK_CHECK
@@ -116,16 +126,34 @@ ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE];
int erts_disable_proc_not_running_opt;
-#define ERTS_SCHED_CHANGING_ONLINE 1
-#define ERTS_SCHED_CHANGING_MULTI_SCHED 2
+#define ERTS_SCHDLR_SSPND_CHNG_WAITER (((long) 1) << 0)
+#define ERTS_SCHDLR_SSPND_CHNG_MSB (((long) 1) << 1)
+#define ERTS_SCHDLR_SSPND_CHNG_ONLN (((long) 1) << 2)
+
+#ifndef DEBUG
+
+#define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
+ erts_smp_atomic_set(&schdlr_sspnd.changing, (VAL))
+
+#else
+
+#define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
+do { \
+ long old_val__ = erts_smp_atomic_xchg(&schdlr_sspnd.changing, \
+ (VAL)); \
+ ASSERT(old_val__ == (OLD_VAL)); \
+} while (0)
+
+#endif
+
static struct {
erts_smp_mtx_t mtx;
erts_smp_cnd_t cnd;
- int changing;
int online;
int curr_online;
int wait_curr_online;
+ erts_smp_atomic_t changing;
erts_smp_atomic_t active;
struct {
erts_smp_atomic_t ongoing;
@@ -231,6 +259,17 @@ typedef union {
ErtsAlignedSchedulerData *erts_aligned_scheduler_data;
+#ifdef ERTS_SMP
+
+typedef union {
+ ErtsSchedulerSleepInfo ssi;
+ char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerSleepInfo))];
+} ErtsAlignedSchedulerSleepInfo;
+
+static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info;
+
+#endif
+
#ifndef BM_COUNTERS
static int processes_busy;
#endif
@@ -288,8 +327,15 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(proclist,
200,
ERTS_ALC_T_PROC_LIST)
-#define ERTS_RUNQ_IX(IX) (&erts_aligned_run_queues[(IX)].runq)
-#define ERTS_SCHEDULER_IX(IX) (&erts_aligned_scheduler_data[(IX)].esd)
+#define ERTS_RUNQ_IX(IX) \
+ (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_run_queues), \
+ &erts_aligned_run_queues[(IX)].runq)
+#define ERTS_SCHEDULER_IX(IX) \
+ (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_schedulers), \
+ &erts_aligned_scheduler_data[(IX)].esd)
+#define ERTS_SCHED_SLEEP_INFO_IX(IX) \
+ (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_schedulers), \
+ &aligned_sched_sleep_info[(IX)].ssi)
#define ERTS_FOREACH_RUNQ(RQVAR, DO) \
do { \
@@ -353,6 +399,11 @@ static void signal_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size
#endif
+static int reader_group_lookup(int logical);
+static void create_tmp_cpu_topology_copy(erts_cpu_topology_t **cpudata,
+ int *cpudata_size);
+static void destroy_tmp_cpu_topology_copy(erts_cpu_topology_t *cpudata);
+
static void early_cpu_bind_init(void);
static void late_cpu_bind_init(void);
@@ -582,6 +633,76 @@ erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data)
#ifdef ERTS_SMP
+void
+erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, long flags)
+{
+ switch (flags & ERTS_SSI_FLGS_SLEEP_TYPE) {
+ case ERTS_SSI_FLG_POLL_SLEEPING:
+ erts_sys_schedule_interrupt(1);
+ break;
+ case ERTS_SSI_FLG_TSE_SLEEPING:
+ erts_tse_set(ssi->event);
+ break;
+ case 0:
+ break;
+ default:
+ erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n",
+ __FILE__, __LINE__);
+ break;
+ }
+}
+
+#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
+void
+erts_smp_notify_check_children_needed(void)
+{
+ int i;
+
+ for (i = 0; i < erts_no_schedulers; i++) {
+ long aux_work;
+ ErtsSchedulerSleepInfo *ssi;
+ ssi = ERTS_SCHED_SLEEP_INFO_IX(i);
+ aux_work = erts_smp_atomic_bor(&ssi->aux_work,
+ ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
+ if (!(aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN))
+ erts_sched_poke(ssi);
+ }
+}
+#endif
+
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+static ERTS_INLINE long
+blockable_aux_work(ErtsSchedulerData *esdp,
+ ErtsSchedulerSleepInfo *ssi,
+ long aux_work)
+{
+ if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
+#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
+ if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) {
+ aux_work = erts_smp_atomic_band(&ssi->aux_work,
+ ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
+ aux_work &= ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN;
+ erts_check_children();
+ }
+#endif
+ }
+ return aux_work;
+}
+
+#endif
+
+#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
+static ERTS_INLINE long
+nonblockable_aux_work(ErtsSchedulerData *esdp,
+ ErtsSchedulerSleepInfo *ssi,
+ long aux_work)
+{
+ if (aux_work & ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK) {
+
+ }
+}
+#endif
+
static void
prepare_for_block(void *vrq)
{
@@ -634,9 +755,33 @@ erts_active_schedulers(void)
return as;
}
+static ERTS_INLINE int
+prepare_for_sys_schedule(void)
+{
+#ifdef ERTS_SMP
+ while (!erts_port_task_have_outstanding_io_tasks()
+ && !erts_smp_atomic_xchg(&doing_sys_schedule, 1)) {
+ if (!erts_port_task_have_outstanding_io_tasks())
+ return 1;
+ erts_smp_atomic_set(&doing_sys_schedule, 0);
+ }
+ return 0;
+#else
+ return !erts_port_task_have_outstanding_io_tasks();
+#endif
+}
+
#ifdef ERTS_SMP
static ERTS_INLINE void
+sched_change_waiting_sys_to_waiting(Uint no, ErtsRunQueue *rq)
+{
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
+ ASSERT(rq->waiting < 0);
+ rq->waiting *= -1;
+}
+
+static ERTS_INLINE void
sched_waiting(Uint no, ErtsRunQueue *rq)
{
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
@@ -676,7 +821,11 @@ empty_runq(ErtsRunQueue *rq)
if (oifls & ERTS_RUNQ_IFLG_NONEMPTY) {
#ifdef DEBUG
long empty = erts_smp_atomic_read(&no_empty_run_queues);
- ASSERT(0 <= empty && empty < erts_no_run_queues);
+ /*
+ * For a short period of time no_empty_run_queues may have
+ * been increased twice for a specific run queue.
+ */
+ ASSERT(0 <= empty && empty < 2*erts_no_run_queues);
#endif
erts_smp_atomic_inc(&no_empty_run_queues);
}
@@ -689,107 +838,314 @@ non_empty_runq(ErtsRunQueue *rq)
if (!(oifls & ERTS_RUNQ_IFLG_NONEMPTY)) {
#ifdef DEBUG
long empty = erts_smp_atomic_read(&no_empty_run_queues);
- ASSERT(0 < empty && empty <= erts_no_run_queues);
+ /*
+ * For a short period of time no_empty_run_queues may have
+ * been increased twice for a specific run queue.
+ */
+ ASSERT(0 < empty && empty <= 2*erts_no_run_queues);
#endif
erts_smp_atomic_dec(&no_empty_run_queues);
}
}
-static ERTS_INLINE int
-sched_spin_wake(ErtsRunQueue *rq)
+static long
+sched_prep_spin_wait(ErtsSchedulerSleepInfo *ssi)
{
-#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
- return 0;
-#else
- long val;
- ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
+ long oflgs;
+ long nflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING);
+ long xflgs = 0;
- val = erts_smp_atomic_read(&rq->spin_waiter);
- ASSERT(val >= 0);
- if (val != 0) {
- erts_smp_atomic_inc(&rq->spin_wake);
- return 1;
- }
- return 0;
-#endif
+ do {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return nflgs;
+ xflgs = oflgs;
+ } while (!(oflgs & ERTS_SSI_FLG_SUSPENDED));
+ return oflgs;
}
-static ERTS_INLINE int
-sched_spin_wake_all(ErtsRunQueue *rq)
+static long
+sched_prep_cont_spin_wait(ErtsSchedulerSleepInfo *ssi)
{
-#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
- return 0;
-#else
- long val;
- ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
+ long oflgs;
+ long nflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING);
+ long xflgs = ERTS_SSI_FLG_WAITING;
- val = erts_smp_atomic_read(&rq->spin_waiter);
- ASSERT(val >= 0);
- if (val != 0)
- erts_smp_atomic_add(&rq->spin_wake, val);
- return val;
-#endif
+ do {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return nflgs;
+ xflgs = oflgs;
+ nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
+ } while (oflgs & ERTS_SSI_FLG_WAITING);
+ return oflgs;
+}
+
+static long
+sched_spin_wait(ErtsSchedulerSleepInfo *ssi, int spincount)
+{
+ long until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
+ int sc = spincount;
+ long flgs;
+
+ do {
+ flgs = erts_smp_atomic_read(&ssi->flags);
+ if ((flgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
+ != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
+ break;
+ }
+ ERTS_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
+ erts_thr_yield();
+ }
+ } while (--sc > 0);
+ return flgs;
+}
+
+static long
+sched_set_sleeptype(ErtsSchedulerSleepInfo *ssi, long sleep_type)
+{
+ long oflgs;
+ long nflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING|sleep_type;
+ long xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
+
+ if (sleep_type == ERTS_SSI_FLG_TSE_SLEEPING)
+ erts_tse_reset(ssi->event);
+
+ while (1) {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return nflgs;
+ if ((oflgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
+ != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
+ return oflgs;
+ }
+ xflgs = oflgs;
+ nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
+ }
}
+#define ERTS_SCHED_WAIT_WOKEN(FLGS) \
+ (((FLGS) & (ERTS_SSI_FLG_WAITING|ERTS_SSI_FLG_SUSPENDED)) \
+ != ERTS_SSI_FLG_WAITING)
+
static void
-sched_sys_wait(Uint no, ErtsRunQueue *rq)
+scheduler_wait(long *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
{
- long dt;
-#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
- int val;
- int spincount = ERTS_SCHED_SLEEP_SPINCOUNT;
+ ErtsSchedulerSleepInfo *ssi = esdp->ssi;
+ int spincount;
+ long flgs;
+#if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
+ || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
+ long aux_work;
+#endif
+
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
+ erts_smp_spin_lock(&rq->sleepers.lock);
+ flgs = sched_prep_spin_wait(ssi);
+ if (flgs & ERTS_SSI_FLG_SUSPENDED) {
+ /* Go suspend instead... */
+ erts_smp_spin_unlock(&rq->sleepers.lock);
+ return;
+ }
+
+ ssi->prev = NULL;
+ ssi->next = rq->sleepers.list;
+ if (rq->sleepers.list)
+ rq->sleepers.list->prev = ssi;
+ rq->sleepers.list = ssi;
+ erts_smp_spin_unlock(&rq->sleepers.lock);
+
+ /*
+ * If all schedulers are waiting, one of them *should*
+ * be waiting in erl_sys_schedule()
+ */
+
+ if (!prepare_for_sys_schedule()) {
+
+ sched_waiting(esdp->no, rq);
+
+ erts_smp_runq_unlock(rq);
+
+ spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
+
+ tse_wait:
+
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ tse_blockable_aux_work:
+ aux_work = blockable_aux_work(esdp, ssi, aux_work);
#endif
+ erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
+
+ while (1) {
- sched_waiting_sys(no, rq);
+#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
+#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+#endif
+ nonblockable_aux_work(esdp, ssi, aux_work);
+#endif
-#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
- erts_smp_atomic_inc(&rq->spin_waiter);
- erts_smp_runq_unlock(rq);
+ flgs = sched_spin_wait(ssi, spincount);
+ if (flgs & ERTS_SSI_FLG_SLEEPING) {
+ ASSERT(flgs & ERTS_SSI_FLG_WAITING);
+ flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_TSE_SLEEPING);
+ if (flgs & ERTS_SSI_FLG_SLEEPING) {
+ int res;
+ ASSERT(flgs & ERTS_SSI_FLG_TSE_SLEEPING);
+ ASSERT(flgs & ERTS_SSI_FLG_WAITING);
+ do {
+ res = erts_tse_wait(ssi->event);
+ } while (res == EINTR);
+ }
+ }
- erl_sys_schedule(1); /* Might give us something to do */
+ if (!(flgs & ERTS_SSI_FLG_WAITING)) {
+ ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
+ break;
+ }
- dt = do_time_read_and_reset();
- if (dt) bump_timer(dt);
+ flgs = sched_prep_cont_spin_wait(ssi);
+ spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
+
+ if (!(flgs & ERTS_SSI_FLG_WAITING)) {
+ ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
+ break;
+ }
+
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
+ erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
+ goto tse_blockable_aux_work;
+ }
+#endif
- while (spincount-- > 0) {
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val != 0) {
- erts_smp_runq_lock(rq);
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val != 0)
- goto woken;
- if (spincount == 0)
- goto sleep;
- erts_smp_runq_unlock(rq);
}
- }
- erts_smp_runq_lock(rq);
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val != 0) {
- woken:
- erts_smp_atomic_dec(&rq->spin_wake);
- ASSERT(erts_smp_atomic_read(&rq->spin_wake) >= 0);
- erts_smp_atomic_dec(&rq->spin_waiter);
- ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
+ erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
+
+ if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
+ erts_smp_atomic_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
+
+ erts_smp_runq_lock(rq);
+ sched_active(esdp->no, rq);
+
}
else {
- sleep:
- erts_smp_atomic_dec(&rq->spin_waiter);
- ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
+ long dt;
+
+ erts_smp_atomic_set(&function_calls, 0);
+ *fcalls = 0;
+
+ sched_waiting_sys(esdp->no, rq);
+
+ erts_smp_runq_unlock(rq);
+
+ spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT;
+
+ while (spincount-- > 0) {
+
+ sys_poll_aux_work:
+
+ erl_sys_schedule(1); /* Might give us something to do */
+
+ dt = do_time_read_and_reset();
+ if (dt) bump_timer(dt);
+
+ sys_aux_work:
+
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ aux_work = blockable_aux_work(esdp, ssi, aux_work);
+#endif
+#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
+#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+#endif
+ nonblockable_aux_work(esdp, ssi, aux_work);
+#endif
+
+ flgs = erts_smp_atomic_read(&ssi->flags);
+ if (!(flgs & ERTS_SSI_FLG_WAITING)) {
+ ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
+ goto sys_woken;
+ }
+ if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
+ flgs = sched_prep_cont_spin_wait(ssi);
+ if (!(flgs & ERTS_SSI_FLG_WAITING)) {
+ ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
+ goto sys_woken;
+ }
+ }
+
+ /*
+ * If we got new I/O tasks we aren't allowed to
+ * call erl_sys_schedule() until it is handled.
+ */
+ if (erts_port_task_have_outstanding_io_tasks()) {
+ erts_smp_atomic_set(&doing_sys_schedule, 0);
+ /*
+ * Got to check that we still got I/O tasks; otherwise
+ * we have to continue checking for I/O...
+ */
+ if (!prepare_for_sys_schedule()) {
+ spincount *= ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT;
+ goto tse_wait;
+ }
+ }
+ }
+
+ erts_smp_runq_lock(rq);
+
/*
* If we got new I/O tasks we aren't allowed to
* sleep in erl_sys_schedule().
*/
- if (!erts_port_task_have_outstanding_io_tasks()) {
-#endif
+ if (erts_port_task_have_outstanding_io_tasks()) {
+ erts_smp_atomic_set(&doing_sys_schedule, 0);
+ /*
+ * Got to check that we still got I/O tasks; otherwise
+ * we have to wait in erl_sys_schedule() after all...
+ */
+ if (prepare_for_sys_schedule())
+ goto do_sys_schedule;
+
+ /*
+ * Not allowed to wait in erl_sys_schedule;
+ * do tse wait instead...
+ */
+ sched_change_waiting_sys_to_waiting(esdp->no, rq);
+ erts_smp_runq_unlock(rq);
+ spincount = 0;
+ goto tse_wait;
+ }
+ else {
+ do_sys_schedule:
erts_sys_schedule_interrupt(0);
+ flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_POLL_SLEEPING);
+ if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
+ if (!(flgs & ERTS_SSI_FLG_WAITING))
+ goto sys_locked_woken;
+ erts_smp_runq_unlock(rq);
+ flgs = sched_prep_cont_spin_wait(ssi);
+ if (!(flgs & ERTS_SSI_FLG_WAITING)) {
+ ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
+ goto sys_woken;
+ }
+ ASSERT(!erts_port_task_have_outstanding_io_tasks());
+ goto sys_poll_aux_work;
+ }
+
+ ASSERT(flgs & ERTS_SSI_FLG_POLL_SLEEPING);
+ ASSERT(flgs & ERTS_SSI_FLG_WAITING);
+
erts_smp_runq_unlock(rq);
erl_sys_schedule(0);
@@ -797,134 +1153,103 @@ sched_sys_wait(Uint no, ErtsRunQueue *rq)
dt = do_time_read_and_reset();
if (dt) bump_timer(dt);
- erts_smp_runq_lock(rq);
+ flgs = sched_prep_cont_spin_wait(ssi);
+ if (flgs & ERTS_SSI_FLG_WAITING)
+ goto sys_aux_work;
-#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
+ sys_woken:
+ erts_smp_runq_lock(rq);
+ sys_locked_woken:
+ erts_smp_atomic_set(&doing_sys_schedule, 0);
+ if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
+ erts_smp_atomic_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
+ sched_active_sys(esdp->no, rq);
}
}
-#endif
-
- sched_active_sys(no, rq);
-}
-static void
-sched_cnd_wait(Uint no, ErtsRunQueue *rq)
-{
-#if ERTS_SCHED_SLEEP_SPINCOUNT != 0
- int val;
- int spincount = ERTS_SCHED_SLEEP_SPINCOUNT;
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
-#endif
-
- sched_waiting(no, rq);
- erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
- prepare_for_block,
- resume_after_block,
- (void *) rq);
-
-#if ERTS_SCHED_SLEEP_SPINCOUNT == 0
- erts_smp_cnd_wait(&rq->cnd, &rq->mtx);
-#else
- erts_smp_atomic_inc(&rq->spin_waiter);
- erts_smp_mtx_unlock(&rq->mtx);
-
- while (spincount-- > 0) {
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val != 0) {
- erts_smp_mtx_lock(&rq->mtx);
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val != 0)
- goto woken;
- if (spincount == 0)
- goto sleep;
- erts_smp_mtx_unlock(&rq->mtx);
- }
- }
-
- erts_smp_mtx_lock(&rq->mtx);
- val = erts_smp_atomic_read(&rq->spin_wake);
- ASSERT(val >= 0);
- if (val == 0) {
- sleep:
- erts_smp_atomic_dec(&rq->spin_waiter);
- ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
- erts_smp_cnd_wait(&rq->cnd, &rq->mtx);
- }
- else {
- woken:
- erts_smp_atomic_dec(&rq->spin_wake);
- ASSERT(erts_smp_atomic_read(&rq->spin_wake) >= 0);
- erts_smp_atomic_dec(&rq->spin_waiter);
- ASSERT(erts_smp_atomic_read(&rq->spin_waiter) >= 0);
- }
-#endif
-
- erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
- prepare_for_block,
- resume_after_block,
- (void *) rq);
-
- sched_active(no, rq);
}
-static void
-wake_one_scheduler(void)
-{
- ASSERT(erts_common_run_queue);
- ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(erts_common_run_queue));
- if (erts_common_run_queue->waiting) {
- if (!sched_spin_wake(erts_common_run_queue)) {
- if (erts_common_run_queue->waiting == -1) /* One scheduler waiting
- and doing so in
- sys_schedule */
- erts_sys_schedule_interrupt(1);
- else
- erts_smp_cnd_signal(&erts_common_run_queue->cnd);
- }
+static ERTS_INLINE long
+ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi)
+{
+ /* reset all flags but suspended */
+ long oflgs;
+ long nflgs = 0;
+ long xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
+ while (1) {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return oflgs;
+ nflgs = oflgs & ERTS_SSI_FLG_SUSPENDED;
+ xflgs = oflgs;
}
}
static void
-wake_scheduler(ErtsRunQueue *rq, int incq)
+wake_scheduler(ErtsRunQueue *rq, int incq, int one)
{
- ASSERT(!erts_common_run_queue);
- ASSERT(-1 <= rq->waiting && rq->waiting <= 1);
- ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
- if (rq->waiting && !rq->woken) {
- if (!sched_spin_wake(rq)) {
- if (rq->waiting < 0)
- erts_sys_schedule_interrupt(1);
- else
- erts_smp_cnd_signal(&rq->cnd);
+ int res;
+ ErtsSchedulerSleepInfo *ssi;
+ ErtsSchedulerSleepList *sl;
+
+ /*
+ * The unlocked run queue is not strictly necessary
+ * from a thread safety or deadlock prevention
+ * perspective. It will, however, cost us performance
+ * if it is locked during wakup of another scheduler,
+ * so all code *should* handle this without having
+ * the lock on the run queue.
+ */
+ ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq));
+
+ sl = &rq->sleepers;
+
+ erts_smp_spin_lock(&sl->lock);
+ ssi = sl->list;
+ if (!ssi)
+ erts_smp_spin_unlock(&sl->lock);
+ else if (one) {
+ long flgs;
+ if (ssi->prev)
+ ssi->prev->next = ssi->next;
+ else {
+ ASSERT(sl->list == ssi);
+ sl->list = ssi->next;
}
- rq->woken = 1;
- if (incq)
+ if (ssi->next)
+ ssi->next->prev = ssi->prev;
+
+ res = sl->list != NULL;
+ erts_smp_spin_unlock(&sl->lock);
+
+ flgs = ssi_flags_set_wake(ssi);
+ erts_sched_finish_poke(ssi, flgs);
+
+ if (incq && !erts_common_run_queue && (flgs & ERTS_SSI_FLG_WAITING))
non_empty_runq(rq);
}
+ else {
+ sl->list = NULL;
+ erts_smp_spin_unlock(&sl->lock);
+ do {
+ ErtsSchedulerSleepInfo *wake_ssi = ssi;
+ ssi = ssi->next;
+ erts_sched_finish_poke(ssi, ssi_flags_set_wake(wake_ssi));
+ } while (ssi);
+ }
}
static void
wake_all_schedulers(void)
{
- if (erts_common_run_queue) {
- erts_smp_runq_lock(erts_common_run_queue);
- if (erts_common_run_queue->waiting) {
- if (erts_common_run_queue->waiting < 0)
- erts_sys_schedule_interrupt(1);
- sched_spin_wake_all(erts_common_run_queue);
- erts_smp_cnd_broadcast(&erts_common_run_queue->cnd);
- }
- erts_smp_runq_unlock(erts_common_run_queue);
- }
+ if (erts_common_run_queue)
+ wake_scheduler(erts_common_run_queue, 0, 0);
else {
int ix;
for (ix = 0; ix < erts_no_run_queues; ix++) {
ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
- erts_smp_runq_lock(rq);
- wake_scheduler(rq, 0);
- erts_smp_runq_unlock(rq);
+ wake_scheduler(rq, 0, 1);
}
}
}
@@ -939,14 +1264,14 @@ chk_wake_sched(ErtsRunQueue *crq, int ix, int activate)
wrq = ERTS_RUNQ_IX(ix);
iflgs = erts_smp_atomic_read(&wrq->info_flags);
if (!(iflgs & (ERTS_RUNQ_IFLG_SUSPENDED|ERTS_RUNQ_IFLG_NONEMPTY))) {
- erts_smp_xrunq_lock(crq, wrq);
if (activate) {
if (ix == erts_smp_atomic_cmpxchg(&balance_info.active_runqs, ix+1, ix)) {
+ erts_smp_xrunq_lock(crq, wrq);
wrq->flags &= ~ERTS_RUNQ_FLG_INACTIVE;
+ erts_smp_xrunq_unlock(crq, wrq);
}
}
- wake_scheduler(wrq, 0);
- erts_smp_xrunq_unlock(crq, wrq);
+ wake_scheduler(wrq, 0, 1);
return 1;
}
return 0;
@@ -992,15 +1317,13 @@ static ERTS_INLINE void
smp_notify_inc_runq(ErtsRunQueue *runq)
{
#ifdef ERTS_SMP
- if (erts_common_run_queue)
- wake_one_scheduler();
- else
- wake_scheduler(runq, 1);
+ if (runq)
+ wake_scheduler(runq, 1, 1);
#endif
}
void
-erts_smp_notify_inc_runq__(ErtsRunQueue *runq)
+erts_smp_notify_inc_runq(ErtsRunQueue *runq)
{
smp_notify_inc_runq(runq);
}
@@ -1146,20 +1469,23 @@ static void
evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
{
Port *prt;
+ int notify_to_rq = 0;
int prio;
int prt_locked = 0;
int rq_locked = 0;
int evac_rq_locked = 1;
+ ErtsMigrateResult mres;
erts_smp_runq_lock(evac_rq);
+ erts_smp_atomic_bor(&evac_rq->scheduler->ssi->flags, ERTS_SSI_FLG_SUSPENDED);
+
evac_rq->flags &= ~ERTS_RUNQ_FLGS_IMMIGRATE_QMASK;
evac_rq->flags |= (ERTS_RUNQ_FLGS_EMIGRATE_QMASK
| ERTS_RUNQ_FLGS_EVACUATE_QMASK
| ERTS_RUNQ_FLG_SUSPENDED);
erts_smp_atomic_bor(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED);
-
/*
* Need to set up evacuation paths first since we
* may release the run queue lock on evac_rq
@@ -1187,9 +1513,11 @@ evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
/* Evacuate scheduled ports */
prt = evac_rq->ports.start;
while (prt) {
- (void) erts_port_migrate(prt, &prt_locked,
+ mres = erts_port_migrate(prt, &prt_locked,
evac_rq, &evac_rq_locked,
rq, &rq_locked);
+ if (mres == ERTS_MIGRATE_SUCCESS)
+ notify_to_rq = 1;
if (prt_locked)
erts_smp_port_unlock(prt);
if (!evac_rq_locked) {
@@ -1218,9 +1546,11 @@ evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
goto end_of_proc;
}
- (void) erts_proc_migrate(proc, &proc_locks,
+ mres = erts_proc_migrate(proc, &proc_locks,
evac_rq, &evac_rq_locked,
rq, &rq_locked);
+ if (mres == ERTS_MIGRATE_SUCCESS)
+ notify_to_rq = 1;
if (proc_locks)
erts_smp_proc_unlock(proc, proc_locks);
if (!evac_rq_locked) {
@@ -1252,10 +1582,13 @@ evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
if (rq_locked)
erts_smp_runq_unlock(rq);
- if (!evac_rq_locked)
- erts_smp_runq_lock(evac_rq);
- wake_scheduler(evac_rq, 0);
- erts_smp_runq_unlock(evac_rq);
+ if (evac_rq_locked)
+ erts_smp_runq_unlock(evac_rq);
+
+ if (notify_to_rq)
+ smp_notify_inc_runq(rq);
+
+ wake_scheduler(evac_rq, 0, 1);
}
static int
@@ -1483,31 +1816,6 @@ try_steal_task(ErtsRunQueue *rq)
return res;
}
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
-void
-erts_smp_notify_check_children_needed(void)
-{
- int i;
- for (i = 0; i < erts_no_schedulers; i++) {
- erts_smp_runq_lock(ERTS_SCHEDULER_IX(i)->run_queue);
- ERTS_SCHEDULER_IX(i)->check_children = 1;
- if (!erts_common_run_queue)
- wake_scheduler(ERTS_SCHEDULER_IX(i)->run_queue, 0);
- erts_smp_runq_unlock(ERTS_SCHEDULER_IX(i)->run_queue);
- }
- if (ongoing_multi_scheduling_block()) {
- /* Also blocked schedulers need to check children */
- erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- for (i = 0; i < erts_no_schedulers; i++)
- ERTS_SCHEDULER_IX(i)->blocked_check_children = 1;
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
- erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
- }
- if (erts_common_run_queue)
- wake_all_schedulers();
-}
-#endif
-
/* Run queue balancing */
typedef struct {
@@ -2100,6 +2408,8 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
erts_smp_atomic_init(&no_empty_run_queues, 0);
#endif
+ erts_no_run_queues = n;
+
for (ix = 0; ix < n; ix++) {
int pix, rix;
ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
@@ -2114,8 +2424,10 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
erts_smp_mtx_init_x(&rq->mtx, "run_queue", make_small(ix + 1));
erts_smp_cnd_init(&rq->cnd);
- erts_smp_atomic_init(&rq->spin_waiter, 0);
- erts_smp_atomic_init(&rq->spin_wake, 0);
+#ifdef ERTS_SMP
+ erts_smp_spinlock_init(&rq->sleepers.lock, "run_queue_sleep_list");
+ rq->sleepers.list = NULL;
+#endif
rq->waiting = 0;
rq->woken = 0;
@@ -2166,7 +2478,6 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
}
erts_common_run_queue = !mrq ? ERTS_RUNQ_IX(0) : NULL;
- erts_no_run_queues = n;
#ifdef ERTS_SMP
@@ -2181,9 +2492,34 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
#endif
+ n = (int) no_schedulers;
+ erts_no_schedulers = n;
+
+#ifdef ERTS_SMP
+ /* Create and initialize scheduler sleep info */
+
+ aligned_sched_sleep_info = erts_alloc(ERTS_ALC_T_SCHDLR_SLP_INFO,
+ (sizeof(ErtsAlignedSchedulerSleepInfo)
+ *(n+1)));
+ if ((((Uint) aligned_sched_sleep_info) & ERTS_CACHE_LINE_MASK) == 0)
+ aligned_sched_sleep_info = ((ErtsAlignedSchedulerSleepInfo *)
+ ((((Uint) aligned_sched_sleep_info)
+ & ~ERTS_CACHE_LINE_MASK)
+ + ERTS_CACHE_LINE_SIZE));
+ for (ix = 0; ix < n; ix++) {
+ ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
+#if 0 /* no need to initialize these... */
+ ssi->next = NULL;
+ ssi->prev = NULL;
+#endif
+ erts_smp_atomic_init(&ssi->flags, 0);
+ ssi->event = NULL; /* initialized in sched_thread_func */
+ erts_smp_atomic_init(&ssi->aux_work, 0);
+ }
+#endif
+
/* Create and initialize scheduler specific data */
- n = (int) no_schedulers;
erts_aligned_scheduler_data = erts_alloc(ERTS_ALC_T_SCHDLR_DATA,
(sizeof(ErtsAlignedSchedulerData)
*(n+1)));
@@ -2200,6 +2536,7 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
#ifdef ERTS_SMP
erts_bits_init_state(&esdp->erl_bits_state);
esdp->match_pseudo_process = NULL;
+ esdp->ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
esdp->free_process = NULL;
#if HALFWORD_HEAP
/* Registers need to be heap allocated (correct memory range) for tracing to work */
@@ -2228,11 +2565,6 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
}
#ifdef ERTS_SMP
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- esdp->check_children = 0;
- esdp->blocked_check_children = 0;
-#endif
- erts_smp_atomic_init(&esdp->suspended, 0);
erts_smp_atomic_init(&esdp->chk_cpu_bind, 0);
#endif
}
@@ -2241,7 +2573,7 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
erts_smp_mtx_init(&schdlr_sspnd.mtx, "schdlr_sspnd");
erts_smp_cnd_init(&schdlr_sspnd.cnd);
- schdlr_sspnd.changing = 0;
+ erts_smp_atomic_init(&schdlr_sspnd.changing, 0);
schdlr_sspnd.online = no_schedulers_online;
schdlr_sspnd.curr_online = no_schedulers;
erts_smp_atomic_init(&schdlr_sspnd.msb.ongoing, 0);
@@ -2264,7 +2596,8 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
if (no_schedulers_online < no_schedulers) {
if (erts_common_run_queue) {
for (ix = no_schedulers_online; ix < no_schedulers; ix++)
- erts_smp_atomic_set(&(ERTS_SCHEDULER_IX(ix)->suspended), 1);
+ erts_smp_atomic_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
+ ERTS_SSI_FLG_SUSPENDED);
}
else {
for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++)
@@ -2275,7 +2608,8 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
schdlr_sspnd.wait_curr_online = no_schedulers_online;
schdlr_sspnd.curr_online *= 2; /* Boot strapping... */
- schdlr_sspnd.changing = ERTS_SCHED_CHANGING_ONLINE;
+ ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
+ | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
erts_smp_atomic_init(&doing_sys_schedule, 0);
@@ -2423,13 +2757,115 @@ susp_sched_resume_block(void *unused)
}
static void
+scheduler_ix_resume_wake(Uint ix)
+{
+ ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
+ long xflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_TSE_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED);
+ long oflgs;
+ do {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, 0, xflgs);
+ if (oflgs == xflgs) {
+ erts_sched_finish_poke(ssi, oflgs);
+ break;
+ }
+ xflgs = oflgs;
+ } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
+}
+
+static long
+sched_prep_spin_suspended(ErtsSchedulerSleepInfo *ssi, long xpct)
+{
+ long oflgs;
+ long nflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED);
+ long xflgs = xpct;
+
+ do {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return nflgs;
+ xflgs = oflgs;
+ } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
+
+ return oflgs;
+}
+
+static long
+sched_spin_suspended(ErtsSchedulerSleepInfo *ssi, int spincount)
+{
+ int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
+ int sc = spincount;
+ long flgs;
+
+ do {
+ flgs = erts_smp_atomic_read(&ssi->flags);
+ if ((flgs & (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED))
+ != (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED)) {
+ break;
+ }
+ ERTS_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
+ erts_thr_yield();
+ }
+ } while (--sc > 0);
+ return flgs;
+}
+
+static long
+sched_set_suspended_sleeptype(ErtsSchedulerSleepInfo *ssi)
+{
+ long oflgs;
+ long nflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_TSE_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED);
+ long xflgs = (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED);
+
+ erts_tse_reset(ssi->event);
+
+ while (1) {
+ oflgs = erts_smp_atomic_cmpxchg(&ssi->flags, nflgs, xflgs);
+ if (oflgs == xflgs)
+ return nflgs;
+ if ((oflgs & (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED))
+ != (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED)) {
+ return oflgs;
+ }
+ xflgs = oflgs;
+ }
+}
+
+static void
suspend_scheduler(ErtsSchedulerData *esdp)
{
+ long flgs;
+ int changing;
long no = (long) esdp->no;
ErtsRunQueue *rq = esdp->run_queue;
+ ErtsSchedulerSleepInfo *ssi = esdp->ssi;
long active_schedulers;
int curr_online = 1;
int wake = 0;
+ int reset_read_group = 0;
+#if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
+ || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
+ long aux_work;
+#endif
/*
* Schedulers may be suspended in two different ways:
@@ -2451,113 +2887,151 @@ suspend_scheduler(ErtsSchedulerData *esdp)
if (scheduler2cpu_map[esdp->no].bound_id >= 0
&& erts_unbind_from_cpu(erts_cpuinfo) == 0) {
esdp->cpu_id = scheduler2cpu_map[esdp->no].bound_id = -1;
+ reset_read_group = 1;
}
erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
+ if (reset_read_group)
+ erts_smp_rwmtx_set_reader_group(0);
+
+ if (esdp->no <= erts_max_main_threads)
+ erts_thr_set_main_status(0, 0);
+
if (erts_system_profile_flags.scheduler)
profile_scheduler(make_small(esdp->no), am_inactive);
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- active_schedulers = erts_smp_atomic_dectest(&schdlr_sspnd.active);
- ASSERT(active_schedulers >= 1);
- if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_MULTI_SCHED) {
- if (active_schedulers == schdlr_sspnd.msb.wait_active)
- wake = 1;
- if (active_schedulers == 1)
- schdlr_sspnd.changing = 0;
- }
-
- while (1) {
+ flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED);
+ if (flgs & ERTS_SSI_FLG_SUSPENDED) {
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- int check_children;
- erts_smp_runq_lock(esdp->run_queue);
- check_children = esdp->check_children;
- esdp->check_children = 0;
- erts_smp_runq_unlock(esdp->run_queue);
- if (check_children) {
- erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
- erts_check_children();
- erts_smp_mtx_lock(&schdlr_sspnd.mtx);
+ active_schedulers = erts_smp_atomic_dectest(&schdlr_sspnd.active);
+ ASSERT(active_schedulers >= 1);
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if (changing & ERTS_SCHDLR_SSPND_CHNG_MSB) {
+ if (active_schedulers == schdlr_sspnd.msb.wait_active)
+ wake = 1;
+ if (active_schedulers == 1) {
+ changing = erts_smp_atomic_band(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_MSB);
+ changing &= ~ERTS_SCHDLR_SSPND_CHNG_MSB;
+ }
}
-#endif
- if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE) {
- int changed = 0;
- if (no > schdlr_sspnd.online && curr_online) {
- schdlr_sspnd.curr_online--;
- curr_online = 0;
- changed = 1;
+ while (1) {
+ if (changing & ERTS_SCHDLR_SSPND_CHNG_ONLN) {
+ int changed = 0;
+ if (no > schdlr_sspnd.online && curr_online) {
+ schdlr_sspnd.curr_online--;
+ curr_online = 0;
+ changed = 1;
+ }
+ else if (no <= schdlr_sspnd.online && !curr_online) {
+ schdlr_sspnd.curr_online++;
+ curr_online = 1;
+ changed = 1;
+ }
+ if (changed
+ && schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
+ wake = 1;
+ if (schdlr_sspnd.online == schdlr_sspnd.curr_online) {
+ changing = erts_smp_atomic_band(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
+ changing &= ~ERTS_SCHDLR_SSPND_CHNG_ONLN;
+ }
}
- else if (no <= schdlr_sspnd.online && !curr_online) {
- schdlr_sspnd.curr_online++;
- curr_online = 1;
- changed = 1;
+
+ if (wake) {
+ erts_smp_cnd_signal(&schdlr_sspnd.cnd);
+ wake = 0;
}
- if (changed
- && schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
- wake = 1;
- if (schdlr_sspnd.online == schdlr_sspnd.curr_online)
- schdlr_sspnd.changing = 0;
- }
- if (wake) {
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
- wake = 0;
- }
+ flgs = erts_smp_atomic_read(&ssi->flags);
+ if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
+ break;
+ erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
- if (!(rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ|ERTS_RUNQ_FLG_SUSPENDED)))
- break;
- if ((rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
- && !erts_smp_atomic_read(&esdp->suspended))
- break;
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ blockable_aux_work:
+ blockable_aux_work(esdp, ssi, aux_work);
+#endif
- erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
- susp_sched_prep_block,
- susp_sched_resume_block,
- NULL);
- while (1) {
+ erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
+ while (1) {
+ long flgs;
+#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
+#ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+#endif
+ nonblockable_aux_work(esdp, ssi, aux_work);
+#endif
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- if (esdp->blocked_check_children)
- break;
+ flgs = sched_spin_suspended(ssi, ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
+ if (flgs == (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED)) {
+ flgs = sched_set_suspended_sleeptype(ssi);
+ if (flgs == (ERTS_SSI_FLG_SLEEPING
+ | ERTS_SSI_FLG_TSE_SLEEPING
+ | ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED)) {
+ int res;
+ do {
+ res = erts_tse_wait(ssi->event);
+ } while (res == EINTR);
+ }
+ }
+
+ flgs = sched_prep_spin_suspended(ssi, (ERTS_SSI_FLG_WAITING
+ | ERTS_SSI_FLG_SUSPENDED));
+ if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
+ break;
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER)
+ break;
+
+
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
+ erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
+ goto blockable_aux_work;
+ }
#endif
- erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
+ }
- if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE)
- break;
+ erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
- if (!(rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
- | ERTS_RUNQ_FLG_SUSPENDED)))
- break;
- if ((rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
- && !erts_smp_atomic_read(&esdp->suspended))
- break;
+ erts_smp_mtx_lock(&schdlr_sspnd.mtx);
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
}
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- esdp->blocked_check_children = 0;
-#endif
+ active_schedulers = erts_smp_atomic_inctest(&schdlr_sspnd.active);
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if ((changing & ERTS_SCHDLR_SSPND_CHNG_MSB)
+ && schdlr_sspnd.online == active_schedulers) {
+ erts_smp_atomic_band(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_MSB);
+ }
- erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
- susp_sched_prep_block,
- susp_sched_resume_block,
- NULL);
- }
+ ASSERT(no <= schdlr_sspnd.online);
+ ASSERT(!erts_smp_atomic_read(&schdlr_sspnd.msb.ongoing));
- active_schedulers = erts_smp_atomic_inctest(&schdlr_sspnd.active);
- if (schdlr_sspnd.changing == ERTS_SCHED_CHANGING_MULTI_SCHED
- && schdlr_sspnd.online == active_schedulers) {
- schdlr_sspnd.changing = 0;
}
+
erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
+ ASSERT(curr_online);
+
if (erts_system_profile_flags.scheduler)
profile_scheduler(make_small(esdp->no), am_active);
+ if (esdp->no <= erts_max_main_threads)
+ erts_thr_set_main_status(1, (int) esdp->no);
+
erts_smp_runq_lock(esdp->run_queue);
non_empty_runq(esdp->run_queue);
@@ -2622,8 +3096,10 @@ erts_schedulers_state(Uint *total,
int yield_allowed)
{
int res;
+ long changing;
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- if (yield_allowed && schdlr_sspnd.changing)
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if (yield_allowed && (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER))
res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
else {
*active = *online = schdlr_sspnd.online;
@@ -2643,6 +3119,7 @@ erts_set_schedulers_online(Process *p,
Sint *old_no)
{
int ix, res, no, have_unlocked_plocks;
+ long changing;
if (new_no < 1 || erts_no_schedulers < new_no)
return ERTS_SCHDLR_SSPND_EINVAL;
@@ -2652,7 +3129,8 @@ erts_set_schedulers_online(Process *p,
have_unlocked_plocks = 0;
no = (int) new_no;
- if (schdlr_sspnd.changing) {
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if (changing) {
res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
}
else {
@@ -2661,17 +3139,19 @@ erts_set_schedulers_online(Process *p,
res = ERTS_SCHDLR_SSPND_DONE;
}
else {
- schdlr_sspnd.changing = ERTS_SCHED_CHANGING_ONLINE;
+ ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
+ | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
schdlr_sspnd.online = no;
if (no > online) {
int ix;
schdlr_sspnd.wait_curr_online = no;
- if (ongoing_multi_scheduling_block())
- /* No schedulers to resume */;
+ if (ongoing_multi_scheduling_block()) {
+ for (ix = online; ix < no; ix++)
+ erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
+ }
else if (erts_common_run_queue) {
for (ix = online; ix < no; ix++)
- erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended,
- 0);
+ scheduler_ix_resume_wake(ix);
}
else {
if (plocks) {
@@ -2685,6 +3165,7 @@ erts_set_schedulers_online(Process *p,
erts_smp_runq_lock(rq);
ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x5);
erts_smp_runq_unlock(rq);
+ scheduler_ix_resume_wake(ix);
}
/*
* Spread evacuation paths among all online
@@ -2699,7 +3180,6 @@ erts_set_schedulers_online(Process *p,
erts_smp_mtx_unlock(&balance_info.update_mtx);
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
}
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
res = ERTS_SCHDLR_SSPND_DONE;
}
else /* if (no < online) */ {
@@ -2716,12 +3196,17 @@ erts_set_schedulers_online(Process *p,
schdlr_sspnd.wait_curr_online = no+1;
}
- if (ongoing_multi_scheduling_block())
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
- else if (erts_common_run_queue) {
+ if (ongoing_multi_scheduling_block()) {
for (ix = no; ix < online; ix++)
- erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended,
- 1);
+ erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
+ }
+ else if (erts_common_run_queue) {
+ for (ix = no; ix < online; ix++) {
+ ErtsSchedulerSleepInfo *ssi;
+ ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
+ erts_smp_atomic_bor(&ssi->flags,
+ ERTS_SSI_FLG_SUSPENDED);
+ }
wake_all_schedulers();
}
else {
@@ -2748,7 +3233,10 @@ erts_set_schedulers_online(Process *p,
erts_smp_atomic_set(&balance_info.used_runqs, no);
erts_smp_mtx_unlock(&balance_info.update_mtx);
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- ERTS_FOREACH_OP_RUNQ(rq, wake_scheduler(rq, 0));
+ for (ix = no; ix < online; ix++) {
+ ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
+ wake_scheduler(rq, 0, 1);
+ }
}
}
@@ -2762,6 +3250,12 @@ erts_set_schedulers_online(Process *p,
susp_sched_prep_block,
susp_sched_resume_block,
NULL);
+ ASSERT(res != ERTS_SCHDLR_SSPND_DONE
+ ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
+ & erts_smp_atomic_read(&schdlr_sspnd.changing))
+ : (ERTS_SCHDLR_SSPND_CHNG_WAITER
+ == erts_smp_atomic_read(&schdlr_sspnd.changing)));
+ erts_smp_atomic_band(&schdlr_sspnd.changing, ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
}
}
@@ -2776,11 +3270,12 @@ ErtsSchedSuspendResult
erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
{
int ix, res, have_unlocked_plocks = 0;
+ long changing;
ErtsProcList *plp;
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
-
- if (schdlr_sspnd.changing) {
+ changing = erts_smp_atomic_read(&schdlr_sspnd.changing);
+ if (changing) {
res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */
}
else if (on) { /* ------ BLOCK ------ */
@@ -2794,19 +3289,22 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
}
else {
+ int online = schdlr_sspnd.online;
p->flags |= F_HAVE_BLCKD_MSCHED;
if (plocks) {
have_unlocked_plocks = 1;
erts_smp_proc_unlock(p, plocks);
}
+ ASSERT(0 == erts_smp_atomic_read(&schdlr_sspnd.msb.ongoing));
erts_smp_atomic_set(&schdlr_sspnd.msb.ongoing, 1);
- if (schdlr_sspnd.online == 1) {
+ if (online == 1) {
res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1);
ASSERT(p->scheduler_data->no == 1);
}
else {
- schdlr_sspnd.changing = ERTS_SCHED_CHANGING_MULTI_SCHED;
+ ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_MSB
+ | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
if (p->scheduler_data->no == 1) {
res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
schdlr_sspnd.msb.wait_active = 1;
@@ -2820,17 +3318,19 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
schdlr_sspnd.msb.wait_active = 2;
}
if (erts_common_run_queue) {
- for (ix = 1; ix < schdlr_sspnd.online; ix++)
- erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended, 1);
+ for (ix = 1; ix < online; ix++)
+ erts_smp_atomic_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
+ ERTS_SSI_FLG_SUSPENDED);
wake_all_schedulers();
}
else {
erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
erts_smp_mtx_lock(&balance_info.update_mtx);
erts_smp_atomic_set(&balance_info.used_runqs, 1);
- for (ix = 0; ix < schdlr_sspnd.online; ix++) {
+ for (ix = 0; ix < online; ix++) {
ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
erts_smp_runq_lock(rq);
+ ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED));
ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7);
erts_smp_runq_unlock(rq);
}
@@ -2855,6 +3355,13 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
susp_sched_prep_block,
susp_sched_resume_block,
NULL);
+ ASSERT(res != ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED
+ ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
+ & erts_smp_atomic_read(&schdlr_sspnd.changing))
+ : (ERTS_SCHDLR_SSPND_CHNG_WAITER
+ == erts_smp_atomic_read(&schdlr_sspnd.changing)));
+ erts_smp_atomic_band(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
}
plp = proclist_create(p);
plp->next = schdlr_sspnd.msb.procs;
@@ -2898,7 +3405,7 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
if (schdlr_sspnd.msb.procs)
res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
else {
- schdlr_sspnd.changing = ERTS_SCHED_CHANGING_MULTI_SCHED;
+ ERTS_SCHDLR_SSPND_CHNG_SET(ERTS_SCHDLR_SSPND_CHNG_MSB, 0);
#ifdef DEBUG
ERTS_FOREACH_RUNQ(rq,
{
@@ -2925,13 +3432,13 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
if (schdlr_sspnd.online == 1) {
/* No schedulers to resume */
ASSERT(erts_smp_atomic_read(&schdlr_sspnd.active) == 1);
- schdlr_sspnd.changing = 0;
+ ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_MSB);
}
else if (erts_common_run_queue) {
for (ix = 1; ix < schdlr_sspnd.online; ix++)
- erts_smp_atomic_set(&ERTS_SCHEDULER_IX(ix)->suspended, 0);
+ erts_smp_atomic_band(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
+ ~ERTS_SSI_FLG_SUSPENDED);
wake_all_schedulers();
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
}
else {
int online = schdlr_sspnd.online;
@@ -2948,6 +3455,7 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
erts_smp_runq_lock(rq);
ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x4);
erts_smp_runq_unlock(rq);
+ scheduler_ix_resume_wake(ix);
}
/* Spread evacuation paths among all online run queues */
@@ -2963,7 +3471,6 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
erts_smp_runq_unlock(ERTS_RUNQ_IX(0));
erts_smp_mtx_unlock(&balance_info.update_mtx);
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
}
res = ERTS_SCHDLR_SSPND_DONE;
}
@@ -3035,18 +3542,34 @@ erts_multi_scheduling_blockers(Process *p)
static void *
sched_thread_func(void *vesdp)
{
+#ifdef ERTS_SMP
+ Uint no = ((ErtsSchedulerData *) vesdp)->no;
+#endif
#ifdef ERTS_ENABLE_LOCK_CHECK
{
char buf[31];
- Uint no = ((ErtsSchedulerData *) vesdp)->no;
erts_snprintf(&buf[0], 31, "scheduler %bpu", no);
erts_lc_set_thread_name(&buf[0]);
}
#endif
- erts_alloc_reg_scheduler_id(((ErtsSchedulerData *) vesdp)->no);
+ erts_alloc_reg_scheduler_id(no);
erts_tsd_set(sched_data_key, vesdp);
#ifdef ERTS_SMP
+
+ if (no <= erts_max_main_threads) {
+ erts_thr_set_main_status(1, (int) no);
+ if (erts_reader_groups) {
+ int rg = (int) no;
+ if (rg > erts_reader_groups)
+ rg = (((int) no) - 1) % erts_reader_groups + 1;
+ erts_smp_rwmtx_set_reader_group(rg);
+ }
+ }
+
erts_proc_lock_prepare_proc_lock_waiter();
+ ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch();
+
+
#endif
erts_register_blockable_thread();
#ifdef HIPE
@@ -3055,30 +3578,30 @@ sched_thread_func(void *vesdp)
erts_thread_init_float();
erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- ASSERT(schdlr_sspnd.changing == ERTS_SCHED_CHANGING_ONLINE);
+ ASSERT(erts_smp_atomic_read(&schdlr_sspnd.changing)
+ & ERTS_SCHDLR_SSPND_CHNG_ONLN);
- schdlr_sspnd.curr_online--;
+ if (--schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online) {
+ erts_smp_atomic_band(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
+ if (((ErtsSchedulerData *) vesdp)->no != 1)
+ erts_smp_cnd_signal(&schdlr_sspnd.cnd);
+ }
- if (((ErtsSchedulerData *) vesdp)->no != 1) {
- if (schdlr_sspnd.online == schdlr_sspnd.curr_online) {
- schdlr_sspnd.changing = 0;
- erts_smp_cnd_broadcast(&schdlr_sspnd.cnd);
+ if (((ErtsSchedulerData *) vesdp)->no == 1) {
+ if (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online) {
+ erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
+ susp_sched_prep_block,
+ susp_sched_resume_block,
+ NULL);
+ while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
+ erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
+ erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
+ susp_sched_prep_block,
+ susp_sched_resume_block,
+ NULL);
}
- }
- else if (schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
- schdlr_sspnd.changing = 0;
- else {
- erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
- susp_sched_prep_block,
- susp_sched_resume_block,
- NULL);
- while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
- erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
- erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
- susp_sched_prep_block,
- susp_sched_resume_block,
- NULL);
- ASSERT(!schdlr_sspnd.changing);
+ ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_WAITER);
}
erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
@@ -3428,6 +3951,7 @@ processor_order_cmp(const void *vx, const void *vy)
static void
check_cpu_bind(ErtsSchedulerData *esdp)
{
+ int rg = 0;
int res;
int cpu_id;
erts_smp_runq_unlock(esdp->run_queue);
@@ -3446,7 +3970,7 @@ check_cpu_bind(ErtsSchedulerData *esdp)
goto unbind;
}
}
- else if (cpu_id < 0 && scheduler2cpu_map[esdp->no].bound_id >= 0) {
+ else if (cpu_id < 0) /* && scheduler2cpu_map[esdp->no].bound_id >= 0) */ {
unbind:
/* Get rid of old binding */
res = erts_unbind_from_cpu(erts_cpuinfo);
@@ -3459,6 +3983,12 @@ check_cpu_bind(ErtsSchedulerData *esdp)
erts_send_error_to_logger_nogl(dsbufp);
}
}
+ if (erts_reader_groups) {
+ if (esdp->cpu_id >= 0)
+ rg = reader_group_lookup(esdp->cpu_id);
+ else
+ rg = (((int) esdp->no) - 1) % erts_reader_groups + 1;
+ }
erts_smp_runq_lock(esdp->run_queue);
#ifdef ERTS_SMP
if (erts_common_run_queue)
@@ -3469,6 +3999,8 @@ check_cpu_bind(ErtsSchedulerData *esdp)
#endif
erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
+ if (erts_reader_groups)
+ erts_smp_rwmtx_set_reader_group(rg);
}
static void
@@ -3497,11 +4029,13 @@ signal_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size)
wake_all_schedulers();
}
else {
- ERTS_FOREACH_RUNQ(rq,
- {
+ for (s_ix = 0; s_ix < erts_no_run_queues; s_ix++) {
+ ErtsRunQueue *rq = ERTS_RUNQ_IX(s_ix);
+ erts_smp_runq_lock(rq);
rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
- wake_scheduler(rq, 0);
- });
+ erts_smp_runq_unlock(rq);
+ wake_scheduler(rq, 0, 1);
+ };
}
#else
check_cpu_bind(erts_get_scheduler_data());
@@ -3541,6 +4075,490 @@ erts_init_scheduler_bind_type(char *how)
return ERTS_INIT_SCHED_BIND_TYPE_SUCCESS;
}
+/*
+ * reader groups map
+ */
+
+typedef struct {
+ int level[ERTS_TOPOLOGY_MAX_DEPTH+1];
+} erts_avail_cput;
+
+typedef struct {
+ int *map;
+ int size;
+ int groups;
+} erts_reader_groups_map_test;
+
+typedef struct {
+ int id;
+ int sub_levels;
+ int reader_groups;
+} erts_rg_count_t;
+
+typedef struct {
+ int logical;
+ int reader_group;
+} erts_reader_groups_map_t;
+
+typedef struct {
+ erts_reader_groups_map_t *map;
+ int map_size;
+ int logical_processors;
+ int groups;
+} erts_make_reader_groups_map_test;
+
+static int reader_groups_available_cpu_check;
+static int reader_groups_logical_processors;
+static int reader_groups_map_size;
+static erts_reader_groups_map_t *reader_groups_map;
+
+#define ERTS_TOPOLOGY_RG ERTS_TOPOLOGY_MAX_DEPTH
+
+static void
+make_reader_groups_map(erts_make_reader_groups_map_test *test);
+
+static Eterm
+get_reader_groups_map(Process *c_p,
+ erts_reader_groups_map_t *map,
+ int map_size,
+ int logical_processors)
+{
+#ifdef DEBUG
+ Eterm *endp;
+#endif
+ Eterm res = NIL, tuple;
+ Eterm *hp;
+ int i;
+
+ hp = HAlloc(c_p, logical_processors*(2+3));
+#ifdef DEBUG
+ endp = hp + logical_processors*(2+3);
+#endif
+ for (i = map_size - 1; i >= 0; i--) {
+ if (map[i].logical >= 0) {
+ tuple = TUPLE2(hp,
+ make_small(map[i].logical),
+ make_small(map[i].reader_group));
+ hp += 3;
+ res = CONS(hp, tuple, res);
+ hp += 2;
+ }
+ }
+ ASSERT(hp == endp);
+ return res;
+}
+
+Eterm
+erts_debug_reader_groups_map(Process *c_p, int groups)
+{
+ Eterm res;
+ erts_make_reader_groups_map_test test;
+
+ test.groups = groups;
+ make_reader_groups_map(&test);
+ if (!test.map)
+ res = NIL;
+ else {
+ res = get_reader_groups_map(c_p,
+ test.map,
+ test.map_size,
+ test.logical_processors);
+ erts_free(ERTS_ALC_T_TMP, test.map);
+ }
+ return res;
+}
+
+
+Eterm
+erts_get_reader_groups_map(Process *c_p)
+{
+ Eterm res;
+ erts_smp_rwmtx_rlock(&erts_cpu_bind_rwmtx);
+ res = get_reader_groups_map(c_p,
+ reader_groups_map,
+ reader_groups_map_size,
+ reader_groups_logical_processors);
+ erts_smp_rwmtx_runlock(&erts_cpu_bind_rwmtx);
+ return res;
+}
+
+static void
+make_available_cpu_topology(erts_avail_cput *no,
+ erts_avail_cput *avail,
+ erts_cpu_topology_t *cpudata,
+ int *size,
+ int test)
+{
+ int len = *size;
+ erts_cpu_topology_t last;
+ int a, i, j;
+
+ no->level[ERTS_TOPOLOGY_NODE] = -1;
+ no->level[ERTS_TOPOLOGY_PROCESSOR] = -1;
+ no->level[ERTS_TOPOLOGY_PROCESSOR_NODE] = -1;
+ no->level[ERTS_TOPOLOGY_CORE] = -1;
+ no->level[ERTS_TOPOLOGY_THREAD] = -1;
+ no->level[ERTS_TOPOLOGY_LOGICAL] = -1;
+
+ last.node = INT_MIN;
+ last.processor = INT_MIN;
+ last.processor_node = INT_MIN;
+ last.core = INT_MIN;
+ last.thread = INT_MIN;
+ last.logical = INT_MIN;
+
+ a = 0;
+
+ for (i = 0; i < len; i++) {
+
+ if (!test && !erts_is_cpu_available(erts_cpuinfo, cpudata[i].logical))
+ continue;
+
+ if (last.node != cpudata[i].node)
+ goto node;
+ if (last.processor != cpudata[i].processor)
+ goto processor;
+ if (last.processor_node != cpudata[i].processor_node)
+ goto processor_node;
+ if (last.core != cpudata[i].core)
+ goto core;
+ ASSERT(last.thread != cpudata[i].thread);
+ goto thread;
+
+ node:
+ no->level[ERTS_TOPOLOGY_NODE]++;
+ processor:
+ no->level[ERTS_TOPOLOGY_PROCESSOR]++;
+ processor_node:
+ no->level[ERTS_TOPOLOGY_PROCESSOR_NODE]++;
+ core:
+ no->level[ERTS_TOPOLOGY_CORE]++;
+ thread:
+ no->level[ERTS_TOPOLOGY_THREAD]++;
+
+ no->level[ERTS_TOPOLOGY_LOGICAL]++;
+
+ for (j = 0; j < ERTS_TOPOLOGY_LOGICAL; j++)
+ avail[a].level[j] = no->level[j];
+
+ avail[a].level[ERTS_TOPOLOGY_LOGICAL] = cpudata[i].logical;
+ avail[a].level[ERTS_TOPOLOGY_RG] = 0;
+
+ ASSERT(last.logical != cpudata[a].logical);
+
+ last = cpudata[i];
+ a++;
+ }
+
+ no->level[ERTS_TOPOLOGY_NODE]++;
+ no->level[ERTS_TOPOLOGY_PROCESSOR]++;
+ no->level[ERTS_TOPOLOGY_PROCESSOR_NODE]++;
+ no->level[ERTS_TOPOLOGY_CORE]++;
+ no->level[ERTS_TOPOLOGY_THREAD]++;
+ no->level[ERTS_TOPOLOGY_LOGICAL]++;
+
+ *size = a;
+}
+
+static int
+reader_group_lookup(int logical)
+{
+ int start = logical % reader_groups_map_size;
+ int ix = start;
+
+ do {
+ if (reader_groups_map[ix].logical == logical) {
+ ASSERT(reader_groups_map[ix].reader_group > 0);
+ return reader_groups_map[ix].reader_group;
+ }
+ ix++;
+ if (ix == reader_groups_map_size)
+ ix = 0;
+ } while (ix != start);
+
+ erl_exit(ERTS_ABORT_EXIT, "Logical cpu id %d not found\n", logical);
+}
+
+static void
+reader_group_insert(erts_reader_groups_map_t *map, int map_size,
+ int logical, int reader_group)
+{
+ int start = logical % map_size;
+ int ix = start;
+
+ do {
+ if (map[ix].logical < 0) {
+ map[ix].logical = logical;
+ map[ix].reader_group = reader_group;
+ return;
+ }
+ ix++;
+ if (ix == map_size)
+ ix = 0;
+ } while (ix != start);
+
+ erl_exit(ERTS_ABORT_EXIT, "Reader groups map full\n");
+}
+
+
+static int
+sub_levels(erts_rg_count_t *rgc, int level, int aix, int avail_sz, erts_avail_cput *avail)
+{
+ int sub_level = level+1;
+ int last = -1;
+ rgc->sub_levels = 0;
+
+ do {
+ if (last != avail[aix].level[sub_level]) {
+ rgc->sub_levels++;
+ last = avail[aix].level[sub_level];
+ }
+ aix++;
+ }
+ while (aix < avail_sz && rgc->id == avail[aix].level[level]);
+ rgc->reader_groups = 0;
+ return aix;
+}
+
+static int
+write_reader_groups(int *rgp, erts_rg_count_t *rgcp,
+ int level, int a,
+ int avail_sz, erts_avail_cput *avail)
+{
+ int rg = *rgp;
+ int sub_level = level+1;
+ int sl_per_gr = rgcp->sub_levels / rgcp->reader_groups;
+ int xsl = rgcp->sub_levels % rgcp->reader_groups;
+ int sls = 0;
+ int last = -1;
+ int xsl_rg_lim = (rgcp->reader_groups - xsl) + rg + 1;
+
+ ASSERT(level < 0 || avail[a].level[level] == rgcp->id)
+
+ do {
+ if (last != avail[a].level[sub_level]) {
+ if (!sls) {
+ sls = sl_per_gr;
+ rg++;
+ if (rg >= xsl_rg_lim)
+ sls++;
+ }
+ last = avail[a].level[sub_level];
+ sls--;
+ }
+ avail[a].level[ERTS_TOPOLOGY_RG] = rg;
+ a++;
+ } while (a < avail_sz && (level < 0
+ || avail[a].level[level] == rgcp->id));
+
+ ASSERT(rgcp->reader_groups == rg - *rgp);
+
+ *rgp = rg;
+
+ return a;
+}
+
+static int
+rg_count_sub_levels_compare(const void *vx, const void *vy)
+{
+ erts_rg_count_t *x = (erts_rg_count_t *) vx;
+ erts_rg_count_t *y = (erts_rg_count_t *) vy;
+ if (x->sub_levels != y->sub_levels)
+ return y->sub_levels - x->sub_levels;
+ return x->id - y->id;
+}
+
+static int
+rg_count_id_compare(const void *vx, const void *vy)
+{
+ erts_rg_count_t *x = (erts_rg_count_t *) vx;
+ erts_rg_count_t *y = (erts_rg_count_t *) vy;
+ return x->id - y->id;
+}
+
+static void
+make_reader_groups_map(erts_make_reader_groups_map_test *test)
+{
+ int i, spread_level, avail_sz;
+ erts_avail_cput no, *avail;
+ erts_cpu_topology_t *cpudata;
+ erts_reader_groups_map_t *map;
+ int map_sz;
+ int groups = erts_reader_groups;
+
+ if (test) {
+ test->map = NULL;
+ test->map_size = 0;
+ groups = test->groups;
+ }
+
+ if (!groups)
+ return;
+
+ if (!test) {
+ if (reader_groups_map)
+ erts_free(ERTS_ALC_T_RDR_GRPS_MAP, reader_groups_map);
+
+ reader_groups_logical_processors = 0;
+ reader_groups_map_size = 0;
+ reader_groups_map = NULL;
+ }
+
+ create_tmp_cpu_topology_copy(&cpudata, &avail_sz);
+
+ if (!cpudata)
+ return;
+
+ cpu_bind_order_sort(cpudata,
+ avail_sz,
+ ERTS_CPU_BIND_NO_SPREAD,
+ 1);
+
+ avail = erts_alloc(ERTS_ALC_T_TMP,
+ sizeof(erts_avail_cput)*avail_sz);
+
+ make_available_cpu_topology(&no, avail, cpudata,
+ &avail_sz, test != NULL);
+
+ destroy_tmp_cpu_topology_copy(cpudata);
+
+ map_sz = avail_sz*2+1;
+
+ if (test) {
+ map = erts_alloc(ERTS_ALC_T_TMP,
+ (sizeof(erts_reader_groups_map_t)
+ * map_sz));
+ test->map = map;
+ test->map_size = map_sz;
+ test->logical_processors = avail_sz;
+ }
+ else {
+ map = erts_alloc(ERTS_ALC_T_RDR_GRPS_MAP,
+ (sizeof(erts_reader_groups_map_t)
+ * map_sz));
+ reader_groups_map = map;
+ reader_groups_logical_processors = avail_sz;
+ reader_groups_map_size = map_sz;
+
+ }
+
+ for (i = 0; i < map_sz; i++) {
+ map[i].logical = -1;
+ map[i].reader_group = 0;
+ }
+
+ spread_level = ERTS_TOPOLOGY_CORE;
+ for (i = ERTS_TOPOLOGY_NODE; i < ERTS_TOPOLOGY_THREAD; i++) {
+ if (no.level[i] > groups) {
+ spread_level = i;
+ break;
+ }
+ }
+
+ if (no.level[spread_level] <= groups) {
+ int a, rg, last = -1;
+ rg = 0;
+ ASSERT(spread_level == ERTS_TOPOLOGY_CORE);
+ for (a = 0; a < avail_sz; a++) {
+ if (last != avail[a].level[spread_level]) {
+ rg++;
+ last = avail[a].level[spread_level];
+ }
+ reader_group_insert(map,
+ map_sz,
+ avail[a].level[ERTS_TOPOLOGY_LOGICAL],
+ rg);
+ }
+ }
+ else { /* groups < no.level[spread_level] */
+ erts_rg_count_t *rg_count;
+ int a, rg, tl, toplevels;
+
+ tl = spread_level-1;
+
+ if (spread_level == ERTS_TOPOLOGY_NODE)
+ toplevels = 1;
+ else
+ toplevels = no.level[tl];
+
+ rg_count = erts_alloc(ERTS_ALC_T_TMP,
+ toplevels*sizeof(erts_rg_count_t));
+
+ if (toplevels == 1) {
+ rg_count[0].id = 0;
+ rg_count[0].sub_levels = no.level[spread_level];
+ rg_count[0].reader_groups = groups;
+ }
+ else {
+ int rgs_per_tl, rgs;
+ rgs = groups;
+ rgs_per_tl = rgs / toplevels;
+
+ a = 0;
+ for (i = 0; i < toplevels; i++) {
+ rg_count[i].id = avail[a].level[tl];
+ a = sub_levels(&rg_count[i], tl, a, avail_sz, avail);
+ }
+
+ qsort(rg_count,
+ toplevels,
+ sizeof(erts_rg_count_t),
+ rg_count_sub_levels_compare);
+
+ for (i = 0; i < toplevels; i++) {
+ if (rg_count[i].sub_levels < rgs_per_tl) {
+ rg_count[i].reader_groups = rg_count[i].sub_levels;
+ rgs -= rg_count[i].sub_levels;
+ }
+ else {
+ rg_count[i].reader_groups = rgs_per_tl;
+ rgs -= rgs_per_tl;
+ }
+ }
+
+ while (rgs > 0) {
+ for (i = 0; i < toplevels; i++) {
+ if (rg_count[i].sub_levels == rg_count[i].reader_groups)
+ break;
+ else {
+ rg_count[i].reader_groups++;
+ if (--rgs == 0)
+ break;
+ }
+ }
+ }
+
+ qsort(rg_count,
+ toplevels,
+ sizeof(erts_rg_count_t),
+ rg_count_id_compare);
+ }
+
+ a = i = rg = 0;
+ while (a < avail_sz) {
+ a = write_reader_groups(&rg, &rg_count[i], tl,
+ a, avail_sz, avail);
+ i++;
+ }
+
+ ASSERT(groups == rg);
+
+ for (a = 0; a < avail_sz; a++)
+ reader_group_insert(map,
+ map_sz,
+ avail[a].level[ERTS_TOPOLOGY_LOGICAL],
+ avail[a].level[ERTS_TOPOLOGY_RG]);
+
+ erts_free(ERTS_ALC_T_TMP, rg_count);
+ }
+
+ erts_free(ERTS_ALC_T_TMP, avail);
+}
+
+/*
+ * CPU topology
+ */
+
typedef struct {
int *id;
int used;
@@ -4054,6 +5072,8 @@ erts_set_cpu_topology(Process *c_p, Eterm term)
sizeof(erts_cpu_topology_t)*cpudata_size);
}
+ make_reader_groups_map(NULL);
+
signal_schedulers_bind_change(cpudata, cpudata_size);
done:
@@ -4457,6 +5477,11 @@ early_cpu_bind_init(void)
cpu_bind_order = ERTS_CPU_BIND_UNDEFINED;
+ reader_groups_available_cpu_check = 1;
+ reader_groups_logical_processors = 0;
+ reader_groups_map_size = 0;
+ reader_groups_map = NULL;
+
if (!erts_get_cpu_topology(erts_cpuinfo, system_cpudata)
|| ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(system_cpudata,
system_cpudata_size)) {
@@ -4492,6 +5517,8 @@ late_cpu_bind_init(void)
: ERTS_CPU_BIND_NONE);
}
+ make_reader_groups_map(NULL);
+
if (cpu_bind_order != ERTS_CPU_BIND_NONE) {
erts_cpu_topology_t *cpudata;
int cpudata_size;
@@ -4502,6 +5529,39 @@ late_cpu_bind_init(void)
}
}
+int
+erts_update_cpu_info(void)
+{
+ int changed;
+ erts_smp_rwmtx_rwlock(&erts_cpu_bind_rwmtx);
+ changed = erts_cpu_info_update(erts_cpuinfo);
+ if (changed) {
+ erts_cpu_topology_t *cpudata;
+ int cpudata_size;
+ erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
+
+ system_cpudata_size = erts_get_cpu_topology_size(erts_cpuinfo);
+ system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA,
+ (sizeof(erts_cpu_topology_t)
+ * system_cpudata_size));
+
+ if (!erts_get_cpu_topology(erts_cpuinfo, system_cpudata)
+ || ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(system_cpudata,
+ system_cpudata_size)) {
+ erts_free(ERTS_ALC_T_CPUDATA, system_cpudata);
+ system_cpudata = NULL;
+ system_cpudata_size = 0;
+ }
+
+ create_tmp_cpu_topology_copy(&cpudata, &cpudata_size);
+ ASSERT(cpudata);
+ signal_schedulers_bind_change(cpudata, cpudata_size);
+ destroy_tmp_cpu_topology_copy(cpudata);
+ }
+ erts_smp_rwmtx_rwunlock(&erts_cpu_bind_rwmtx);
+ return changed;
+}
+
#ifdef ERTS_SMP
static void
@@ -5357,7 +6417,7 @@ dequeue_process(ErtsRunQueue *runq, Process *p)
}
/* schedule a process */
-static ERTS_INLINE void
+static ERTS_INLINE ErtsRunQueue *
internal_add_to_runq(ErtsRunQueue *runq, Process *p)
{
Uint32 prev_status = p->status;
@@ -5368,12 +6428,12 @@ internal_add_to_runq(ErtsRunQueue *runq, Process *p)
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
if (p->status_flags & ERTS_PROC_SFLG_INRUNQ)
- return;
+ return NULL;
else if (p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) {
ASSERT(p->status != P_SUSPENDED);
ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p);
p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ;
- return;
+ return NULL;
}
ASSERT(!p->scheduler_data);
#endif
@@ -5412,20 +6472,23 @@ internal_add_to_runq(ErtsRunQueue *runq, Process *p)
profile_runnable_proc(p, am_active);
}
- smp_notify_inc_runq(add_runq);
-
if (add_runq != runq)
erts_smp_runq_unlock(add_runq);
+
+ return add_runq;
}
void
erts_add_to_runq(Process *p)
{
+ ErtsRunQueue *notify_runq;
ErtsRunQueue *runq = erts_get_runq_proc(p);
erts_smp_runq_lock(runq);
- internal_add_to_runq(runq, p);
+ notify_runq = internal_add_to_runq(runq, p);
erts_smp_runq_unlock(runq);
+ smp_notify_inc_runq(notify_runq);
+
}
/* Possibly remove a scheduled process we need to suspend */
@@ -5564,8 +6627,6 @@ erts_proc_migrate(Process *p, ErtsProcLocks *plcks,
p->run_queue = to_rq;
enqueue_process(to_rq, p);
- smp_notify_inc_runq(to_rq);
-
return ERTS_MIGRATE_SUCCESS;
}
#endif /* ERTS_SMP */
@@ -5762,30 +6823,6 @@ erts_set_process_priority(Process *p, Eterm new_value)
return old_value;
}
-#ifdef ERTS_SMP
-
-static ERTS_INLINE int
-prepare_for_sys_schedule(void)
-{
- while (!erts_port_task_have_outstanding_io_tasks()
- && !erts_smp_atomic_xchg(&doing_sys_schedule, 1)) {
- if (!erts_port_task_have_outstanding_io_tasks())
- return 1;
- erts_smp_atomic_set(&doing_sys_schedule, 0);
- }
- return 0;
-}
-
-#else
-
-static ERTS_INLINE int
-prepare_for_sys_schedule(void)
-{
- return !erts_port_task_have_outstanding_io_tasks();
-}
-
-#endif
-
/* note that P_RUNNING is only set so that we don't try to remove
** running processes from the schedule queue if they exit - a running
** process not being in the schedule queue!!
@@ -5920,8 +6957,11 @@ Process *schedule(Process *p, int calls)
p->status_flags &= ~ERTS_PROC_SFLG_RUNNING;
if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) {
+ ErtsRunQueue *notify_runq;
p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ;
- internal_add_to_runq(rq, p);
+ notify_runq = internal_add_to_runq(rq, p);
+ if (notify_runq != rq)
+ smp_notify_inc_runq(notify_runq);
}
#endif
@@ -5989,7 +7029,10 @@ Process *schedule(Process *p, int calls)
| ERTS_RUNQ_FLG_CHK_CPU_BIND
| ERTS_RUNQ_FLG_SUSPENDED)) {
if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
- || erts_smp_atomic_read(&esdp->suspended)) {
+ || (erts_smp_atomic_read(&esdp->ssi->flags)
+ & ERTS_SSI_FLG_SUSPENDED)) {
+ ASSERT(erts_smp_atomic_read(&esdp->ssi->flags)
+ & ERTS_SSI_FLG_SUSPENDED);
suspend_scheduler(esdp);
}
if ((rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND)
@@ -5998,12 +7041,21 @@ Process *schedule(Process *p, int calls)
}
}
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- if (esdp->check_children) {
- esdp->check_children = 0;
- erts_smp_runq_unlock(rq);
- erts_check_children();
- erts_smp_runq_lock(rq);
+#if defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK) \
+ || defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK)
+ {
+ ErtsSchedulerSleepInfo *ssi = esdp->ssi;
+ long aux_work = erts_smp_atomic_read(&ssi->aux_work);
+ if (aux_work) {
+ erts_smp_runq_unlock(rq);
+#ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+ aux_work = blockable_aux_work(esdp, ssi, aux_work);
+#endif
+#ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
+ nonblockable_aux_work(esdp, ssi, aux_work);
+#endif
+ erts_smp_runq_lock(rq);
+ }
}
#endif
@@ -6035,7 +7087,10 @@ Process *schedule(Process *p, int calls)
if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
| ERTS_RUNQ_FLG_SUSPENDED)) {
if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
- || erts_smp_atomic_read(&esdp->suspended)) {
+ || (erts_smp_atomic_read(&esdp->ssi->flags)
+ & ERTS_SSI_FLG_SUSPENDED)) {
+ ASSERT(erts_smp_atomic_read(&esdp->ssi->flags)
+ & ERTS_SSI_FLG_SUSPENDED);
non_empty_runq(rq);
goto continue_check_activities_to_run;
}
@@ -6052,17 +7107,7 @@ Process *schedule(Process *p, int calls)
}
}
- if (prepare_for_sys_schedule()) {
- erts_smp_atomic_set(&function_calls, 0);
- fcalls = 0;
- sched_sys_wait(esdp->no, rq);
- erts_smp_atomic_set(&doing_sys_schedule, 0);
- }
- else {
- /* If all schedulers are waiting, one of them *should*
- be waiting in erl_sys_schedule() */
- sched_cnd_wait(esdp->no, rq);
- }
+ scheduler_wait(&fcalls, esdp, rq);
non_empty_runq(rq);
@@ -6124,7 +7169,7 @@ Process *schedule(Process *p, int calls)
else {
if (erts_common_run_queue) {
if (erts_common_run_queue->waiting)
- wake_one_scheduler();
+ wake_scheduler(erts_common_run_queue, 0, 1);
}
else if (erts_smp_atomic_read(&no_empty_run_queues) != 0) {
wake_scheduler_on_empty_runq(rq);
@@ -6439,8 +7484,8 @@ erts_schedule_misc_op(void (*func)(void *), void *arg)
else
rq->misc.start = molp;
rq->misc.end = molp;
- smp_notify_inc_runq(rq);
erts_smp_runq_unlock(rq);
+ smp_notify_inc_runq(rq);
}
static void
@@ -6682,7 +7727,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
Eterm args, /* Arguments for function (must be well-formed list). */
ErlSpawnOpts* so) /* Options for spawn. */
{
- ErtsRunQueue *rq;
+ ErtsRunQueue *rq, *notify_runq;
Process *p;
Sint arity; /* Number of arguments. */
#ifndef HYBRID
@@ -6761,11 +7806,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
/*
* Must initialize binary lists here before copying binaries to process.
*/
- p->off_heap.mso = NULL;
-#ifndef HYBRID /* FIND ME! */
- p->off_heap.funs = NULL;
-#endif
- p->off_heap.externals = NULL;
+ p->off_heap.first = NULL;
p->off_heap.overhead = 0;
heap_need +=
@@ -6855,7 +7896,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->group_leader =
IS_CONST(parent->group_leader)
? parent->group_leader
- : STORE_NC(&p->htop, &p->off_heap.externals, parent->group_leader);
+ : STORE_NC(&p->htop, &p->off_heap, parent->group_leader);
}
erts_get_default_tracing(&p->trace_flags, &p->tracer_proc);
@@ -6999,10 +8040,12 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
#endif
p->status = P_WAITING;
- internal_add_to_runq(rq, p);
+ notify_runq = internal_add_to_runq(rq, p);
erts_smp_runq_unlock(rq);
+ smp_notify_inc_runq(notify_runq);
+
res = p->id;
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
@@ -7056,11 +8099,7 @@ void erts_init_empty_process(Process *p)
memset(&(p->u.tm), 0, sizeof(ErlTimer));
#endif
p->next = NULL;
- p->off_heap.mso = NULL;
-#ifndef HYBRID /* FIND ME! */
- p->off_heap.funs = NULL;
-#endif
- p->off_heap.externals = NULL;
+ p->off_heap.first = NULL;
p->off_heap.overhead = 0;
p->reg = NULL;
p->heap_sz = 0;
@@ -7207,11 +8246,7 @@ erts_debug_verify_clean_empty_process(Process* p)
/* Thing that erts_cleanup_empty_process() cleans up */
- ASSERT(p->off_heap.mso == NULL);
-#ifndef HYBRID /* FIND ME! */
- ASSERT(p->off_heap.funs == NULL);
-#endif
- ASSERT(p->off_heap.externals == NULL);
+ ASSERT(p->off_heap.first == NULL);
ASSERT(p->off_heap.overhead == 0);
ASSERT(p->mbuf == NULL);
@@ -7225,11 +8260,7 @@ erts_cleanup_empty_process(Process* p)
/* We only check fields that are known to be used... */
erts_cleanup_offheap(&p->off_heap);
- p->off_heap.mso = NULL;
-#ifndef HYBRID /* FIND ME! */
- p->off_heap.funs = NULL;
-#endif
- p->off_heap.externals = NULL;
+ p->off_heap.first = NULL;
p->off_heap.overhead = 0;
if (p->mbuf != NULL) {
@@ -7266,7 +8297,7 @@ delete_process(Process* p)
* The mso list should not be used anymore, but if it is, make sure that
* we'll notice.
*/
- p->off_heap.mso = (void *) 0x8DEFFACD;
+ p->off_heap.first = (void *) 0x8DEFFACD;
if (p->arg_reg != p->def_arg_reg) {
erts_free(ERTS_ALC_T_ARG_REG, p->arg_reg);
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 8f9f7f004e..0cc4a715ad 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -89,6 +89,7 @@ extern int erts_sched_thread_suggested_stack_size;
#define ERTS_SCHED_THREAD_MAX_STACK_SIZE 8192 /* Kilo words */
#ifdef ERTS_SMP
+extern Uint erts_max_main_threads;
#include "erl_bits.h"
#endif
@@ -219,6 +220,51 @@ typedef enum {
ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED
} ErtsMigrateResult;
+#define ERTS_SSI_FLG_SLEEPING (((long) 1) << 0)
+#define ERTS_SSI_FLG_POLL_SLEEPING (((long) 1) << 1)
+#define ERTS_SSI_FLG_TSE_SLEEPING (((long) 1) << 2)
+#define ERTS_SSI_FLG_WAITING (((long) 1) << 3)
+#define ERTS_SSI_FLG_SUSPENDED (((long) 1) << 4)
+
+#define ERTS_SSI_FLGS_SLEEP_TYPE \
+ (ERTS_SSI_FLG_TSE_SLEEPING|ERTS_SSI_FLG_POLL_SLEEPING)
+
+#define ERTS_SSI_FLGS_SLEEP \
+ (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLGS_SLEEP_TYPE)
+
+#define ERTS_SSI_FLGS_ALL \
+ (ERTS_SSI_FLGS_SLEEP \
+ | ERTS_SSI_FLG_WAITING \
+ | ERTS_SSI_FLG_SUSPENDED)
+
+
+#if !defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK) \
+ && defined(ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN)
+#define ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
+#endif
+
+#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((long) 1) << 0)
+
+#define ERTS_SSI_BLOCKABLE_AUX_WORK_MASK \
+ (ERTS_SSI_AUX_WORK_CHECK_CHILDREN)
+#define ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK \
+ (0)
+
+typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo;
+
+typedef struct {
+ erts_smp_spinlock_t lock;
+ ErtsSchedulerSleepInfo *list;
+} ErtsSchedulerSleepList;
+
+struct ErtsSchedulerSleepInfo_ {
+ ErtsSchedulerSleepInfo *next;
+ ErtsSchedulerSleepInfo *prev;
+ erts_smp_atomic_t flags;
+ erts_tse_t *event;
+ erts_smp_atomic_t aux_work;
+};
+
/* times to reschedule low prio process before running */
#define RESCHEDULE_LOW 8
@@ -271,8 +317,9 @@ struct ErtsRunQueue_ {
erts_smp_mtx_t mtx;
erts_smp_cnd_t cnd;
- erts_smp_atomic_t spin_waiter;
- erts_smp_atomic_t spin_wake;
+#ifdef ERTS_SMP
+ ErtsSchedulerSleepList sleepers;
+#endif
ErtsSchedulerData *scheduler;
int waiting; /* < 0 in sys schedule; > 0 on cnd variable */
@@ -353,6 +400,7 @@ struct ErtsSchedulerData_ {
ethr_tid tid; /* Thread id */
struct erl_bits_state erl_bits_state; /* erl_bits.c state */
void *match_pseudo_process; /* erl_db_util.c:db_prog_match() */
+ ErtsSchedulerSleepInfo *ssi;
Process *free_process;
#endif
#if !HEAP_ON_C_STACK
@@ -374,11 +422,6 @@ struct ErtsSchedulerData_ {
#ifdef ERTS_SMP
/* NOTE: These fields are modified under held mutexes by other threads */
-#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
- int check_children; /* run queue mutex */
- int blocked_check_children; /* schdlr_sspnd mutex */
-#endif
- erts_smp_atomic_t suspended; /* Only used when common run queue */
erts_smp_atomic_t chk_cpu_bind; /* Only used when common run queue */
#endif
};
@@ -828,7 +871,7 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags;
#define F_INSLPQUEUE (1 << 1) /* Set if in timer queue */
#define F_TIMO (1 << 2) /* Set if timeout */
#define F_HEAP_GROW (1 << 3)
-#define F_NEED_FULLSWEEP (1 << 4) /* If process has old binaries & funs. */
+#define F_NEED_FULLSWEEP (1 << 4)
#define F_USING_DB (1 << 5) /* If have created tables */
#define F_DISTRIBUTION (1 << 6) /* Process used in distribution */
#define F_USING_DDLL (1 << 7) /* Process has used the DDLL interface */
@@ -982,6 +1025,7 @@ int erts_init_scheduler_bind_type(char *how);
#define ERTS_INIT_CPU_TOPOLOGY_MISSING 9
int erts_init_cpu_topology(char *topology_str);
+int erts_update_cpu_info(void);
void erts_pre_init_process(void);
void erts_late_init_process(void);
@@ -1085,6 +1129,9 @@ void erts_handle_pending_exit(Process *, ErtsProcLocks);
void erts_deep_process_dump(int, void *);
+Eterm erts_get_reader_groups_map(Process *c_p);
+Eterm erts_debug_reader_groups_map(Process *c_p, int groups);
+
Sint erts_test_next_pid(int, Uint);
Eterm erts_debug_processes(Process *c_p);
Eterm erts_debug_processes_bif_info(Process *c_p);
@@ -1509,29 +1556,30 @@ extern int erts_disable_proc_not_running_opt;
#define ERTS_MIN_PROCESSES 16
#endif
-#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
-ERTS_GLB_INLINE void erts_smp_notify_inc_runq(ErtsRunQueue *runq);
-void erts_smp_notify_inc_runq__(ErtsRunQueue *runq);
-#endif /* ERTS_INCLUDE_SCHEDULER_INTERNALS */
+void erts_smp_notify_inc_runq(ErtsRunQueue *runq);
-#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+#ifdef ERTS_SMP
+void erts_sched_finish_poke(ErtsSchedulerSleepInfo *, long);
+ERTS_GLB_INLINE void erts_sched_poke(ErtsSchedulerSleepInfo *ssi);
-#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
ERTS_GLB_INLINE void
-erts_smp_notify_inc_runq(ErtsRunQueue *runq)
+erts_sched_poke(ErtsSchedulerSleepInfo *ssi)
{
-#ifdef ERTS_SMP
- ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
- if (runq->waiting)
- erts_smp_notify_inc_runq__(runq);
-#endif
+ long flags = erts_smp_atomic_read(&ssi->flags);
+ ASSERT(!(flags & ERTS_SSI_FLG_SLEEPING)
+ || (flags & ERTS_SSI_FLG_WAITING));
+ if (flags & ERTS_SSI_FLG_SLEEPING) {
+ flags = erts_smp_atomic_band(&ssi->flags, ~ERTS_SSI_FLGS_SLEEP);
+ erts_sched_finish_poke(ssi, flags);
+ }
}
-#endif /* ERTS_INCLUDE_SCHEDULER_INTERNALS */
-
#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
+#endif /* #ifdef ERTS_SMP */
+
#include "erl_process_lock.h"
#undef ERTS_INCLUDE_SCHEDULER_INTERNALS
diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c
index 52440fb635..a4d12139e9 100644
--- a/erts/emulator/beam/erl_process_lock.c
+++ b/erts/emulator/beam/erl_process_lock.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2007-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2007-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -71,9 +71,12 @@ const Process erts_proc_lock_busy;
#ifdef ERTS_SMP
-/*#define ERTS_PROC_LOCK_SPIN_ON_GATE*/
-#define ERTS_PROC_LOCK_SPIN_COUNT_MAX 16000
+#define ERTS_PROC_LOCK_SPIN_COUNT_MAX 2000
+#define ERTS_PROC_LOCK_SPIN_COUNT_SCHED_INC 32
#define ERTS_PROC_LOCK_SPIN_COUNT_BASE 1000
+#define ERTS_PROC_LOCK_AUX_SPIN_COUNT 50
+
+#define ERTS_PROC_LOCK_SPIN_UNTIL_YIELD 25
#ifdef ERTS_PROC_LOCK_DEBUG
#define ERTS_PROC_LOCK_HARD_DEBUG
@@ -83,32 +86,19 @@ const Process erts_proc_lock_busy;
static void check_queue(erts_proc_lock_t *lck);
#endif
-
-typedef struct erts_proc_lock_waiter_t_ erts_proc_lock_waiter_t;
-struct erts_proc_lock_waiter_t_ {
- erts_proc_lock_waiter_t *next;
- erts_proc_lock_waiter_t *prev;
- ErtsProcLocks wait_locks;
- erts_smp_gate_t gate;
- erts_proc_lock_queues_t *queues;
-};
+#if SIZEOF_INT < 4
+#error "The size of the 'uflgs' field of the erts_tse_t type is too small"
+#endif
struct erts_proc_lock_queues_t_ {
erts_proc_lock_queues_t *next;
- erts_proc_lock_waiter_t *queue[ERTS_PROC_LOCK_MAX_BIT+1];
-};
-
-struct erts_proc_lock_thr_spec_data_t_ {
- erts_proc_lock_queues_t *qs;
- erts_proc_lock_waiter_t *wtr;
+ erts_tse_t *queue[ERTS_PROC_LOCK_MAX_BIT+1];
};
static erts_proc_lock_queues_t zeroqs = {0};
-static erts_smp_spinlock_t wtr_lock;
-static erts_proc_lock_waiter_t *waiter_free_list;
+static erts_smp_spinlock_t qs_lock;
static erts_proc_lock_queues_t *queue_free_list;
-static erts_tsd_key_t waiter_key;
#ifdef ERTS_ENABLE_LOCK_CHECK
static struct {
@@ -122,35 +112,26 @@ static struct {
erts_pix_lock_t erts_pix_locks[ERTS_NO_OF_PIX_LOCKS];
static int proc_lock_spin_count;
-static int proc_lock_trans_spin_cost;
+static int aux_thr_proc_lock_spin_count;
-static void cleanup_waiter(void);
+static void cleanup_tse(void);
void
erts_init_proc_lock(void)
{
int i;
int cpus;
- erts_smp_spinlock_init(&wtr_lock, "proc_lck_wtr_alloc");
+ erts_smp_spinlock_init(&qs_lock, "proc_lck_qs_alloc");
for (i = 0; i < ERTS_NO_OF_PIX_LOCKS; i++) {
-#if ERTS_PROC_LOCK_MUTEX_IMPL
-#ifdef ERTS_ENABLE_LOCK_COUNT
- erts_smp_mtx_init_x(&erts_pix_locks[i].u.mtx, "pix_lock", make_small(i));
-#else
- erts_smp_mtx_init(&erts_pix_locks[i].u.mtx, "pix_lock");
-#endif
-#else
#ifdef ERTS_ENABLE_LOCK_COUNT
- erts_smp_spinlock_init_x(&erts_pix_locks[i].u.spnlck, "pix_lock", make_small(i));
+ erts_smp_spinlock_init_x(&erts_pix_locks[i].u.spnlck,
+ "pix_lock", make_small(i));
#else
erts_smp_spinlock_init(&erts_pix_locks[i].u.spnlck, "pix_lock");
#endif
-#endif
}
- waiter_free_list = NULL;
queue_free_list = NULL;
- erts_tsd_key_create(&waiter_key);
- erts_thr_install_exit_handler(cleanup_waiter);
+ erts_thr_install_exit_handler(cleanup_tse);
#ifdef ERTS_ENABLE_LOCK_CHECK
lc_id.proc_lock_main = erts_lc_get_lock_order_id("proc_main");
lc_id.proc_lock_link = erts_lc_get_lock_order_id("proc_link");
@@ -158,86 +139,106 @@ erts_init_proc_lock(void)
lc_id.proc_lock_status = erts_lc_get_lock_order_id("proc_status");
#endif
cpus = erts_get_cpu_configured(erts_cpuinfo);
- if (cpus > 1)
- proc_lock_spin_count = (ERTS_PROC_LOCK_SPIN_COUNT_BASE
- * ((int) erts_no_schedulers));
- else if (cpus == 1)
- proc_lock_spin_count = 0;
- else /* No of cpus unknown. Assume multi proc, but be conservative. */
+ if (cpus > 1) {
proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_BASE;
- if (proc_lock_spin_count > ERTS_PROC_LOCK_SPIN_COUNT_MAX)
- proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_MAX;
- proc_lock_trans_spin_cost = proc_lock_spin_count/20;
-}
-
-static ERTS_INLINE erts_proc_lock_waiter_t *
-alloc_wtr(void)
-{
- erts_proc_lock_waiter_t *wtr;
- erts_smp_spin_lock(&wtr_lock);
- wtr = waiter_free_list;
- if (wtr) {
- waiter_free_list = wtr->next;
- ERTS_LC_ASSERT(queue_free_list);
- wtr->queues = queue_free_list;
- queue_free_list = wtr->queues->next;
- erts_smp_spin_unlock(&wtr_lock);
+ proc_lock_spin_count += (ERTS_PROC_LOCK_SPIN_COUNT_SCHED_INC
+ * ((int) erts_no_schedulers));
+ aux_thr_proc_lock_spin_count = ERTS_PROC_LOCK_AUX_SPIN_COUNT;
}
- else {
- erts_smp_spin_unlock(&wtr_lock);
- wtr = erts_alloc(ERTS_ALC_T_PROC_LCK_WTR,
- sizeof(erts_proc_lock_waiter_t));
- erts_smp_gate_init(&wtr->gate);
- wtr->wait_locks = (ErtsProcLocks) 0;
- wtr->queues = erts_alloc(ERTS_ALC_T_PROC_LCK_QS,
- sizeof(erts_proc_lock_queues_t));
- sys_memcpy((void *) wtr->queues,
- (void *) &zeroqs,
- sizeof(erts_proc_lock_queues_t));
+ else if (cpus == 1) {
+ proc_lock_spin_count = 0;
+ aux_thr_proc_lock_spin_count = 0;
}
- return wtr;
+ else { /* No of cpus unknown. Assume multi proc, but be conservative. */
+ proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_BASE/2;
+ aux_thr_proc_lock_spin_count = ERTS_PROC_LOCK_AUX_SPIN_COUNT/2;
+ }
+ if (proc_lock_spin_count > ERTS_PROC_LOCK_SPIN_COUNT_MAX)
+ proc_lock_spin_count = ERTS_PROC_LOCK_SPIN_COUNT_MAX;
}
#ifdef ERTS_ENABLE_LOCK_CHECK
static void
-check_unused_waiter(erts_proc_lock_waiter_t *wtr)
+check_unused_tse(erts_tse_t *wtr)
{
int i;
- ERTS_LC_ASSERT(wtr->wait_locks == 0);
+ erts_proc_lock_queues_t *queues = wtr->udata;
+ ERTS_LC_ASSERT(wtr->uflgs == 0);
for (i = 0; i <= ERTS_PROC_LOCK_MAX_BIT; i++)
- ERTS_LC_ASSERT(!wtr->queues->queue[i]);
+ ERTS_LC_ASSERT(!queues->queue[i]);
}
-#define CHECK_UNUSED_WAITER(W) check_unused_waiter((W))
+#define CHECK_UNUSED_TSE(W) check_unused_tse((W))
#else
-#define CHECK_UNUSED_WAITER(W)
+#define CHECK_UNUSED_TSE(W)
#endif
+static ERTS_INLINE erts_tse_t *
+tse_fetch(erts_pix_lock_t *pix_lock)
+{
+ erts_tse_t *tse = erts_tse_fetch();
+ if (!tse->udata) {
+ erts_proc_lock_queues_t *qs;
+#if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL
+ if (pix_lock)
+ erts_pix_unlock(pix_lock);
+#endif
+ erts_smp_spin_lock(&qs_lock);
+ qs = queue_free_list;
+ if (qs) {
+ queue_free_list = queue_free_list->next;
+ erts_smp_spin_unlock(&qs_lock);
+ }
+ else {
+ erts_smp_spin_unlock(&qs_lock);
+ qs = erts_alloc(ERTS_ALC_T_PROC_LCK_QS,
+ sizeof(erts_proc_lock_queues_t));
+ sys_memcpy((void *) qs,
+ (void *) &zeroqs,
+ sizeof(erts_proc_lock_queues_t));
+ }
+ tse->udata = qs;
+#if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL
+ if (pix_lock)
+ erts_pix_lock(pix_lock);
+#endif
+ }
+ tse->uflgs = 0;
+ return tse;
+}
static ERTS_INLINE void
-free_wtr(erts_proc_lock_waiter_t *wtr)
+tse_return(erts_tse_t *tse, int force_free_q)
{
- CHECK_UNUSED_WAITER(wtr);
- erts_smp_spin_lock(&wtr_lock);
- wtr->next = waiter_free_list;
- waiter_free_list = wtr;
- wtr->queues->next = queue_free_list;
- queue_free_list = wtr->queues;
- erts_smp_spin_unlock(&wtr_lock);
+ CHECK_UNUSED_TSE(tse);
+ if (force_free_q || erts_tse_is_tmp(tse)) {
+ erts_proc_lock_queues_t *qs = tse->udata;
+ ASSERT(qs);
+ erts_smp_spin_lock(&qs_lock);
+ qs->next = queue_free_list;
+ queue_free_list = qs;
+ erts_smp_spin_unlock(&qs_lock);
+ tse->udata = NULL;
+ }
+ erts_tse_return(tse);
}
void
erts_proc_lock_prepare_proc_lock_waiter(void)
{
- erts_tsd_set(waiter_key, (void *) alloc_wtr());
+ tse_return(tse_fetch(NULL), 0);
}
static void
-cleanup_waiter(void)
+cleanup_tse(void)
{
- erts_proc_lock_waiter_t *wtr = erts_tsd_get(waiter_key);
- if (wtr)
- free_wtr(wtr);
+ erts_tse_t *tse = erts_tse_fetch();
+ if (tse) {
+ if (tse->udata)
+ tse_return(tse, 1);
+ else
+ erts_tse_return(tse);
+ }
}
@@ -250,7 +251,7 @@ cleanup_waiter(void)
static ERTS_INLINE void
enqueue_waiter(erts_proc_lock_queues_t *qs,
int ix,
- erts_proc_lock_waiter_t *wtr)
+ erts_tse_t *wtr)
{
if (!qs->queue[ix]) {
qs->queue[ix] = wtr;
@@ -266,10 +267,10 @@ enqueue_waiter(erts_proc_lock_queues_t *qs,
}
}
-static erts_proc_lock_waiter_t *
+static erts_tse_t *
dequeue_waiter(erts_proc_lock_queues_t *qs, int ix)
{
- erts_proc_lock_waiter_t *wtr = qs->queue[ix];
+ erts_tse_t *wtr = qs->queue[ix];
ERTS_LC_ASSERT(qs->queue[ix]);
if (wtr->next == wtr) {
ERTS_LC_ASSERT(qs->queue[ix]->prev == wtr);
@@ -295,10 +296,10 @@ dequeue_waiter(erts_proc_lock_queues_t *qs, int ix)
* lock.
*/
static ERTS_INLINE void
-try_aquire(erts_proc_lock_t *lck, erts_proc_lock_waiter_t *wtr)
+try_aquire(erts_proc_lock_t *lck, erts_tse_t *wtr)
{
ErtsProcLocks got_locks = (ErtsProcLocks) 0;
- ErtsProcLocks locks = wtr->wait_locks;
+ ErtsProcLocks locks = wtr->uflgs;
int lock_no;
ERTS_LC_ASSERT(lck->queues);
@@ -334,7 +335,7 @@ try_aquire(erts_proc_lock_t *lck, erts_proc_lock_waiter_t *wtr)
}
}
- wtr->wait_locks &= ~got_locks;
+ wtr->uflgs &= ~got_locks;
}
/*
@@ -350,8 +351,8 @@ transfer_locks(Process *p,
int unlock)
{
int transferred = 0;
- erts_proc_lock_waiter_t *wake = NULL;
- erts_proc_lock_waiter_t *wtr;
+ erts_tse_t *wake = NULL;
+ erts_tse_t *wtr;
ErtsProcLocks unset_waiter = 0;
ErtsProcLocks tlocks = trnsfr_lcks;
int lock_no;
@@ -377,11 +378,11 @@ transfer_locks(Process *p,
ERTS_LC_ASSERT(wtr);
if (!qs->queue[lock_no])
unset_waiter |= lock;
- ERTS_LC_ASSERT(wtr->wait_locks & lock);
- wtr->wait_locks &= ~lock;
- if (wtr->wait_locks)
+ ERTS_LC_ASSERT(wtr->uflgs & lock);
+ wtr->uflgs &= ~lock;
+ if (wtr->uflgs)
try_aquire(&p->lock, wtr);
- if (!wtr->wait_locks) {
+ if (!wtr->uflgs) {
/*
* The other thread got all locks it needs;
* need to wake it up.
@@ -412,9 +413,10 @@ transfer_locks(Process *p,
erts_pix_unlock(pix_lock);
do {
- erts_proc_lock_waiter_t *tmp = wake;
+ erts_tse_t *tmp = wake;
wake = wake->next;
- erts_smp_gate_let_through(&tmp->gate, 1);
+ erts_atomic_set(&tmp->uaflgs, 0);
+ erts_tse_set(tmp);
} while (wake);
if (!unlock)
@@ -462,26 +464,16 @@ wait_for_locks(Process *p,
ErtsProcLocks olflgs)
{
erts_pix_lock_t *pix_lock = pixlck ? pixlck : ERTS_PID2PIXLOCK(p->id);
- int tsd;
- erts_proc_lock_waiter_t *wtr;
+ erts_tse_t *wtr;
+ erts_proc_lock_queues_t *qs;
/* Acquire a waiter object on which this thread can wait. */
- wtr = erts_tsd_get(waiter_key);
- if (wtr)
- tsd = 1;
- else {
-#if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL
- erts_pix_unlock(pix_lock);
-#endif
- wtr = alloc_wtr();
- tsd = 0;
-#if ERTS_PROC_LOCK_SPINLOCK_IMPL && !ERTS_PROC_LOCK_ATOMIC_IMPL
- erts_pix_lock(pix_lock);
-#endif
- }
+ wtr = tse_fetch(pix_lock);
/* Record which locks this waiter needs. */
- wtr->wait_locks = need_locks;
+ wtr->uflgs = need_locks;
+
+ ASSERT((wtr->uflgs & ~ERTS_PROC_LOCKS_ALL) == 0);
#if ERTS_PROC_LOCK_ATOMIC_IMPL
erts_pix_lock(pix_lock);
@@ -489,14 +481,16 @@ wait_for_locks(Process *p,
ERTS_LC_ASSERT(erts_lc_pix_lock_is_locked(pix_lock));
+ qs = wtr->udata;
+ ASSERT(qs);
/* Provide the process with waiter queues, if it doesn't have one. */
if (!p->lock.queues) {
- wtr->queues->next = NULL;
- p->lock.queues = wtr->queues;
+ qs->next = NULL;
+ p->lock.queues = qs;
}
else {
- wtr->queues->next = p->lock.queues->next;
- p->lock.queues->next = wtr->queues;
+ qs->next = p->lock.queues->next;
+ p->lock.queues->next = qs;
}
#ifdef ERTS_PROC_LOCK_HARD_DEBUG
@@ -506,46 +500,59 @@ wait_for_locks(Process *p,
/* Try to aquire locks one at a time in lock order and set wait flag */
try_aquire(&p->lock, wtr);
+ ASSERT((wtr->uflgs & ~ERTS_PROC_LOCKS_ALL) == 0);
+
#ifdef ERTS_PROC_LOCK_HARD_DEBUG
check_queue(&p->lock);
#endif
- if (wtr->wait_locks) { /* We didn't get them all; need to wait... */
- /* Got to wait for locks... */
+ if (wtr->uflgs) {
+ /* We didn't get them all; need to wait... */
+
+ ASSERT((wtr->uflgs & ~ERTS_PROC_LOCKS_ALL) == 0);
+
+ erts_atomic_set(&wtr->uaflgs, 1);
erts_pix_unlock(pix_lock);
- /*
- * Wait for needed locks. When we return all needed locks have
- * have been acquired by other threads and transfered to us.
- */
-#ifdef ERTS_PROC_LOCK_SPIN_ON_GATE
- erts_smp_gate_swait(&wtr->gate, proc_lock_spin_count);
-#else
- erts_smp_gate_wait(&wtr->gate);
-#endif
+ while (1) {
+ int res;
+ erts_tse_reset(wtr);
+
+ if (erts_atomic_read(&wtr->uaflgs) == 0)
+ break;
+
+ /*
+ * Wait for needed locks. When we are woken all needed locks have
+ * have been acquired by other threads and transfered to us.
+ * However, we need to be prepared for spurious wakeups.
+ */
+ do {
+ res = erts_tse_wait(wtr); /* might return EINTR */
+ } while (res != 0);
+ }
erts_pix_lock(pix_lock);
+
+ ASSERT(wtr->uflgs == 0);
}
/* Recover some queues to store in the waiter. */
ERTS_LC_ASSERT(p->lock.queues);
if (p->lock.queues->next) {
- wtr->queues = p->lock.queues->next;
- p->lock.queues->next = wtr->queues->next;
+ qs = p->lock.queues->next;
+ p->lock.queues->next = qs->next;
}
else {
- wtr->queues = p->lock.queues;
+ qs = p->lock.queues;
p->lock.queues = NULL;
}
+ wtr->udata = qs;
erts_pix_unlock(pix_lock);
ERTS_LC_ASSERT(locks == (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks));
- if (tsd)
- CHECK_UNUSED_WAITER(wtr);
- else
- free_wtr(wtr);
+ tse_return(wtr, 0);
}
/*
@@ -563,52 +570,57 @@ erts_proc_lock_failed(Process *p,
ErtsProcLocks locks,
ErtsProcLocks old_lflgs)
{
-#ifdef ERTS_PROC_LOCK_SPIN_ON_GATE
- int spin_count = 0;
-#else
- int spin_count = proc_lock_spin_count;
-#endif
-
+ int until_yield = ERTS_PROC_LOCK_SPIN_UNTIL_YIELD;
+ int thr_spin_count;
+ int spin_count;
ErtsProcLocks need_locks = locks;
ErtsProcLocks olflgs = old_lflgs;
- while (need_locks != 0)
- {
- ErtsProcLocks can_grab = in_order_locks(olflgs, need_locks);
+ if (erts_thr_get_main_status())
+ thr_spin_count = proc_lock_spin_count;
+ else
+ thr_spin_count = aux_thr_proc_lock_spin_count;
+
+ spin_count = thr_spin_count;
+
+ while (need_locks != 0) {
+ ErtsProcLocks can_grab;
+
+ can_grab = in_order_locks(olflgs, need_locks);
- if (can_grab == 0)
- {
+ if (can_grab == 0) {
/* Someone already has the lowest-numbered lock we want. */
- if (spin_count-- <= 0)
- {
+ if (spin_count-- <= 0) {
/* Too many retries, give up and sleep for the lock. */
wait_for_locks(p, pixlck, locks, need_locks, olflgs);
return;
}
+ ERTS_SPIN_BODY;
+
+ if (--until_yield == 0) {
+ until_yield = ERTS_PROC_LOCK_SPIN_UNTIL_YIELD;
+ erts_thr_yield();
+ }
+
olflgs = ERTS_PROC_LOCK_FLGS_READ_(&p->lock);
}
- else
- {
+ else {
/* Try to grab all of the grabbable locks at once with cmpxchg. */
ErtsProcLocks grabbed = olflgs | can_grab;
ErtsProcLocks nflgs =
- ERTS_PROC_LOCK_FLGS_CMPXCHG_(&p->lock, grabbed, olflgs);
+ ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(&p->lock, grabbed, olflgs);
- if (nflgs == olflgs)
- {
+ if (nflgs == olflgs) {
/* Success! We grabbed the 'can_grab' locks. */
olflgs = grabbed;
need_locks &= ~can_grab;
-#ifndef ERTS_PROC_LOCK_SPIN_ON_GATE
/* Since we made progress, reset the spin count. */
- spin_count = proc_lock_spin_count;
-#endif
+ spin_count = thr_spin_count;
}
- else
- {
+ else {
/* Compare-and-exchange failed, try again. */
olflgs = nflgs;
}
@@ -1407,7 +1419,7 @@ check_queue(erts_proc_lock_t *lck)
wtr = (((ErtsProcLocks) 1) << lock_no) << ERTS_PROC_LOCK_WAITER_SHIFT;
if (lflgs & wtr) {
int n;
- erts_proc_lock_waiter_t *wtr;
+ erts_tse_t *wtr;
ERTS_LC_ASSERT(lck->queues && lck->queues->queue[lock_no]);
wtr = lck->queues->queue[lock_no];
n = 0;
diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h
index d71e5a0a6e..7cfc9893fa 100644
--- a/erts/emulator/beam/erl_process_lock.h
+++ b/erts/emulator/beam/erl_process_lock.h
@@ -255,11 +255,7 @@ void erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks);
typedef struct {
union {
-#if ERTS_PROC_LOCK_MUTEX_IMPL
- erts_smp_mtx_t mtx;
-#else
erts_smp_spinlock_t spnlck;
-#endif
char buf[64]; /* Try to get locks in different cache lines */
} u;
} erts_pix_lock_t;
@@ -277,9 +273,12 @@ typedef struct {
((ErtsProcLocks) erts_smp_atomic_band(&(L)->flags, (long) (MSK)))
#define ERTS_PROC_LOCK_FLGS_BOR_(L, MSK) \
((ErtsProcLocks) erts_smp_atomic_bor(&(L)->flags, (long) (MSK)))
-#define ERTS_PROC_LOCK_FLGS_CMPXCHG_(L, NEW, EXPECTED) \
- ((ErtsProcLocks) erts_smp_atomic_cmpxchg(&(L)->flags, \
- (long) (NEW), (long) (EXPECTED)))
+#define ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(L, NEW, EXPECTED) \
+ ((ErtsProcLocks) erts_smp_atomic_cmpxchg_acqb(&(L)->flags, \
+ (long) (NEW), (long) (EXPECTED)))
+#define ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(L, NEW, EXPECTED) \
+ ((ErtsProcLocks) erts_smp_atomic_cmpxchg_relb(&(L)->flags, \
+ (long) (NEW), (long) (EXPECTED)))
#define ERTS_PROC_LOCK_FLGS_READ_(L) \
((ErtsProcLocks) erts_smp_atomic_read(&(L)->flags))
@@ -289,6 +288,9 @@ ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_band(erts_proc_lock_t *,
ErtsProcLocks);
ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_bor(erts_proc_lock_t *,
ErtsProcLocks);
+ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *,
+ ErtsProcLocks,
+ ErtsProcLocks);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
@@ -322,7 +324,9 @@ erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *lck, ErtsProcLocks new,
#define ERTS_PROC_LOCK_FLGS_BAND_(L, MSK) erts_proc_lock_flags_band((L), (MSK))
#define ERTS_PROC_LOCK_FLGS_BOR_(L, MSK) erts_proc_lock_flags_bor((L), (MSK))
-#define ERTS_PROC_LOCK_FLGS_CMPXCHG_(L, NEW, EXPECTED) \
+#define ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(L, NEW, EXPECTED) \
+ erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED))
+#define ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(L, NEW, EXPECTED) \
erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED))
#define ERTS_PROC_LOCK_FLGS_READ_(L) ((L)->flags)
@@ -348,9 +352,9 @@ ERTS_GLB_INLINE ErtsProcLocks erts_smp_proc_raw_trylock__(Process *p,
ErtsProcLocks locks);
#ifdef ERTS_ENABLE_LOCK_COUNT
ERTS_GLB_INLINE void erts_smp_proc_lock_x__(Process *,
- erts_pix_lock_t *,
- ErtsProcLocks,
- char *file, unsigned int line);
+ erts_pix_lock_t *,
+ ErtsProcLocks,
+ char *file, unsigned int line);
#else
ERTS_GLB_INLINE void erts_smp_proc_lock__(Process *,
erts_pix_lock_t *,
@@ -372,30 +376,18 @@ ERTS_GLB_INLINE void erts_proc_lock_op_debug(Process *, ErtsProcLocks, int);
ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *pixlck)
{
ERTS_LC_ASSERT(pixlck);
-#if ERTS_PROC_LOCK_MUTEX_IMPL
- erts_smp_mtx_lock(&pixlck->u.mtx);
-#else
erts_smp_spin_lock(&pixlck->u.spnlck);
-#endif
}
ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *pixlck)
{
ERTS_LC_ASSERT(pixlck);
-#if ERTS_PROC_LOCK_MUTEX_IMPL
- erts_smp_mtx_unlock(&pixlck->u.mtx);
-#else
erts_smp_spin_unlock(&pixlck->u.spnlck);
-#endif
}
ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *pixlck)
{
-#if ERTS_PROC_LOCK_MUTEX_IMPL
- return erts_smp_lc_mtx_is_locked(&pixlck->u.mtx);
-#else
return erts_smp_lc_spinlock_is_locked(&pixlck->u.spnlck);
-#endif
}
/*
@@ -417,9 +409,9 @@ erts_smp_proc_raw_trylock__(Process *p, ErtsProcLocks locks)
ErtsProcLocks expct_lflgs = 0;
while (1) {
- ErtsProcLocks lflgs = ERTS_PROC_LOCK_FLGS_CMPXCHG_(&p->lock,
- expct_lflgs | locks,
- expct_lflgs);
+ ErtsProcLocks lflgs = ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(&p->lock,
+ expct_lflgs | locks,
+ expct_lflgs);
if (ERTS_LIKELY(lflgs == expct_lflgs)) {
/* We successfully grabbed all locks. */
return 0;
@@ -535,7 +527,7 @@ erts_smp_proc_unlock__(Process *p,
if (want_lflgs != old_lflgs) {
ErtsProcLocks new_lflgs =
- ERTS_PROC_LOCK_FLGS_CMPXCHG_(&p->lock, want_lflgs, old_lflgs);
+ ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(&p->lock, want_lflgs, old_lflgs);
if (new_lflgs != old_lflgs) {
/* cmpxchg failed, try again. */
diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h
index 03d2a586e3..b41fa70476 100644
--- a/erts/emulator/beam/erl_smp.h
+++ b/erts/emulator/beam/erl_smp.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
/*
@@ -43,9 +43,17 @@ typedef erts_thr_init_data_t erts_smp_thr_init_data_t;
typedef erts_tid_t erts_smp_tid_t;
typedef erts_mtx_t erts_smp_mtx_t;
typedef erts_cnd_t erts_smp_cnd_t;
+#define ERTS_SMP_RWMTX_OPT_DEFAULT_INITER ERTS_RWMTX_OPT_DEFAULT_INITER
+#define ERTS_SMP_RWMTX_TYPE_NORMAL ERTS_RWMTX_TYPE_NORMAL
+#define ERTS_SMP_RWMTX_TYPE_FREQUENT_READ ERTS_RWMTX_TYPE_FREQUENT_READ
+#define ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ \
+ ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ
+#define ERTS_SMP_RWMTX_LONG_LIVED ERTS_RWMTX_LONG_LIVED
+#define ERTS_SMP_RWMTX_SHORT_LIVED ERTS_RWMTX_SHORT_LIVED
+#define ERTS_SMP_RWMTX_UNKNOWN_LIVED ERTS_RWMTX_UNKNOWN_LIVED
+typedef erts_rwmtx_opt_t erts_smp_rwmtx_opt_t;
typedef erts_rwmtx_t erts_smp_rwmtx_t;
typedef erts_tsd_key_t erts_smp_tsd_key_t;
-typedef erts_gate_t erts_smp_gate_t;
typedef ethr_atomic_t erts_smp_atomic_t;
typedef erts_spinlock_t erts_smp_spinlock_t;
typedef erts_rwlock_t erts_smp_rwlock_t;
@@ -54,15 +62,27 @@ void erts_thr_fatal_error(int, char *); /* implemented in erl_init.c */
#else /* #ifdef ERTS_SMP */
-#define ERTS_SMP_THR_OPTS_DEFAULT_INITER 0
+#define ERTS_SMP_THR_OPTS_DEFAULT_INITER {0}
typedef int erts_smp_thr_opts_t;
typedef int erts_smp_thr_init_data_t;
typedef int erts_smp_tid_t;
typedef int erts_smp_mtx_t;
typedef int erts_smp_cnd_t;
+#define ERTS_SMP_RWMTX_OPT_DEFAULT_INITER {0}
+#define ERTS_SMP_RWMTX_TYPE_NORMAL 0
+#define ERTS_SMP_RWMTX_TYPE_FREQUENT_READ 0
+#define ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ 0
+#define ERTS_SMP_RWMTX_LONG_LIVED 0
+#define ERTS_SMP_RWMTX_SHORT_LIVED 0
+#define ERTS_SMP_RWMTX_UNKNOWN_LIVED 0
+typedef struct {
+ char type;
+ char lived;
+ int main_spincount;
+ int aux_spincount;
+} erts_smp_rwmtx_opt_t;
typedef int erts_smp_rwmtx_t;
typedef int erts_smp_tsd_key_t;
-typedef int erts_smp_gate_t;
typedef long erts_smp_atomic_t;
#if __GNUC__ > 2
typedef struct { } erts_smp_spinlock_t;
@@ -103,8 +123,6 @@ ERTS_GLB_INLINE void erts_smp_mtx_init_locked_x(erts_smp_mtx_t *mtx,
ERTS_GLB_INLINE void erts_smp_mtx_init(erts_smp_mtx_t *mtx, char *name);
ERTS_GLB_INLINE void erts_smp_mtx_init_locked(erts_smp_mtx_t *mtx, char *name);
ERTS_GLB_INLINE void erts_smp_mtx_destroy(erts_smp_mtx_t *mtx);
-ERTS_GLB_INLINE void erts_smp_mtx_set_forksafe(erts_smp_mtx_t *mtx);
-ERTS_GLB_INLINE void erts_smp_mtx_unset_forksafe(erts_smp_mtx_t *mtx);
ERTS_GLB_INLINE int erts_smp_mtx_trylock(erts_smp_mtx_t *mtx);
#ifdef ERTS_ENABLE_LOCK_COUNT
ERTS_GLB_INLINE void erts_smp_mtx_lock_x(erts_smp_mtx_t *mtx, char *file, int line);
@@ -119,9 +137,17 @@ ERTS_GLB_INLINE void erts_smp_cnd_wait(erts_smp_cnd_t *cnd,
erts_smp_mtx_t *mtx);
ERTS_GLB_INLINE void erts_smp_cnd_signal(erts_smp_cnd_t *cnd);
ERTS_GLB_INLINE void erts_smp_cnd_broadcast(erts_smp_cnd_t *cnd);
+ERTS_GLB_INLINE void erts_smp_rwmtx_set_reader_group(int no);
+ERTS_GLB_INLINE void erts_smp_rwmtx_init_opt_x(erts_smp_rwmtx_t *rwmtx,
+ erts_smp_rwmtx_opt_t *opt,
+ char *name,
+ Eterm extra);
ERTS_GLB_INLINE void erts_smp_rwmtx_init_x(erts_smp_rwmtx_t *rwmtx,
char *name,
Eterm extra);
+ERTS_GLB_INLINE void erts_smp_rwmtx_init_opt(erts_smp_rwmtx_t *rwmtx,
+ erts_smp_rwmtx_opt_t *opt,
+ char *name);
ERTS_GLB_INLINE void erts_smp_rwmtx_init(erts_smp_rwmtx_t *rwmtx,
char *name);
ERTS_GLB_INLINE void erts_smp_rwmtx_destroy(erts_smp_rwmtx_t *rwmtx);
@@ -155,6 +181,16 @@ ERTS_GLB_INLINE long erts_smp_atomic_cmpxchg(erts_smp_atomic_t *xchgp,
long expected);
ERTS_GLB_INLINE long erts_smp_atomic_bor(erts_smp_atomic_t *var, long mask);
ERTS_GLB_INLINE long erts_smp_atomic_band(erts_smp_atomic_t *var, long mask);
+ERTS_GLB_INLINE long erts_smp_atomic_read_acqb(erts_smp_atomic_t *var);
+ERTS_GLB_INLINE void erts_smp_atomic_set_relb(erts_smp_atomic_t *var, long i);
+ERTS_GLB_INLINE void erts_smp_atomic_dec_relb(erts_smp_atomic_t *decp);
+ERTS_GLB_INLINE long erts_smp_atomic_dectest_relb(erts_smp_atomic_t *decp);
+ERTS_GLB_INLINE long erts_smp_atomic_cmpxchg_acqb(erts_smp_atomic_t *xchgp,
+ long new,
+ long exp);
+ERTS_GLB_INLINE long erts_smp_atomic_cmpxchg_relb(erts_smp_atomic_t *xchgp,
+ long new,
+ long exp);
ERTS_GLB_INLINE void erts_smp_spinlock_init_x(erts_smp_spinlock_t *lock,
char *name,
Eterm extra);
@@ -190,12 +226,6 @@ ERTS_GLB_INLINE void erts_smp_tsd_key_create(erts_smp_tsd_key_t *keyp);
ERTS_GLB_INLINE void erts_smp_tsd_key_delete(erts_smp_tsd_key_t key);
ERTS_GLB_INLINE void erts_smp_tsd_set(erts_smp_tsd_key_t key, void *value);
ERTS_GLB_INLINE void * erts_smp_tsd_get(erts_smp_tsd_key_t key);
-ERTS_GLB_INLINE void erts_smp_gate_init(erts_smp_gate_t *gp);
-ERTS_GLB_INLINE void erts_smp_gate_destroy(erts_smp_gate_t *gp);
-ERTS_GLB_INLINE void erts_smp_gate_close(erts_smp_gate_t *gp);
-ERTS_GLB_INLINE void erts_smp_gate_let_through(erts_smp_gate_t *gp, unsigned no);
-ERTS_GLB_INLINE void erts_smp_gate_wait(erts_smp_gate_t *gp);
-ERTS_GLB_INLINE void erts_smp_gate_swait(erts_smp_gate_t *gp, int spincount);
#ifdef ERTS_THR_HAVE_SIG_FUNCS
#define ERTS_SMP_THR_HAVE_SIG_FUNCS 1
@@ -331,22 +361,6 @@ erts_smp_mtx_destroy(erts_smp_mtx_t *mtx)
#endif
}
-ERTS_GLB_INLINE void
-erts_smp_mtx_set_forksafe(erts_smp_mtx_t *mtx)
-{
-#ifdef ERTS_SMP
- erts_mtx_set_forksafe(mtx);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_mtx_unset_forksafe(erts_smp_mtx_t *mtx)
-{
-#ifdef ERTS_SMP
- erts_mtx_unset_forksafe(mtx);
-#endif
-}
-
ERTS_GLB_INLINE int
erts_smp_mtx_trylock(erts_smp_mtx_t *mtx)
{
@@ -433,6 +447,25 @@ erts_smp_cnd_broadcast(erts_smp_cnd_t *cnd)
}
ERTS_GLB_INLINE void
+erts_smp_rwmtx_set_reader_group(int no)
+{
+#ifdef ERTS_SMP
+ erts_rwmtx_set_reader_group(no);
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_smp_rwmtx_init_opt_x(erts_smp_rwmtx_t *rwmtx,
+ erts_smp_rwmtx_opt_t *opt,
+ char *name,
+ Eterm extra)
+{
+#ifdef ERTS_SMP
+ erts_rwmtx_init_opt_x(rwmtx, opt, name, extra);
+#endif
+}
+
+ERTS_GLB_INLINE void
erts_smp_rwmtx_init_x(erts_smp_rwmtx_t *rwmtx, char *name, Eterm extra)
{
#ifdef ERTS_SMP
@@ -441,6 +474,16 @@ erts_smp_rwmtx_init_x(erts_smp_rwmtx_t *rwmtx, char *name, Eterm extra)
}
ERTS_GLB_INLINE void
+erts_smp_rwmtx_init_opt(erts_smp_rwmtx_t *rwmtx,
+ erts_smp_rwmtx_opt_t *opt,
+ char *name)
+{
+#ifdef ERTS_SMP
+ erts_rwmtx_init_opt(rwmtx, opt, name);
+#endif
+}
+
+ERTS_GLB_INLINE void
erts_smp_rwmtx_init(erts_smp_rwmtx_t *rwmtx, char *name)
{
#ifdef ERTS_SMP
@@ -709,6 +752,73 @@ erts_smp_atomic_band(erts_smp_atomic_t *var, long mask)
#endif
}
+ERTS_GLB_INLINE long
+erts_smp_atomic_read_acqb(erts_smp_atomic_t *var)
+{
+#ifdef ERTS_SMP
+ return erts_atomic_read_acqb(var);
+#else
+ return *var;
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_smp_atomic_set_relb(erts_smp_atomic_t *var, long i)
+{
+#ifdef ERTS_SMP
+ erts_atomic_set_relb(var, i);
+#else
+ *var = i;
+#endif
+}
+
+ERTS_GLB_INLINE void erts_smp_atomic_dec_relb(erts_smp_atomic_t *decp)
+{
+#ifdef ERTS_SMP
+ erts_atomic_dec_relb(decp);
+#else
+ --(*decp);
+#endif
+}
+
+ERTS_GLB_INLINE long
+erts_smp_atomic_dectest_relb(erts_smp_atomic_t *decp)
+{
+#ifdef ERTS_SMP
+ return erts_atomic_dectest_relb(decp);
+#else
+ return --(*decp);
+#endif
+}
+
+ERTS_GLB_INLINE long erts_smp_atomic_cmpxchg_acqb(erts_smp_atomic_t *xchgp,
+ long new,
+ long exp)
+{
+#ifdef ERTS_SMP
+ return erts_atomic_cmpxchg_acqb(xchgp, new, exp);
+#else
+ long old = *xchgp;
+ if (old == exp)
+ *xchgp = new;
+ return old;
+#endif
+}
+
+ERTS_GLB_INLINE long erts_smp_atomic_cmpxchg_relb(erts_smp_atomic_t *xchgp,
+ long new,
+ long exp)
+{
+#ifdef ERTS_SMP
+ return erts_atomic_cmpxchg_relb(xchgp, new, exp);
+#else
+ long old = *xchgp;
+ if (old == exp)
+ *xchgp = new;
+ return old;
+#endif
+}
+
ERTS_GLB_INLINE void
erts_smp_spinlock_init_x(erts_smp_spinlock_t *lock, char *name, Eterm extra)
{
@@ -919,54 +1029,6 @@ erts_smp_tsd_get(erts_smp_tsd_key_t key)
#endif
}
-ERTS_GLB_INLINE void
-erts_smp_gate_init(erts_smp_gate_t *gp)
-{
-#ifdef ERTS_SMP
- erts_gate_init((erts_gate_t *) gp);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_gate_destroy(erts_smp_gate_t *gp)
-{
-#ifdef ERTS_SMP
- erts_gate_destroy((erts_gate_t *) gp);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_gate_close(erts_smp_gate_t *gp)
-{
-#ifdef ERTS_SMP
- erts_gate_close((erts_gate_t *) gp);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_gate_let_through(erts_smp_gate_t *gp, unsigned no)
-{
-#ifdef ERTS_SMP
- erts_gate_let_through((erts_gate_t *) gp, no);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_gate_wait(erts_smp_gate_t *gp)
-{
-#ifdef ERTS_SMP
- erts_gate_wait((erts_gate_t *) gp);
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_smp_gate_swait(erts_smp_gate_t *gp, int spincount)
-{
-#ifdef ERTS_SMP
- erts_gate_swait((erts_gate_t *) gp, spincount);
-#endif
-}
-
#ifdef ERTS_THR_HAVE_SIG_FUNCS
#define ERTS_SMP_THR_HAVE_SIG_FUNCS 1
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index 3a8c30fe6a..b8e4473141 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -821,10 +821,10 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |A A A A A A A A A A A A A A A A A A A A A A A A A A|t t t t|0 0| Thing
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N| Next
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E E| ErlNode
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N| Next
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X| Data 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* . . .
@@ -835,7 +835,7 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm)
* t : External pid thing tag (1100)
* t : External port thing tag (1101)
* t : External ref thing tag (1110)
- * N : Next (external thing) pointer
+ * N : Next (off_heap) pointer
* E : ErlNode pointer
* X : Type specific data
*
@@ -852,13 +852,16 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_ref_node,Eterm)
/* XXX:PaN - this structure is not perfect for halfword heap, it takes
a lot of memory due to padding, and the array will not begin at the end of the
structure, as otherwise expected. Be sure to access data.ui32 array and not try
- to do pointer manipulation on an Eterm * to reach the actual data... */
+ to do pointer manipulation on an Eterm * to reach the actual data...
+ XXX:Sverk - Problem made worse by "one off-heap list" when 'next' pointer
+ must align with 'next' in ProcBin, erl_fun_thing and erl_off_heap_header.
+*/
typedef struct external_thing_ {
/* ----+ */
Eterm header; /* | */
- struct external_thing_ *next; /* > External thing head */
- struct erl_node_ *node; /* | */
+ struct erl_node_* node; /* > External thing head */
+ struct erl_off_heap_header* next; /* | */
/* ----+ */
union {
Uint32 ui32[1];
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index 35b338c6eb..0b7269262e 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -25,6 +25,11 @@
#ifndef ERL_THREAD_H__
#define ERL_THREAD_H__
+#define ERTS_SPIN_BODY ETHR_SPIN_BODY
+
+#define ERTS_MAX_READER_GROUPS 8
+extern int erts_reader_groups;
+
#include "sys.h"
#ifdef USE_THREADS
@@ -48,6 +53,7 @@
#define ERTS_THR_OPTS_DEFAULT_INITER ETHR_THR_OPTS_DEFAULT_INITER
typedef ethr_thr_opts erts_thr_opts_t;
typedef ethr_init_data erts_thr_init_data_t;
+typedef ethr_late_init_data erts_thr_late_init_data_t;
typedef ethr_tid erts_tid_t;
/* mutex */
@@ -73,8 +79,19 @@ typedef struct {
erts_lcnt_lock_t lcnt;
#endif
} erts_rwmtx_t;
+
+#define ERTS_RWMTX_OPT_DEFAULT_INITER ETHR_RWMUTEX_OPT_DEFAULT_INITER
+#define ERTS_RWMTX_TYPE_NORMAL ETHR_RWMUTEX_TYPE_NORMAL
+#define ERTS_RWMTX_TYPE_FREQUENT_READ ETHR_RWMUTEX_TYPE_FREQUENT_READ
+#define ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ \
+ ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ
+#define ERTS_RWMTX_LONG_LIVED ETHR_RWMUTEX_LONG_LIVED
+#define ERTS_RWMTX_SHORT_LIVED ETHR_RWMUTEX_SHORT_LIVED
+#define ERTS_RWMTX_UNKNOWN_LIVED ETHR_RWMUTEX_UNKNOWN_LIVED
+typedef ethr_rwmutex_opt erts_rwmtx_opt_t;
+
typedef ethr_tsd_key erts_tsd_key_t;
-typedef ethr_gate erts_gate_t;
+typedef ethr_ts_event erts_tse_t;
typedef ethr_atomic_t erts_atomic_t;
/* spinlock */
@@ -103,25 +120,14 @@ typedef ethr_timeval erts_thr_timeval_t;
__decl_noreturn void __noreturn erts_thr_fatal_error(int, char *);
/* implemented in erl_init.c */
-#ifdef ERTS_ENABLE_LOCK_CHECK
-#define ERTS_REC_MTX_INITER \
- {ETHR_REC_MUTEX_INITER, \
- ERTS_LC_LOCK_INIT(-1,THE_NON_VALUE,ERTS_LC_FLG_LT_MUTEX)}
-#define ERTS_MTX_INITER \
- {ETHR_MUTEX_INITER, \
- ERTS_LC_LOCK_INIT(-1, THE_NON_VALUE, ERTS_LC_FLG_LT_MUTEX)}
-#else
-#define ERTS_REC_MTX_INITER {ETHR_REC_MUTEX_INITER}
-#define ERTS_MTX_INITER {ETHR_MUTEX_INITER}
-#endif
-#define ERTS_CND_INITER ETHR_COND_INITER
#define ERTS_THR_INIT_DATA_DEF_INITER ETHR_INIT_DATA_DEFAULT_INITER
+#define ERTS_THR_LATE_INIT_DATA_DEF_INITER \
+ ETHR_LATE_INIT_DATA_DEFAULT_INITER
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
# define ERTS_HAVE_REC_MTX_INIT ETHR_HAVE_ETHR_REC_MUTEX_INIT
#endif
-
#else /* #ifdef USE_THREADS */
#define ERTS_THR_MEMORY_BARRIER
@@ -129,12 +135,26 @@ __decl_noreturn void __noreturn erts_thr_fatal_error(int, char *);
#define ERTS_THR_OPTS_DEFAULT_INITER 0
typedef int erts_thr_opts_t;
typedef int erts_thr_init_data_t;
+typedef int erts_thr_late_init_data_t;
typedef int erts_tid_t;
typedef int erts_mtx_t;
typedef int erts_cnd_t;
+#define ERTS_RWMTX_OPT_DEFAULT_INITER {0}
+#define ERTS_RWMTX_TYPE_NORMAL 0
+#define ERTS_RWMTX_TYPE_FREQUENT_READ 0
+#define ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ 0
+#define ERTS_RWMTX_LONG_LIVED 0
+#define ERTS_RWMTX_SHORT_LIVED 0
+#define ERTS_RWMTX_UNKNOWN_LIVED 0
+typedef struct {
+ char type;
+ char lived;
+ int main_spincount;
+ int aux_spincount;
+} erts_rwmtx_opt_t;
typedef int erts_rwmtx_t;
typedef int erts_tsd_key_t;
-typedef int erts_gate_t;
+typedef int erts_tse_t;
typedef long erts_atomic_t;
#if __GNUC__ > 2
typedef struct { } erts_spinlock_t;
@@ -148,7 +168,6 @@ typedef struct {
long tv_nsec;
} erts_thr_timeval_t;
-#define ERTS_REC_MTX_INITER 0
#define ERTS_MTX_INITER 0
#define ERTS_CND_INITER 0
#define ERTS_THR_INIT_DATA_DEF_INITER 0
@@ -158,6 +177,7 @@ typedef struct {
#endif /* #ifdef USE_THREADS */
ERTS_GLB_INLINE void erts_thr_init(erts_thr_init_data_t *id);
+ERTS_GLB_INLINE void erts_thr_late_init(erts_thr_late_init_data_t *id);
ERTS_GLB_INLINE void erts_thr_create(erts_tid_t *tid, void * (*func)(void *),
void *arg, erts_thr_opts_t *opts);
ERTS_GLB_INLINE void erts_thr_join(erts_tid_t tid, void **thr_res);
@@ -166,9 +186,6 @@ ERTS_GLB_INLINE void erts_thr_exit(void *res);
ERTS_GLB_INLINE void erts_thr_install_exit_handler(void (*exit_handler)(void));
ERTS_GLB_INLINE erts_tid_t erts_thr_self(void);
ERTS_GLB_INLINE int erts_equal_tids(erts_tid_t x, erts_tid_t y);
-#ifdef ERTS_HAVE_REC_MTX_INIT
-ERTS_GLB_INLINE void erts_rec_mtx_init(erts_mtx_t *mtx);
-#endif
ERTS_GLB_INLINE void erts_mtx_init_x(erts_mtx_t *mtx, char *name, Eterm extra);
ERTS_GLB_INLINE void erts_mtx_init_x_opt(erts_mtx_t *mtx, char *name, Eterm extra, Uint16 opt);
ERTS_GLB_INLINE void erts_mtx_init_locked_x(erts_mtx_t *mtx,
@@ -177,8 +194,6 @@ ERTS_GLB_INLINE void erts_mtx_init_locked_x(erts_mtx_t *mtx,
ERTS_GLB_INLINE void erts_mtx_init(erts_mtx_t *mtx, char *name);
ERTS_GLB_INLINE void erts_mtx_init_locked(erts_mtx_t *mtx, char *name);
ERTS_GLB_INLINE void erts_mtx_destroy(erts_mtx_t *mtx);
-ERTS_GLB_INLINE void erts_mtx_set_forksafe(erts_mtx_t *mtx);
-ERTS_GLB_INLINE void erts_mtx_unset_forksafe(erts_mtx_t *mtx);
ERTS_GLB_INLINE int erts_mtx_trylock(erts_mtx_t *mtx);
#ifdef ERTS_ENABLE_LOCK_COUNT
ERTS_GLB_INLINE void erts_mtx_lock_x(erts_mtx_t *mtx, char *file, unsigned int line);
@@ -192,9 +207,17 @@ ERTS_GLB_INLINE void erts_cnd_destroy(erts_cnd_t *cnd);
ERTS_GLB_INLINE void erts_cnd_wait(erts_cnd_t *cnd, erts_mtx_t *mtx);
ERTS_GLB_INLINE void erts_cnd_signal(erts_cnd_t *cnd);
ERTS_GLB_INLINE void erts_cnd_broadcast(erts_cnd_t *cnd);
+ERTS_GLB_INLINE void erts_rwmtx_set_reader_group(int no);
+ERTS_GLB_INLINE void erts_rwmtx_init_opt_x(erts_rwmtx_t *rwmtx,
+ erts_rwmtx_opt_t *opt,
+ char *name,
+ Eterm extra);
ERTS_GLB_INLINE void erts_rwmtx_init_x(erts_rwmtx_t *rwmtx,
char *name,
Eterm extra);
+ERTS_GLB_INLINE void erts_rwmtx_init_opt(erts_rwmtx_t *rwmtx,
+ erts_rwmtx_opt_t *opt,
+ char *name);
ERTS_GLB_INLINE void erts_rwmtx_init(erts_rwmtx_t *rwmtx,
char *name);
ERTS_GLB_INLINE void erts_rwmtx_destroy(erts_rwmtx_t *rwmtx);
@@ -228,6 +251,20 @@ ERTS_GLB_INLINE long erts_atomic_cmpxchg(erts_atomic_t *xchgp,
long expected);
ERTS_GLB_INLINE long erts_atomic_bor(erts_atomic_t *var, long mask);
ERTS_GLB_INLINE long erts_atomic_band(erts_atomic_t *var, long mask);
+ERTS_GLB_INLINE long erts_atomic_read_acqb(erts_atomic_t *var);
+ERTS_GLB_INLINE void erts_atomic_set_relb(erts_atomic_t *var, long i);
+ERTS_GLB_INLINE void erts_atomic_dec_relb(erts_atomic_t *decp);
+ERTS_GLB_INLINE long erts_atomic_dectest_relb(erts_atomic_t *decp);
+ERTS_GLB_INLINE long erts_atomic_cmpxchg_acqb(erts_atomic_t *xchgp,
+ long new,
+ long exp);
+ERTS_GLB_INLINE long erts_atomic_cmpxchg_relb(erts_atomic_t *xchgp,
+ long new,
+ long exp);
+ERTS_GLB_INLINE void erts_spinlock_init_x_opt(erts_spinlock_t *lock,
+ char *name,
+ Eterm extra,
+ Uint16 opt);
ERTS_GLB_INLINE void erts_spinlock_init_x(erts_spinlock_t *lock,
char *name,
Eterm extra);
@@ -263,12 +300,16 @@ ERTS_GLB_INLINE void erts_tsd_key_create(erts_tsd_key_t *keyp);
ERTS_GLB_INLINE void erts_tsd_key_delete(erts_tsd_key_t key);
ERTS_GLB_INLINE void erts_tsd_set(erts_tsd_key_t key, void *value);
ERTS_GLB_INLINE void * erts_tsd_get(erts_tsd_key_t key);
-ERTS_GLB_INLINE void erts_gate_init(erts_gate_t *gp);
-ERTS_GLB_INLINE void erts_gate_destroy(erts_gate_t *gp);
-ERTS_GLB_INLINE void erts_gate_close(erts_gate_t *gp);
-ERTS_GLB_INLINE void erts_gate_let_through(erts_gate_t *gp, unsigned no);
-ERTS_GLB_INLINE void erts_gate_wait(erts_gate_t *gp);
-ERTS_GLB_INLINE void erts_gate_swait(erts_gate_t *gp, int spincount);
+ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void);
+ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep);
+ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep);
+ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep);
+ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep);
+ERTS_GLB_INLINE int erts_tse_swait(erts_tse_t *ep, int spincount);
+ERTS_GLB_INLINE int erts_tse_is_tmp(erts_tse_t *ep);
+ERTS_GLB_INLINE void erts_thr_set_main_status(int, int);
+ERTS_GLB_INLINE int erts_thr_get_main_status(void);
+ERTS_GLB_INLINE void erts_thr_yield(void);
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
#define ERTS_THR_HAVE_SIG_FUNCS 1
@@ -290,6 +331,16 @@ erts_thr_init(erts_thr_init_data_t *id)
}
ERTS_GLB_INLINE void
+erts_thr_late_init(erts_thr_late_init_data_t *id)
+{
+#ifdef USE_THREADS
+ int res = ethr_late_init(id);
+ if (res)
+ erts_thr_fatal_error(res, "complete initialization of thread library");
+#endif
+}
+
+ERTS_GLB_INLINE void
erts_thr_create(erts_tid_t *tid, void * (*func)(void *), void *arg,
erts_thr_opts_t *opts)
{
@@ -362,20 +413,6 @@ erts_equal_tids(erts_tid_t x, erts_tid_t y)
#endif
}
-
-#ifdef ERTS_HAVE_REC_MTX_INIT
-ERTS_GLB_INLINE void
-erts_rec_mtx_init(erts_mtx_t *mtx)
-{
-#ifdef USE_THREADS
- int res = ethr_rec_mutex_init(&mtx->mtx);
- if (res)
- erts_thr_fatal_error(res, "initialize recursive mutex");
-#endif
-}
-#endif
-
-
ERTS_GLB_INLINE void
erts_mtx_init_x(erts_mtx_t *mtx, char *name, Eterm extra)
{
@@ -422,9 +459,7 @@ erts_mtx_init_locked_x(erts_mtx_t *mtx, char *name, Eterm extra)
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init_lock_x(&mtx->lcnt, name, ERTS_LCNT_LT_MUTEX, extra);
#endif
- res = ethr_mutex_lock(&mtx->mtx);
- if (res)
- erts_thr_fatal_error(res, "lock mutex");
+ ethr_mutex_lock(&mtx->mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &mtx->lc);
#endif
@@ -463,9 +498,7 @@ erts_mtx_init_locked(erts_mtx_t *mtx, char *name)
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init_lock(&mtx->lcnt, name, ERTS_LCNT_LT_MUTEX);
#endif
- res = ethr_mutex_lock(&mtx->mtx);
- if (res)
- erts_thr_fatal_error(res, "lock mutex");
+ ethr_mutex_lock(&mtx->mtx);
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &mtx->lc);
#endif
@@ -492,26 +525,6 @@ erts_mtx_destroy(erts_mtx_t *mtx)
#endif
}
-ERTS_GLB_INLINE void
-erts_mtx_set_forksafe(erts_mtx_t *mtx)
-{
-#ifdef USE_THREADS
- int res = ethr_mutex_set_forksafe(&mtx->mtx);
- if (res != 0 && res != ENOTSUP)
- erts_thr_fatal_error(res, "set mutex forksafe");
-#endif
-}
-
-ERTS_GLB_INLINE void
-erts_mtx_unset_forksafe(erts_mtx_t *mtx)
-{
-#ifdef USE_THREADS
- int res = ethr_mutex_unset_forksafe(&mtx->mtx);
- if (res != 0 && res != ENOTSUP)
- erts_thr_fatal_error(res, "unset mutex forksafe");
-#endif
-}
-
ERTS_GLB_INLINE int
erts_mtx_trylock(erts_mtx_t *mtx)
{
@@ -531,11 +544,7 @@ erts_mtx_trylock(erts_mtx_t *mtx)
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock(&mtx->lcnt, res);
-#endif
-
- if (res != 0 && res != EBUSY)
- erts_thr_fatal_error(res, "try lock mutex");
-
+#endif
return res;
#else
return 0;
@@ -551,19 +560,16 @@ erts_mtx_lock(erts_mtx_t *mtx)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock(&mtx->lc);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock(&mtx->lcnt);
#endif
- res = ethr_mutex_lock(&mtx->mtx);
+ ethr_mutex_lock(&mtx->mtx);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&mtx->lcnt, file, line);
#endif
- if (res)
- erts_thr_fatal_error(res, "lock mutex");
#endif
}
@@ -571,16 +577,13 @@ ERTS_GLB_INLINE void
erts_mtx_unlock(erts_mtx_t *mtx)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock(&mtx->lc);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock(&mtx->lcnt);
#endif
- res = ethr_mutex_unlock(&mtx->mtx);
- if (res)
- erts_thr_fatal_error(res, "unlock mutex");
+ ethr_mutex_unlock(&mtx->mtx);
#endif
}
@@ -648,9 +651,7 @@ ERTS_GLB_INLINE void
erts_cnd_signal(erts_cnd_t *cnd)
{
#ifdef USE_THREADS
- int res = ethr_cond_signal(cnd);
- if (res)
- erts_thr_fatal_error(res, "signal on condition variable");
+ ethr_cond_signal(cnd);
#endif
}
@@ -659,19 +660,34 @@ ERTS_GLB_INLINE void
erts_cnd_broadcast(erts_cnd_t *cnd)
{
#ifdef USE_THREADS
- int res = ethr_cond_broadcast(cnd);
- if (res)
- erts_thr_fatal_error(res, "broadcast on condition variable");
+ ethr_cond_broadcast(cnd);
#endif
}
/* rwmutex */
ERTS_GLB_INLINE void
-erts_rwmtx_init_x(erts_rwmtx_t *rwmtx, char *name, Eterm extra)
+erts_rwmtx_set_reader_group(int no)
{
#ifdef USE_THREADS
- int res = ethr_rwmutex_init(&rwmtx->rwmtx);
+ int res;
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_check_no_locked_of_type(ERTS_LC_FLG_LT_RWMUTEX);
+#endif
+ res = ethr_rwmutex_set_reader_group(no);
+ if (res != 0)
+ erts_thr_fatal_error(res, "set reader group");
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_rwmtx_init_opt_x(erts_rwmtx_t *rwmtx,
+ erts_rwmtx_opt_t *opt,
+ char *name,
+ Eterm extra)
+{
+#ifdef USE_THREADS
+ int res = ethr_rwmutex_init_opt(&rwmtx->rwmtx, opt);
if (res != 0)
erts_thr_fatal_error(res, "initialize rwmutex");
#ifdef ERTS_ENABLE_LOCK_CHECK
@@ -684,10 +700,20 @@ erts_rwmtx_init_x(erts_rwmtx_t *rwmtx, char *name, Eterm extra)
}
ERTS_GLB_INLINE void
-erts_rwmtx_init(erts_rwmtx_t *rwmtx, char *name)
+erts_rwmtx_init_x(erts_rwmtx_t *rwmtx,
+ char *name,
+ Eterm extra)
+{
+ erts_rwmtx_init_opt_x(rwmtx, NULL, name, extra);
+}
+
+ERTS_GLB_INLINE void
+erts_rwmtx_init_opt(erts_rwmtx_t *rwmtx,
+ erts_rwmtx_opt_t *opt,
+ char *name)
{
#ifdef USE_THREADS
- int res = ethr_rwmutex_init(&rwmtx->rwmtx);
+ int res = ethr_rwmutex_init_opt(&rwmtx->rwmtx, opt);
if (res != 0)
erts_thr_fatal_error(res, "initialize rwmutex");
#ifdef ERTS_ENABLE_LOCK_CHECK
@@ -700,6 +726,12 @@ erts_rwmtx_init(erts_rwmtx_t *rwmtx, char *name)
}
ERTS_GLB_INLINE void
+erts_rwmtx_init(erts_rwmtx_t *rwmtx, char *name)
+{
+ erts_rwmtx_init_opt(rwmtx, NULL, name);
+}
+
+ERTS_GLB_INLINE void
erts_rwmtx_destroy(erts_rwmtx_t *rwmtx)
{
#ifdef USE_THREADS
@@ -736,9 +768,6 @@ erts_rwmtx_tryrlock(erts_rwmtx_t *rwmtx)
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock_opt(&rwmtx->lcnt, res, ERTS_LCNT_LO_READ);
#endif
-
- if (res != 0 && res != EBUSY)
- erts_thr_fatal_error(res, "try read lock rwmutex");
return res;
#else
@@ -754,19 +783,16 @@ erts_rwmtx_rlock(erts_rwmtx_t *rwmtx)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock_flg(&rwmtx->lc, ERTS_LC_FLG_LO_READ);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&rwmtx->lcnt, ERTS_LCNT_LO_READ);
#endif
- res = ethr_rwmutex_rlock(&rwmtx->rwmtx);
+ ethr_rwmutex_rlock(&rwmtx->rwmtx);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&rwmtx->lcnt, file, line);
#endif
- if (res != 0)
- erts_thr_fatal_error(res, "read lock rwmutex");
#endif
}
@@ -774,16 +800,13 @@ ERTS_GLB_INLINE void
erts_rwmtx_runlock(erts_rwmtx_t *rwmtx)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&rwmtx->lc, ERTS_LC_FLG_LO_READ);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&rwmtx->lcnt, ERTS_LCNT_LO_READ);
#endif
- res = ethr_rwmutex_runlock(&rwmtx->rwmtx);
- if (res != 0)
- erts_thr_fatal_error(res, "read unlock rwmutex");
+ ethr_rwmutex_runlock(&rwmtx->rwmtx);
#endif
}
@@ -808,9 +831,6 @@ erts_rwmtx_tryrwlock(erts_rwmtx_t *rwmtx)
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock_opt(&rwmtx->lcnt, res, ERTS_LCNT_LO_READ_WRITE);
#endif
-
- if (res != 0 && res != EBUSY)
- erts_thr_fatal_error(res, "try write lock rwmutex");
return res;
#else
@@ -826,19 +846,16 @@ erts_rwmtx_rwlock(erts_rwmtx_t *rwmtx)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock_flg(&rwmtx->lc, ERTS_LC_FLG_LO_READ_WRITE);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&rwmtx->lcnt, ERTS_LCNT_LO_READ_WRITE);
#endif
- res = ethr_rwmutex_rwlock(&rwmtx->rwmtx);
+ ethr_rwmutex_rwlock(&rwmtx->rwmtx);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&rwmtx->lcnt, file, line);
#endif
- if (res != 0)
- erts_thr_fatal_error(res, "write lock rwmutex");
#endif
}
@@ -846,16 +863,13 @@ ERTS_GLB_INLINE void
erts_rwmtx_rwunlock(erts_rwmtx_t *rwmtx)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&rwmtx->lc, ERTS_LC_FLG_LO_READ_WRITE);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&rwmtx->lcnt, ERTS_LCNT_LO_READ_WRITE);
#endif
- res = ethr_rwmutex_rwunlock(&rwmtx->rwmtx);
- if (res != 0)
- erts_thr_fatal_error(res, "write unlock rwmutex");
+ ethr_rwmutex_rwunlock(&rwmtx->rwmtx);
#endif
}
@@ -917,9 +931,7 @@ ERTS_GLB_INLINE void
erts_atomic_init(erts_atomic_t *var, long i)
{
#ifdef USE_THREADS
- int res = ethr_atomic_init(var, i);
- if (res)
- erts_thr_fatal_error(res, "perform atomic init");
+ ethr_atomic_init(var, i);
#else
*var = i;
#endif
@@ -929,9 +941,7 @@ ERTS_GLB_INLINE void
erts_atomic_set(erts_atomic_t *var, long i)
{
#ifdef USE_THREADS
- int res = ethr_atomic_set(var, i);
- if (res)
- erts_thr_fatal_error(res, "perform atomic set");
+ ethr_atomic_set(var, i);
#else
*var = i;
#endif
@@ -941,11 +951,7 @@ ERTS_GLB_INLINE long
erts_atomic_read(erts_atomic_t *var)
{
#ifdef USE_THREADS
- long i;
- int res = ethr_atomic_read(var, &i);
- if (res)
- erts_thr_fatal_error(res, "perform atomic read");
- return i;
+ return ethr_atomic_read(var);
#else
return *var;
#endif
@@ -955,11 +961,7 @@ ERTS_GLB_INLINE long
erts_atomic_inctest(erts_atomic_t *incp)
{
#ifdef USE_THREADS
- long test;
- int res = ethr_atomic_inctest(incp, &test);
- if (res)
- erts_thr_fatal_error(res, "perform atomic increment and test");
- return test;
+ return ethr_atomic_inc_read(incp);
#else
return ++(*incp);
#endif
@@ -969,11 +971,7 @@ ERTS_GLB_INLINE long
erts_atomic_dectest(erts_atomic_t *decp)
{
#ifdef USE_THREADS
- long test;
- int res = ethr_atomic_dectest(decp, &test);
- if (res)
- erts_thr_fatal_error(res, "perform atomic decrement and test");
- return test;
+ return ethr_atomic_dec_read(decp);
#else
return --(*decp);
#endif
@@ -983,9 +981,7 @@ ERTS_GLB_INLINE void
erts_atomic_inc(erts_atomic_t *incp)
{
#ifdef USE_THREADS
- int res = ethr_atomic_inc(incp);
- if (res)
- erts_thr_fatal_error(res, "perform atomic increment");
+ ethr_atomic_inc(incp);
#else
++(*incp);
#endif
@@ -995,9 +991,7 @@ ERTS_GLB_INLINE void
erts_atomic_dec(erts_atomic_t *decp)
{
#ifdef USE_THREADS
- int res = ethr_atomic_dec(decp);
- if (res)
- erts_thr_fatal_error(res, "perform atomic decrement");
+ ethr_atomic_dec(decp);
#else
--(*decp);
#endif
@@ -1007,11 +1001,7 @@ ERTS_GLB_INLINE long
erts_atomic_addtest(erts_atomic_t *addp, long i)
{
#ifdef USE_THREADS
- long test;
- int res = ethr_atomic_addtest(addp, i, &test);
- if (res)
- erts_thr_fatal_error(res, "perform atomic addition and test");
- return test;
+ return ethr_atomic_add_read(addp, i);
#else
return *addp += i;
#endif
@@ -1021,9 +1011,7 @@ ERTS_GLB_INLINE void
erts_atomic_add(erts_atomic_t *addp, long i)
{
#ifdef USE_THREADS
- int res = ethr_atomic_add(addp, i);
- if (res)
- erts_thr_fatal_error(res, "perform atomic addition");
+ ethr_atomic_add(addp, i);
#else
*addp += i;
#endif
@@ -1034,9 +1022,7 @@ erts_atomic_xchg(erts_atomic_t *xchgp, long new)
{
long old;
#ifdef USE_THREADS
- int res = ethr_atomic_xchg(xchgp, new, &old);
- if (res)
- erts_thr_fatal_error(res, "perform atomic exchange");
+ return ethr_atomic_xchg(xchgp, new);
#else
old = *xchgp;
*xchgp = new;
@@ -1048,11 +1034,7 @@ ERTS_GLB_INLINE long
erts_atomic_cmpxchg(erts_atomic_t *xchgp, long new, long expected)
{
#ifdef USE_THREADS
- long old;
- int res = ethr_atomic_cmpxchg(xchgp, new, expected, &old);
- if (ERTS_UNLIKELY(res != 0))
- erts_thr_fatal_error(res, "perform atomic exchange");
- return old;
+ return ethr_atomic_cmpxchg(xchgp, new, expected);
#else
long old = *xchgp;
if (old == expected)
@@ -1064,31 +1046,95 @@ erts_atomic_cmpxchg(erts_atomic_t *xchgp, long new, long expected)
ERTS_GLB_INLINE long
erts_atomic_bor(erts_atomic_t *var, long mask)
{
- long old;
#ifdef USE_THREADS
- int res = ethr_atomic_or_old(var, mask, &old);
- if (res != 0)
- erts_thr_fatal_error(res, "perform atomic bitwise or");
+ return ethr_atomic_read_bor(var, mask);
#else
+ long old;
old = *var;
*var |= mask;
-#endif
return old;
+#endif
}
ERTS_GLB_INLINE long
erts_atomic_band(erts_atomic_t *var, long mask)
{
- long old;
#ifdef USE_THREADS
- int res = ethr_atomic_and_old(var, mask, &old);
- if (res != 0)
- erts_thr_fatal_error(res, "perform atomic bitwise and");
+ return ethr_atomic_read_band(var, mask);
#else
+ long old;
old = *var;
*var &= mask;
+ return old;
+#endif
+}
+
+ERTS_GLB_INLINE long
+erts_atomic_read_acqb(erts_atomic_t *var)
+{
+#ifdef USE_THREADS
+ return ethr_atomic_read_acqb(var);
+#else
+ return *var;
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_atomic_set_relb(erts_atomic_t *var, long i)
+{
+#ifdef USE_THREADS
+ ethr_atomic_set_relb(var, i);
+#else
+ *var = i;
+#endif
+}
+
+ERTS_GLB_INLINE void
+erts_atomic_dec_relb(erts_atomic_t *decp)
+{
+#ifdef USE_THREADS
+ ethr_atomic_dec_relb(decp);
+#else
+ --(*decp);
+#endif
+}
+
+ERTS_GLB_INLINE long
+erts_atomic_dectest_relb(erts_atomic_t *decp)
+{
+#ifdef USE_THREADS
+ return ethr_atomic_dec_read_relb(decp);
+#else
+ return --(*decp);
#endif
+}
+
+ERTS_GLB_INLINE long erts_atomic_cmpxchg_acqb(erts_atomic_t *xchgp,
+ long new,
+ long exp)
+{
+#ifdef USE_THREADS
+ return ethr_atomic_cmpxchg_acqb(xchgp, new, exp);
+#else
+ long old = *xchgp;
+ if (old == exp)
+ *xchgp = new;
+ return old;
+#endif
+}
+
+ERTS_GLB_INLINE long erts_atomic_cmpxchg_relb(erts_atomic_t *xchgp,
+ long new,
+ long exp)
+{
+#ifdef USE_THREADS
+ return ethr_atomic_cmpxchg_relb(xchgp, new, exp);
+#else
+ long old = *xchgp;
+ if (old == exp)
+ *xchgp = new;
return old;
+#endif
}
/* spinlock */
@@ -1112,6 +1158,26 @@ erts_spinlock_init_x(erts_spinlock_t *lock, char *name, Eterm extra)
}
ERTS_GLB_INLINE void
+erts_spinlock_init_x_opt(erts_spinlock_t *lock, char *name, Eterm extra,
+ Uint16 opt)
+{
+#ifdef USE_THREADS
+ int res = ethr_spinlock_init(&lock->slck);
+ if (res)
+ erts_thr_fatal_error(res, "init spinlock");
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_init_lock_x(&lock->lc, name, ERTS_LC_FLG_LT_SPINLOCK, extra);
+#endif
+#ifdef ERTS_ENABLE_LOCK_COUNT
+ erts_lcnt_init_lock_x(&lock->lcnt, name, ERTS_LCNT_LT_SPINLOCK|opt, extra);
+#endif
+#else
+ (void)lock;
+#endif
+}
+
+
+ERTS_GLB_INLINE void
erts_spinlock_init(erts_spinlock_t *lock, char *name)
{
#ifdef USE_THREADS
@@ -1152,16 +1218,13 @@ ERTS_GLB_INLINE void
erts_spin_unlock(erts_spinlock_t *lock)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock(&lock->lc);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock(&lock->lcnt);
#endif
- res = ethr_spin_unlock(&lock->slck);
- if (res)
- erts_thr_fatal_error(res, "release spin lock");
+ ethr_spin_unlock(&lock->slck);
#else
(void)lock;
#endif
@@ -1175,19 +1238,16 @@ erts_spin_lock(erts_spinlock_t *lock)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock(&lock->lc);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock(&lock->lcnt);
#endif
- res = ethr_spin_lock(&lock->slck);
+ ethr_spin_lock(&lock->slck);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&lock->lcnt, file, line);
#endif
- if (res)
- erts_thr_fatal_error(res, "take spin lock");
#else
(void)lock;
#endif
@@ -1268,16 +1328,13 @@ ERTS_GLB_INLINE void
erts_read_unlock(erts_rwlock_t *lock)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&lock->lc, ERTS_LC_FLG_LO_READ);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&lock->lcnt, ERTS_LCNT_LO_READ);
#endif
- res = ethr_read_unlock(&lock->rwlck);
- if (res)
- erts_thr_fatal_error(res, "release read lock");
+ ethr_read_unlock(&lock->rwlck);
#else
(void)lock;
#endif
@@ -1291,19 +1348,16 @@ erts_read_lock(erts_rwlock_t *lock)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock_flg(&lock->lc, ERTS_LC_FLG_LO_READ);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&lock->lcnt, ERTS_LCNT_LO_READ);
#endif
- res = ethr_read_lock(&lock->rwlck);
+ ethr_read_lock(&lock->rwlck);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&lock->lcnt, file, line);
#endif
- if (res)
- erts_thr_fatal_error(res, "take read lock");
#else
(void)lock;
#endif
@@ -1313,16 +1367,13 @@ ERTS_GLB_INLINE void
erts_write_unlock(erts_rwlock_t *lock)
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&lock->lc, ERTS_LC_FLG_LO_READ_WRITE);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&lock->lcnt, ERTS_LCNT_LO_READ_WRITE);
#endif
- res = ethr_write_unlock(&lock->rwlck);
- if (res)
- erts_thr_fatal_error(res, "release write lock");
+ ethr_write_unlock(&lock->rwlck);
#else
(void)lock;
#endif
@@ -1336,19 +1387,16 @@ erts_write_lock(erts_rwlock_t *lock)
#endif
{
#ifdef USE_THREADS
- int res;
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_lock_flg(&lock->lc, ERTS_LC_FLG_LO_READ_WRITE);
#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&lock->lcnt, ERTS_LCNT_LO_READ_WRITE);
#endif
- res = ethr_write_lock(&lock->rwlck);
+ ethr_write_lock(&lock->rwlck);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_post_x(&lock->lcnt, file, line);
#endif
- if (res)
- erts_thr_fatal_error(res, "take write lock");
#else
(void)lock;
#endif
@@ -1432,66 +1480,95 @@ erts_tsd_get(erts_tsd_key_t key)
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_init(erts_gate_t *gp)
+ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void)
{
#ifdef USE_THREADS
- int res = ethr_gate_init((ethr_gate *) gp);
- if (res != 0)
- erts_thr_fatal_error(res, "initialize gate");
+ return (erts_tse_t *) ethr_get_ts_event();
+#else
+ return (erts_tse_t *) NULL;
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_destroy(erts_gate_t *gp)
+ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep)
{
#ifdef USE_THREADS
- int res = ethr_gate_destroy((ethr_gate *) gp);
- if (res != 0)
- erts_thr_fatal_error(res, "destroy gate");
+ ethr_leave_ts_event(ep);
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_close(erts_gate_t *gp)
+ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep)
{
#ifdef USE_THREADS
- int res = ethr_gate_close((ethr_gate *) gp);
- if (res != 0)
- erts_thr_fatal_error(res, "close gate");
+ ethr_event_set(&((ethr_ts_event *) ep)->event);
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_let_through(erts_gate_t *gp, unsigned no)
+ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep)
{
#ifdef USE_THREADS
- int res = ethr_gate_let_through((ethr_gate *) gp, no);
- if (res != 0)
- erts_thr_fatal_error(res, "let through gate");
+ ethr_event_reset(&((ethr_ts_event *) ep)->event);
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_wait(erts_gate_t *gp)
+ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep)
+{
+#ifdef USE_THREADS
+ return ethr_event_wait(&((ethr_ts_event *) ep)->event);
+#else
+ return ENOTSUP;
+#endif
+}
+
+ERTS_GLB_INLINE int erts_tse_swait(erts_tse_t *ep, int spincount)
+{
+#ifdef USE_THREADS
+ return ethr_event_swait(&((ethr_ts_event *) ep)->event, spincount);
+#else
+ return ENOTSUP;
+#endif
+}
+
+ERTS_GLB_INLINE int erts_tse_is_tmp(erts_tse_t *ep)
{
#ifdef USE_THREADS
- int res = ethr_gate_wait((ethr_gate *) gp);
+ return (ep->iflgs & ETHR_TS_EV_TMP) == ETHR_TS_EV_TMP;
+#else
+ return 0;
+#endif
+}
+
+ERTS_GLB_INLINE void erts_thr_set_main_status(int on, int no)
+{
+#ifdef USE_THREADS
+ int res = ethr_set_main_thr_status(on, no);
if (res != 0)
- erts_thr_fatal_error(res, "wait on gate");
+ erts_thr_fatal_error(res, "set thread main status");
#endif
}
-ERTS_GLB_INLINE void
-erts_gate_swait(erts_gate_t *gp, int spincount)
+ERTS_GLB_INLINE int erts_thr_get_main_status(void)
{
#ifdef USE_THREADS
- int res = ethr_gate_swait((ethr_gate *) gp, spincount);
+ int main_status;
+ int res = ethr_get_main_thr_status(&main_status);
if (res != 0)
- erts_thr_fatal_error(res, "swait on gate");
+ erts_thr_fatal_error(res, "get thread main status");
+ return main_status;
+#else
+ return 1;
#endif
}
+ERTS_GLB_INLINE void erts_thr_yield(void)
+{
+#ifdef USE_THREADS
+ int res = ETHR_YIELD();
+ if (res != 0)
+ erts_thr_fatal_error(res, "yield");
+#endif
+}
+
+
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
ERTS_GLB_INLINE void
diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c
index 66b05c0e9d..5e81a2d624 100644
--- a/erts/emulator/beam/export.c
+++ b/erts/emulator/beam/export.c
@@ -43,8 +43,6 @@ static erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table.
#define export_read_unlock() erts_smp_rwmtx_runlock(&export_table_lock)
#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock)
#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock)
-#define export_init_lock() erts_smp_rwmtx_init(&export_table_lock, \
- "export_tab")
extern BeamInstr* em_call_error_handler;
extern BeamInstr* em_call_traced_function;
@@ -111,8 +109,12 @@ void
init_export_table(void)
{
HashFunctions f;
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+
+ erts_smp_rwmtx_init_opt(&export_table_lock, &rwmtx_opt, "export_tab");
- export_init_lock();
f.hash = (H_FUN) export_hash;
f.cmp = (HCMP_FUN) export_cmp;
f.alloc = (HALLOC_FUN) export_alloc;
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index f41b61d73d..d7c8aa84e9 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -65,11 +65,9 @@
# endif
#endif
-/*
- * For backward compatibility reasons, only encode integers that
- * fit in 28 bits (signed) using INTEGER_EXT.
+/* Does Sint fit in Sint32?
*/
-#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2)
+#define IS_SSMALL32(x) (((Uint) (((x) >> (32-1)) + 1)) < 2)
/*
* Valid creations for nodes are 1, 2, or 3. 0 can also be sent
@@ -504,7 +502,7 @@ erts_make_dist_ext_copy(ErtsDistExternal *edep, Uint xsize)
ASSERT(edep->ext_endp >= edep->extp);
ext_sz = edep->ext_endp - edep->extp;
- align_sz = ERTS_WORD_ALIGN_PAD_SZ(dist_ext_sz + ext_sz);
+ align_sz = ERTS_EXTRA_DATA_ALIGN_SZ(dist_ext_sz + ext_sz);
new_edep = erts_alloc(ERTS_ALC_T_EXT_TERM_DATA,
dist_ext_sz + ext_sz + align_sz + xsize);
@@ -1470,11 +1468,11 @@ dec_pid(ErtsDistExternal *edep, Eterm** hpp, byte* ep, ErlOffHeap* off_heap, Ete
*hpp += EXTERNAL_THING_HEAD_SIZE + 1;
etp->header = make_external_pid_header(1);
- etp->next = off_heap->externals;
+ etp->next = off_heap->first;
etp->node = node;
etp->data.ui[0] = data;
- off_heap->externals = etp;
+ off_heap->first = (struct erl_off_heap_header*) etp;
*objp = make_external_pid(etp);
}
return ep;
@@ -1571,13 +1569,15 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
case SMALL_DEF:
{
+ /* From R14B we no longer restrict INTEGER_EXT to 28 bits,
+ * as done earlier for backward compatibility reasons. */
Sint val = signed_val(obj);
if ((Uint)val < 256) {
*ep++ = SMALL_INTEGER_EXT;
put_int8(val, ep);
ep++;
- } else if (sizeof(Sint) == 4 || IS_SSMALL28(val)) {
+ } else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) {
*ep++ = INTEGER_EXT;
put_int32(val, ep);
ep += 4;
@@ -1599,18 +1599,32 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
break;
case BIG_DEF:
- if ((n = big_bytes(obj)) < 256) {
- *ep++ = SMALL_BIG_EXT;
- put_int8(n, ep);
- ep += 1;
- }
- else {
- *ep++ = LARGE_BIG_EXT;
- put_int32(n, ep);
- ep += 4;
+ {
+ int sign = big_sign(obj);
+ n = big_bytes(obj);
+ if (sizeof(Sint)==4 && n<=4) {
+ Uint dig = big_digit(obj,0);
+ Sint val = sign ? -dig : dig;
+ if ((val<0) == sign) {
+ *ep++ = INTEGER_EXT;
+ put_int32(val, ep);
+ ep += 4;
+ break;
+ }
+ }
+ if (n < 256) {
+ *ep++ = SMALL_BIG_EXT;
+ put_int8(n, ep);
+ ep += 1;
+ }
+ else {
+ *ep++ = LARGE_BIG_EXT;
+ put_int32(n, ep);
+ ep += 4;
+ }
+ *ep++ = sign;
+ ep = big_to_bytes(obj, ep);
}
- *ep++ = big_sign(obj);
- ep = big_to_bytes(obj, ep);
break;
case PID_DEF:
@@ -1896,69 +1910,30 @@ is_external_string(Eterm list, int* p_is_string)
return len;
}
-/* Assumes that the ones to undo are preluding the lists. */
+/* Assumes that the ones to undo are preluding the list. */
static void
undo_offheap_in_area(ErlOffHeap* off_heap, Eterm* start, Eterm* end)
{
const Uint area_sz = (end - start) * sizeof(Eterm);
- struct proc_bin* mso;
- struct proc_bin** mso_nextp = NULL;
-#ifndef HYBRID /* FIND ME! */
- struct erl_fun_thing* funs;
- struct erl_fun_thing** funs_nextp = NULL;
-#endif
- struct external_thing_* ext;
- struct external_thing_** ext_nextp = NULL;
-
- for (mso = off_heap->mso; ; mso=mso->next) {
- if (!in_area(mso, start, area_sz)) {
- if (mso_nextp != NULL) {
- *mso_nextp = NULL;
- erts_cleanup_mso(off_heap->mso);
- off_heap->mso = mso;
+ struct erl_off_heap_header* hdr;
+ struct erl_off_heap_header** hdr_nextp = NULL;
+
+ for (hdr = off_heap->first; ; hdr=hdr->next) {
+ if (!in_area(hdr, start, area_sz)) {
+ if (hdr_nextp != NULL) {
+ *hdr_nextp = NULL;
+ erts_cleanup_offheap(off_heap);
+ off_heap->first = hdr;
}
break;
}
- mso_nextp = &mso->next;
+ hdr_nextp = &hdr->next;
}
-#ifndef HYBRID /* FIND ME! */
- for (funs = off_heap->funs; ; funs=funs->next) {
- if (!in_area(funs, start, area_sz)) {
- if (funs_nextp != NULL) {
- *funs_nextp = NULL;
- erts_cleanup_funs(off_heap->funs);
- off_heap->funs = funs;
- }
- break;
- }
- funs_nextp = &funs->next;
- }
-#endif
- for (ext = off_heap->externals; ; ext=ext->next) {
- if (!in_area(ext, start, area_sz)) {
- if (ext_nextp != NULL) {
- *ext_nextp = NULL;
- erts_cleanup_externals(off_heap->externals);
- off_heap->externals = ext;
- }
- break;
- }
- ext_nextp = &ext->next;
- }
-
- /* Assert that the ones to undo were indeed preluding the lists. */
+ /* Assert that the ones to undo were indeed preluding the list. */
#ifdef DEBUG
- for (mso = off_heap->mso; mso != NULL; mso=mso->next) {
- ASSERT(!in_area(mso, start, area_sz));
- }
-# ifndef HYBRID /* FIND ME! */
- for (funs = off_heap->funs; funs != NULL; funs=funs->next) {
- ASSERT(!in_area(funs, start, area_sz));
- }
-# endif
- for (ext = off_heap->externals; ext != NULL; ext=ext->next) {
- ASSERT(!in_area(ext, start, area_sz));
+ for (hdr = off_heap->first; hdr != NULL; hdr = hdr->next) {
+ ASSERT(!in_area(hdr, start, area_sz));
}
#endif /* DEBUG */
}
@@ -2202,11 +2177,11 @@ dec_term_atom_common:
hp += EXTERNAL_THING_HEAD_SIZE + 1;
etp->header = make_external_port_header(1);
- etp->next = off_heap->externals;
+ etp->next = off_heap->first;
etp->node = node;
etp->data.ui[0] = num;
- off_heap->externals = etp;
+ off_heap->first = (struct erl_off_heap_header*)etp;
*objp = make_external_port(etp);
}
@@ -2284,10 +2259,10 @@ dec_term_atom_common:
#else
etp->header = make_external_ref_header(ref_words);
#endif
- etp->next = off_heap->externals;
+ etp->next = off_heap->first;
etp->node = node;
- off_heap->externals = etp;
+ off_heap->first = (struct erl_off_heap_header*)etp;
*objp = make_external_ref(etp);
ref_num = &(etp->data.ui32[0]);
}
@@ -2330,8 +2305,8 @@ dec_term_atom_common:
hp += PROC_BIN_SIZE;
pb->thing_word = HEADER_PROC_BIN;
pb->size = n;
- pb->next = off_heap->mso;
- off_heap->mso = pb;
+ pb->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*)pb;
pb->val = dbin;
pb->bytes = (byte*) dbin->orig_bytes;
pb->flags = 0;
@@ -2367,8 +2342,8 @@ dec_term_atom_common:
pb = (ProcBin *) hp;
pb->thing_word = HEADER_PROC_BIN;
pb->size = n;
- pb->next = off_heap->mso;
- off_heap->mso = pb;
+ pb->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*)pb;
pb->val = dbin;
pb->bytes = (byte*) dbin->orig_bytes;
pb->flags = 0;
@@ -2488,8 +2463,8 @@ dec_term_atom_common:
* It is safe to link the fun into the fun list only when
* no more validity tests can fail.
*/
- funp->next = off_heap->funs;
- off_heap->funs = funp;
+ funp->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*)funp;
#endif
funp->fe = erts_put_fun_entry2(module, old_uniq, old_index,
@@ -2566,8 +2541,8 @@ dec_term_atom_common:
* It is safe to link the fun into the fun list only when
* no more validity tests can fail.
*/
- funp->next = off_heap->funs;
- off_heap->funs = funp;
+ funp->next = off_heap->first;
+ off_heap->first = (struct erl_off_heap_header*)funp;
#endif
old_uniq = unsigned_val(temp);
@@ -2687,7 +2662,7 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
if ((Uint)val < 256)
result += 1 + 1; /* SMALL_INTEGER_EXT */
- else if (sizeof(Sint) == 4 || IS_SSMALL28(val))
+ else if (sizeof(Sint) == 4 || IS_SSMALL32(val))
result += 1 + 4; /* INTEGER_EXT */
else {
DeclareTmpHeapNoproc(tmp_big,2);
@@ -2699,7 +2674,10 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
}
break;
case BIG_DEF:
- if ((i = big_bytes(obj)) < 256)
+ i = big_bytes(obj);
+ if (sizeof(Sint)==4 && i <= 4 && (big_digit(obj,0)-big_sign(obj)) < (1<<31))
+ result += 1 + 4; /* INTEGER_EXT */
+ else if (i < 256)
result += 1 + 1 + 1 + i; /* tag,size,sign,digits */
else
result += 1 + 4 + 1 + i; /* tag,size,sign,digits */
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index db86b4d796..cee48bbeb0 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -211,7 +211,7 @@ ERTS_GLB_INLINE void *
erts_dist_ext_trailer(ErtsDistExternal *edep)
{
void *res = (void *) (edep->ext_endp
- + ERTS_WORD_ALIGN_PAD_SZ(edep->ext_endp));
+ + ERTS_EXTRA_DATA_ALIGN_SZ(edep->ext_endp));
ASSERT((((UWord) res) % sizeof(Uint)) == 0);
return res;
}
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index b4a7a22082..280421952e 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -464,7 +464,10 @@ typedef union {
typedef struct proc_bin {
Eterm thing_word; /* Subtag REFC_BINARY_SUBTAG. */
Uint size; /* Binary size in bytes. */
- struct proc_bin *next; /* Pointer to next ProcBin. */
+#if HALFWORD_HEAP
+ void* dummy_ptr_padding__;
+#endif
+ struct erl_off_heap_header *next;
Binary *val; /* Pointer to Binary structure. */
byte *bytes; /* Pointer to the actual data bytes. */
Uint flags; /* Flag word. */
@@ -494,8 +497,8 @@ erts_mk_magic_binary_term(Eterm **hpp, ErlOffHeap *ohp, Binary *mbp)
pb->thing_word = HEADER_PROC_BIN;
pb->size = 0;
- pb->next = ohp->mso;
- ohp->mso = pb;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*) pb;
pb->val = mbp;
pb->bytes = (byte *) mbp->orig_bytes;
pb->flags = 0;
@@ -512,6 +515,15 @@ erts_mk_magic_binary_term(Eterm **hpp, ErlOffHeap *ohp, Binary *mbp)
&& (thing_subtag(*binary_val((T))) == REFC_BINARY_SUBTAG) \
&& (((ProcBin *) binary_val((T)))->val->flags & BIN_FLAG_MAGIC))
+
+union erl_off_heap_ptr {
+ struct erl_off_heap_header* hdr;
+ ProcBin *pb;
+ struct erl_fun_thing* fun;
+ struct external_thing_* ext;
+ Eterm* ep;
+};
+
/* arrays that get malloced at startup */
extern Port* erts_port;
extern erts_smp_atomic_t erts_ports_alive;
@@ -823,7 +835,6 @@ Eterm erts_new_heap_binary(Process *p, byte *buf, int len, byte** datap);
Eterm erts_new_mso_binary(Process*, byte*, int);
Eterm new_binary(Process*, byte*, int);
Eterm erts_realloc_binary(Eterm bin, size_t size);
-void erts_cleanup_mso(ProcBin* pb);
/* erl_bif_info.c */
@@ -1015,7 +1026,7 @@ void print_pass_through(int, byte*, int);
/* beam_emu.c */
int catchlevel(Process*);
-void init_emulator(_VOID_);
+void init_emulator(void);
void process_main(void);
Eterm build_stacktrace(Process* c_p, Eterm exc);
Eterm expand_error_value(Process* c_p, Uint freason, Eterm Value);
@@ -1499,7 +1510,6 @@ void p_slpq(_VOID_);
void erts_silence_warn_unused_result(long unused);
void erts_cleanup_offheap(ErlOffHeap *offheap);
-void erts_cleanup_externals(ExternalThing *);
Uint erts_fit_in_bits(Uint);
int list_length(Eterm);
@@ -1532,7 +1542,7 @@ erts_bld_atom_2uint_3tup_list(Uint **hpp, Uint *szp, Sint length,
Eterm atoms[], Uint uints1[], Uint uints2[]);
Eterm store_external_or_ref_in_proc_(Process *, Eterm);
-Eterm store_external_or_ref_(Uint **, ExternalThing **, Eterm);
+Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm);
#define NC_HEAP_SIZE(NC) \
(ASSERT_EXPR(is_node_container((NC))), \
@@ -1676,7 +1686,7 @@ int io_list_to_buf(Eterm, char*, int);
int io_list_to_buf2(Eterm, char*, int);
int io_list_len(Eterm);
int is_string(Eterm);
-void erl_at_exit(FUNCTION(void,(*),(void*)), void*);
+void erl_at_exit(void (*) (void*), void*);
Eterm collect_memory(Process *);
void dump_memory_to_fd(int);
int dump_memory_data(const char *);
@@ -1957,5 +1967,5 @@ erts_alloc_message_heap(Uint size,
# define UnUseTmpHeap(Size,Proc) /* Nothing */
# define UseTmpHeapNoproc(Size) /* Nothing */
# define UnUseTmpHeapNoproc(Size) /* Nothing */
-#endif
-#endif
+#endif /* HEAP_ON_C_STACK */
+#endif /* !__GLOBAL_H__ */
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 68625801cf..b840f65cdd 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -1575,8 +1575,8 @@ static void deliver_read_message(Port* prt, Eterm to,
pb = (ProcBin *) hp;
pb->thing_word = HEADER_PROC_BIN;
pb->size = len;
- pb->next = ohp->mso;
- ohp->mso = pb;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*)pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
@@ -1725,8 +1725,8 @@ deliver_vec_message(Port* prt, /* Port */
}
pb->thing_word = HEADER_PROC_BIN;
pb->size = iov->iov_len;
- pb->next = ohp->mso;
- ohp->mso = pb;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*)pb;
pb->val = ErlDrvBinary2Binary(b);
pb->bytes = base;
pb->flags = 0;
@@ -2259,8 +2259,8 @@ erts_port_control(Process* p, Port* prt, Uint command, Eterm iolist)
ProcBin* pb = (ProcBin *) HAlloc(p, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = dbin->orig_size;
- pb->next = MSO(p).mso;
- MSO(p).mso = pb;
+ pb->next = MSO(p).first;
+ MSO(p).first = (struct erl_off_heap_header*)pb;
pb->val = ErlDrvBinary2Binary(dbin);
pb->bytes = (byte*) dbin->orig_bytes;
pb->flags = 0;
@@ -3033,8 +3033,8 @@ driver_deliver_term(ErlDrvPort port,
driver_binary_inc_refc(b); /* caller will free binary */
pb->thing_word = HEADER_PROC_BIN;
pb->size = size;
- pb->next = ohp->mso;
- ohp->mso = pb;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*)pb;
pb->val = ErlDrvBinary2Binary(b);
pb->bytes = ((byte*) b->orig_bytes) + offset;
pb->flags = 0;
@@ -3072,8 +3072,8 @@ driver_deliver_term(ErlDrvPort port,
hp += PROC_BIN_SIZE;
pbp->thing_word = HEADER_PROC_BIN;
pbp->size = size;
- pbp->next = ohp->mso;
- ohp->mso = pbp;
+ pbp->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*)pbp;
pbp->val = bp;
pbp->bytes = (byte*) bp->orig_bytes;
pbp->flags = 0;
diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c
index 8c8029d450..5bcd567b5f 100644
--- a/erts/emulator/beam/packet_parser.c
+++ b/erts/emulator/beam/packet_parser.c
@@ -679,7 +679,7 @@ int packet_parse_http(const char* buf, int len, int* statep,
while (n && SP(ptr)) {
ptr++; n--;
}
- if (ptr==p0) return -1;
+ if (ptr==p0 && n>0) return -1;
/* NOTE: the syntax allows empty reason phrases */
(*statep) = !0;
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index 900ebcbbf7..c9bb7bbe91 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -39,8 +39,6 @@ static Hash process_reg;
static erts_smp_rwmtx_t regtab_rwmtx;
-#define reg_lock_init() erts_smp_rwmtx_init(&regtab_rwmtx, \
- "reg_tab")
#define reg_try_read_lock() erts_smp_rwmtx_tryrlock(&regtab_rwmtx)
#define reg_try_write_lock() erts_smp_rwmtx_tryrwlock(&regtab_rwmtx)
#define reg_read_lock() erts_smp_rwmtx_rlock(&regtab_rwmtx)
@@ -147,8 +145,11 @@ static void reg_free(RegProc *obj)
void init_register_table(void)
{
HashFunctions f;
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
- reg_lock_init();
+ erts_smp_rwmtx_init_opt(&regtab_rwmtx, &rwmtx_opt, "reg_tab");
f.hash = (H_FUN) reg_hash;
f.cmp = (HCMP_FUN) reg_cmp;
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index ca87d3d70f..0031568af6 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -25,14 +25,6 @@
# define NO_FPE_SIGNALS
#endif
-/* Never use elib-malloc when purify-memory-tracing */
-#if defined(PURIFY)
-#undef ENABLE_ELIB_MALLOC
-#undef ELIB_HEAP_SBRK
-#undef ELIB_ALLOC_IS_CLIB
-#endif
-
-
/* xxxP __VXWORKS__ */
#ifdef VXWORKS
#include <vxWorks.h>
@@ -171,23 +163,6 @@ void erl_assert_error(char* expr, char* file, int line);
#include <stdarg.h>
-#if defined(__STDC__) || defined(_MSC_VER)
-# define EXTERN_FUNCTION(t, f, x) extern t f x
-# define FUNCTION(t, f, x) t f x
-# define _DOTS_ ...
-# define _VOID_ void
-#elif defined(__cplusplus)
-# define EXTERN_FUNCTION(f, x) extern "C" { f x }
-# define FUNCTION(t, f, x) t f x
-# define _DOTS_ ...
-# define _VOID_ void
-#else
-# define EXTERN_FUNCTION(t, f, x) extern t f (/*x*/)
-# define FUNCTION(t, f, x) t f (/*x*/)
-# define _DOTS_
-# define _VOID_
-#endif
-
/* This isn't sys-dependent, but putting it here benefits sys.c and drivers
- allow use of 'const' regardless of compiler */
@@ -197,7 +172,7 @@ void erl_assert_error(char* expr, char* file, int line);
#ifdef VXWORKS
/* Replace VxWorks' printf with a real one that does fprintf(stdout, ...) */
-EXTERN_FUNCTION(int, real_printf, (const char *fmt, ...));
+int real_printf(const char *fmt, ...);
# define printf real_printf
#endif
@@ -359,15 +334,8 @@ typedef unsigned char byte;
#error 64-bit architecture, but no appropriate type to use for Uint64 and Sint64 found
#endif
-#if defined(ARCH_64)
-# define ERTS_WORD_ALIGN_PAD_SZ(X) \
+# define ERTS_EXTRA_DATA_ALIGN_SZ(X) \
(((size_t) 8) - (((size_t) (X)) & ((size_t) 7)))
-#elif defined(ARCH_32)
-# define ERTS_WORD_ALIGN_PAD_SZ(X) \
- (((size_t) 4) - (((size_t) (X)) & ((size_t) 3)))
-#else
-#error "Not supported..."
-#endif
#include "erl_lock_check.h"
#include "erl_smp.h"
@@ -667,12 +635,12 @@ extern void erl_sys_args(int *argc, char **argv);
extern void erl_sys_schedule(int);
void sys_tty_reset(int);
-EXTERN_FUNCTION(int, sys_max_files, (_VOID_));
+int sys_max_files(void);
void sys_init_io(void);
Preload* sys_preloaded(void);
-EXTERN_FUNCTION(unsigned char*, sys_preload_begin, (Preload*));
-EXTERN_FUNCTION(void, sys_preload_end, (Preload*));
-EXTERN_FUNCTION(int, sys_get_key, (int));
+unsigned char* sys_preload_begin(Preload*);
+void sys_preload_end(Preload*);
+int sys_get_key(int);
void elapsed_time_both(unsigned long *ms_user, unsigned long *ms_sys,
unsigned long *ms_user_diff, unsigned long *ms_sys_diff);
void wall_clock_elapsed_time_both(unsigned long *ms_total,
@@ -689,7 +657,7 @@ int local_to_univ(Sint *year, Sint *month, Sint *day,
Sint *hour, Sint *minute, Sint *second, int isdst);
void get_now(Uint*, Uint*, Uint*);
void get_sys_now(Uint*, Uint*, Uint*);
-EXTERN_FUNCTION(void, set_break_quit, (void (*)(void), void (*)(void)));
+void set_break_quit(void (*)(void), void (*)(void));
void os_flavor(char*, unsigned);
void os_version(int*, int*, int*);
@@ -729,7 +697,7 @@ int erts_write_env(char *key, char *value);
#define ERTS_DEFAULT_MMAP_THRESHOLD (128 * 1024)
#define ERTS_DEFAULT_MMAP_MAX 64
-EXTERN_FUNCTION(int, sys_alloc_opt, (int, int));
+int sys_alloc_opt(int, int);
typedef struct {
Sint trim_threshold;
@@ -738,7 +706,7 @@ typedef struct {
Sint mmap_max;
} SysAllocStat;
-EXTERN_FUNCTION(void, sys_alloc_stat, (SysAllocStat *));
+void sys_alloc_stat(SysAllocStat *);
/* Block the whole system... */
@@ -1127,13 +1095,10 @@ erts_refc_read(erts_refc_t *refcp, long min_val)
extern int erts_use_kernel_poll;
#endif
-void elib_ensure_initialized(void);
-
-
#if defined(VXWORKS)
/* NOTE! sys_calloc2 does not exist on other
platforms than VxWorks and OSE */
-EXTERN_FUNCTION(void*, sys_calloc2, (Uint, Uint));
+void* sys_calloc2(Uint, Uint);
#endif /* VXWORKS || OSE */
@@ -1225,8 +1190,8 @@ EXTERN_FUNCTION(void*, sys_calloc2, (Uint, Uint));
*/
#ifdef DEBUG
-EXTERN_FUNCTION(void, erl_debug, (char* format, ...));
-EXTERN_FUNCTION(void, erl_bin_write, (unsigned char *, int, int));
+void erl_debug(char* format, ...);
+void erl_bin_write(unsigned char *, int, int);
# define DEBUGF(x) erl_debug x
#else
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index da6f9ed12f..ab5e8b5d4a 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -48,11 +48,11 @@
#undef M_MMAP_THRESHOLD
#undef M_MMAP_MAX
-#if !defined(ELIB_ALLOC_IS_CLIB) && defined(__GLIBC__) && defined(HAVE_MALLOC_H)
+#if defined(__GLIBC__) && defined(HAVE_MALLOC_H)
#include <malloc.h>
#endif
-#if defined(ELIB_ALLOC_IS_CLIB) || !defined(HAVE_MALLOPT)
+#if !defined(HAVE_MALLOPT)
#undef HAVE_MALLOPT
#define HAVE_MALLOPT 0
#endif
@@ -162,13 +162,8 @@ erts_heap_alloc(Process* p, Uint need)
bp->alloc_size = n;
bp->used_size = n;
MBUF_SIZE(p) += n;
- bp->off_heap.mso = NULL;
-#ifndef HYBRID /* FIND ME! */
- bp->off_heap.funs = NULL;
-#endif
- bp->off_heap.externals = NULL;
+ bp->off_heap.first = NULL;
bp->off_heap.overhead = 0;
-
return bp->mem;
}
@@ -409,7 +404,7 @@ erts_bld_uint64(Uint **hpp, Uint *szp, Uint64 ui64)
}
else {
if (szp)
- *szp = ERTS_UINT64_HEAP_SIZE(ui64);
+ *szp += ERTS_UINT64_HEAP_SIZE(ui64);
if (hpp)
res = erts_uint64_to_big(ui64, hpp);
}
@@ -426,7 +421,7 @@ erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64)
}
else {
if (szp)
- *szp = ERTS_SINT64_HEAP_SIZE(si64);
+ *szp += ERTS_SINT64_HEAP_SIZE(si64);
if (hpp)
res = erts_sint64_to_big(si64, hpp);
}
@@ -2729,21 +2724,8 @@ not_equal:
}
-void
-erts_cleanup_externals(ExternalThing *etp)
-{
- ExternalThing *tetp;
-
- tetp = etp;
-
- while(tetp) {
- erts_deref_node_entry(tetp->node);
- tetp = tetp->next;
- }
-}
-
Eterm
-store_external_or_ref_(Uint **hpp, ExternalThing **etpp, Eterm ns)
+store_external_or_ref_(Uint **hpp, ErlOffHeap* oh, Eterm ns)
{
Uint i;
Uint size;
@@ -2762,8 +2744,8 @@ store_external_or_ref_(Uint **hpp, ExternalThing **etpp, Eterm ns)
erts_refc_inc(&((ExternalThing *) to_hp)->node->refc, 2);
- ((ExternalThing *) to_hp)->next = *etpp;
- *etpp = (ExternalThing *) to_hp;
+ ((struct erl_off_heap_header*) to_hp)->next = oh->first;
+ oh->first = (struct erl_off_heap_header*) to_hp;
return make_external(to_hp);
}
@@ -2792,7 +2774,7 @@ store_external_or_ref_in_proc_(Process *proc, Eterm ns)
sz = NC_HEAP_SIZE(ns);
ASSERT(sz > 0);
hp = HAlloc(proc, sz);
- return store_external_or_ref_(&hp, &MSO(proc).externals, ns);
+ return store_external_or_ref_(&hp, &MSO(proc), ns);
}
void bin_write(int to, void *to_arg, byte* buf, int sz)
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 60ae4cb108..c450f10f48 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -104,7 +104,7 @@
#include <ctype.h>
#include <sys/types.h>
-extern void erl_exit(int n, char *fmt, _DOTS_);
+void erl_exit(int n, char *fmt, ...);
static ErlDrvSysInfo sys_info;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 87691fc1bc..059288d1cb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -1045,7 +1045,7 @@ struct erl_drv_entry inet_driver_entry =
};
/* XXX: is this a driver interface function ??? */
-extern void erl_exit(int n, char*, _DOTS_);
+void erl_exit(int n, char*, ...);
/*
* Malloc wrapper,
@@ -9333,11 +9333,13 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
if (err != ERRNO_BLOCK) {
if (!desc->active) {
#ifdef HAVE_SCTP
- if (short_recv)
+ if (short_recv) {
async_error_am(desc, am_short_recv);
- else
-#else
+ } else {
async_error(desc, err);
+ }
+#else
+ async_error(desc, err);
#endif
driver_cancel_timer(desc->port);
sock_select(desc,FD_READ,0);
diff --git a/erts/emulator/drivers/unix/mem_drv.c b/erts/emulator/drivers/unix/mem_drv.c
deleted file mode 100644
index 1417ca1121..0000000000
--- a/erts/emulator/drivers/unix/mem_drv.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/* Purpose: Access to elib memory statistics */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sys.h"
-#include "erl_driver.h"
-#include "elib_stat.h"
-
-#define MAP_BUF_SIZE 1000 /* Max map size */
-#define HISTO_BUF_SIZE 100 /* Max histogram buckets */
-
-static ErlDrvData mem_start(ErlDrvPort);
-static int mem_init(void);
-static void mem_stop(ErlDrvData);
-static void mem_command(ErlDrvData, char*, int);
-
-const struct driver_entry mem_driver_entry = {
- mem_init,
- mem_start,
- mem_stop,
- mem_command,
- NULL,
- NULL,
- "mem_drv"
-};
-
-static int mem_init(void)
-{
- return 0;
-}
-
-static ErlDrvData mem_start(ErlDrvPort port, char* buf)
-{
- return (ErlDrvData)port;
-}
-
-static void mem_stop(ErlDrvData port)
-{
-}
-
-void putint32(p, v)
-byte* p; int v;
-{
- p[0] = (v >> 24) & 0xff;
- p[1] = (v >> 16) & 0xff;
- p[2] = (v >> 8) & 0xff;
- p[3] = (v) & 0xff;
-}
-
-int getint16(p)
-byte* p;
-{
- return (p[0] << 8) | p[1];
-}
-
-/*
-** Command:
-** m L1 L0 -> a heap map of length L1*256 + L0 is returned
-** s -> X3 X2 X1 X0 Y3 Y2 Y1 Y0 Z3 Z2 Z1 Z0
-** X == Total heap size bytes
-** Y == Total free bytes
-** Z == Size of largest free block in bytes
-**
-** h L1 L0 B0 -> Generate a logarithm historgram base B with L buckets
-** l L1 L0 S0 -> Generate a linear histogram with step S with L buckets
-*/
-unsigned char outbuf[HISTO_BUF_SIZE*2*4];
-
-static void mem_command(ErlDrvData port, char* buf, int count)
-{
- if ((count == 1) && buf[0] == 's') {
- struct elib_stat info;
- char v[3*4];
-
- elib_stat(&info);
-
- putint32(v, info.mem_total*4);
- putint32(v+4, info.mem_free*4);
- putint32(v+8, info.max_free*4);
- driver_output((ErlDrvPort)port, v, 12);
- return;
- }
- else if ((count == 3) && buf[0] == 'm') {
- char w[MAP_BUF_SIZE];
- int n = getint16(buf+1);
-
- if (n > MAP_BUF_SIZE)
- n = MAP_BUF_SIZE;
- elib_heap_map(w, n);
- driver_output((ErlDrvPort)port, w, n);
- return;
- }
- else if ((count == 4) && (buf[0] == 'h' || buf[0] == 'l')) {
- unsigned long vf[HISTO_BUF_SIZE];
- unsigned long va[HISTO_BUF_SIZE];
- int n = getint16(buf+1);
- int base = (unsigned char) buf[3];
-
- if (n >= HISTO_BUF_SIZE)
- n = HISTO_BUF_SIZE;
- if (buf[0] == 'l')
- base = -base;
- if (elib_histo(vf, va, n, base) < 0) {
- driver_failure((ErlDrvPort)port, -1);
- return;
- }
- else {
- char* p = outbuf;
- int i;
-
- for (i = 0; i < n; i++) {
- putint32(p, vf[i]);
- p += 4;
- }
- for (i = 0; i < n; i++) {
- putint32(p, va[i]);
- p += 4;
- }
- driver_output((ErlDrvPort)port, outbuf, n*8);
- }
- return;
- }
- driver_failure((ErlDrvPort)port, -1);
-}
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 0052ac0739..b19f632f52 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -98,7 +98,7 @@ extern STATUS copy(char *, char *);
#define EF_SAFE_REALLOC(P, S) ef_safe_realloc((P), (S))
#define EF_FREE(P) do { if((P)) driver_free((P)); } while(0)
-extern void erl_exit(int n, char *fmt, _DOTS_);
+void erl_exit(int n, char *fmt, ...);
static void *ef_safe_alloc(Uint s)
{
@@ -127,7 +127,7 @@ static void *ef_safe_realloc(void *op, Uint s)
(s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0')))
#ifdef VXWORKS
-static FUNCTION(int, vxworks_to_posix, (int vx_errno));
+static int vxworks_to_posix(int vx_errno);
#endif
/*
@@ -146,7 +146,7 @@ static FUNCTION(int, vxworks_to_posix, (int vx_errno));
#define CHECK_PATHLEN(X,Y) /* Nothing */
#endif
-static FUNCTION(int, check_error, (int result, Efile_error* errInfo));
+static int check_error(int result, Efile_error* errInfo);
static int
check_error(int result, Efile_error *errInfo)
diff --git a/erts/emulator/drivers/win32/mem_drv.c b/erts/emulator/drivers/win32/mem_drv.c
deleted file mode 100644
index fa7c46eca8..0000000000
--- a/erts/emulator/drivers/win32/mem_drv.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-/* Purpose: Access to elib memory statistics */
-
-#include "sys.h"
-#include "erl_driver.h"
-#include "elib_stat.h"
-
-#define MAP_BUF_SIZE 1000 /* Max map size */
-#define HISTO_BUF_SIZE 100 /* Max histogram buckets */
-
-static ErlDrvData mem_start(ErlDrvPort, char*);
-static int mem_init(void);
-static void mem_stop(ErlDrvData);
-static void mem_command(ErlDrvData);
-
-ErlDrvEntry mem_driver_entry = {
- mem_init,
- mem_start,
- mem_stop,
- mem_command,
- NULL,
- NULL,
- "mem_drv"
-};
-
-static int mem_init(void)
-{
- return 0;
-}
-
-static ErlDrvData mem_start(ErlDrvPort port, char* buf)
-{
- return (ErlDrvData)port;
-}
-
-static void mem_stop(ErlDrvData port)
-{
-}
-
-void putint32(p, v)
-byte* p; int v;
-{
- p[0] = (v >> 24) & 0xff;
- p[1] = (v >> 16) & 0xff;
- p[2] = (v >> 8) & 0xff;
- p[3] = (v) & 0xff;
-}
-
-int getint16(p)
-byte* p;
-{
- return (p[0] << 8) | p[1];
-}
-
-/*
-** Command:
-** m L1 L0 -> a heap map of length L1*256 + L0 is returned
-** s -> X3 X2 X1 X0 Y3 Y2 Y1 Y0 Z3 Z2 Z1 Z0
-** X == Total heap size bytes
-** Y == Total free bytes
-** Z == Size of largest free block in bytes
-**
-** h L1 L0 B0 -> Generate a logarithm histogram base B with L buckets
-** l L1 L0 S0 -> Generate a linear histogram with step S with L buckets
-*/
-unsigned char outbuf[HISTO_BUF_SIZE*2*4];
-
-static void mem_command(ErlDrvData port, char* buf, int count)
-{
- if ((count == 1) && buf[0] == 's') {
- struct elib_stat info;
- char v[3*4];
-
- elib_stat(&info);
-
- putint32(v, info.mem_total*4);
- putint32(v+4, info.mem_free*4);
- putint32(v+8, info.max_free*4);
- driver_output((ErlDrvPort)port, v, 12);
- return;
- }
- else if ((count == 3) && buf[0] == 'm') {
- char w[MAP_BUF_SIZE];
- int n = getint16(buf+1);
-
- if (n > MAP_BUF_SIZE)
- n = MAP_BUF_SIZE;
- elib_heap_map(w, n);
- driver_output((ErlDrvPort)port, w, n);
- return;
- }
- else if ((count == 4) && (buf[0] == 'h' || buf[0] == 'l')) {
- unsigned long vf[HISTO_BUF_SIZE];
- unsigned long va[HISTO_BUF_SIZE];
- int n = getint16(buf+1);
- int base = (unsigned char) buf[3];
-
- if (n >= HISTO_BUF_SIZE)
- n = HISTO_BUF_SIZE;
- if (buf[0] == 'l')
- base = -base;
- if (elib_histo(vf, va, n, base) < 0) {
- driver_failure((ErlDrvPort)port, -1);
- return;
- }
- else {
- char* p = outbuf;
- int i;
-
- for (i = 0; i < n; i++) {
- putint32(p, vf[i]);
- p += 4;
- }
- for (i = 0; i < n; i++) {
- putint32(p, va[i]);
- p += 4;
- }
- driver_output((ErlDrvPort)port, outbuf, n*8);
- }
- return;
- }
- driver_failure((ErlDrvPort)port, -1);
-}
-
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index b0abfd2310..2a877d8ace 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -440,9 +440,12 @@ BIF_RETTYPE hipe_bifs_alloc_data_2(BIF_ALIST_2)
align != sizeof(long) && align != sizeof(double)))
BIF_ERROR(BIF_P, BADARG);
nrbytes = unsigned_val(BIF_ARG_2);
+ if (nrbytes == 0)
+ BIF_RET(make_small(0));
block = erts_alloc(ERTS_ALC_T_HIPE, nrbytes);
if ((unsigned long)block & (align-1))
- fprintf(stderr, "Yikes! erts_alloc() returned misaligned address %p\r\n", block);
+ fprintf(stderr, "%s: erts_alloc(%lu) returned %p which is not %lu-byte aligned\r\n",
+ __FUNCTION__, (unsigned long)nrbytes, block, (unsigned long)align);
BIF_RET(address_to_term(block, BIF_P));
}
diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c
index a77aec7919..900dfc5a8a 100644
--- a/erts/emulator/hipe/hipe_mkliterals.c
+++ b/erts/emulator/hipe/hipe_mkliterals.c
@@ -261,7 +261,7 @@ static const struct literal {
/* Field offsets in a process struct */
{ "P_HP", offsetof(struct process, htop) },
{ "P_HP_LIMIT", offsetof(struct process, stop) },
- { "P_OFF_HEAP_MSO", offsetof(struct process, off_heap.mso) },
+ { "P_OFF_HEAP_FIRST", offsetof(struct process, off_heap.first) },
{ "P_MBUF", offsetof(struct process, mbuf) },
{ "P_ID", offsetof(struct process, id) },
{ "P_FLAGS", offsetof(struct process, flags) },
@@ -456,7 +456,7 @@ static const struct rts_param {
} rts_params[] = {
{ 1, "P_OFF_HEAP_FUNS",
#if !defined(HYBRID)
- 1, offsetof(struct process, off_heap.funs)
+ 1, offsetof(struct process, off_heap.first)
#endif
},
diff --git a/erts/emulator/obsolete/driver.h b/erts/emulator/obsolete/driver.h
deleted file mode 100644
index 708fe68e1a..0000000000
--- a/erts/emulator/obsolete/driver.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-/*
- * OLD, OBSOLETE include file for erlang driver writers.
- * New drivers should use erl_driver.h instead.
- */
-
-#ifndef __DRIVER_H__
-#define __DRIVER_H__
-
-#include <stdlib.h>
-#include "driver_int.h"
-
-#undef _ANSI_ARGS_
-#undef CONST
-
-#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE)
-# define _USING_PROTOTYPES_ 1
-# define _ANSI_ARGS_(x) x
-# define CONST const
-#else
-# define _ANSI_ARGS_(x) ()
-# define CONST
-#endif
-
-#ifdef __cplusplus
-# define EXTERN extern "C"
-#else
-# define EXTERN extern
-#endif
-
-/* Values for mode arg to driver_select() */
-
-#define DO_READ (1 << 0)
-#define DO_WRITE (1 << 1)
-
-/* Flags for set_port_control_flags() */
-#define PORT_CONTROL_FLAG_BINARY 1
-#define PORT_CONTROL_FLAG_HEAVY 2
-
-/* This macro is used to name a dynamic driver's init function in */
-/* a way that doesn't lead to conflicts. This is crucial when using */
-/* operating systems that has one namespace for all symbols */
-/* (e.g. VxWorks). Example: if you have an dynamic driver C source */
-/* file named echo_drv.c, you use the macro like this: */
-/* int DRIVER_INIT(echo_drv)(void *handle) */
-#if defined(VXWORKS)
-# define DRIVER_INIT(DRIVER_NAME) DRIVER_NAME ## _init
-#elif defined(__WIN32__)
-# define DRIVER_INIT(DRIVER_NAME) __declspec(dllexport) driver_init
-#else
-# define DRIVER_INIT(DRIVER_NAME) driver_init
-#endif
-
-typedef int (*F_PTR)(); /* a function pointer */
-typedef long (*L_PTR)(); /* pointer to a function returning long */
-
-extern int null_func();
-
-/* This structure MUST match Binary in global.h exactly!!! */
-typedef struct driver_binary {
- int orig_size; /* total length of binary */
- char orig_bytes[1]; /* the data (char instead of byte!) */
-} DriverBinary;
-
-typedef struct {
- int vsize; /* length of vectors */
- int size; /* total size in bytes */
- SysIOVec* iov;
- DriverBinary** binv;
-} ErlIOVec;
-
-/*
- * OLD, OBSOLETE driver entry structure.
- */
-
-typedef struct driver_entry {
- F_PTR init; /* called at system start up (no args) */
- L_PTR start; /* called when some one does an open_port
- args: port, command (nul-terminated),
- additional/alternate args for fd/vanilla/spawn driver.
- return value -1 means failure, other
- is saved and passed to the other funcs */
- F_PTR stop; /* called when port is closed, and when the
- emulator is halted - arg: start_return */
- F_PTR output; /* called when we have output from erlang to the port
- args: start_return, buf, buflen */
- F_PTR ready_input; /* called when we have input from one of the driver's
- file descriptors - args: start_return, fd */
- F_PTR ready_output; /* called when output is possible to one of the driver's
- file descriptors - args: start_return, fd */
- char *driver_name; /* name supplied as {driver,Name,Args} to open_port */
-
- F_PTR finish; /* called before unloading (DYNAMIC DRIVERS ONLY) */
- void *handle; /* file handle (DYNAMIC DRIVERS ONLY) */
- F_PTR control; /* "ioctl" for drivers (invoked by port_command/3) */
- F_PTR timeout; /* Reserved */
- F_PTR outputv; /* Reserved */
- F_PTR ready_async; /* Completion routine for driver_async */
- F_PTR padding1[3]; /* pad to match size of modern driver struct */
- int padding2[4]; /* more pad */
- F_PTR padding3[3]; /* even more padding */
-} DriverEntry;
-
-
-/* These are the kernel functions available for driver writers */
-
-EXTERN int driver_select _ANSI_ARGS_((int,int,int,int));
-
-EXTERN int driver_output _ANSI_ARGS_((int, char*, int));
-EXTERN int driver_output2 _ANSI_ARGS_((int, char*, int, char*, int));
-EXTERN int driver_output_binary _ANSI_ARGS_((int, char*, int,
- DriverBinary*, int, int));
-EXTERN int driver_outputv _ANSI_ARGS_((int, char*,int,ErlIOVec*,int));
-
-EXTERN int driver_vec_to_buf _ANSI_ARGS_((ErlIOVec*, char*, int));
-
-EXTERN int driver_set_timer _ANSI_ARGS_((int, unsigned long));
-EXTERN int driver_cancel_timer _ANSI_ARGS_((int));
-
-/*
- * The following functions are used to initiate a close of a port
- * from a driver.
- */
-EXTERN int driver_failure_eof _ANSI_ARGS_((int));
-EXTERN int driver_failure_atom _ANSI_ARGS_((int, char *));
-EXTERN int driver_failure_posix _ANSI_ARGS_((int, int));
-EXTERN int driver_failure _ANSI_ARGS_((int, int));
-EXTERN int driver_exit _ANSI_ARGS_ ((int, int));
-
-EXTERN char* erl_errno_id _ANSI_ARGS_((int error));
-EXTERN void set_busy_port _ANSI_ARGS_((int, int));
-EXTERN void add_driver_entry _ANSI_ARGS_((DriverEntry *));
-EXTERN int remove_driver_entry _ANSI_ARGS_((DriverEntry *));
-EXTERN void set_port_control_flags _ANSI_ARGS_((int, int));
-
-/* Binary interface */
-/* NOTE: DO NOT overwrite a binary with new data (if the data is delivered);
-** since the binary is a shared object it MUST be written once.
-*/
-
-EXTERN DriverBinary* driver_alloc_binary _ANSI_ARGS_((int));
-EXTERN DriverBinary* driver_realloc_binary _ANSI_ARGS_((DriverBinary*, int));
-EXTERN void driver_free_binary _ANSI_ARGS_((DriverBinary*));
-
-
-/* Queue interface */
-EXTERN int driver_enqv _ANSI_ARGS_((int, ErlIOVec*, int));
-EXTERN int driver_pushqv _ANSI_ARGS_((int, ErlIOVec*, int));
-EXTERN int driver_deq _ANSI_ARGS_((int, int));
-EXTERN SysIOVec* driver_peekq _ANSI_ARGS_((int, int*));
-EXTERN int driver_sizeq _ANSI_ARGS_((int));
-EXTERN int driver_enq_bin _ANSI_ARGS_((int, DriverBinary*, int, int));
-EXTERN int driver_enq _ANSI_ARGS_((int, char*, int));
-EXTERN int driver_pushq_bin _ANSI_ARGS_((int, DriverBinary*, int, int));
-EXTERN int driver_pushq _ANSI_ARGS_((int, char*, int));
-
-/* Memory management */
-EXTERN void *driver_alloc _ANSI_ARGS_((size_t));
-EXTERN void *driver_realloc _ANSI_ARGS_((void*, size_t));
-EXTERN void driver_free _ANSI_ARGS_((void*));
-
-/* Shared / dynamic link libraries */
-EXTERN void *driver_dl_open _ANSI_ARGS_((char *));
-EXTERN void *driver_dl_sym _ANSI_ARGS_((void *, char *));
-EXTERN int driver_dl_close _ANSI_ARGS_((void *));
-EXTERN char *driver_dl_error _ANSI_ARGS_((void));
-
-/* Async IO functions */
-EXTERN long driver_async _ANSI_ARGS_((int,
- unsigned int*,
- void (*)(void*),
- void *,
- void (*)(void*)));
-EXTERN int driver_async_cancel _ANSI_ARGS_((long));
-
-EXTERN int driver_lock_driver _ANSI_ARGS_((int));
-
-/* Threads */
-typedef void* erl_mutex_t;
-typedef void* erl_cond_t;
-typedef void* erl_thread_t;
-
-EXTERN erl_mutex_t erts_mutex_create _ANSI_ARGS_((void));
-EXTERN int erts_mutex_destroy _ANSI_ARGS_((erl_mutex_t));
-EXTERN int erts_mutex_lock _ANSI_ARGS_((erl_mutex_t));
-EXTERN int erts_mutex_unlock _ANSI_ARGS_((erl_mutex_t));
-
-EXTERN erl_cond_t erts_cond_create _ANSI_ARGS_((void));
-EXTERN int erts_cond_destroy _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_signal _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_broadcast _ANSI_ARGS_((erl_cond_t));
-EXTERN int erts_cond_wait _ANSI_ARGS_((erl_cond_t, erl_mutex_t));
-EXTERN int erts_cond_timedwait _ANSI_ARGS_((erl_cond_t, erl_mutex_t, long));
-
-EXTERN int erts_thread_create _ANSI_ARGS_((erl_thread_t*,
- void* (*func)(void*),
- void* arg,
- int detached));
-EXTERN erl_thread_t erts_thread_self _ANSI_ARGS_((void));
-EXTERN void erts_thread_exit _ANSI_ARGS_((void*));
-EXTERN int erts_thread_join _ANSI_ARGS_((erl_thread_t, void**));
-EXTERN int erts_thread_kill _ANSI_ARGS_((erl_thread_t));
-
-
-typedef unsigned long DriverTermData;
-
-#define TERM_DATA(x) ((DriverTermData) (x))
-
-/* Possible types to send from driver Argument type */
-#define ERL_DRV_NIL ((DriverTermData) 1) /* None */
-#define ERL_DRV_ATOM ((DriverTermData) 2) /* driver_mk_atom(string) */
-#define ERL_DRV_INT ((DriverTermData) 3) /* int */
-#define ERL_DRV_PORT ((DriverTermData) 4) /* driver_mk_port(ix) */
-#define ERL_DRV_BINARY ((DriverTermData) 5) /* ErlDriverBinary*, int */
-#define ERL_DRV_STRING ((DriverTermData) 6) /* char*, int */
-#define ERL_DRV_TUPLE ((DriverTermData) 7) /* int */
-#define ERL_DRV_LIST ((DriverTermData) 8) /* int */
-#define ERL_DRV_STRING_CONS ((DriverTermData) 9) /* char*, int */
-#define ERL_DRV_PID ((DriverTermData) 10) /* driver_connected,... */
-
-/* DriverTermData is the type to use for casts when building
- * terms that should be sent to connected process,
- * for instance a tuple on the form {tcp, Port, [Tag|Binary]}
- *
- * DriverTermData spec[] = {
- * ERL_DRV_ATOM, driver_mk_atom("tcp"),
- * ERL_DRV_PORT, driver_mk_port(drv->ix),
- * ERL_DRV_INT, REPLY_TAG,
- * ERL_DRV_BIN, 50, TERM_DATA(buffer),
- * ERL_DRV_LIST, 2,
- * ERL_DRV_TUPLE, 3,
- * }
- *
- */
-
-EXTERN DriverTermData driver_mk_atom _ANSI_ARGS_ ((char*));
-EXTERN DriverTermData driver_mk_port _ANSI_ARGS_ ((int));
-EXTERN DriverTermData driver_connected _ANSI_ARGS_((int));
-EXTERN DriverTermData driver_caller _ANSI_ARGS_((int));
-
-EXTERN int driver_output_term _ANSI_ARGS_((int, DriverTermData *, int));
-EXTERN int driver_send_term _ANSI_ARGS_((int, DriverTermData, DriverTermData *, int));
-
-#endif
-
-
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 09fb6337f7..c17806d96c 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -286,7 +286,7 @@ struct ErtsPollSet_ {
ErtsPollSet next;
int internal_fd_limit;
ErtsFdStatus *fds_status;
- int no_of_user_fds;
+ erts_smp_atomic_t no_of_user_fds;
int fds_status_len;
#if ERTS_POLL_USE_KERNEL_POLL
int kp_fd;
@@ -852,7 +852,7 @@ write_batch_buf(ErtsPollSet ps, ErtsPollBatchBuf *bbp)
ps->fds_status[fd].flags |= ERTS_POLL_FD_FLG_USEFLBCK;
ASSERT(ps->fds_status[fd].used_events);
ps->fds_status[fd].used_events = 0;
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
update_fallback_pollset(ps, fd);
ASSERT(ps->fds_status[fd].flags & ERTS_POLL_FD_FLG_INFLBCK);
break;
@@ -902,11 +902,11 @@ batch_update_pollset(ErtsPollSet ps, int fd, ErtsPollBatchBuf *bbp)
events = ERTS_POLL_EV_E2N(ps->fds_status[fd].events);
if (!events) {
buf[buf_len].events = POLLREMOVE;
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
}
else if (!ps->fds_status[fd].used_events) {
buf[buf_len].events = events;
- ps->no_of_user_fds++;
+ erts_smp_atomic_inc(&ps->no_of_user_fds);
}
else {
if ((ps->fds_status[fd].flags & ERTS_POLL_FD_FLG_RST)
@@ -996,12 +996,12 @@ batch_update_pollset(ErtsPollSet ps, int fd, ErtsPollBatchBuf *bbp)
}
if (used_events) {
if (!events) {
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
}
}
else {
if (events)
- ps->no_of_user_fds++;
+ erts_smp_atomic_inc(&ps->no_of_user_fds);
}
ASSERT((events & ~(ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT)) == 0);
ASSERT((used_events & ~(ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT)) == 0);
@@ -1075,7 +1075,7 @@ update_pollset(ErtsPollSet ps, int fd)
epe.data.fd = epe_templ.data.fd;
res = epoll_ctl(ps->kp_fd, EPOLL_CTL_DEL, fd, &epe);
} while (res != 0 && errno == EINTR);
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
ps->fds_status[fd].used_events = 0;
}
@@ -1083,11 +1083,11 @@ update_pollset(ErtsPollSet ps, int fd)
/* A note on EPOLL_CTL_DEL: linux kernel versions before 2.6.9
need a non-NULL event pointer even though it is ignored... */
op = EPOLL_CTL_DEL;
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
}
else if (!ps->fds_status[fd].used_events) {
op = EPOLL_CTL_ADD;
- ps->no_of_user_fds++;
+ erts_smp_atomic_inc(&ps->no_of_user_fds);
}
else {
op = EPOLL_CTL_MOD;
@@ -1137,7 +1137,7 @@ update_pollset(ErtsPollSet ps, int fd)
/* Fall through ... */
case EPOLL_CTL_ADD: {
ps->fds_status[fd].flags |= ERTS_POLL_FD_FLG_USEFLBCK;
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
#if ERTS_POLL_USE_CONCURRENT_UPDATE
if (!*update_fallback) {
*update_fallback = 1;
@@ -1225,7 +1225,7 @@ static int update_pollset(ErtsPollSet ps, int fd)
#if ERTS_POLL_USE_FALLBACK
ASSERT(ps->fds_status[fd].flags & ERTS_POLL_FD_FLG_INFLBCK);
#endif
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
last_pix = --ps->no_poll_fds;
if (pix != last_pix) {
/* Move last pix to this pix */
@@ -1252,7 +1252,7 @@ static int update_pollset(ErtsPollSet ps, int fd)
ASSERT(!(ps->fds_status[fd].flags & ERTS_POLL_FD_FLG_INFLBCK)
|| fd == ps->kp_fd);
#endif
- ps->no_of_user_fds++;
+ erts_smp_atomic_inc(&ps->no_of_user_fds);
ps->fds_status[fd].pix = pix = ps->no_poll_fds++;
if (pix >= ps->poll_fds_len)
grow_poll_fds(ps, pix);
@@ -1303,7 +1303,7 @@ static int update_pollset(ErtsPollSet ps, int fd)
if (!ps->fds_status[fd].used_events) {
ASSERT(events);
- ps->no_of_user_fds++;
+ erts_smp_atomic_inc(&ps->no_of_user_fds);
#if ERTS_POLL_USE_FALLBACK
ps->no_select_fds++;
ps->fds_status[fd].flags |= ERTS_POLL_FD_FLG_INFLBCK;
@@ -1311,7 +1311,7 @@ static int update_pollset(ErtsPollSet ps, int fd)
}
else if (!events) {
ASSERT(ps->fds_status[fd].used_events);
- ps->no_of_user_fds--;
+ erts_smp_atomic_dec(&ps->no_of_user_fds);
ps->fds_status[fd].events = events;
#if ERTS_POLL_USE_FALLBACK
ps->no_select_fds--;
@@ -1912,7 +1912,8 @@ static ERTS_INLINE int
check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res, int *ps_locked)
{
ASSERT(!*ps_locked);
- if (ps->no_of_user_fds == 0 && tv->tv_usec == 0 && tv->tv_sec == 0) {
+ if (erts_smp_atomic_read(&ps->no_of_user_fds) == 0
+ && tv->tv_usec == 0 && tv->tv_sec == 0) {
/* Nothing to poll and zero timeout; done... */
return 0;
}
@@ -1950,7 +1951,7 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res, int *ps_locked)
* the maximum number of file descriptors in the poll set.
*/
struct dvpoll poll_res;
- int nfds = ps->no_of_user_fds;
+ int nfds = (int) erts_smp_atomic_read(&ps->no_of_user_fds);
#ifdef ERTS_SMP
nfds++; /* Wakeup pipe */
#endif
@@ -2228,7 +2229,7 @@ ERTS_POLL_EXPORT(erts_poll_create_pollset)(void)
ps->internal_fd_limit = 0;
ps->fds_status = NULL;
ps->fds_status_len = 0;
- ps->no_of_user_fds = 0;
+ erts_smp_atomic_init(&ps->no_of_user_fds, 0);
#if ERTS_POLL_USE_KERNEL_POLL
ps->kp_fd = -1;
#if ERTS_POLL_USE_EPOLL
@@ -2326,7 +2327,7 @@ ERTS_POLL_EXPORT(erts_poll_create_pollset)(void)
#if ERTS_POLL_USE_FALLBACK
ps->fallback_used = 0;
#endif
- ps->no_of_user_fds = 0; /* Don't count wakeup pipe and fallback fd */
+ erts_smp_atomic_set(&ps->no_of_user_fds, 0); /* Don't count wakeup pipe and fallback fd */
erts_smp_spin_lock(&pollsets_lock);
ps->next = pollsets;
@@ -2472,7 +2473,7 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip)
pip->memory_size = size;
- pip->poll_set_size = ps->no_of_user_fds;
+ pip->poll_set_size = (int) erts_smp_atomic_read(&ps->no_of_user_fds);
#ifdef ERTS_SMP
pip->poll_set_size++; /* Wakeup pipe */
#endif
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 737ffd9f94..af4ab693dc 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -123,8 +123,6 @@ static ErtsSysReportExit *report_exit_transit_list;
extern int check_async_ready(void);
extern int driver_interrupt(int, int);
-/*EXTERN_FUNCTION(void, increment_time, (int));*/
-/*EXTERN_FUNCTION(int, next_time, (_VOID_));*/
extern void do_break(void);
extern void erl_sys_args(int*, char**);
@@ -221,10 +219,10 @@ static struct fd_data {
} *fd_data; /* indexed by fd */
/* static FUNCTION(int, write_fill, (int, char*, int)); unused? */
-static FUNCTION(void, note_child_death, (int, int));
+static void note_child_death(int, int);
#if CHLDWTHR
-static FUNCTION(void *, child_waiter, (void *));
+static void* child_waiter(void *);
#endif
/********************* General functions ****************************/
@@ -384,18 +382,6 @@ MALLOC_USE_HASH(1);
#endif
#ifdef USE_THREADS
-static void *ethr_internal_alloc(size_t size)
-{
- return erts_alloc_fnf(ERTS_ALC_T_ETHR_INTERNAL, (Uint) size);
-}
-static void *ethr_internal_realloc(void *ptr, size_t size)
-{
- return erts_realloc_fnf(ERTS_ALC_T_ETHR_INTERNAL, ptr, (Uint) size);
-}
-static void ethr_internal_free(void *ptr)
-{
- erts_free(ERTS_ALC_T_ETHR_INTERNAL, ptr);
-}
#ifdef ERTS_THR_HAVE_SIG_FUNCS
/*
@@ -488,9 +474,6 @@ erts_sys_pre_init(void)
#ifdef USE_THREADS
{
erts_thr_init_data_t eid = ERTS_THR_INIT_DATA_DEF_INITER;
- eid.alloc = ethr_internal_alloc;
- eid.realloc = ethr_internal_realloc;
- eid.free = ethr_internal_free;
eid.thread_create_child_func = thr_create_prepare_child;
/* Before creation in parent */
@@ -538,13 +521,14 @@ erts_sys_pre_init(void)
#endif
#endif /* USE_THREADS */
erts_smp_atomic_init(&sys_misc_mem_sz, 0);
- erts_smp_rwmtx_init(&environ_rwmtx, "environ");
}
void
erl_sys_init(void)
{
+ erts_smp_rwmtx_init(&environ_rwmtx, "environ");
#if !DISABLE_VFORK
+ {
int res;
char bindir[MAXPATHLEN];
size_t bindirsz = sizeof(bindir);
@@ -574,6 +558,7 @@ erl_sys_init(void)
bindir,
DIR_SEPARATOR_CHAR,
CHILD_SETUP_PROG_NAME);
+ }
#endif
#ifdef USE_SETLINEBUF
@@ -2575,7 +2560,6 @@ extern Preload pre_loaded[];
void erts_sys_alloc_init(void)
{
- elib_ensure_initialized();
}
void *erts_sys_alloc(ErtsAlcType_t t, void *x, Uint sz)
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index c59c99f65e..5a682ab045 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -799,8 +799,17 @@ sys_chars_to_double(char* buf, double* fp)
}
#ifdef NO_FPE_SIGNALS
- if (errno == ERANGE && (*fp == 0.0 || *fp == HUGE_VAL || *fp == -HUGE_VAL)) {
- return -1;
+ if (errno == ERANGE) {
+ if (*fp == HUGE_VAL || *fp == -HUGE_VAL) {
+ /* overflow, should give error */
+ return -1;
+ } else if (t == s && *fp == 0.0) {
+ /* This should give 0.0 - OTP-7178 */
+ errno = 0;
+
+ } else if (*fp == 0.0) {
+ return -1;
+ }
}
#endif
return 0;
@@ -810,7 +819,9 @@ int
matherr(struct exception *exc)
{
#if !defined(NO_FPE_SIGNALS)
- set_current_fp_exception((unsigned long)__builtin_return_address(0));
+ volatile unsigned long *fpexnp = erts_get_current_fp_exception();
+ if (fpexnp != NULL)
+ *fpexnp = (unsigned long)__builtin_return_address(0);
#endif
return 1;
}
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index bd02cf85eb..15d4cd7361 100644
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -37,7 +37,7 @@
void erts_sys_init_float(void);
void erl_start(int, char**);
-void erl_exit(int n, char*, _DOTS_);
+void erl_exit(int n, char*, ...);
void erl_error(char*, va_list);
void erl_crash_dump(char*, int, char*, ...);
@@ -67,10 +67,10 @@ static void async_read_file(struct async_io* aio, LPVOID buf, DWORD numToRead);
static int async_write_file(struct async_io* aio, LPVOID buf, DWORD numToWrite);
static int get_overlapped_result(struct async_io* aio,
LPDWORD pBytesRead, BOOL wait);
-static FUNCTION(BOOL, CreateChildProcess, (char *, HANDLE, HANDLE,
- HANDLE, LPHANDLE, BOOL,
- LPVOID, LPTSTR, unsigned,
- char **, int *));
+static BOOL CreateChildProcess(char *, HANDLE, HANDLE,
+ HANDLE, LPHANDLE, BOOL,
+ LPVOID, LPTSTR, unsigned,
+ char **, int *);
static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL);
static int ApplicationType(const char* originalName, char fullPath[MAX_PATH],
BOOL search_in_path, BOOL handle_quotes,
@@ -93,7 +93,7 @@ static erts_smp_mtx_t sys_driver_data_lock;
#define APPL_WIN3X 2
#define APPL_WIN32 3
-static FUNCTION(int, driver_write, (long, HANDLE, byte*, int));
+static int driver_write(long, HANDLE, byte*, int);
static void common_stop(int);
static int create_file_thread(struct async_io* aio, int mode);
#ifdef ERTS_SMP
@@ -2627,7 +2627,6 @@ erts_sys_main_thread(void)
void erts_sys_alloc_init(void)
{
- elib_ensure_initialized();
}
void *erts_sys_alloc(ErtsAlcType_t t, void *x, Uint sz)
@@ -2974,19 +2973,6 @@ check_supported_os_version(void)
}
#ifdef USE_THREADS
-static void *ethr_internal_alloc(size_t size)
-{
- return erts_alloc_fnf(ERTS_ALC_T_ETHR_INTERNAL, (Uint) size);
-}
-static void *ethr_internal_realloc(void *ptr, size_t size)
-{
- return erts_realloc_fnf(ERTS_ALC_T_ETHR_INTERNAL, ptr, (Uint) size);
-}
-static void ethr_internal_free(void *ptr)
-{
- erts_free(ERTS_ALC_T_ETHR_INTERNAL, ptr);
-}
-
#ifdef ERTS_ENABLE_LOCK_COUNT
static void
thr_create_prepare_child(void *vtcdp)
@@ -3005,14 +2991,9 @@ erts_sys_pre_init(void)
#ifdef USE_THREADS
{
erts_thr_init_data_t eid = ERTS_THR_INIT_DATA_DEF_INITER;
- eid.alloc = ethr_internal_alloc;
- eid.realloc = ethr_internal_realloc;
- eid.free = ethr_internal_free;
-
#ifdef ERTS_ENABLE_LOCK_COUNT
eid.thread_create_child_func = thr_create_prepare_child;
#endif
-
erts_thr_init(&eid);
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init();
@@ -3020,7 +3001,6 @@ erts_sys_pre_init(void)
}
#endif
erts_smp_atomic_init(&sys_misc_mem_sz, 0);
- erts_sys_env_init();
}
void noinherit_std_handle(DWORD type)
@@ -3036,6 +3016,8 @@ void erl_sys_init(void)
{
HANDLE handle;
+ erts_sys_env_init();
+
noinherit_std_handle(STD_OUTPUT_HANDLE);
noinherit_std_handle(STD_INPUT_HANDLE);
noinherit_std_handle(STD_ERROR_HANDLE);
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 5ec17a5e2a..a4c02da626 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -75,7 +75,6 @@ MODULES= \
node_container_SUITE \
nofrag_SUITE \
num_bif_SUITE \
- obsolete_SUITE \
op_SUITE \
port_SUITE \
port_bif_SUITE \
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index 6cde286871..d9e961be2f 100644
--- a/erts/emulator/test/decode_packet_SUITE.erl
+++ b/erts/emulator/test/decode_packet_SUITE.erl
@@ -304,6 +304,10 @@ http(Config) when is_list(Config) ->
{ok, {http_request, 'GET', ResB, {1,1}}, Rest} = decode_pkt(http_bin,Bin)
end,
lists:foreach(UriF, http_uri_variants()),
+
+ %% Response with empty phrase
+ ?line {ok,{http_response,{1,1},200,[]},<<>>} = decode_pkt(http, <<"HTTP/1.1 200\r\n">>, []),
+ ?line {ok,{http_response,{1,1},200,<<>>},<<>>} = decode_pkt(http_bin, <<"HTTP/1.1 200\r\n">>, []),
ok.
http_with_bin(http) ->
diff --git a/erts/emulator/test/float_SUITE.erl b/erts/emulator/test/float_SUITE.erl
index 102e472ea6..99e9457985 100644
--- a/erts/emulator/test/float_SUITE.erl
+++ b/erts/emulator/test/float_SUITE.erl
@@ -22,7 +22,10 @@
-include("test_server.hrl").
-export([all/1,init_per_testcase/2,fin_per_testcase/2,
- fpe/1,fp_drv/1,fp_drv_thread/1,denormalized/1,match/1,bad_float_unpack/1]).
+ fpe/1,fp_drv/1,fp_drv_thread/1,denormalized/1,match/1,
+ bad_float_unpack/1]).
+-export([otp_7178/1]).
+
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
Dog = ?t:timetrap(?t:minutes(3)),
@@ -33,7 +36,29 @@ fin_per_testcase(_Func, Config) ->
?t:timetrap_cancel(Dog).
all(suite) ->
- [fpe,fp_drv,fp_drv_thread,denormalized,match,bad_float_unpack].
+ [fpe,
+ fp_drv,
+ fp_drv_thread,
+ otp_7178,
+ denormalized,
+ match,
+ bad_float_unpack].
+
+%%
+%% OTP-7178, list_to_float on very small numbers should give 0.0
+%% instead of exception, i.e. ignore underflow.
+%%
+otp_7178(suite) ->
+ [];
+otp_7178(doc) ->
+ ["test that list_to_float on very small numbers give 0.0"];
+otp_7178(Config) when is_list(Config) ->
+ ?line X = list_to_float("1.0e-325"),
+ ?line true = (X < 0.00000001) and (X > -0.00000001),
+ ?line Y = list_to_float("1.0e-325325325"),
+ ?line true = (Y < 0.00000001) and (Y > -0.00000001),
+ ?line {'EXIT', {badarg,_}} = (catch list_to_float("1.0e83291083210")),
+ ok.
%% Forces floating point exceptions and tests that subsequent, legal,
%% operations are calculated correctly. Original version by Sebastian
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 85bdb8bff8..f5d1871bfb 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -480,14 +480,14 @@ otp_5292_test() ->
S2 = md5([md5(hash_int(S, E, PH)) || {Start, N, Sz} <- d(),
{S, E} <- int(Start, N, Sz)]),
?line Comment = case S1 of
- <<43,186,76,102,87,4,110,245,203,177,206,6,130,69,43,99>> ->
+ <<4,248,208,156,200,131,7,1,173,13,239,173,112,81,16,174>> ->
?line big = erlang:system_info(endian),
"Big endian machine";
- <<21,206,139,15,149,28,167,81,98,225,132,254,49,125,174,195>> ->
+ <<180,28,33,231,239,184,71,125,76,47,227,241,78,184,176,233>> ->
?line little = erlang:system_info(endian),
"Little endian machine"
end,
- ?line <<140,37,79,80,26,242,130,22,20,229,123,240,223,244,43,99>> = S2,
+ ?line <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2,
?line 2 = erlang:hash(1, (1 bsl 27) -1),
?line {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))),
{comment, Comment}.
@@ -507,7 +507,7 @@ hash_int(Start, End, F) ->
{Start, End, md5(HL)}.
md5(T) ->
- erlang:md5(term_to_binary(T)).
+ erlang:md5(term_to_binary(T)).
bit_level_binaries() ->
?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 888bf582d8..f45cfa3e4a 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -30,7 +30,7 @@
fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
types/1, many_args/1, binaries/1, get_string/1, get_atom/1, api_macros/1,
from_array/1, iolist_as_binary/1, resource/1, resource_binary/1, resource_takeover/1,
- threading/1, send/1, send2/1, send_threaded/1, neg/1, is_checks/1,
+ threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1, is_checks/1,
get_length/1, make_atom/1, make_string/1]).
-export([many_args_100/100]).
@@ -51,7 +51,7 @@
all(suite) ->
[basic, reload, upgrade, heap_frag, types, many_args, binaries, get_string,
get_atom, api_macros, from_array, iolist_as_binary, resource, resource_binary,
- resource_takeover, threading, send, send2, send_threaded, neg, is_checks,
+ resource_takeover, threading, send, send2, send3, send_threaded, neg, is_checks,
get_length, make_atom, make_string].
%%init_per_testcase(_Case, Config) ->
@@ -916,7 +916,164 @@ forwarder(To, N) ->
other_term() ->
{fun(X,Y) -> X*Y end, make_ref()}.
-
+
+send3(doc) -> ["Message sending stress test"];
+send3(Config) when is_list(Config) ->
+ %% Let a number of processes send random message blobs between each other
+ %% using enif_send. Kill and spawn new ones randomly to keep a ~constant
+ %% number of workers running.
+ Seed = now(),
+ io:format("seed: ~p\n",[Seed]),
+ random:seed(Seed),
+ ets:new(nif_SUITE,[named_table,public]),
+ ?line true = ets:insert(nif_SUITE,{send3,0,0,0,0}),
+ timer:send_after(10000, timeout), % Run for 10 seconds
+ SpawnCnt = send3_controller(0, [], [], 20),
+ ?line [{_,Rcv,SndOk,SndFail,Balance}] = ets:lookup(nif_SUITE,send3),
+ io:format("spawns=~p received=~p, sent=~p send-failure=~p balance=~p\n",
+ [SpawnCnt,Rcv,SndOk,SndFail,Balance]),
+ ets:delete(nif_SUITE).
+
+send3_controller(SpawnCnt, [], _, infinity) ->
+ SpawnCnt;
+send3_controller(SpawnCnt0, Mons0, Pids0, Tick) ->
+ receive
+ timeout ->
+ io:format("Timeout. Sending 'halt' to ~p\n",[Pids0]),
+ lists:foreach(fun(P) -> P ! {halt,self()} end, Pids0),
+ lists:foreach(fun(P) -> receive {halted,P} -> ok end end, Pids0),
+ QTot = lists:foldl(fun(P,QSum) ->
+ {message_queue_len,QLen} =
+ erlang:process_info(P,message_queue_len),
+ QSum + QLen
+ end, 0, Pids0),
+ io:format("Total queue length ~p\n",[QTot]),
+ lists:foreach(fun(P) -> P ! die end, Pids0),
+ send3_controller(SpawnCnt0, Mons0, [], infinity);
+ {'DOWN', MonRef, process, _Pid, _} ->
+ Mons1 = lists:delete(MonRef, Mons0),
+ %%io:format("Got DOWN from ~p. Monitors left: ~p\n",[Pid,Mons1]),
+ send3_controller(SpawnCnt0, Mons1, Pids0, Tick)
+ after Tick ->
+ Max = 20,
+ N = length(Pids0),
+ PidN = random:uniform(Max),
+ %%io:format("N=~p PidN=~p Pids0=~p\n", [N,PidN,Pids0]),
+ case PidN > N of
+ true ->
+ {NewPid,Mon} = spawn_opt(fun send3_proc/0, [link,monitor]),
+ lists:foreach(fun(P) -> P ! {is_born,NewPid} end, Pids0),
+ ?line Balance = ets:lookup_element(nif_SUITE,send3,5),
+ Inject = (Balance =< 0),
+ case Inject of
+ true -> ok;
+ false -> ets:update_element(nif_SUITE,send3,{5,-1})
+ end,
+ NewPid ! {pids,Pids0,Inject},
+ send3_controller(SpawnCnt0+1, [Mon|Mons0], [NewPid|Pids0], Tick);
+ false ->
+ KillPid = lists:nth(PidN,Pids0),
+ KillPid ! die,
+ Pids1 = lists:delete(KillPid, Pids0),
+ lists:foreach(fun(P) -> P ! {is_dead,KillPid} end, Pids1),
+ send3_controller(SpawnCnt0, Mons0, Pids1, Tick)
+ end
+ end.
+
+send3_proc() ->
+ %%io:format("Process ~p spawned\n",[self()]),
+ send3_proc([self()], {0,0,0}, {1,2,3,4,5}).
+send3_proc(Pids0, Counters={Rcv,SndOk,SndFail}, State0) ->
+ %%io:format("~p: Pids0=~p", [self(), Pids0]),
+ %%timer:sleep(10),
+ receive
+ {pids, Pids1, Inject} ->
+ %%io:format("~p: got ~p Inject=~p\n", [self(), Pids1, Inject]),
+ ?line Pids0 = [self()],
+ Pids2 = [self() | Pids1],
+ case Inject of
+ true -> send3_proc_send(Pids2, Counters, State0);
+ false -> send3_proc(Pids2, Counters, State0)
+ end;
+ {is_born, Pid} ->
+ %%io:format("~p: is_born ~p, got ~p\n", [self(), Pid, Pids0]),
+ send3_proc([Pid | Pids0], Counters, State0);
+ {is_dead, Pid} ->
+ Pids1 = lists:delete(Pid,Pids0),
+ %%io:format("~p: is_dead ~p, got ~p\n", [self(), Pid, Pids1]),
+ send3_proc(Pids1, Counters, State0);
+ {blob, Blob0} ->
+ %%io:format("~p: blob ~p\n", [self(), Blob0]),
+ State1 = send3_new_state(State0, Blob0),
+ send3_proc_send(Pids0, {Rcv+1,SndOk,SndFail}, State1);
+ die ->
+ %%io:format("Process ~p terminating, stats = ~p\n",[self(),Counters]),
+ {message_queue_len,Dropped} = erlang:process_info(self(),message_queue_len),
+ _R = ets:update_counter(nif_SUITE,send3,
+ [{2,Rcv},{3,SndOk},{4,SndFail},{5,1-Dropped}]),
+ %%io:format("~p: dies R=~p\n", [self(), R]),
+ ok;
+ {halt,Papa} ->
+ Papa ! {halted,self()},
+ io:format("~p halted\n",[self()]),
+ receive die -> ok end,
+ io:format("~p dying\n",[self()])
+ end.
+
+send3_proc_send(Pids, {Rcv,SndOk,SndFail}, State0) ->
+ To = lists:nth(random:uniform(length(Pids)),Pids),
+ Blob = send3_make_blob(),
+ State1 = send3_new_state(State0,Blob),
+ case send3_send(To, Blob) of
+ true ->
+ send3_proc(Pids, {Rcv,SndOk+1,SndFail}, State1);
+ false ->
+ send3_proc(Pids, {Rcv,SndOk,SndFail+1}, State1)
+ end.
+
+
+send3_make_blob() ->
+ case random:uniform(20)-1 of
+ 0 -> {term,[]};
+ N ->
+ MsgEnv = alloc_msgenv(),
+ repeat(N bsr 1,
+ fun(_) -> grow_blob(MsgEnv,other_term(),random:uniform(1 bsl 20))
+ end, void),
+ case (N band 1) of
+ 0 -> {term,copy_blob(MsgEnv)};
+ 1 -> {msgenv,MsgEnv}
+ end
+ end.
+
+send3_send(Pid, Msg) ->
+ %% 90% enif_send and 10% normal bang
+ case random:uniform(10) of
+ 1 -> send3_send_bang(Pid,Msg);
+ _ -> send3_send_nif(Pid,Msg)
+ end.
+send3_send_nif(Pid, {term,Blob}) ->
+ %%io:format("~p send term nif\n",[self()]),
+ send_term(Pid, {blob, Blob}) =:= 1;
+send3_send_nif(Pid, {msgenv,MsgEnv}) ->
+ %%io:format("~p send blob nif\n",[self()]),
+ send3_blob(MsgEnv, Pid, blob) =:= 1.
+
+send3_send_bang(Pid, {term,Blob}) ->
+ %%io:format("~p send term bang\n",[self()]),
+ Pid ! {blob, Blob},
+ true;
+send3_send_bang(Pid, {msgenv,MsgEnv}) ->
+ %%io:format("~p send blob bang\n",[self()]),
+ Pid ! {blob, copy_blob(MsgEnv)},
+ true.
+
+send3_new_state(State, Blob) ->
+ case random:uniform(5+2) of
+ N when N =< 5-> setelement(N, State, Blob);
+ _ -> State % Don't store blob
+ end.
+
neg(doc) -> ["Negative testing of load_nif"];
neg(Config) when is_list(Config) ->
TmpMem = tmpmem(),
@@ -1070,10 +1227,13 @@ send_new_blob(_,_) -> ?nif_stub.
alloc_msgenv() -> ?nif_stub.
clear_msgenv(_) -> ?nif_stub.
grow_blob(_,_) -> ?nif_stub.
+grow_blob(_,_,_) -> ?nif_stub.
send_blob(_,_) -> ?nif_stub.
+send3_blob(_,_,_) -> ?nif_stub.
send_blob_thread(_,_,_) -> ?nif_stub.
join_send_thread(_) -> ?nif_stub.
-
+copy_blob(_) -> ?nif_stub.
+send_term(_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index c8cd323b7e..17f644829f 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1038,36 +1038,41 @@ static ERL_NIF_TERM make_term_copy(struct make_term_info* mti, int n)
{
return enif_make_copy(mti->dst_env, mti->other_term);
}
+
+typedef ERL_NIF_TERM Make_term_Func(struct make_term_info*, int);
+static Make_term_Func* make_funcs[] = {
+ make_term_binary,
+ make_term_int,
+ make_term_ulong,
+ make_term_double,
+ make_term_atom,
+ make_term_existing_atom,
+ make_term_string,
+ //make_term_ref,
+ make_term_sub_binary,
+ make_term_uint,
+ make_term_long,
+ make_term_tuple0,
+ make_term_list0,
+ make_term_resource,
+ make_term_new_binary,
+ make_term_caller_pid,
+ make_term_tuple,
+ make_term_list,
+ make_term_list_cell,
+ make_term_tuple_from_array,
+ make_term_list_from_array,
+ make_term_garbage,
+ make_term_copy
+};
+static unsigned num_of_make_funcs()
+{
+ return sizeof(make_funcs)/sizeof(*make_funcs);
+}
static int make_term_n(struct make_term_info* mti, int n, ERL_NIF_TERM* res)
{
- typedef ERL_NIF_TERM Make_term_Func(struct make_term_info*, int);
- static Make_term_Func* funcs[] = {
- make_term_binary,
- make_term_int,
- make_term_ulong,
- make_term_double,
- make_term_atom,
- make_term_existing_atom,
- make_term_string,
- //make_term_ref,
- make_term_sub_binary,
- make_term_uint,
- make_term_long,
- make_term_tuple0,
- make_term_list0,
- make_term_resource,
- make_term_new_binary,
- make_term_caller_pid,
- make_term_tuple,
- make_term_list,
- make_term_list_cell,
- make_term_tuple_from_array,
- make_term_list_from_array,
- make_term_garbage,
- make_term_copy
- };
- if (n < sizeof(funcs)/sizeof(*funcs)) {
- *res = funcs[n](mti, n);
+ if (n < num_of_make_funcs()) {
+ *res = make_funcs[n](mti, n);
push_term(mti, *res);
return 1;
}
@@ -1167,14 +1172,14 @@ static ERL_NIF_TERM grow_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
{
union { void* vp; struct make_term_info* p; }mti;
ERL_NIF_TERM term;
- if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || (argc>2 && !enif_get_uint(env,argv[2], &mti.p->n))) {
return enif_make_badarg(env);
}
mti.p->caller_env = env;
mti.p->other_term = argv[1];
- while (!make_term_n(mti.p, mti.p->n++, &term)) {
- mti.p->n = 0;
- }
+ mti.p->n %= num_of_make_funcs();
+ make_term_n(mti.p, mti.p->n++, &term);
mti.p->blob = enif_make_list_cell(mti.p->dst_env, term, mti.p->blob);
return atom_ok;
}
@@ -1194,6 +1199,23 @@ static ERL_NIF_TERM send_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_tuple3(env, atom_ok, enif_make_int(env,res), copy);
}
+static ERL_NIF_TERM send3_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ ErlNifPid to;
+ ERL_NIF_TERM copy;
+ int res;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || !enif_get_local_pid(env, argv[1], &to)) {
+ return enif_make_badarg(env);
+ }
+ mti.p->blob = enif_make_tuple2(mti.p->dst_env,
+ enif_make_copy(mti.p->dst_env, argv[2]),
+ mti.p->blob);
+ res = enif_send(env, &to, mti.p->dst_env, mti.p->blob);
+ return enif_make_int(env,res);
+}
+
void* threaded_sender(void *arg)
{
@@ -1253,6 +1275,28 @@ static ERL_NIF_TERM join_send_thread(ErlNifEnv* env, int argc, const ERL_NIF_TER
return enif_make_tuple2(env, atom_ok, enif_make_int(env, mti.p->send_res));
}
+static ERL_NIF_TERM copy_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_copy(env, mti.p->blob);
+}
+
+static ERL_NIF_TERM send_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifEnv* menv;
+ ErlNifPid pid;
+ int ret;
+ if (!enif_get_local_pid(env, argv[0], &pid)) {
+ return enif_make_badarg(env);
+ }
+ menv = enif_alloc_env();
+ ret = enif_send(env, &pid, menv, enif_make_copy(menv, argv[1]));
+ enif_free_env(menv);
+ return enif_make_int(env, ret);
+}
static ErlNifFunc nif_funcs[] =
{
@@ -1291,9 +1335,13 @@ static ErlNifFunc nif_funcs[] =
{"alloc_msgenv", 0, alloc_msgenv},
{"clear_msgenv", 1, clear_msgenv},
{"grow_blob", 2, grow_blob},
+ {"grow_blob", 3, grow_blob},
{"send_blob", 2, send_blob},
+ {"send3_blob", 3, send3_blob},
{"send_blob_thread", 3, send_blob_thread},
- {"join_send_thread", 1, join_send_thread}
+ {"join_send_thread", 1, join_send_thread},
+ {"copy_blob", 1, copy_blob},
+ {"send_term", 2, send_term}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/obsolete_SUITE.erl b/erts/emulator/test/obsolete_SUITE.erl
deleted file mode 100644
index b191f84ee0..0000000000
--- a/erts/emulator/test/obsolete_SUITE.erl
+++ /dev/null
@@ -1,123 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-
--module(obsolete_SUITE).
--author('[email protected]').
--compile(nowarn_obsolete_guard).
-
--export([all/1]).
-
--export([erl_threads/1]).
-
--include("test_server.hrl").
-
--define(DEFAULT_TIMETRAP_SECS, 240).
-
-all(doc) -> [];
-all(suite) ->
- case catch erlang:system_info({wordsize,external}) of
- 4 -> [erl_threads];
- _ -> {skip, "Only expected to work on true 32-bit architectures"}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Testcases %%
-%% %%
-
-erl_threads(suite) -> [];
-erl_threads(doc) -> [];
-erl_threads(Cfg) ->
- ?line case erlang:system_info(threads) of
- true ->
- ?line drv_case(Cfg, erl_threads);
- false ->
- ?line {skip, "Emulator not compiled with threads support"}
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Internal functions %%
-%% %%
-
-drv_case(Config, CaseName) ->
- drv_case(Config, CaseName, "").
-
-drv_case(Config, CaseName, TimeTrap) when integer(TimeTrap) ->
- drv_case(Config, CaseName, "", TimeTrap);
-drv_case(Config, CaseName, Command) when list(Command) ->
- drv_case(Config, CaseName, Command, ?DEFAULT_TIMETRAP_SECS).
-
-drv_case(Config, CaseName, TimeTrap, Command) when list(Command),
- integer(TimeTrap) ->
- drv_case(Config, CaseName, Command, TimeTrap);
-drv_case(Config, CaseName, Command, TimeTrap) when list(Config),
- atom(CaseName),
- list(Command),
- integer(TimeTrap) ->
- case ?t:os_type() of
- {Family, _} when Family == unix; Family == win32 ->
- ?line run_drv_case(Config, CaseName, Command, TimeTrap);
- SkipOs ->
- ?line {skipped,
- lists:flatten(["Not run on "
- | io_lib:format("~p",[SkipOs])])}
- end.
-
-run_drv_case(Config, CaseName, Command, TimeTrap) ->
- ?line Dog = test_server:timetrap(test_server:seconds(TimeTrap)),
- ?line DataDir = ?config(data_dir,Config),
- case erl_ddll:load_driver(DataDir, CaseName) of
- ok -> ok;
- {error, Error} ->
- io:format("~s\n", [erl_ddll:format_error(Error)]),
- ?line ?t:fail()
- end,
- ?line Port = open_port({spawn, atom_to_list(CaseName)}, []),
- ?line true = is_port(Port),
- ?line Port ! {self(), {command, Command}},
- ?line Result = receive_drv_result(Port, CaseName),
- ?line Port ! {self(), close},
- ?line receive
- {Port, closed} ->
- ok
- end,
- ?line ok = erl_ddll:unload_driver(CaseName),
- ?line test_server:timetrap_cancel(Dog),
- ?line Result.
-
-receive_drv_result(Port, CaseName) ->
- ?line receive
- {print, Port, CaseName, Str} ->
- ?line ?t:format("~s", [Str]),
- ?line receive_drv_result(Port, CaseName);
- {'EXIT', Port, Error} ->
- ?line ?t:fail(Error);
- {'EXIT', error, Error} ->
- ?line ?t:fail(Error);
- {failed, Port, CaseName, Comment} ->
- ?line ?t:fail(Comment);
- {skipped, Port, CaseName, Comment} ->
- ?line {skipped, Comment};
- {succeeded, Port, CaseName, ""} ->
- ?line succeeded;
- {succeeded, Port, CaseName, Comment} ->
- ?line {comment, Comment}
- end.
diff --git a/erts/emulator/test/obsolete_SUITE_data/Makefile.src b/erts/emulator/test/obsolete_SUITE_data/Makefile.src
deleted file mode 100644
index d8e2b861c0..0000000000
--- a/erts/emulator/test/obsolete_SUITE_data/Makefile.src
+++ /dev/null
@@ -1,33 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
-#
-
-TEST_DRVS = erl_threads@dll@
-CC = @CC@
-LD = @LD@
-CFLAGS = @SHLIB_CFLAGS@ -I@erl_include@ @DEFS@
-SHLIB_EXTRA_LDLIBS = testcase_driver@obj@
-
-all: $(TEST_DRVS)
-
-@SHLIB_RULES@
-
-testcase_driver@obj@: testcase_driver.c testcase_driver.h
-$(TEST_DRVS): testcase_driver@obj@
-
-
-
diff --git a/erts/emulator/test/obsolete_SUITE_data/erl_threads.c b/erts/emulator/test/obsolete_SUITE_data/erl_threads.c
deleted file mode 100644
index 27a5163121..0000000000
--- a/erts/emulator/test/obsolete_SUITE_data/erl_threads.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* ``The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved via the world wide web at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- * AB. All Rights Reserved.''
- *
- * $Id$
- */
-
-#include "testcase_driver.h"
-
-#ifndef __WIN32__
-
-#define NO_OF_THREADS 2
-
-#include <unistd.h>
-#include <errno.h>
-
-static int die;
-static int cw_passed;
-static int res_tf0;
-static int res_tf1;
-static erl_mutex_t mtx;
-static erl_cond_t cnd;
-static erl_thread_t tid[NO_OF_THREADS];
-static int need_join[NO_OF_THREADS];
-
-typedef struct {
- int n;
-} thr_arg_t;
-
-
-static void *tf0(void *vta)
-{
- int r;
-
- if (((thr_arg_t *) vta)->n != 0)
- goto fail;
-
- r = erts_mutex_lock(mtx);
- if (r != 0) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- r = erts_cond_wait(cnd, mtx);
- if (r != 0 || die) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- cw_passed++;
-
- r = erts_cond_wait(cnd, mtx);
- if (r != 0 || die) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- cw_passed++;
-
- r = erts_mutex_unlock(mtx);
- if (r != 0)
- goto fail;
-
- res_tf0 = 0;
-
- return (void *) &res_tf0;
-
- fail:
- return NULL;
-}
-
-
-static void *tf1(void *vta)
-{
- int r;
-
- if (((thr_arg_t *) vta)->n != 1)
- goto fail;
-
- r = erts_mutex_lock(mtx);
- if (r != 0) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- r = erts_cond_wait(cnd, mtx);
- if (r != 0 || die) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- cw_passed++;
-
- r = erts_cond_wait(cnd, mtx);
- if (r != 0 || die) {
- erts_mutex_unlock(mtx);
- goto fail;
- }
-
- cw_passed++;
-
- r = erts_mutex_unlock(mtx);
- if (r != 0)
- goto fail;
-
- res_tf1 = 1;
-
- erts_thread_exit((void *) &res_tf1);
-
- res_tf1 = 4711;
-
- fail:
- return NULL;
-}
-
-#endif /* #ifndef __WIN32__ */
-
-void
-testcase_run(TestCaseState_t *tcs)
-{
-#ifdef __WIN32__
- testcase_skipped(tcs, "Nothing to test; not supported on windows.");
-#else
- int i, r;
- void *tres[NO_OF_THREADS];
- thr_arg_t ta[NO_OF_THREADS];
- erl_thread_t t1;
-
- die = 0;
- cw_passed = 0;
-
- for (i = 0; i < NO_OF_THREADS; i++)
- need_join[i] = 0;
-
- res_tf0 = 17;
- res_tf1 = 17;
-
- cnd = mtx = NULL;
-
- /* Create mutex and cond */
- mtx = erts_mutex_create();
- ASSERT(tcs, mtx);
- cnd = erts_cond_create();
- ASSERT(tcs, cnd);
-
- /* Create the threads */
- ta[0].n = 0;
- r = erts_thread_create(&tid[0], tf0, (void *) &ta[0], 0);
- ASSERT(tcs, r == 0);
- need_join[0] = 1;
-
- ta[1].n = 1;
- r = erts_thread_create(&tid[1], tf1, (void *) &ta[1], 0);
- ASSERT(tcs, r == 0);
- need_join[1] = 1;
-
- /* Make sure the threads waits on cond wait */
- sleep(1);
-
- r = erts_mutex_lock(mtx);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- ASSERT_CLNUP(tcs, cw_passed == 0, (void) erts_mutex_unlock(mtx));
-
-
- /* Let one thread pass one cond wait */
- r = erts_cond_signal(cnd);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- r = erts_mutex_unlock(mtx);
- ASSERT(tcs, r == 0);
-
- sleep(1);
-
- r = erts_mutex_lock(mtx);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- ASSERT_CLNUP(tcs, cw_passed == 1, (void) erts_mutex_unlock(mtx));
-
-
- /* Let both threads pass one cond wait */
- r = erts_cond_broadcast(cnd);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- r = erts_mutex_unlock(mtx);
- ASSERT(tcs, r == 0);
-
- sleep(1);
-
- r = erts_mutex_lock(mtx);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- ASSERT_CLNUP(tcs, cw_passed == 3, (void) erts_mutex_unlock(mtx));
-
-
- /* Let the thread that only have passed one cond wait pass the other one */
- r = erts_cond_signal(cnd);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- r = erts_mutex_unlock(mtx);
- ASSERT(tcs, r == 0);
-
- sleep(1);
-
- r = erts_mutex_lock(mtx);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- ASSERT_CLNUP(tcs, cw_passed == 4, (void) erts_mutex_unlock(mtx));
-
- /* Both threads should have passed both cond waits and exited;
- join them and check returned values */
-
- r = erts_thread_join(tid[0], &tres[0]);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
- need_join[0] = 0;
-
- ASSERT_CLNUP(tcs, tres[0] == &res_tf0, (void) erts_mutex_unlock(mtx));
- ASSERT_CLNUP(tcs, res_tf0 == 0, (void) erts_mutex_unlock(mtx));
-
- r = erts_thread_join(tid[1], &tres[1]);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
- need_join[1] = 0;
-
- ASSERT_CLNUP(tcs, tres[1] == &res_tf1, (void) erts_mutex_unlock(mtx));
- ASSERT_CLNUP(tcs, res_tf1 == 1, (void) erts_mutex_unlock(mtx));
-
- /* Test signaling when noone waits */
-
- r = erts_cond_signal(cnd);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- /* Test broadcasting when noone waits */
-
- r = erts_cond_broadcast(cnd);
- ASSERT_CLNUP(tcs, r == 0, (void) erts_mutex_unlock(mtx));
-
- /* erts_cond_timedwait() not supported anymore */
- r = erts_cond_timedwait(cnd, mtx, 1000);
- ASSERT_CLNUP(tcs, r != 0, (void) erts_mutex_unlock(mtx));
- ASSERT_CLNUP(tcs,
- strcmp(erl_errno_id(r), "enotsup") == 0,
- (void) erts_mutex_unlock(mtx));
-
- r = erts_mutex_unlock(mtx);
- ASSERT(tcs, r == 0);
-
- r = erts_mutex_destroy(mtx);
- ASSERT(tcs, r == 0);
- mtx = NULL;
-
- r = erts_cond_destroy(cnd);
- ASSERT(tcs, r == 0);
- cnd = NULL;
-
- /* ... */
- t1 = erts_thread_self();
-
- if (cw_passed == 4711) {
- /* We don't want to execute this just check that the
- symbol/symbols is/are defined */
- erts_thread_kill(t1);
- }
-
-#endif /* #ifndef __WIN32__ */
-}
-
-char *
-testcase_name(void)
-{
- return "erl_threads";
-}
-
-void
-testcase_cleanup(TestCaseState_t *tcs)
-{
- int i;
- for (i = 0; i < NO_OF_THREADS; i++) {
- if (need_join[i]) {
- erts_mutex_lock(mtx);
- die = 1;
- erts_cond_broadcast(cnd);
- erts_mutex_unlock(mtx);
- erts_thread_join(tid[1], NULL);
- }
- }
- if (mtx)
- erts_mutex_destroy(mtx);
- if (cnd)
- erts_cond_destroy(cnd);
-}
-
diff --git a/erts/emulator/test/obsolete_SUITE_data/testcase_driver.c b/erts/emulator/test/obsolete_SUITE_data/testcase_driver.c
deleted file mode 100644
index 99d5adb041..0000000000
--- a/erts/emulator/test/obsolete_SUITE_data/testcase_driver.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/* ``The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved via the world wide web at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- * AB. All Rights Reserved.''
- *
- * $Id$
- */
-
-#include "testcase_driver.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <setjmp.h>
-#include <string.h>
-
-#ifdef __WIN32__
-#undef HAVE_VSNPRINTF
-#define HAVE_VSNPRINTF 1
-#define vsnprintf _vsnprintf
-#endif
-
-#ifndef HAVE_VSNPRINTF
-#define HAVE_VSNPRINTF 0
-#endif
-
-#define COMMENT_BUF_SZ 4096
-
-#define TESTCASE_FAILED 0
-#define TESTCASE_SKIPPED 1
-#define TESTCASE_SUCCEEDED 2
-
-typedef struct {
- TestCaseState_t visible;
- int port;
- int result;
- jmp_buf done_jmp_buf;
- char *comment;
- char comment_buf[COMMENT_BUF_SZ];
-} InternalTestCaseState_t;
-
-long testcase_drv_start(int port, char *command);
-int testcase_drv_stop(long drv_data);
-int testcase_drv_run(long drv_data, char *buf, int len);
-
-static DriverEntry testcase_drv_entry = {
- NULL,
- testcase_drv_start,
- testcase_drv_stop,
- testcase_drv_run
-};
-
-
-int DRIVER_INIT(testcase_drv)(void *arg)
-{
- testcase_drv_entry.driver_name = testcase_name();
- return (int) &testcase_drv_entry;
-}
-
-long
-testcase_drv_start(int port, char *command)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *)
- driver_alloc(sizeof(InternalTestCaseState_t));
- if (!itcs) {
- return -1;
- }
-
- itcs->visible.testcase_name = testcase_name();
- itcs->visible.extra = NULL;
- itcs->port = port;
- itcs->result = TESTCASE_FAILED;
- itcs->comment = "";
-
- return (long) itcs;
-}
-
-int
-testcase_drv_stop(long drv_data)
-{
- testcase_cleanup((TestCaseState_t *) drv_data);
- driver_free((void *) drv_data);
- return 0;
-}
-
-int
-testcase_drv_run(long drv_data, char *buf, int len)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data;
- DriverTermData result_atom;
- DriverTermData msg[12];
-
- itcs->visible.command = buf;
- itcs->visible.command_len = len;
-
- if (setjmp(itcs->done_jmp_buf) == 0) {
- testcase_run((TestCaseState_t *) itcs);
- itcs->result = TESTCASE_SUCCEEDED;
- }
-
- switch (itcs->result) {
- case TESTCASE_SUCCEEDED:
- result_atom = driver_mk_atom("succeeded");
- break;
- case TESTCASE_SKIPPED:
- result_atom = driver_mk_atom("skipped");
- break;
- case TESTCASE_FAILED:
- default:
- result_atom = driver_mk_atom("failed");
- break;
- }
-
- msg[0] = ERL_DRV_ATOM;
- msg[1] = (DriverTermData) result_atom;
-
- msg[2] = ERL_DRV_PORT;
- msg[3] = driver_mk_port(itcs->port);
-
- msg[4] = ERL_DRV_ATOM;
- msg[5] = driver_mk_atom(itcs->visible.testcase_name);
-
- msg[6] = ERL_DRV_STRING;
- msg[7] = (DriverTermData) itcs->comment;
- msg[8] = (DriverTermData) strlen(itcs->comment);
-
- msg[9] = ERL_DRV_TUPLE;
- msg[10] = (DriverTermData) 4;
-
- driver_output_term(itcs->port, msg, 11);
- return 0;
-}
-
-int
-testcase_assertion_failed(TestCaseState_t *tcs,
- char *file, int line, char *assertion)
-{
- testcase_failed(tcs, "%s:%d: Assertion failed: \"%s\"",
- file, line, assertion);
- return 0;
-}
-
-void
-testcase_printf(TestCaseState_t *tcs, char *frmt, ...)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
- DriverTermData msg[12];
- va_list va;
- va_start(va, frmt);
-#if HAVE_VSNPRINTF
- vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
-#else
- vsprintf(itcs->comment_buf, frmt, va);
-#endif
- va_end(va);
-
- msg[0] = ERL_DRV_ATOM;
- msg[1] = (DriverTermData) driver_mk_atom("print");
-
- msg[2] = ERL_DRV_PORT;
- msg[3] = driver_mk_port(itcs->port);
-
- msg[4] = ERL_DRV_ATOM;
- msg[5] = driver_mk_atom(itcs->visible.testcase_name);
-
- msg[6] = ERL_DRV_STRING;
- msg[7] = (DriverTermData) itcs->comment_buf;
- msg[8] = (DriverTermData) strlen(itcs->comment_buf);
-
- msg[9] = ERL_DRV_TUPLE;
- msg[10] = (DriverTermData) 4;
-
- driver_output_term(itcs->port, msg, 11);
-}
-
-
-void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
- va_list va;
- va_start(va, frmt);
-#if HAVE_VSNPRINTF
- vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
-#else
- vsprintf(itcs->comment_buf, frmt, va);
-#endif
- va_end(va);
-
- itcs->result = TESTCASE_SUCCEEDED;
- itcs->comment = itcs->comment_buf;
-
- longjmp(itcs->done_jmp_buf, 1);
-}
-
-void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
- va_list va;
- va_start(va, frmt);
-#if HAVE_VSNPRINTF
- vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
-#else
- vsprintf(itcs->comment_buf, frmt, va);
-#endif
- va_end(va);
-
- itcs->result = TESTCASE_SKIPPED;
- itcs->comment = itcs->comment_buf;
-
- longjmp(itcs->done_jmp_buf, 1);
-}
-
-void testcase_failed(TestCaseState_t *tcs, char *frmt, ...)
-{
- InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
- char buf[10];
- size_t bufsz = sizeof(buf);
- va_list va;
- va_start(va, frmt);
-#if HAVE_VSNPRINTF
- vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
-#else
- vsprintf(itcs->comment_buf, frmt, va);
-#endif
- va_end(va);
-
- itcs->result = TESTCASE_FAILED;
- itcs->comment = itcs->comment_buf;
-
- if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0
- && strcmp("true", buf) == 0) {
- fprintf(stderr, "Testcase \"%s\" failed: %s\n",
- itcs->visible.testcase_name, itcs->comment);
- abort();
- }
-
- longjmp(itcs->done_jmp_buf, 1);
-}
-
-void *testcase_alloc(size_t size)
-{
- return driver_alloc(size);
-}
-
-void *testcase_realloc(void *ptr, size_t size)
-{
- return driver_realloc(ptr, size);
-}
-
-void testcase_free(void *ptr)
-{
- driver_free(ptr);
-}
diff --git a/erts/emulator/test/obsolete_SUITE_data/testcase_driver.h b/erts/emulator/test/obsolete_SUITE_data/testcase_driver.h
deleted file mode 100644
index 3d85ca6df0..0000000000
--- a/erts/emulator/test/obsolete_SUITE_data/testcase_driver.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* ``The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved via the world wide web at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- * AB. All Rights Reserved.''
- *
- * $Id$
- */
-
-#ifndef TESTCASE_DRIVER_H__
-#define TESTCASE_DRIVER_H__
-
-#include "obsolete/driver.h"
-#include <stdlib.h>
-
-typedef struct {
- char *testcase_name;
- char *command;
- int command_len;
- void *extra;
-} TestCaseState_t;
-
-#define ASSERT_CLNUP(TCS, B, CLN) \
-do { \
- if (!(B)) { \
- CLN; \
- testcase_assertion_failed((TCS), __FILE__, __LINE__, #B); \
- } \
-} while (0)
-
-#define ASSERT(TCS, B) ASSERT_CLNUP(TCS, B, (void) 0)
-
-void testcase_printf(TestCaseState_t *tcs, char *frmt, ...);
-void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...);
-void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...);
-void testcase_failed(TestCaseState_t *tcs, char *frmt, ...);
-int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line,
- char *assertion);
-void *testcase_alloc(size_t size);
-void *testcase_realloc(void *ptr, size_t size);
-void testcase_free(void *ptr);
-
-
-char *testcase_name(void);
-void testcase_run(TestCaseState_t *tcs);
-void testcase_cleanup(TestCaseState_t *tcs);
-
-#endif
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index ab727b7cb1..4f4458802c 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -33,7 +33,7 @@
-include("test_server.hrl").
%-compile(export_all).
--export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+-export([all/1, init_per_testcase/2, fin_per_testcase/2, end_per_suite/1]).
-export([equal/1,
few_low/1,
@@ -49,7 +49,8 @@
cpu_topology/1,
sct_cmd/1,
sbt_cmd/1,
- scheduler_suspend/1]).
+ scheduler_suspend/1,
+ reader_groups/1]).
-define(DEFAULT_TIMEOUT, ?t:minutes(10)).
@@ -67,7 +68,8 @@ all(suite) ->
equal_with_high_max,
bound_process,
scheduler_bind,
- scheduler_suspend].
+ scheduler_suspend,
+ reader_groups].
init_per_testcase(Case, Config) when is_list(Config) ->
Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
@@ -81,6 +83,10 @@ fin_per_testcase(_Case, Config) when is_list(Config) ->
?t:timetrap_cancel(Dog),
ok.
+end_per_suite(Config) ->
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ Config.
+
-define(ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED, (2000*2000)).
-define(DEFAULT_TEST_REDS_PER_SCHED, 200000000).
@@ -965,12 +971,361 @@ sst3_loop(S, N) ->
erlang:system_flag(schedulers_online, 1),
erlang:system_flag(schedulers_online, S),
sst3_loop(S, N-1).
+
+reader_groups(Config) when is_list(Config) ->
+ %% White box testing. These results are correct, but other results
+ %% could be too...
+
+ %% The actual tilepro64 topology
+ CPUT0 = [{processor,[{node,[{core,{logical,0}},
+ {core,{logical,1}},
+ {core,{logical,2}},
+ {core,{logical,8}},
+ {core,{logical,9}},
+ {core,{logical,10}},
+ {core,{logical,11}},
+ {core,{logical,16}},
+ {core,{logical,17}},
+ {core,{logical,18}},
+ {core,{logical,19}},
+ {core,{logical,24}},
+ {core,{logical,25}},
+ {core,{logical,27}},
+ {core,{logical,29}}]},
+ {node,[{core,{logical,3}},
+ {core,{logical,4}},
+ {core,{logical,5}},
+ {core,{logical,6}},
+ {core,{logical,7}},
+ {core,{logical,12}},
+ {core,{logical,13}},
+ {core,{logical,14}},
+ {core,{logical,15}},
+ {core,{logical,20}},
+ {core,{logical,21}},
+ {core,{logical,22}},
+ {core,{logical,23}},
+ {core,{logical,28}},
+ {core,{logical,30}}]},
+ {node,[{core,{logical,31}},
+ {core,{logical,36}},
+ {core,{logical,37}},
+ {core,{logical,38}},
+ {core,{logical,44}},
+ {core,{logical,45}},
+ {core,{logical,46}},
+ {core,{logical,47}},
+ {core,{logical,51}},
+ {core,{logical,52}},
+ {core,{logical,53}},
+ {core,{logical,54}},
+ {core,{logical,55}},
+ {core,{logical,60}},
+ {core,{logical,61}}]},
+ {node,[{core,{logical,26}},
+ {core,{logical,32}},
+ {core,{logical,33}},
+ {core,{logical,34}},
+ {core,{logical,35}},
+ {core,{logical,39}},
+ {core,{logical,40}},
+ {core,{logical,41}},
+ {core,{logical,42}},
+ {core,{logical,43}},
+ {core,{logical,48}},
+ {core,{logical,49}},
+ {core,{logical,50}},
+ {core,{logical,58}}]}]}],
+
+ ?line [{0,1},{1,1},{2,1},{3,3},{4,3},{5,3},{6,3},{7,3},{8,1},{9,1},{10,1},
+ {11,1},{12,3},{13,3},{14,4},{15,4},{16,2},{17,2},{18,2},{19,2},
+ {20,4},{21,4},{22,4},{23,4},{24,2},{25,2},{26,7},{27,2},{28,4},
+ {29,2},{30,4},{31,5},{32,7},{33,7},{34,7},{35,7},{36,5},{37,5},
+ {38,5},{39,7},{40,7},{41,8},{42,8},{43,8},{44,5},{45,5},{46,5},
+ {47,6},{48,8},{49,8},{50,8},{51,6},{52,6},{53,6},{54,6},{55,6},
+ {58,8},{60,6},{61,6}]
+ = reader_groups_map(CPUT0, 8),
+
+ CPUT1 = [n([p([c([t(l(0)),t(l(1)),t(l(2)),t(l(3))]),
+ c([t(l(4)),t(l(5)),t(l(6)),t(l(7))]),
+ c([t(l(8)),t(l(9)),t(l(10)),t(l(11))]),
+ c([t(l(12)),t(l(13)),t(l(14)),t(l(15))])]),
+ p([c([t(l(16)),t(l(17)),t(l(18)),t(l(19))]),
+ c([t(l(20)),t(l(21)),t(l(22)),t(l(23))]),
+ c([t(l(24)),t(l(25)),t(l(26)),t(l(27))]),
+ c([t(l(28)),t(l(29)),t(l(30)),t(l(31))])])]),
+ n([p([c([t(l(32)),t(l(33)),t(l(34)),t(l(35))]),
+ c([t(l(36)),t(l(37)),t(l(38)),t(l(39))]),
+ c([t(l(40)),t(l(41)),t(l(42)),t(l(43))]),
+ c([t(l(44)),t(l(45)),t(l(46)),t(l(47))])]),
+ p([c([t(l(48)),t(l(49)),t(l(50)),t(l(51))]),
+ c([t(l(52)),t(l(53)),t(l(54)),t(l(55))]),
+ c([t(l(56)),t(l(57)),t(l(58)),t(l(59))]),
+ c([t(l(60)),t(l(61)),t(l(62)),t(l(63))])])]),
+ n([p([c([t(l(64)),t(l(65)),t(l(66)),t(l(67))]),
+ c([t(l(68)),t(l(69)),t(l(70)),t(l(71))]),
+ c([t(l(72)),t(l(73)),t(l(74)),t(l(75))]),
+ c([t(l(76)),t(l(77)),t(l(78)),t(l(79))])]),
+ p([c([t(l(80)),t(l(81)),t(l(82)),t(l(83))]),
+ c([t(l(84)),t(l(85)),t(l(86)),t(l(87))]),
+ c([t(l(88)),t(l(89)),t(l(90)),t(l(91))]),
+ c([t(l(92)),t(l(93)),t(l(94)),t(l(95))])])]),
+ n([p([c([t(l(96)),t(l(97)),t(l(98)),t(l(99))]),
+ c([t(l(100)),t(l(101)),t(l(102)),t(l(103))]),
+ c([t(l(104)),t(l(105)),t(l(106)),t(l(107))]),
+ c([t(l(108)),t(l(109)),t(l(110)),t(l(111))])]),
+ p([c([t(l(112)),t(l(113)),t(l(114)),t(l(115))]),
+ c([t(l(116)),t(l(117)),t(l(118)),t(l(119))]),
+ c([t(l(120)),t(l(121)),t(l(122)),t(l(123))]),
+ c([t(l(124)),t(l(125)),t(l(126)),t(l(127))])])])],
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,2},{5,2},{6,2},{7,2},{8,3},{9,3},
+ {10,3},{11,3},{12,4},{13,4},{14,4},{15,4},{16,5},{17,5},{18,5},
+ {19,5},{20,6},{21,6},{22,6},{23,6},{24,7},{25,7},{26,7},{27,7},
+ {28,8},{29,8},{30,8},{31,8},{32,9},{33,9},{34,9},{35,9},{36,10},
+ {37,10},{38,10},{39,10},{40,11},{41,11},{42,11},{43,11},{44,12},
+ {45,12},{46,12},{47,12},{48,13},{49,13},{50,13},{51,13},{52,14},
+ {53,14},{54,14},{55,14},{56,15},{57,15},{58,15},{59,15},{60,16},
+ {61,16},{62,16},{63,16},{64,17},{65,17},{66,17},{67,17},{68,18},
+ {69,18},{70,18},{71,18},{72,19},{73,19},{74,19},{75,19},{76,20},
+ {77,20},{78,20},{79,20},{80,21},{81,21},{82,21},{83,21},{84,22},
+ {85,22},{86,22},{87,22},{88,23},{89,23},{90,23},{91,23},{92,24},
+ {93,24},{94,24},{95,24},{96,25},{97,25},{98,25},{99,25},{100,26},
+ {101,26},{102,26},{103,26},{104,27},{105,27},{106,27},{107,27},
+ {108,28},{109,28},{110,28},{111,28},{112,29},{113,29},{114,29},
+ {115,29},{116,30},{117,30},{118,30},{119,30},{120,31},{121,31},
+ {122,31},{123,31},{124,32},{125,32},{126,32},{127,32}]
+ = reader_groups_map(CPUT1, 128),
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,1},{5,1},{6,1},{7,1},{8,1},{9,1},{10,1},
+ {11,1},{12,1},{13,1},{14,1},{15,1},{16,1},{17,1},{18,1},{19,1},
+ {20,1},{21,1},{22,1},{23,1},{24,1},{25,1},{26,1},{27,1},{28,1},
+ {29,1},{30,1},{31,1},{32,1},{33,1},{34,1},{35,1},{36,1},{37,1},
+ {38,1},{39,1},{40,1},{41,1},{42,1},{43,1},{44,1},{45,1},{46,1},
+ {47,1},{48,1},{49,1},{50,1},{51,1},{52,1},{53,1},{54,1},{55,1},
+ {56,1},{57,1},{58,1},{59,1},{60,1},{61,1},{62,1},{63,1},{64,2},
+ {65,2},{66,2},{67,2},{68,2},{69,2},{70,2},{71,2},{72,2},{73,2},
+ {74,2},{75,2},{76,2},{77,2},{78,2},{79,2},{80,2},{81,2},{82,2},
+ {83,2},{84,2},{85,2},{86,2},{87,2},{88,2},{89,2},{90,2},{91,2},
+ {92,2},{93,2},{94,2},{95,2},{96,2},{97,2},{98,2},{99,2},{100,2},
+ {101,2},{102,2},{103,2},{104,2},{105,2},{106,2},{107,2},{108,2},
+ {109,2},{110,2},{111,2},{112,2},{113,2},{114,2},{115,2},{116,2},
+ {117,2},{118,2},{119,2},{120,2},{121,2},{122,2},{123,2},{124,2},
+ {125,2},{126,2},{127,2}]
+ = reader_groups_map(CPUT1, 2),
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,2},{5,2},{6,2},{7,2},{8,3},{9,3},{10,3},
+ {11,3},{12,3},{13,3},{14,3},{15,3},{16,4},{17,4},{18,4},{19,4},
+ {20,4},{21,4},{22,4},{23,4},{24,5},{25,5},{26,5},{27,5},{28,5},
+ {29,5},{30,5},{31,5},{32,6},{33,6},{34,6},{35,6},{36,6},{37,6},
+ {38,6},{39,6},{40,7},{41,7},{42,7},{43,7},{44,7},{45,7},{46,7},
+ {47,7},{48,8},{49,8},{50,8},{51,8},{52,8},{53,8},{54,8},{55,8},
+ {56,9},{57,9},{58,9},{59,9},{60,9},{61,9},{62,9},{63,9},{64,10},
+ {65,10},{66,10},{67,10},{68,10},{69,10},{70,10},{71,10},{72,11},
+ {73,11},{74,11},{75,11},{76,11},{77,11},{78,11},{79,11},{80,12},
+ {81,12},{82,12},{83,12},{84,12},{85,12},{86,12},{87,12},{88,13},
+ {89,13},{90,13},{91,13},{92,13},{93,13},{94,13},{95,13},{96,14},
+ {97,14},{98,14},{99,14},{100,14},{101,14},{102,14},{103,14},
+ {104,15},{105,15},{106,15},{107,15},{108,15},{109,15},{110,15},
+ {111,15},{112,16},{113,16},{114,16},{115,16},{116,16},{117,16},
+ {118,16},{119,16},{120,17},{121,17},{122,17},{123,17},{124,17},
+ {125,17},{126,17},{127,17}]
+ = reader_groups_map(CPUT1, 17),
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,1},{5,1},{6,1},{7,1},{8,1},{9,1},{10,1},
+ {11,1},{12,1},{13,1},{14,1},{15,1},{16,2},{17,2},{18,2},{19,2},
+ {20,2},{21,2},{22,2},{23,2},{24,2},{25,2},{26,2},{27,2},{28,2},
+ {29,2},{30,2},{31,2},{32,3},{33,3},{34,3},{35,3},{36,3},{37,3},
+ {38,3},{39,3},{40,3},{41,3},{42,3},{43,3},{44,3},{45,3},{46,3},
+ {47,3},{48,4},{49,4},{50,4},{51,4},{52,4},{53,4},{54,4},{55,4},
+ {56,4},{57,4},{58,4},{59,4},{60,4},{61,4},{62,4},{63,4},{64,5},
+ {65,5},{66,5},{67,5},{68,5},{69,5},{70,5},{71,5},{72,5},{73,5},
+ {74,5},{75,5},{76,5},{77,5},{78,5},{79,5},{80,6},{81,6},{82,6},
+ {83,6},{84,6},{85,6},{86,6},{87,6},{88,6},{89,6},{90,6},{91,6},
+ {92,6},{93,6},{94,6},{95,6},{96,7},{97,7},{98,7},{99,7},{100,7},
+ {101,7},{102,7},{103,7},{104,7},{105,7},{106,7},{107,7},{108,7},
+ {109,7},{110,7},{111,7},{112,7},{113,7},{114,7},{115,7},{116,7},
+ {117,7},{118,7},{119,7},{120,7},{121,7},{122,7},{123,7},{124,7},
+ {125,7},{126,7},{127,7}]
+ = reader_groups_map(CPUT1, 7),
+
+ ?line CPUT2 = [p([c(l(0)),c(l(1)),c(l(2)),c(l(3)),c(l(4))]),
+ p([t(l(5)),t(l(6)),t(l(7)),t(l(8)),t(l(9))]),
+ p([t(l(10))]),
+ p([c(l(11)),c(l(12)),c(l(13))]),
+ p([c(l(14)),c(l(15))])],
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,1},
+ {5,2},{6,2},{7,2},{8,2},{9,2},
+ {10,3},
+ {11,4},{12,4},{13,4},
+ {14,5},{15,5}] = reader_groups_map(CPUT2, 5),
+
+
+ ?line [{0,1},{1,1},{2,2},{3,2},{4,2},
+ {5,3},{6,3},{7,3},{8,3},{9,3},
+ {10,4},
+ {11,5},{12,5},{13,5},
+ {14,6},{15,6}] = reader_groups_map(CPUT2, 6),
+
+ ?line [{0,1},{1,1},{2,2},{3,2},{4,2},
+ {5,3},{6,3},{7,3},{8,3},{9,3},
+ {10,4},
+ {11,5},{12,6},{13,6},
+ {14,7},{15,7}] = reader_groups_map(CPUT2, 7),
+
+ ?line [{0,1},{1,1},{2,2},{3,2},{4,2},
+ {5,3},{6,3},{7,3},{8,3},{9,3},
+ {10,4},
+ {11,5},{12,6},{13,6},
+ {14,7},{15,8}] = reader_groups_map(CPUT2, 8),
+
+ ?line [{0,1},{1,2},{2,2},{3,3},{4,3},
+ {5,4},{6,4},{7,4},{8,4},{9,4},
+ {10,5},
+ {11,6},{12,7},{13,7},
+ {14,8},{15,9}] = reader_groups_map(CPUT2, 9),
+
+ ?line [{0,1},{1,2},{2,2},{3,3},{4,3},
+ {5,4},{6,4},{7,4},{8,4},{9,4},
+ {10,5},
+ {11,6},{12,7},{13,8},
+ {14,9},{15,10}] = reader_groups_map(CPUT2, 10),
+
+ ?line [{0,1},{1,2},{2,3},{3,4},{4,4},
+ {5,5},{6,5},{7,5},{8,5},{9,5},
+ {10,6},
+ {11,7},{12,8},{13,9},
+ {14,10},{15,11}] = reader_groups_map(CPUT2, 11),
+
+ ?line [{0,1},{1,2},{2,3},{3,4},{4,5},
+ {5,6},{6,6},{7,6},{8,6},{9,6},
+ {10,7},
+ {11,8},{12,9},{13,10},
+ {14,11},{15,12}] = reader_groups_map(CPUT2, 100),
+
+ CPUT3 = [p([t(l(5)),t(l(6)),t(l(7)),t(l(8)),t(l(9))]),
+ p([t(l(10))]),
+ p([c(l(11)),c(l(12)),c(l(13))]),
+ p([c(l(14)),c(l(15))]),
+ p([c(l(0)),c(l(1)),c(l(2)),c(l(3)),c(l(4))])],
+
+ ?line [{0,5},{1,5},{2,6},{3,6},{4,6},
+ {5,1},{6,1},{7,1},{8,1},{9,1},
+ {10,2},{11,3},{12,3},{13,3},
+ {14,4},{15,4}] = reader_groups_map(CPUT3, 6),
+
+ CPUT4 = [p([t(l(0)),t(l(1)),t(l(2)),t(l(3)),t(l(4))]),
+ p([t(l(5))]),
+ p([c(l(6)),c(l(7)),c(l(8))]),
+ p([c(l(9)),c(l(10))]),
+ p([c(l(11)),c(l(12)),c(l(13)),c(l(14)),c(l(15))])],
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,1},
+ {5,2},
+ {6,3},{7,3},{8,3},
+ {9,4},{10,4},
+ {11,5},{12,5},{13,6},{14,6},{15,6}] = reader_groups_map(CPUT4, 6),
+
+ ?line [{0,1},{1,1},{2,1},{3,1},{4,1},
+ {5,2},
+ {6,3},{7,4},{8,4},
+ {9,5},{10,5},
+ {11,6},{12,6},{13,7},{14,7},{15,7}] = reader_groups_map(CPUT4, 7),
+
+ ?line [{0,1},{65535,2}] = reader_groups_map([c(l(0)),c(l(65535))], 10),
+
+ ?line ok.
+reader_groups_map(CPUT, Groups) ->
+ Old = erlang:system_info({cpu_topology, defined}),
+ erlang:system_flag(cpu_topology, CPUT),
+ enable_internal_state(),
+ Res = erts_debug:get_internal_state({reader_groups_map, Groups}),
+ erlang:system_flag(cpu_topology, Old),
+ lists:sort(Res).
+
%%
%% Utils
%%
+tilera_cpu_topology() ->
+ [{processor,[{node,[{core,{logical,0}},
+ {core,{logical,1}},
+ {core,{logical,2}},
+ {core,{logical,8}},
+ {core,{logical,9}},
+ {core,{logical,10}},
+ {core,{logical,11}},
+ {core,{logical,16}},
+ {core,{logical,17}},
+ {core,{logical,18}},
+ {core,{logical,19}},
+ {core,{logical,24}},
+ {core,{logical,25}},
+ {core,{logical,27}},
+ {core,{logical,29}}]},
+ {node,[{core,{logical,3}},
+ {core,{logical,4}},
+ {core,{logical,5}},
+ {core,{logical,6}},
+ {core,{logical,7}},
+ {core,{logical,12}},
+ {core,{logical,13}},
+ {core,{logical,14}},
+ {core,{logical,15}},
+ {core,{logical,20}},
+ {core,{logical,21}},
+ {core,{logical,22}},
+ {core,{logical,23}},
+ {core,{logical,28}},
+ {core,{logical,30}}]},
+ {node,[{core,{logical,31}},
+ {core,{logical,36}},
+ {core,{logical,37}},
+ {core,{logical,38}},
+ {core,{logical,44}},
+ {core,{logical,45}},
+ {core,{logical,46}},
+ {core,{logical,47}},
+ {core,{logical,51}},
+ {core,{logical,52}},
+ {core,{logical,53}},
+ {core,{logical,54}},
+ {core,{logical,55}},
+ {core,{logical,60}},
+ {core,{logical,61}}]},
+ {node,[{core,{logical,26}},
+ {core,{logical,32}},
+ {core,{logical,33}},
+ {core,{logical,34}},
+ {core,{logical,35}},
+ {core,{logical,39}},
+ {core,{logical,40}},
+ {core,{logical,41}},
+ {core,{logical,42}},
+ {core,{logical,43}},
+ {core,{logical,48}},
+ {core,{logical,49}},
+ {core,{logical,50}},
+ {core,{logical,58}}]}]}].
+
+l(Id) ->
+ {logical, Id}.
+
+t(X) ->
+ {thread, X}.
+
+c(X) ->
+ {core, X}.
+
+p(X) ->
+ {processor, X}.
+
+n(X) ->
+ {node, X}.
+
mcall(Node, Funs) ->
Parent = self(),
Refs = lists:map(fun (Fun) ->
diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl
index 489adbd660..5fd01a9ac5 100644
--- a/erts/emulator/test/send_term_SUITE.erl
+++ b/erts/emulator/test/send_term_SUITE.erl
@@ -76,40 +76,43 @@ basic(Config) when is_list(Config) ->
?line ExpectedBinTup = term(P, 7),
%% single terms
- ?line [] = term(P, 8), % ERL_DRV_NIL
- ?line '' = term(P, 9), % ERL_DRV_ATOM
- ?line an_atom = term(P, 10), % ERL_DRV_ATOM
- ?line -4711 = term(P, 11), % ERL_DRV_INT
- ?line 4711 = term(P, 12), % ERL_DRV_UINT
- ?line P = term(P, 13), % ERL_DRV_PORT
- ?line <<>> = term(P, 14), % ERL_DRV_BINARY
- ?line <<"hejsan">> = term(P, 15), % ERL_DRV_BINARY
- ?line <<>> = term(P, 16), % ERL_DRV_BUF2BINARY
- ?line <<>> = term(P, 17), % ERL_DRV_BUF2BINARY
- ?line <<"hoppsan">> = term(P, 18), % ERL_DRV_BUF2BINARY
- ?line "" = term(P, 19), % ERL_DRV_STRING
- ?line "" = term(P, 20), % ERL_DRV_STRING
- ?line "hippsan" = term(P, 21), % ERL_DRV_STRING
- ?line {} = term(P, 22), % ERL_DRV_TUPLE
- ?line [] = term(P, 23), % ERL_DRV_LIST
- ?line Self = term(P, 24), % ERL_DRV_PID
- ?line [] = term(P, 25), % ERL_DRV_STRING_CONS
- ?line AFloat = term(P, 26), % ERL_DRV_FLOAT
+ Singles = [{[], 8}, % ERL_DRV_NIL
+ {'', 9}, % ERL_DRV_ATOM
+ {an_atom, 10}, % ERL_DRV_ATOM
+ {-4711, 11}, % ERL_DRV_INT
+ {4711, 12}, % ERL_DRV_UINT
+ {P, 13}, % ERL_DRV_PORT
+ {<<>>, 14}, % ERL_DRV_BINARY
+ {<<"hejsan">>, 15}, % ERL_DRV_BINARY
+ {<<>>, 16}, % ERL_DRV_BUF2BINARY
+ {<<>>, 17}, % ERL_DRV_BUF2BINARY
+ {<<"hoppsan">>, 18}, % ERL_DRV_BUF2BINARY
+ {"", 19}, % ERL_DRV_STRING
+ {"", 20}, % ERL_DRV_STRING
+ {"hippsan", 21}, % ERL_DRV_STRING
+ {{}, 22}, % ERL_DRV_TUPLE
+ {[], 23}, % ERL_DRV_LIST
+ {Self, 24}, % ERL_DRV_PID
+ {[], 25}, % ERL_DRV_STRING_CONS
+ {[], 27}, % ERL_DRV_EXT2TERM
+ {18446744073709551615, 28}, % ERL_DRV_UINT64
+ {20233590931456, 29}, % ERL_DRV_UINT64
+ {4711, 30}, % ERL_DRV_UINT64
+ {0, 31}, % ERL_DRV_UINT64
+ {9223372036854775807, 32}, % ERL_DRV_INT64
+ {20233590931456, 33}, % ERL_DRV_INT64
+ {4711, 34}, % ERL_DRV_INT64
+ {0, 35}, % ERL_DRV_INT64
+ {-1, 36}, % ERL_DRV_INT64
+ {-4711, 37}, % ERL_DRV_INT64
+ {-20233590931456, 38}, % ERL_DRV_INT64
+ {-9223372036854775808, 39}], % ERL_DRV_INT64
+ ?line {Terms, Ops} = lists:unzip(Singles),
+ ?line Terms = term(P,Ops),
+
+ AFloat = term(P, 26), % ERL_DRV_FLOAT
?line true = AFloat < 0.001,
?line true = AFloat > -0.001,
- ?line [] = term(P, 27), % ERL_DRV_EXT2TERM
- ?line 18446744073709551615 = term(P, 28), % ERL_DRV_UINT64
- ?line 20233590931456 = term(P, 29), % ERL_DRV_UINT64
- ?line 4711 = term(P, 30), % ERL_DRV_UINT64
- ?line 0 = term(P, 31), % ERL_DRV_UINT64
- ?line 9223372036854775807 = term(P, 32), % ERL_DRV_INT64
- ?line 20233590931456 = term(P, 33), % ERL_DRV_INT64
- ?line 4711 = term(P, 34), % ERL_DRV_INT64
- ?line 0 = term(P, 35), % ERL_DRV_INT64
- ?line -1 = term(P, 36), % ERL_DRV_INT64
- ?line -4711 = term(P, 37), % ERL_DRV_INT64
- ?line -20233590931456 = term(P, 38), % ERL_DRV_INT64
- ?line -9223372036854775808 = term(P, 39), % ERL_DRV_INT64
%% Failure cases.
?line [] = term(P, 127),
diff --git a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
index 6638de0560..165cce2e9d 100644
--- a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
+++ b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
@@ -17,6 +17,7 @@
*/
#include "erl_driver.h"
+#include <stdio.h>
#include <errno.h>
#include <string.h>
@@ -65,12 +66,21 @@ static void fail_term(ErlDrvTermData* msg, int len, int line);
static void send_term_drv_run(ErlDrvData port, char *buf, int count)
{
- ErlDrvTermData msg[1024];
-
- switch (*buf) {
+ char buf7[1024];
+ ErlDrvTermData spec[1024];
+ ErlDrvTermData* msg = spec;
+ ErlDrvBinary* bins[15];
+ int bin_ix = 0;
+ ErlDrvSInt64 s64[15];
+ int s64_ix = 0;
+ ErlDrvUInt64 u64[15];
+ int u64_ix = 0;
+ int i = 0;
+
+ for (i=0; i<count; i++) switch (buf[i]) {
case 0:
msg[0] = ERL_DRV_NIL;
- output_term(msg, 1);
+ msg += 1;
break;
case 1: /* Most term types inside a tuple. */
@@ -102,7 +112,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[22] = driver_connected(erlang_port);
msg[23] = ERL_DRV_TUPLE;
msg[24] = (ErlDrvTermData) 7;
- output_term(msg, 25);
+ msg += 25;
}
break;
@@ -117,7 +127,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[i] = ERL_DRV_NIL;
msg[i+1] = ERL_DRV_LIST;
msg[i+2] = (ErlDrvTermData) 201;
- output_term(msg, i+3);
+ msg += i+3;
}
break;
@@ -126,7 +136,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
ErlDrvBinary* bin;
int i;
- bin = driver_alloc_binary(256);
+ bin = bins[bin_ix++] = driver_alloc_binary(256);
for (i = 0; i < 256; i++) {
bin->orig_bytes[i] = i;
}
@@ -140,8 +150,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[7] = (ErlDrvTermData) 23;
msg[8] = ERL_DRV_TUPLE;
msg[9] = (ErlDrvTermData) 2;
- output_term(msg, 10);
- driver_free_binary(bin);
+ msg += 10;
}
break;
@@ -152,11 +161,11 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[3] = driver_caller(erlang_port);
msg[4] = ERL_DRV_TUPLE;
msg[5] = (ErlDrvTermData) 2;
- output_term(msg, 6);
+ msg += 6;
break;
case 5:
- output_term(msg, make_ext_term_list(msg, 0));
+ msg += make_ext_term_list(msg, 0);
break;
case 6:
@@ -166,94 +175,91 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[3] = ~((ErlDrvTermData) 0);
msg[4] = ERL_DRV_TUPLE;
msg[5] = (ErlDrvTermData) 2;
- output_term(msg, 6);
+ msg += 6;
break;
case 7: {
int len = 0;
- char buf[1024];
- memset(buf, 17, sizeof(buf));
+ memset(buf7, 17, sizeof(buf7));
/* empty heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */
msg[len++] = (ErlDrvTermData) 0;
/* empty heap binary again */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0]; /* ptr is ok if size == 0 */
+ msg[len++] = (ErlDrvTermData) buf7; /* ptr is ok if size == 0 */
msg[len++] = (ErlDrvTermData) 0;
/* heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0];
+ msg[len++] = (ErlDrvTermData) buf7;
msg[len++] = (ErlDrvTermData) 17;
/* off heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0];
- msg[len++] = (ErlDrvTermData) sizeof(buf);
+ msg[len++] = (ErlDrvTermData) buf7;
+ msg[len++] = (ErlDrvTermData) sizeof(buf7);
msg[len++] = ERL_DRV_TUPLE;
msg[len++] = (ErlDrvTermData) 4;
- output_term(msg, len);
+ msg += len;
break;
}
case 8:
msg[0] = ERL_DRV_NIL;
- output_term(msg, 1);
+ msg += 1;
break;
case 9:
msg[0] = ERL_DRV_ATOM;
msg[1] = (ErlDrvTermData) driver_mk_atom("");
- output_term(msg, 2);
+ msg += 2;
break;
case 10:
msg[0] = ERL_DRV_ATOM;
msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom");
- output_term(msg, 2);
+ msg += 2;
break;
case 11:
msg[0] = ERL_DRV_INT;
msg[1] = (ErlDrvTermData) -4711;
- output_term(msg, 2);
+ msg += 2;
break;
case 12:
msg[0] = ERL_DRV_UINT;
msg[1] = (ErlDrvTermData) 4711;
- output_term(msg, 2);
+ msg += 2;
break;
case 13:
msg[0] = ERL_DRV_PORT;
msg[1] = driver_mk_port(erlang_port);
- output_term(msg, 2);
+ msg += 2;
break;
case 14: {
- ErlDrvBinary *dbin = driver_alloc_binary(0);
+ ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(0);
msg[0] = ERL_DRV_BINARY;
msg[1] = (ErlDrvTermData) dbin;
msg[2] = (ErlDrvTermData) 0;
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
- driver_free_binary(dbin);
+ msg += 4;
break;
}
case 15: {
- char buf[] = "hejsan";
- ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1);
+ static const char buf[] = "hejsan";
+ ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(sizeof(buf)-1);
if (dbin)
memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1);
msg[0] = ERL_DRV_BINARY;
msg[1] = (ErlDrvTermData) dbin;
msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0);
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
- driver_free_binary(dbin);
+ msg += 4;
break;
}
@@ -261,24 +267,24 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) NULL;
msg[2] = (ErlDrvTermData) 0;
- output_term(msg, 3);
+ msg += 3;
break;
case 17: {
- char buf[] = "";
+ static const char buf[] = "";
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 18: {
- char buf[] = "hoppsan";
+ static const char buf[] = "hoppsan";
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
@@ -286,44 +292,44 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) 0;
- output_term(msg, 3);
+ msg += 3;
break;
case 20: {
- char buf[] = "";
+ static const char buf[] = "";
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 21: {
- char buf[] = "hippsan";
+ static const char buf[] = "hippsan";
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 22:
msg[0] = ERL_DRV_TUPLE;
msg[1] = (ErlDrvTermData) 0;
- output_term(msg, 2);
+ msg += 2;
break;
case 23:
msg[0] = ERL_DRV_NIL;
msg[1] = ERL_DRV_LIST;
msg[2] = (ErlDrvTermData) 1;
- output_term(msg, 3);
+ msg += 3;
break;
case 24:
msg[0] = ERL_DRV_PID;
msg[1] = driver_connected(erlang_port);
- output_term(msg, 2);
+ msg += 2;
break;
case 25:
@@ -331,132 +337,131 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[1] = ERL_DRV_STRING_CONS;
msg[2] = (ErlDrvTermData) "";
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
+ msg += 4;
break;
case 26: {
- double my_float = 0.0;
+ static double my_float = 0.0;
msg[0] = ERL_DRV_FLOAT;
msg[1] = (ErlDrvTermData) &my_float;
- output_term(msg, 2);
+ msg += 2;
break;
}
case 27: {
- char buf[] = {131, 106}; /* [] */
+ static char buf[] = {131, 106}; /* [] */
msg[0] = ERL_DRV_EXT2TERM;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf);
- output_term(msg, 3);
+ msg += 3;
break;
}
case 28: {
- ErlDrvUInt64 x = ~((ErlDrvUInt64) 0);
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = ~((ErlDrvUInt64) 0);
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 29: {
- ErlDrvUInt64 x = ((ErlDrvUInt64) 4711) << 32;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = ((ErlDrvUInt64) 4711) << 32;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 30: {
- ErlDrvUInt64 x = 4711;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = 4711;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 31: {
- ErlDrvUInt64 x = 0;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = 0;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 32: {
- ErlDrvSInt64 x = ((((ErlDrvUInt64) 0x7fffffff) << 32)
- | ((ErlDrvUInt64) 0xffffffff));
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((((ErlDrvUInt64) 0x7fffffff) << 32) | ((ErlDrvUInt64) 0xffffffff));
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 33: {
- ErlDrvSInt64 x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32);
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32);
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 34: {
- ErlDrvSInt64 x = 4711;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = 4711;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 35: {
- ErlDrvSInt64 x = 0;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = 0;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 36: {
- ErlDrvSInt64 x = -1;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = -1;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 37: {
- ErlDrvSInt64 x = -4711;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = -4711;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 38: {
- ErlDrvSInt64 x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 39: {
- ErlDrvSInt64 x = ((ErlDrvSInt64) 1) << 63;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((ErlDrvSInt64) 1) << 63;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
@@ -464,7 +469,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
case 127: /* Error cases */
{
long refc;
- ErlDrvBinary* bin = driver_alloc_binary(256);
+ ErlDrvBinary* bin = bins[bin_ix++] = driver_alloc_binary(256);
FAIL_TERM(msg, 0);
@@ -537,7 +542,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
refc = driver_binary_get_refc(bin);
if (refc > 3) {
char sbuf[128];
- sprintf(sbuf, "bad_refc:%d", refc);
+ sprintf(sbuf, "bad_refc:%ld", refc);
driver_failure_atom(erlang_port, sbuf);
}
driver_free_binary(bin);
@@ -644,6 +649,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
/* Signal end of test case */
msg[0] = ERL_DRV_NIL;
driver_output_term(erlang_port, msg, 1);
+ return;
}
break;
@@ -651,6 +657,16 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
driver_failure_atom(erlang_port, "bad_request");
break;
}
+ if (count > 1) {
+ *msg++ = ERL_DRV_NIL;
+ *msg++ = ERL_DRV_LIST;
+ *msg++ = count + 1;
+ }
+ output_term(spec, msg-spec);
+ if ((bin_ix|s64_ix|u64_ix) > 15) abort();
+ while (bin_ix) {
+ driver_free_binary(bins[--bin_ix]);
+ }
}
static void output_term(ErlDrvTermData* msg, int len)
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
index c509c49b39..9c2ce065bb 100644
--- a/erts/epmd/src/epmd.c
+++ b/erts/epmd/src/epmd.c
@@ -226,11 +226,17 @@ int main(int argc, char** argv)
else
usage(g);
epmd_cleanup_exit(g,0);
+ } else if (strcmp(argv[0], "-stop") == 0) {
+ if (argc == 2)
+ stop_cli(g, argv[1]);
+ else
+ usage(g);
+ epmd_cleanup_exit(g,0);
}
else
usage(g);
}
- dbg_printf(g,0,"epmd running - daemon = %d",g->is_daemon);
+ dbg_printf(g,1,"epmd running - daemon = %d",g->is_daemon);
#ifndef NO_SYSCONF
if ((g->max_conn = sysconf(_SC_OPEN_MAX)) <= 0)
@@ -382,7 +388,7 @@ static void run_daemon(EpmdVars *g)
static void usage(EpmdVars *g)
{
fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon]\n");
- fprintf(stderr, " [-d|-debug] [-port No] [-names|-kill]\n\n");
+ fprintf(stderr, " [-d|-debug] [-port No] [-names|-kill|-stop name]\n\n");
fprintf(stderr, "See the Erlang epmd manual page for info about the usage.\n");
fprintf(stderr, "The -port and DbgExtra options are\n\n");
fprintf(stderr, " -port No\n");
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
index c12f711bc5..2aed861390 100644
--- a/erts/epmd/src/epmd_cli.c
+++ b/erts/epmd/src/epmd_cli.c
@@ -54,6 +54,42 @@ void kill_epmd(EpmdVars *g)
}
}
+void stop_cli(EpmdVars *g, char *name)
+{
+ char buf[1024];
+ int fd, rval, bsize;
+
+ bsize = strlen(name);
+ if (bsize > 1000) {
+ printf("epmd: Name too long!");
+ epmd_cleanup_exit(g, 1);
+ }
+
+ fd = conn_to_epmd(g);
+ bsize++;
+ put_int16(bsize, buf);
+ buf[2] = EPMD_STOP_REQ;
+ bsize += 2;
+ strcpy(buf+3, name);
+
+ if (write(fd, buf, bsize) != bsize) {
+ printf("epmd: Can't write to epmd\n");
+ epmd_cleanup_exit(g,1);
+ }
+ if ((rval = read_fill(fd,buf,7)) == 7) {
+ buf[7] = '\000';
+ printf("%s\n", buf);
+ epmd_cleanup_exit(g,0);
+ } else if (rval < 0) {
+ printf("epmd: failed to read answer from local epmd\n");
+ epmd_cleanup_exit(g,1);
+ } else { /* rval is now 0 or 1 */
+ buf[rval] = '\0';
+ printf("epmd: local epmd responded with <%s>\n", buf);
+ epmd_cleanup_exit(g,1);
+ }
+}
+
/* what == EPMD_NAMES_REQ || EPMD_DUMP_REQ */
void epmd_call(EpmdVars *g,int what)
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index 34f657fb16..c836bf0bb7 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -591,7 +591,7 @@ static void do_request(g, fd, s, buf, bsize)
if (bsize <= 1)
{
- dbg_printf(g,0,"packet to small for request PORT2_REQ (%d)", bsize);
+ dbg_printf(g,0,"packet too small for request PORT2_REQ (%d)", bsize);
return;
}
@@ -740,7 +740,7 @@ static void do_request(g, fd, s, buf, bsize)
dbg_printf(g,1,"** got STOP_REQ");
if (bsize <= 1 )
{
- dbg_printf(g,0,"packet to small for request STOP_REQ (%d)",bsize);
+ dbg_printf(g,0,"packet too small for request STOP_REQ (%d)",bsize);
return;
}
@@ -902,7 +902,7 @@ static void node_init(EpmdVars *g)
/* We have got a close on a connection and it may be a
- EPMD_ALIVE_CLOSE_REQ. Note that this call shouild be called
+ EPMD_ALIVE_CLOSE_REQ. Note that this call should be called
*before* calling conn_close() */
static int node_unreg(EpmdVars *g,char *name)
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 6551b2999a..96655662b8 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -98,7 +98,7 @@ endif
ifeq ($(TARGET),win32)
ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal_r$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@
else
-ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@
+ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ -lm
endif
# ----------------------------------------------------
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index f79f5cc978..76ce0a7e3c 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -131,6 +131,12 @@ static char *plush_val_switches[] = {
NULL
};
+/* +r arguments with values */
+static char *plusr_val_switches[] = {
+ "g",
+ NULL
+};
+
/*
* Define sleep(seconds) in terms of Sleep() on Windows.
@@ -872,6 +878,21 @@ int main(int argc, char **argv)
i++;
}
break;
+ case 'r':
+ if (!is_one_of_strings(&argv[i][2],
+ plusr_val_switches))
+ goto the_default;
+ else {
+ if (i+1 >= argc
+ || argv[i+1][0] == '-'
+ || argv[i+1][0] == '+')
+ usage(argv[i]);
+ argv[i][0] = '-';
+ add_Eargs(argv[i]);
+ add_Eargs(argv[i+1]);
+ i++;
+ }
+ break;
case 's':
if (!is_one_of_strings(&argv[i][2],
pluss_val_switches))
@@ -1069,11 +1090,12 @@ usage_aux(void)
"[-hybrid] "
#endif
"[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] "
- "[-args_file FILENAME] "
- "[+A THREADS] [+a SIZE] [+B[c|d|i]] [+c] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
+ "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c] "
+ "[+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
"[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+R COMPAT_REL] "
- "[+r] [+s SCHEDULER_OPTION] [+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] [+T LEVEL] [+V] [+v] [+W<i|w>] "
- "[args ...]\n");
+ "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] "
+ "[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] [+T LEVEL] [+V] [+v] "
+ "[+W<i|w>] [args ...]\n");
exit(1);
}
diff --git a/erts/include/internal/erl_misc_utils.h b/erts/include/internal/erl_misc_utils.h
index 82e9ba3798..507e1726f4 100644
--- a/erts/include/internal/erl_misc_utils.h
+++ b/erts/include/internal/erl_misc_utils.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2010. 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
@@ -34,7 +34,7 @@ typedef struct {
erts_cpu_info_t *erts_cpu_info_create(void);
void erts_cpu_info_destroy(erts_cpu_info_t *cpuinfo);
-void erts_cpu_info_update(erts_cpu_info_t *cpuinfo);
+int erts_cpu_info_update(erts_cpu_info_t *cpuinfo);
int erts_get_cpu_configured(erts_cpu_info_t *cpuinfo);
int erts_get_cpu_online(erts_cpu_info_t *cpuinfo);
int erts_get_cpu_available(erts_cpu_info_t *cpuinfo);
@@ -50,4 +50,9 @@ int erts_unbind_from_cpu_str(char *str);
int erts_milli_sleep(long);
+#ifdef __WIN32__
+int erts_map_win_error_to_errno(DWORD win_error);
+int erts_get_last_win_errno(void);
+#endif
+
#endif /* #ifndef ERL_MISC_UTILS_H_ */
diff --git a/erts/include/internal/ethr_internal.h b/erts/include/internal/ethr_internal.h
new file mode 100644
index 0000000000..e9c3daf783
--- /dev/null
+++ b/erts/include/internal/ethr_internal.h
@@ -0,0 +1,67 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Internal ethread exports
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_INTERNAL_H__
+#define ETHR_INTERNAL_H__
+
+#include "erl_misc_utils.h"
+
+extern ethr_memory_allocators ethr_mem__;
+extern erts_cpu_info_t *ethr_cpu_info__;
+extern size_t ethr_pagesize__;
+extern size_t ethr_min_stack_size__; /* kilo words */
+extern size_t ethr_max_stack_size__; /* kilo words */
+extern int ethr_not_completely_inited__;
+extern int ethr_not_inited__;
+
+extern void *(*ethr_thr_prepare_func__)(void);
+extern void (*ethr_thr_parent_func__)(void *);
+extern void (*ethr_thr_child_func__)(void *);
+
+#define ETHR_PAGE_ALIGN(SZ) \
+ (((((size_t) (SZ)) - 1)/ethr_pagesize__ + 1)*ethr_pagesize__)
+#define ETHR_B2KW(B) ((((size_t) (B)) - 1)/(sizeof(void *)*1024) + 1)
+#define ETHR_KW2B(KW) (((size_t) (KW))*sizeof(void *)*1024)
+
+#undef ETHR_STACK_GUARD_SIZE
+#ifdef ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE
+# define ETHR_STACK_GUARD_SIZE (ethr_pagesize__)
+#endif
+
+/* implemented in lib_src/<thr-lib>/ethread.c */
+int ethr_set_tse__(ethr_ts_event *tsep);
+ethr_ts_event *ethr_get_tse__(void);
+ETHR_PROTO_NORETURN__ ethr_abort__(void);
+#ifdef ETHR_WIN32_THREADS
+int ethr_win_get_errno__(void);
+#endif
+
+/* implemented in lib_src/common/ethread_aux.c */
+int ethr_init_common__(ethr_init_data *id);
+int ethr_late_init_common__(ethr_late_init_data *lid);
+void ethr_run_exit_handlers__(void);
+void ethr_ts_event_destructor__(void *vtsep);
+
+
+#endif
diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h
new file mode 100644
index 0000000000..4ce3e75c78
--- /dev/null
+++ b/erts/include/internal/ethr_mutex.h
@@ -0,0 +1,510 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Mutex, rwmutex and condition variable implementation
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_MUTEX_H__
+#define ETHR_MUTEX_H__
+
+#define ETHR_RWMUTEX_INITIALIZED 0x99999999
+#define ETHR_MUTEX_INITIALIZED 0x77777777
+#define ETHR_COND_INITIALIZED 0x55555555
+
+#if 0
+# define ETHR_MTX_HARD_DEBUG
+#endif
+
+#ifdef ETHR_MTX_HARD_DEBUG
+# ifdef __GNUC__
+# warning ETHR_MTX_HARD_DEBUG
+# endif
+/*# define ETHR_MTX_HARD_DEBUG_LFS*/
+/*# define ETHR_MTX_HARD_DEBUG_FENCE*/
+/*# define ETHR_MTX_HARD_DEBUG_Q*/
+# define ETHR_MTX_HARD_DEBUG_WSQ
+
+# if !defined(ETHR_MTX_HARD_DEBUG_WSQ) && defined(ETHR_MTX_HARD_DEBUG_Q)
+# define ETHR_MTX_HARD_DEBUG_WSQ
+# endif
+#endif
+
+#if defined(ETHR_USE_OWN_RWMTX_IMPL__) || defined(ETHR_USE_OWN_MTX_IMPL__)
+
+#if 0
+# define ETHR_MTX_Q_LOCK_SPINLOCK__
+# define ETHR_MTX_QLOCK_TYPE__ ethr_spinlock_t
+#elif defined(ETHR_PTHREADS)
+# define ETHR_MTX_Q_LOCK_PTHREAD_MUTEX__
+# define ETHR_MTX_QLOCK_TYPE__ pthread_mutex_t
+#elif defined(ETHR_WIN32_THREADS)
+# define ETHR_MTX_Q_LOCK_CRITICAL_SECTION__
+# define ETHR_MTX_QLOCK_TYPE__ CRITICAL_SECTION
+#else
+# error Need a qlock implementation
+#endif
+
+#define ETHR_RWMTX_W_FLG__ (((long) 1) << 31)
+#define ETHR_RWMTX_W_WAIT_FLG__ (((long) 1) << 30)
+#define ETHR_RWMTX_R_WAIT_FLG__ (((long) 1) << 29)
+
+/* frequent read kind */
+#define ETHR_RWMTX_R_FLG__ (((long) 1) << 28)
+#define ETHR_RWMTX_R_PEND_UNLCK_MASK__ (ETHR_RWMTX_R_FLG__ - 1)
+#define ETHR_RWMTX_R_MASK__ (ETHR_RWMTX_R_WAIT_FLG__ - 1)
+
+/* normal kind */
+#define ETHR_RWMTX_RS_MASK__ (ETHR_RWMTX_R_WAIT_FLG__ - 1)
+
+#define ETHR_RWMTX_WAIT_FLGS__ \
+ (ETHR_RWMTX_W_WAIT_FLG__|ETHR_RWMTX_R_WAIT_FLG__)
+
+#define ETHR_CND_WAIT_FLG__ ETHR_RWMTX_R_WAIT_FLG__
+
+struct ethr_mutex_base_ {
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+ long pre_fence;
+#endif
+ ethr_atomic_t flgs;
+ ETHR_MTX_QLOCK_TYPE__ qlck;
+ ethr_ts_event *q;
+ short aux_scnt;
+ short main_scnt;
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ int ws;
+#endif
+#ifdef ETHR_MTX_HARD_DEBUG_LFS
+ ethr_atomic_t hdbg_lfs;
+#endif
+};
+
+#endif
+
+typedef struct {
+ int main_spincount;
+ int aux_spincount;
+} ethr_mutex_opt;
+
+typedef struct {
+ int main_spincount;
+ int aux_spincount;
+} ethr_cond_opt;
+
+#ifdef ETHR_USE_OWN_MTX_IMPL__
+
+typedef struct ethr_mutex_ ethr_mutex;
+struct ethr_mutex_ {
+ struct ethr_mutex_base_ mtxb;
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+ long post_fence;
+#endif
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+typedef struct ethr_cond_ ethr_cond;
+struct ethr_cond_ {
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+ struct {
+ long pre_fence;
+ } mtxb; /* mtxb allows us to use same macro as for mutex and rwmutex... */
+#endif
+ ETHR_MTX_QLOCK_TYPE__ qlck;
+ ethr_ts_event *q;
+ short aux_scnt;
+ short main_scnt;
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+ long post_fence;
+#endif
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+#else /* pthread */
+
+typedef struct ethr_mutex_ ethr_mutex;
+struct ethr_mutex_ {
+ pthread_mutex_t pt_mtx;
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+typedef struct ethr_cond_ ethr_cond;
+struct ethr_cond_ {
+ pthread_cond_t pt_cnd;
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+#endif /* pthread */
+
+int ethr_mutex_init_opt(ethr_mutex *, ethr_mutex_opt *);
+int ethr_mutex_init(ethr_mutex *);
+int ethr_mutex_destroy(ethr_mutex *);
+#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_MUTEX_IMPL__)
+int ethr_mutex_trylock(ethr_mutex *);
+void ethr_mutex_lock(ethr_mutex *);
+void ethr_mutex_unlock(ethr_mutex *);
+#endif
+int ethr_cond_init_opt(ethr_cond *, ethr_cond_opt *);
+int ethr_cond_init(ethr_cond *);
+int ethr_cond_destroy(ethr_cond *);
+void ethr_cond_signal(ethr_cond *);
+void ethr_cond_broadcast(ethr_cond *);
+int ethr_cond_wait(ethr_cond *, ethr_mutex *);
+
+typedef enum {
+ ETHR_RWMUTEX_TYPE_NORMAL,
+ ETHR_RWMUTEX_TYPE_FREQUENT_READ,
+ ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ
+} ethr_rwmutex_type;
+
+typedef enum {
+ ETHR_RWMUTEX_LONG_LIVED,
+ ETHR_RWMUTEX_SHORT_LIVED,
+ ETHR_RWMUTEX_UNKNOWN_LIVED
+} ethr_rwmutex_lived;
+
+typedef struct {
+ ethr_rwmutex_type type;
+ ethr_rwmutex_lived lived;
+ int main_spincount;
+ int aux_spincount;
+} ethr_rwmutex_opt;
+
+#define ETHR_RWMUTEX_OPT_DEFAULT_INITER \
+ {ETHR_RWMUTEX_TYPE_NORMAL, ETHR_RWMUTEX_UNKNOWN_LIVED, -1, -1}
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+
+typedef union {
+ struct {
+ ethr_atomic_t readers;
+ int waiting_readers;
+ int byte_offset;
+ ethr_rwmutex_lived lived;
+ } data;
+ char align__[ETHR_CACHE_LINE_SIZE];
+} ethr_rwmtx_readers_array__;
+
+typedef struct ethr_rwmutex_ ethr_rwmutex;
+struct ethr_rwmutex_ {
+ struct ethr_mutex_base_ mtxb;
+ ethr_rwmutex_type type;
+ ethr_ts_event *rq_end;
+ union {
+ ethr_rwmtx_readers_array__ *ra;
+ int rs;
+ } tdata;
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+ long post_fence;
+#endif
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+#else /* pthread_rwlock */
+
+typedef struct ethr_rwmutex_ ethr_rwmutex;
+struct ethr_rwmutex_ {
+ pthread_rwlock_t pt_rwlock;
+#if ETHR_XCHK
+ int initialized;
+#endif
+};
+
+#endif /* pthread_rwlock */
+
+int ethr_rwmutex_set_reader_group(int);
+int ethr_rwmutex_init_opt(ethr_rwmutex *, ethr_rwmutex_opt *);
+int ethr_rwmutex_init(ethr_rwmutex *);
+int ethr_rwmutex_destroy(ethr_rwmutex *);
+#if defined(ETHR_USE_OWN_RWMTX_IMPL__) \
+ || !defined(ETHR_TRY_INLINE_FUNCS) \
+ || defined(ETHR_MUTEX_IMPL__)
+int ethr_rwmutex_tryrlock(ethr_rwmutex *);
+void ethr_rwmutex_rlock(ethr_rwmutex *);
+void ethr_rwmutex_runlock(ethr_rwmutex *);
+int ethr_rwmutex_tryrwlock(ethr_rwmutex *);
+void ethr_rwmutex_rwlock(ethr_rwmutex *);
+void ethr_rwmutex_rwunlock(ethr_rwmutex *);
+#endif
+
+#ifdef ETHR_MTX_HARD_DEBUG
+#define ETHR_MTX_HARD_ASSERT(A) \
+ ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, #A)))
+#else
+#define ETHR_MTX_HARD_ASSERT(A) ((void) 1)
+#endif
+
+#ifdef ETHR_MTX_HARD_DEBUG_LFS
+# define ETHR_MTX_HARD_DEBUG_LFS_INIT(MTXB) \
+do { \
+ ethr_atomic_init(&(MTXB)->hdbg_lfs, 0); \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_RLOCK(MTXB) \
+do { \
+ long val__; \
+ ETHR_COMPILER_BARRIER; \
+ val__ = ethr_atomic_inc_read(&(MTXB)->hdbg_lfs); \
+ ETHR_MTX_HARD_ASSERT(val__ > 0); \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_TRYRLOCK(MTXB, RES) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if ((RES) == 0) \
+ ETHR_MTX_HARD_DEBUG_LFS_RLOCK((MTXB)); \
+ else \
+ ETHR_MTX_HARD_ASSERT((RES) == EBUSY); \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_RUNLOCK(MTXB) \
+do { \
+ long val__ = ethr_atomic_dec_read(&(MTXB)->hdbg_lfs); \
+ ETHR_MTX_HARD_ASSERT(val__ >= 0); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(MTXB) \
+do { \
+ long val__; \
+ ETHR_COMPILER_BARRIER; \
+ val__ = ethr_atomic_dec_read(&(MTXB)->hdbg_lfs); \
+ ETHR_MTX_HARD_ASSERT(val__ == -1); \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(MTXB, RES) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ if ((RES) == 0) \
+ ETHR_MTX_HARD_DEBUG_LFS_RWLOCK((MTXB)); \
+ else \
+ ETHR_MTX_HARD_ASSERT((RES) == EBUSY); \
+} while (0)
+# define ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(MTXB) \
+do { \
+ long val__ = ethr_atomic_inctest(&(MTXB)->hdbg_lfs); \
+ ETHR_MTX_HARD_ASSERT(val__ == 0); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+#else
+# define ETHR_MTX_HARD_DEBUG_LFS_INIT(MTXB)
+# define ETHR_MTX_HARD_DEBUG_LFS_RLOCK(MTXB)
+# define ETHR_MTX_HARD_DEBUG_LFS_TRYRLOCK(MTXB, RES)
+# define ETHR_MTX_HARD_DEBUG_LFS_RUNLOCK(MTXB)
+# define ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(MTXB)
+# define ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(MTXB, RES)
+# define ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(MTXB)
+#endif
+
+#ifdef ETHR_MTX_HARD_DEBUG_FENCE
+
+#if ETHR_SIZEOF_PTR == 8
+# define ETHR_MTX_HARD_DEBUG_PRE_FENCE 0xdeadbeefdeadbeefL
+# define ETHR_MTX_HARD_DEBUG_POST_FENCE 0xdeaddeaddeaddeadL
+#else
+# define ETHR_MTX_HARD_DEBUG_PRE_FENCE 0xdeaddeadL
+# define ETHR_MTX_HARD_DEBUG_POST_FENCE 0xdeaddeadL
+#endif
+
+#define ETHR_MTX_HARD_DEBUG_FENCE_CHK(X) \
+do { \
+ ETHR_COMPILER_BARRIER; \
+ ETHR_MTX_HARD_ASSERT((X)->mtxb.pre_fence == ETHR_MTX_HARD_DEBUG_PRE_FENCE);\
+ ETHR_MTX_HARD_ASSERT((X)->post_fence == ETHR_MTX_HARD_DEBUG_POST_FENCE); \
+ ETHR_COMPILER_BARRIER; \
+} while (0)
+#define ETHR_MTX_HARD_DEBUG_FENCE_INIT(X) \
+do { \
+ (X)->mtxb.pre_fence = ETHR_MTX_HARD_DEBUG_PRE_FENCE; \
+ (X)->post_fence = ETHR_MTX_HARD_DEBUG_POST_FENCE; \
+} while (0)
+#else
+#define ETHR_MTX_HARD_DEBUG_FENCE_CHK(X)
+#define ETHR_MTX_HARD_DEBUG_FENCE_INIT(X)
+#endif
+
+#ifdef ETHR_USE_OWN_MTX_IMPL__
+
+#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT 1000
+#define ETHR_MTX_DEFAULT_AUX_SPINCOUNT 50
+
+#define ETHR_CND_DEFAULT_MAIN_SPINCOUNT 0
+#define ETHR_CND_DEFAULT_AUX_SPINCOUNT 0
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_MUTEX_IMPL__)
+
+void ethr_mutex_lock_wait__(ethr_mutex *, long);
+void ethr_mutex_unlock_wake__(ethr_mutex *, long);
+
+static ETHR_INLINE int
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
+{
+ long act;
+ int res;
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ act = ethr_atomic_cmpxchg_acqb(&mtx->mtxb.flgs, ETHR_RWMTX_W_FLG__, 0);
+ res = (act == 0) ? 0 : EBUSY;
+
+ ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(&mtx->mtxb, res);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ ETHR_COMPILER_BARRIER;
+ return res;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
+{
+ long act;
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ act = ethr_atomic_cmpxchg_acqb(&mtx->mtxb.flgs, ETHR_RWMTX_W_FLG__, 0);
+ if (act != 0)
+ ethr_mutex_lock_wait__(mtx, act);
+
+ ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&mtx->mtxb);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ ETHR_COMPILER_BARRIER;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
+{
+ long act;
+ ETHR_COMPILER_BARRIER;
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+ ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(&mtx->mtxb);
+
+ act = ethr_atomic_cmpxchg_relb(&mtx->mtxb.flgs, 0, ETHR_RWMTX_W_FLG__);
+ if (act != ETHR_RWMTX_W_FLG__)
+ ethr_mutex_unlock_wake__(mtx, act);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+}
+
+#endif /* ETHR_TRY_INLINE_FUNCS */
+
+#else /* pthread_mutex */
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_MUTEX_IMPL__)
+
+static ETHR_INLINE int
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
+{
+ int res;
+ res = pthread_mutex_trylock(&mtx->pt_mtx);
+ if (res != 0 && res != EBUSY)
+ ETHR_FATAL_ERROR__(res);
+ return res;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
+{
+ int res = pthread_mutex_lock(&mtx->pt_mtx);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
+{
+ int res = pthread_mutex_unlock(&mtx->pt_mtx);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+#endif /* ETHR_TRY_INLINE_FUNCS */
+
+#endif /* pthread_mutex */
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+
+#define ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT 1000
+#define ETHR_RWMTX_DEFAULT_AUX_SPINCOUNT 50
+
+#else /* pthread_rwlock */
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_MUTEX_IMPL__)
+
+static ETHR_INLINE int
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_tryrdlock(&rwmtx->pt_rwlock);
+ if (res != 0 && res != EBUSY)
+ ETHR_FATAL_ERROR__(res);
+ return res;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_rdlock(&rwmtx->pt_rwlock);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_runlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_unlock(&rwmtx->pt_rwlock);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+static ETHR_INLINE int
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrwlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_trywrlock(&rwmtx->pt_rwlock);
+ if (res != 0 && res != EBUSY)
+ ETHR_FATAL_ERROR__(res);
+ return res;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_wrlock(&rwmtx->pt_rwlock);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwunlock)(ethr_rwmutex *rwmtx)
+{
+ int res = pthread_rwlock_unlock(&rwmtx->pt_rwlock);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+#endif /* ETHR_TRY_INLINE_FUNCS */
+
+#endif /* pthread_rwlock */
+
+int ethr_mutex_lib_init(int);
+int ethr_mutex_lib_late_init(int, int);
+
+#endif /* #ifndef ETHR_MUTEX_H__ */
diff --git a/erts/include/internal/ethr_optimized_fallbacks.h b/erts/include/internal/ethr_optimized_fallbacks.h
new file mode 100644
index 0000000000..2f9f987d0b
--- /dev/null
+++ b/erts/include/internal/ethr_optimized_fallbacks.h
@@ -0,0 +1,185 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: "Optimized" fallbacks used when native ops are missing
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_OPTIMIZED_FALLBACKS_H__
+#define ETHR_OPTIMIZED_FALLBACKS_H__
+
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
+#endif
+
+#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
+#define ETHR_HAVE_OPTIMIZED_SPINLOCKS 1
+#elif defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
+/* --- Optimized spinlocks using pthread spinlocks -------------------------- */
+#define ETHR_HAVE_OPTIMIZED_SPINLOCKS 1
+
+typedef pthread_spinlock_t ethr_opt_spinlock_t;
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+static ETHR_INLINE int
+ethr_opt_spinlock_init(ethr_opt_spinlock_t *lock)
+{
+ return pthread_spin_init((pthread_spinlock_t *) lock, 0);
+}
+
+static ETHR_INLINE int
+ethr_opt_spinlock_destroy(ethr_opt_spinlock_t *lock)
+{
+ return pthread_spin_destroy((pthread_spinlock_t *) lock);
+}
+
+
+static ETHR_INLINE int
+ethr_opt_spin_unlock(ethr_opt_spinlock_t *lock)
+{
+ return pthread_spin_unlock((pthread_spinlock_t *) lock);
+}
+
+static ETHR_INLINE int
+ethr_opt_spin_lock(ethr_opt_spinlock_t *lock)
+{
+ return pthread_spin_lock((pthread_spinlock_t *) lock);
+}
+
+#endif
+
+#elif defined(ETHR_HAVE_NATIVE_ATOMICS)
+/* --- Native spinlocks using native atomics -------------------------------- */
+#define ETHR_HAVE_NATIVE_SPINLOCKS 1
+#define ETHR_HAVE_OPTIMIZED_SPINLOCKS 1
+
+typedef ethr_native_atomic_t ethr_native_spinlock_t;
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+static ETHR_INLINE void
+ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
+{
+ ethr_native_atomic_init((ethr_native_atomic_t *) lock, 0);
+}
+
+static ETHR_INLINE void
+ethr_native_spin_unlock(ethr_native_spinlock_t *lock)
+{
+ ETHR_COMPILER_BARRIER;
+ ETHR_ASSERT(ethr_native_atomic_read((ethr_native_atomic_t *) lock) == 1);
+ ethr_native_atomic_set_relb((ethr_native_atomic_t *) lock, 0);
+}
+
+static ETHR_INLINE void
+ethr_native_spin_lock(ethr_native_spinlock_t *lock)
+{
+ while (ethr_native_atomic_cmpxchg_acqb((ethr_native_atomic_t *) lock,
+ (long) 1, (long) 0) != 0) {
+ ETHR_SPIN_BODY;
+ }
+ ETHR_COMPILER_BARRIER;
+}
+
+#endif
+
+#endif
+
+
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+#define ETHR_HAVE_OPTIMIZED_RWSPINLOCKS 1
+#elif defined(ETHR_HAVE_NATIVE_ATOMICS)
+/* --- Native rwspinlocks using native atomics ------------------------------ */
+#define ETHR_HAVE_NATIVE_RWSPINLOCKS 1
+#define ETHR_HAVE_OPTIMIZED_RWSPINLOCKS 1
+
+typedef ethr_native_atomic_t ethr_native_rwlock_t;
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+#define ETHR_WLOCK_FLAG__ (((long) 1) << 30)
+
+static ETHR_INLINE void
+ethr_native_rwlock_init(ethr_native_rwlock_t *lock)
+{
+ ethr_native_atomic_init((ethr_native_atomic_t *) lock, 0);
+}
+
+static ETHR_INLINE void
+ethr_native_read_unlock(ethr_native_rwlock_t *lock)
+{
+ ETHR_COMPILER_BARRIER;
+#ifdef DEBUG
+ ETHR_ASSERT(ethr_native_atomic_read((ethr_native_atomic_t *) lock) >= 0);
+#endif
+ ethr_native_atomic_dec_relb((ethr_native_atomic_t *) lock);
+}
+
+static ETHR_INLINE void
+ethr_native_read_lock(ethr_native_rwlock_t *lock)
+{
+ long act, exp = 0;
+ while (1) {
+ act = ethr_native_atomic_cmpxchg_acqb((ethr_native_atomic_t *) lock,
+ exp+1, exp);
+ if (act == exp)
+ break;
+ ETHR_SPIN_BODY;
+ exp = (act & ETHR_WLOCK_FLAG__) ? 0 : act;
+ }
+ ETHR_COMPILER_BARRIER;
+}
+
+static ETHR_INLINE void
+ethr_native_write_unlock(ethr_native_rwlock_t *lock)
+{
+ ETHR_COMPILER_BARRIER;
+ ETHR_ASSERT(ethr_native_atomic_read((ethr_native_atomic_t *) lock)
+ == ETHR_WLOCK_FLAG__);
+ ethr_native_atomic_set_relb((ethr_native_atomic_t *) lock, 0);
+}
+
+static ETHR_INLINE void
+ethr_native_write_lock(ethr_native_rwlock_t *lock)
+{
+ long act, exp = 0;
+ while (1) {
+ act = ethr_native_atomic_cmpxchg_acqb((ethr_native_atomic_t *) lock,
+ exp|ETHR_WLOCK_FLAG__, exp);
+ if (act == exp)
+ break;
+ ETHR_SPIN_BODY;
+ exp = act & ~ETHR_WLOCK_FLAG__;
+ }
+ act |= ETHR_WLOCK_FLAG__;
+ /* Wait for readers to leave */
+ while (act != ETHR_WLOCK_FLAG__) {
+ ETHR_SPIN_BODY;
+ act = ethr_native_atomic_read_acqb((ethr_native_atomic_t *) lock);
+ }
+ ETHR_COMPILER_BARRIER;
+}
+
+#endif
+
+#endif
+
+#endif
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index 4e7a38cd5c..4a205699bd 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -33,20 +33,9 @@
#include <stdlib.h>
#include "erl_errno.h"
-/*
- * Extra memory barrier requirements:
- * - ethr_atomic_or_old() needs to enforce a memory barrier sufficient
- * for a lock operation.
- * - ethr_atomic_and_old() needs to enforce a memory barrier sufficient
- * for an unlock operation.
- * - ethr_atomic_cmpxchg() needs to enforce a memory barrier sufficient
- * for a lock and unlock operation.
- */
-
-
-#undef ETHR_USE_RWMTX_FALLBACK
#undef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
-#undef ETHR_HAVE_OPTIMIZED_LOCKS
+#undef ETHR_HAVE_OPTIMIZED_SPINLOCK
+#undef ETHR_HAVE_OPTIMIZED_RWSPINLOCK
typedef struct {
long tv_sec;
@@ -54,6 +43,10 @@ typedef struct {
} ethr_timeval;
#if defined(DEBUG)
+# define ETHR_DEBUG
+#endif
+
+#if defined(ETHR_DEBUG)
# undef ETHR_XCHK
# define ETHR_XCHK 1
#else
@@ -68,47 +61,57 @@ typedef struct {
#elif defined(__WIN32__)
# define ETHR_INLINE __forceinline
#endif
-#if defined(DEBUG) || !defined(ETHR_INLINE) || ETHR_XCHK \
+#if defined(ETHR_DEBUG) || !defined(ETHR_INLINE) || ETHR_XCHK \
|| (defined(__GNUC__) && defined(ERTS_MIXED_CYGWIN_VC))
# undef ETHR_INLINE
# define ETHR_INLINE
# undef ETHR_TRY_INLINE_FUNCS
#endif
-#ifdef ETHR_FORCE_INLINE_FUNCS
-# define ETHR_TRY_INLINE_FUNCS
-#endif
-#if !defined(ETHR_DISABLE_NATIVE_IMPLS) \
- && (defined(PURIFY) || defined(VALGRIND) || defined(ERTS_MIXED_CYGWIN_VC))
+#if !defined(ETHR_DISABLE_NATIVE_IMPLS) && (defined(PURIFY)||defined(VALGRIND))
# define ETHR_DISABLE_NATIVE_IMPLS
#endif
-#define ETHR_RWMUTEX_INITIALIZED 0x99999999
-#define ETHR_MUTEX_INITIALIZED 0x77777777
-#define ETHR_COND_INITIALIZED 0x55555555
+/* Assume 64-byte cache line size */
+#define ETHR_CACHE_LINE_SIZE 64L
+#define ETHR_CACHE_LINE_MASK (ETHR_CACHE_LINE_SIZE - 1)
-#define ETHR_CACHE_LINE_SIZE 64
+#define ETHR_CACHE_LINE_ALIGN_SIZE(SZ) \
+ (((((SZ) - 1) / ETHR_CACHE_LINE_SIZE) + 1) * ETHR_CACHE_LINE_SIZE)
-#ifdef ETHR_INLINE_FUNC_NAME_
-# define ETHR_CUSTOM_INLINE_FUNC_NAME_
-#else
+#ifndef ETHR_INLINE_FUNC_NAME_
# define ETHR_INLINE_FUNC_NAME_(X) X
#endif
-#define ETHR_COMPILER_BARRIER ethr_compiler_barrier()
-#ifdef __GNUC__
-# undef ETHR_COMPILER_BARRIER
-# define ETHR_COMPILER_BARRIER __asm__ __volatile__("":::"memory")
+#if !defined(__func__)
+# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
+# if !defined(__GNUC__) || __GNUC__ < 2
+# define __func__ "[unknown_function]"
+# else
+# define __func__ __FUNCTION__
+# endif
+# endif
#endif
-#ifdef DEBUG
+int ethr_assert_failed(const char *file, int line, const char *func, char *a);
+#ifdef ETHR_DEBUG
#define ETHR_ASSERT(A) \
- ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, #A)))
-int ethr_assert_failed(char *f, int l, char *a);
+ ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__, #A)))
#else
#define ETHR_ASSERT(A) ((void) 1)
#endif
+#if defined(__GNUC__)
+# define ETHR_PROTO_NORETURN__ void __attribute__((noreturn))
+# define ETHR_IMPL_NORETURN__ void
+#elif defined(__WIN32__) && defined(_MSC_VER)
+# define ETHR_PROTO_NORETURN__ __declspec(noreturn) void
+# define ETHR_IMPL_NORETURN__ __declspec(noreturn) void
+#else
+# define ETHR_PROTO_NORETURN__ void
+# define ETHR_IMPL_NORETURN__ void
+#endif
+
#if defined(ETHR_PTHREADS)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* The pthread implementation *
@@ -118,7 +121,9 @@ int ethr_assert_failed(char *f, int l, char *a);
#error "_GNU_SOURCE not defined. Please, compile all files with -D_GNU_SOURCE."
#endif
-#if defined(ETHR_HAVE_MIT_PTHREAD_H)
+#if defined(ETHR_NEED_NPTL_PTHREAD_H)
+#include <nptl/pthread.h>
+#elif defined(ETHR_HAVE_MIT_PTHREAD_H)
#include <pthread/mit/pthread.h>
#elif defined(ETHR_HAVE_PTHREAD_H)
#include <pthread.h>
@@ -128,130 +133,23 @@ int ethr_assert_failed(char *f, int l, char *a);
typedef pthread_t ethr_tid;
-typedef struct ethr_mutex_ ethr_mutex;
-struct ethr_mutex_ {
- pthread_mutex_t pt_mtx;
- int is_rec_mtx;
- ethr_mutex *prev;
- ethr_mutex *next;
-#if ETHR_XCHK
- int initialized;
-#endif
-};
-
-typedef struct ethr_cond_ ethr_cond;
-struct ethr_cond_ {
- pthread_cond_t pt_cnd;
-#if ETHR_XCHK
- int initialized;
-#endif
-};
+typedef pthread_key_t ethr_tsd_key;
-#ifndef ETHR_HAVE_PTHREAD_RWLOCK_INIT
-#define ETHR_USE_RWMTX_FALLBACK
-#else
-typedef struct ethr_rwmutex_ ethr_rwmutex;
-struct ethr_rwmutex_ {
- pthread_rwlock_t pt_rwlock;
-#if ETHR_XCHK
- int initialized;
-#endif
-};
-#endif
+#define ETHR_HAVE_ETHR_SIG_FUNCS 1
-/* Static initializers */
-#if ETHR_XCHK
-#define ETHR_MUTEX_XCHK_INITER , ETHR_MUTEX_INITIALIZED
-#define ETHR_COND_XCHK_INITER , ETHR_COND_INITIALIZED
-#else
-#define ETHR_MUTEX_XCHK_INITER
-#define ETHR_COND_XCHK_INITER
+#if defined(PURIFY) || defined(VALGRIND)
+# define ETHR_FORCE_PTHREAD_RWLOCK
+# define ETHR_FORCE_PTHREAD_MUTEX
#endif
-#define ETHR_MUTEX_INITER {PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL ETHR_MUTEX_XCHK_INITER}
-#define ETHR_COND_INITER {PTHREAD_COND_INITIALIZER ETHR_COND_XCHK_INITER}
-
-#if defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE) \
- || defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
-# define ETHR_HAVE_ETHR_REC_MUTEX_INIT 1
-# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-# define ETHR_REC_MUTEX_INITER \
- {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, 1, NULL, NULL ETHR_MUTEX_XCHK_INITER}
-# endif
-#else
-# undef ETHR_HAVE_ETHR_REC_MUTEX_INIT
+#if !defined(ETHR_FORCE_PTHREAD_RWLOCK)
+# define ETHR_USE_OWN_RWMTX_IMPL__
#endif
-#ifndef ETHR_HAVE_PTHREAD_ATFORK
-# define ETHR_NO_FORKSAFETY 1
+#if !defined(ETHR_FORCE_PTHREAD_MUTEX) && 0
+# define ETHR_USE_OWN_MTX_IMPL__
#endif
-typedef pthread_key_t ethr_tsd_key;
-
-#define ETHR_HAVE_ETHR_SIG_FUNCS 1
-
-#ifdef ETHR_TRY_INLINE_FUNCS
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
-{
- return pthread_mutex_trylock(&mtx->pt_mtx);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
-{
- return pthread_mutex_lock(&mtx->pt_mtx);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
-{
- return pthread_mutex_unlock(&mtx->pt_mtx);
-}
-
-#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_tryrdlock(&rwmtx->pt_rwlock);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_rdlock(&rwmtx->pt_rwlock);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_runlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_unlock(&rwmtx->pt_rwlock);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrwlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_trywrlock(&rwmtx->pt_rwlock);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_wrlock(&rwmtx->pt_rwlock);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwunlock)(ethr_rwmutex *rwmtx)
-{
- return pthread_rwlock_unlock(&rwmtx->pt_rwlock);
-}
-
-#endif /* ETHR_HAVE_PTHREAD_RWLOCK_INIT */
-
-#endif /* ETHR_TRY_INLINE_FUNCS */
-
#elif defined(ETHR_WIN32_THREADS)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* The native win32 threads implementation *
@@ -273,409 +171,22 @@ ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwunlock)(ethr_rwmutex *rwmtx)
# undef WIN32_LEAN_AND_MEAN
#endif
-/* Types */
-typedef long ethr_tid; /* thread id type */
-typedef struct {
- volatile int initialized;
- CRITICAL_SECTION cs;
-#if ETHR_XCHK
- int is_rec_mtx;
-#endif
-} ethr_mutex;
-
-typedef struct cnd_wait_event__ cnd_wait_event_;
+struct ethr_join_data_;
+/* Types */
typedef struct {
- volatile int initialized;
- CRITICAL_SECTION cs;
- cnd_wait_event_ *queue;
- cnd_wait_event_ *queue_end;
-} ethr_cond;
-
-#define ETHR_USE_RWMTX_FALLBACK
-
-/* Static initializers */
-
-#define ETHR_MUTEX_INITER {0}
-#define ETHR_COND_INITER {0}
-
-#define ETHR_REC_MUTEX_INITER ETHR_MUTEX_INITER
-
-#define ETHR_HAVE_ETHR_REC_MUTEX_INIT 1
+ long id;
+ struct ethr_join_data_ *jdata;
+} ethr_tid; /* thread id type */
typedef DWORD ethr_tsd_key;
#undef ETHR_HAVE_ETHR_SIG_FUNCS
-#ifdef ETHR_TRY_INLINE_FUNCS
-int ethr_fake_static_mutex_init(ethr_mutex *mtx);
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
-{
- if (!mtx->initialized) {
- int res = ethr_fake_static_mutex_init(mtx);
- if (res != 0)
- return res;
- }
- return TryEnterCriticalSection(&mtx->cs) ? 0 : EBUSY;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
-{
- if (!mtx->initialized) {
- int res = ethr_fake_static_mutex_init(mtx);
- if (res != 0)
- return res;
- }
- EnterCriticalSection(&mtx->cs);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
-{
- LeaveCriticalSection(&mtx->cs);
- return 0;
-}
-
-#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
-
-#ifdef ERTS_MIXED_CYGWIN_VC
-
-/* atomics */
-
-#ifdef _MSC_VER
-# if _MSC_VER < 1300
-# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0 /* Dont trust really old compilers */
-# else
-# if defined(_M_IX86)
-# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
-# else /* I.e. IA64 */
-# if _MSC_VER >= 1400
-# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
-# else
-# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0
-# endif
-# endif
-# endif
-# if _MSC_VER >= 1400
-# include <intrin.h>
-# undef ETHR_COMPILER_BARRIER
-# define ETHR_COMPILER_BARRIER _ReadWriteBarrier()
-# endif
-#pragma intrinsic(_ReadWriteBarrier)
-#pragma intrinsic(_InterlockedAnd)
-#pragma intrinsic(_InterlockedOr)
-#else
-# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0
-#endif
-
-#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
-#define ETHR_HAVE_OPTIMIZED_LOCKS 1
-
-#define ETHR_MEMORY_BARRIER \
-do { \
- volatile LONG x___ = 0; \
- (void) _InterlockedCompareExchange(&x___, (LONG) 1, (LONG) 0); \
-} while (0)
-
-typedef struct {
- volatile LONG value;
-} ethr_atomic_t;
-
-typedef struct {
- volatile LONG locked;
-} ethr_spinlock_t;
-
-typedef struct {
- volatile LONG counter;
-} ethr_rwlock_t;
-#define ETHR_WLOCK_FLAG__ (((LONG) 1) << 30)
-
-#ifdef ETHR_TRY_INLINE_FUNCS
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
-{
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- var->value = (LONG) i;
-#else
- (void) InterlockedExchange(&var->value, (LONG) i);
-#endif
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
-{
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- var->value = (LONG) i;
-#else
- (void) InterlockedExchange(&var->value, (LONG) i);
-#endif
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
-{
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- *i = var->value;
-#else
- *i = InterlockedExchangeAdd(&var->value, (LONG) 0);
-#endif
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
-{
- (void) InterlockedExchangeAdd(&var->value, (LONG) incr);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *var,
- long i,
- long *testp)
-{
- *testp = InterlockedExchangeAdd(&var->value, (LONG) i);
- *testp += i;
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *var)
-{
- (void) InterlockedIncrement(&var->value);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *var)
-{
- (void) InterlockedDecrement(&var->value);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *var, long *testp)
-{
- *testp = (long) InterlockedIncrement(&var->value);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *var, long *testp)
-{
- *testp = (long) InterlockedDecrement(&var->value);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
- long mask,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- *
- * According to msdn _InterlockedAnd() provides a full
- * memory barrier.
- */
- *old = (long) _InterlockedAnd(&var->value, mask);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
- long mask,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- *
- * According to msdn _InterlockedOr() provides a full
- * memory barrier.
- */
- *old = (long) _InterlockedOr(&var->value, mask);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
- long new,
- long expected,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- *
- * According to msdn _InterlockedCompareExchange() provides a full
- * memory barrier.
- */
- *old = _InterlockedCompareExchange(&var->value, (LONG) new, (LONG) expected);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
- long new,
- long *old)
-{
- *old = (long) InterlockedExchange(&var->value, (LONG) new);
- return 0;
-}
-
-/*
- * According to msdn InterlockedExchange() provides a full
- * memory barrier.
- */
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
-{
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- lock->locked = (LONG) 0;
-#else
- (void) InterlockedExchange(&lock->locked, (LONG) 0);
-#endif
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
-{
- return 0;
-}
-
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
-{
- ETHR_COMPILER_BARRIER;
- {
-#ifdef DEBUG
- LONG old =
-#endif
- InterlockedExchange(&lock->locked, (LONG) 0);
-#ifdef DEBUG
- ETHR_ASSERT(old == 1);
-#endif
- }
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
-{
- LONG old;
- do {
- old = InterlockedExchange(&lock->locked, (LONG) 1);
- } while (old != (LONG) 0);
- ETHR_COMPILER_BARRIER;
- return 0;
-}
+#define ETHR_USE_OWN_RWMTX_IMPL__
+#define ETHR_USE_OWN_MTX_IMPL__
-/*
- * According to msdn InterlockedIncrement, InterlockedDecrement,
- * and InterlockedExchangeAdd(), _InterlockedAnd, and _InterlockedOr
- * provides full memory barriers.
- */
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
-{
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- lock->counter = (LONG) 0;
-#else
- (void) InterlockedExchange(&lock->counter, (LONG) 0);
-#endif
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
-{
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
-{
- ETHR_COMPILER_BARRIER;
- {
-#ifdef DEBUG
- LONG old =
-#endif
- InterlockedDecrement(&lock->counter);
- ETHR_ASSERT(old != 0);
- }
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
-{
- while (1) {
- LONG old = InterlockedIncrement(&lock->counter);
- if ((old & ETHR_WLOCK_FLAG__) == 0)
- break; /* Got read lock */
- /* Restore and wait for writers to unlock */
- old = InterlockedDecrement(&lock->counter);
- while (old & ETHR_WLOCK_FLAG__) {
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- old = lock->counter;
-#else
- old = InterlockedExchangeAdd(&lock->counter, (LONG) 0);
-#endif
- }
- }
- ETHR_COMPILER_BARRIER;
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
-{
- ETHR_COMPILER_BARRIER;
- {
-#ifdef DEBUG
- LONG old =
-#endif
- _InterlockedAnd(&lock->counter, ~ETHR_WLOCK_FLAG__);
- ETHR_ASSERT(old & ETHR_WLOCK_FLAG__);
- }
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
-{
- LONG old;
- do {
- old = _InterlockedOr(&lock->counter, ETHR_WLOCK_FLAG__);
- } while (old & ETHR_WLOCK_FLAG__);
- /* We got the write part of the lock; wait for readers to unlock */
- while ((old & ~ETHR_WLOCK_FLAG__) != 0) {
-#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
- old = lock->counter;
-#else
- old = InterlockedExchangeAdd(&lock->counter, (LONG) 0);
-#endif
- ETHR_ASSERT(old & ETHR_WLOCK_FLAG__);
- }
- ETHR_COMPILER_BARRIER;
- return 0;
-}
-
-#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
-
-#endif /* #ifdef ERTS_MIXED_CYGWIN_VC */
+#define ETHR_YIELD() (Sleep(0), 0)
#else /* No supported thread lib found */
@@ -687,6 +198,12 @@ ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
#endif
+#ifdef SIZEOF_LONG
+#if SIZEOF_LONG < ETHR_SIZEOF_PTR
+#error size of long currently needs to be at least the same as size of void *
+#endif
+#endif
+
/* __builtin_expect() is needed by both native atomics code
* and the fallback code */
#if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
@@ -698,6 +215,8 @@ ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
# if defined(__GNUC__)
# if defined(ETHR_PREFER_GCC_NATIVE_IMPLS)
# include "gcc/ethread.h"
+# elif defined(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS)
+# include "libatomic_ops/ethread.h"
# endif
# ifndef ETHR_HAVE_NATIVE_ATOMICS
# if ETHR_SIZEOF_PTR == 4
@@ -718,115 +237,141 @@ ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
# endif
# endif
# include "gcc/ethread.h"
+# include "libatomic_ops/ethread.h"
# endif
+# elif defined(ETHR_WIN32_THREADS)
+# include "win/ethread.h"
# endif
-#endif /* !defined(ETHR_DISABLE_NATIVE_IMPLS) */
-
-#ifdef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
-# undef ETHR_HAVE_NATIVE_ATOMICS
-#endif
-#ifdef ETHR_HAVE_OPTIMIZED_LOCKS
-# undef ETHR_HAVE_NATIVE_LOCKS
-#endif
+#endif /* !ETHR_DISABLE_NATIVE_IMPLS */
-#ifdef ETHR_HAVE_NATIVE_ATOMICS
-#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
-#endif
-#ifdef ETHR_HAVE_NATIVE_LOCKS
-#define ETHR_HAVE_OPTIMIZED_LOCKS 1
+#if defined(__GNUC__)
+# ifndef ETHR_COMPILER_BARRIER
+# define ETHR_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory")
+# endif
+# ifndef ETHR_SPIN_BODY
+# if defined(__i386__) || defined(__x86_64__)
+# define ETHR_SPIN_BODY __asm__ __volatile__("rep;nop" : : : "memory")
+# elif defined(__ia64__)
+# define ETHR_SPIN_BODY __asm__ __volatile__("hint @pause" : : : "memory")
+# elif defined(__sparc__)
+# define ETHR_SPIN_BODY __asm__ __volatile__("membar #LoadLoad")
+# else
+# define ETHR_SPIN_BODY ETHR_COMPILER_BARRIER
+# endif
+# endif
+#elif defined(ETHR_WIN32_THREADS)
+# ifndef ETHR_COMPILER_BARRIER
+# include <intrin.h>
+# pragma intrinsic(_ReadWriteBarrier)
+# define ETHR_COMPILER_BARRIER _ReadWriteBarrier()
+# endif
+# ifndef ETHR_SPIN_BODY
+# define ETHR_SPIN_BODY do {YieldProcessor();ETHR_COMPILER_BARRIER;} while(0)
+# endif
#endif
-typedef struct {
- unsigned open;
- ethr_mutex mtx;
- ethr_cond cnd;
-} ethr_gate;
+#define ETHR_YIELD_AFTER_BUSY_LOOPS 50
-#ifdef ETHR_HAVE_NATIVE_ATOMICS
+#ifndef ETHR_HAVE_NATIVE_ATOMICS
/*
- * Map ethread native atomics to ethread API atomics.
+ * ETHR_*MEMORY_BARRIER orders between locked and atomic accesses only,
+ * i.e. when our lock based atomic fallback is used, a noop is sufficient.
*/
-typedef ethr_native_atomic_t ethr_atomic_t;
+#define ETHR_MEMORY_BARRIER do { } while (0)
+#define ETHR_WRITE_MEMORY_BARRIER do { } while (0)
+#define ETHR_READ_MEMORY_BARRIER do { } while (0)
+#define ETHR_READ_DEPEND_MEMORY_BARRIER do { } while (0)
#endif
-#ifdef ETHR_HAVE_NATIVE_LOCKS
-/*
- * Map ethread native spinlocks to ethread API spinlocks.
- */
-typedef ethr_native_spinlock_t ethr_spinlock_t;
-/*
- * Map ethread native rwlocks to ethread API rwlocks.
- */
-typedef ethr_native_rwlock_t ethr_rwlock_t;
+#ifndef ETHR_WRITE_MEMORY_BARRIER
+# define ETHR_WRITE_MEMORY_BARRIER ETHR_MEMORY_BARRIER
+# define ETHR_WRITE_MEMORY_BARRIER_IS_FULL
#endif
-
-#ifdef ETHR_USE_RWMTX_FALLBACK
-typedef struct {
- ethr_mutex mtx;
- ethr_cond rcnd;
- ethr_cond wcnd;
- unsigned readers;
- unsigned waiting_readers;
- unsigned waiting_writers;
-#if ETHR_XCHK
- int initialized;
+#ifndef ETHR_READ_MEMORY_BARRIER
+# define ETHR_READ_MEMORY_BARRIER ETHR_MEMORY_BARRIER
+# define ETHR_READ_MEMORY_BARRIER_IS_FULL
#endif
-} ethr_rwmutex;
+#ifndef ETHR_READ_DEPEND_MEMORY_BARRIER
+# define ETHR_READ_DEPEND_MEMORY_BARRIER ETHR_COMPILER_BARRIER
+# define ETHR_READ_DEPEND_MEMORY_BARRIER_IS_COMPILER_BARRIER
#endif
-#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
-typedef long ethr_atomic_t;
-#endif
+#define ETHR_FATAL_ERROR__(ERR) \
+ ethr_fatal_error__(__FILE__, __LINE__, __func__, (ERR))
-#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
+ETHR_PROTO_NORETURN__ ethr_fatal_error__(const char *file,
+ int line,
+ const char *func,
+ int err);
-#if defined(ETHR_WIN32_THREADS)
-typedef struct {
- CRITICAL_SECTION cs;
-} ethr_spinlock_t;
-typedef struct {
- CRITICAL_SECTION cs;
- unsigned counter;
-} ethr_rwlock_t;
+void ethr_compiler_barrier_fallback(void);
+#ifndef ETHR_COMPILER_BARRIER
+# define ETHR_COMPILER_BARRIER ethr_compiler_barrier_fallback()
+#endif
-int ethr_do_spinlock_init(ethr_spinlock_t *lock);
-int ethr_do_rwlock_init(ethr_rwlock_t *lock);
+#ifndef ETHR_SPIN_BODY
+# define ETHR_SPIN_BODY ETHR_COMPILER_BARRIER
+#endif
-#define ETHR_RWLOCK_WRITERS (((unsigned) 1) << 31)
+#ifndef ETHR_YIELD
+# if defined(ETHR_HAVE_SCHED_YIELD)
+# ifdef ETHR_HAVE_SCHED_H
+# include <sched.h>
+# endif
+# include <errno.h>
+# if defined(ETHR_SCHED_YIELD_RET_INT)
+# define ETHR_YIELD() (sched_yield() < 0 ? errno : 0)
+# else
+# define ETHR_YIELD() (sched_yield(), 0)
+# endif
+# elif defined(ETHR_HAVE_PTHREAD_YIELD)
+# if defined(ETHR_PTHREAD_YIELD_RET_INT)
+# define ETHR_YIELD() pthread_yield()
+# else
+# define ETHR_YIELD() (pthread_yield(), 0)
+# endif
+# else
+# define ETHR_YIELD() (ethr_compiler_barrier(), 0)
+# endif
+#endif
+
+#include "ethr_optimized_fallbacks.h"
-#elif defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
-typedef struct {
- pthread_spinlock_t spnlck;
-} ethr_spinlock_t;
typedef struct {
- pthread_spinlock_t spnlck;
- unsigned counter;
-} ethr_rwlock_t;
-#define ETHR_RWLOCK_WRITERS (((unsigned) 1) << 31)
+ void *(*thread_create_prepare_func)(void);
+ void (*thread_create_parent_func)(void *);
+ void (*thread_create_child_func)(void *);
+} ethr_init_data;
-#else /* ethr mutex/rwmutex */
+#define ETHR_INIT_DATA_DEFAULT_INITER {NULL, NULL, NULL}
typedef struct {
- ethr_mutex mtx;
-} ethr_spinlock_t;
+ void *(*alloc)(size_t);
+ void *(*realloc)(void *, size_t);
+ void (*free)(void *);
+} ethr_memory_allocator;
+
+#define ETHR_MEM_ALLOC_DEF_INITER__ {NULL, NULL, NULL}
typedef struct {
- ethr_rwmutex rwmtx;
-} ethr_rwlock_t;
+ ethr_memory_allocator std;
+ ethr_memory_allocator sl;
+ ethr_memory_allocator ll;
+} ethr_memory_allocators;
-#endif /* end mutex/rwmutex */
-#endif /* ETHR_HAVE_OPTIMIZED_LOCKS */
+#define ETHR_MEM_ALLOCS_DEF_INITER__ \
+ {ETHR_MEM_ALLOC_DEF_INITER__, \
+ ETHR_MEM_ALLOC_DEF_INITER__, \
+ ETHR_MEM_ALLOC_DEF_INITER__}
typedef struct {
- void *(*alloc)(size_t);
- void *(*realloc)(void *, size_t);
- void (*free)(void *);
- void *(*thread_create_prepare_func)(void);
- void (*thread_create_parent_func)(void *);
- void (*thread_create_child_func)(void *);
-} ethr_init_data;
+ ethr_memory_allocators mem;
+ int reader_groups;
+ int main_threads;
+} ethr_late_init_data;
-#define ETHR_INIT_DATA_DEFAULT_INITER {malloc, realloc, free, NULL, NULL, NULL}
+#define ETHR_LATE_INIT_DATA_DEFAULT_INITER \
+ {ETHR_MEM_ALLOCS_DEF_INITER__, 0, 0}
typedef struct {
int detached; /* boolean (default false) */
@@ -835,18 +380,15 @@ typedef struct {
#define ETHR_THR_OPTS_DEFAULT_INITER {0, -1}
-#if defined(ETHR_CUSTOM_INLINE_FUNC_NAME_) || !defined(ETHR_TRY_INLINE_FUNCS)
-# define ETHR_NEED_MTX_PROTOTYPES__
-# define ETHR_NEED_RWMTX_PROTOTYPES__
+
+#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
# define ETHR_NEED_SPINLOCK_PROTOTYPES__
+# define ETHR_NEED_RWSPINLOCK_PROTOTYPES__
# define ETHR_NEED_ATOMIC_PROTOTYPES__
#endif
-#if !defined(ETHR_NEED_RWMTX_PROTOTYPES__) && defined(ETHR_USE_RWMTX_FALLBACK)
-# define ETHR_NEED_RWMTX_PROTOTYPES__
-#endif
-
int ethr_init(ethr_init_data *);
+int ethr_late_init(ethr_late_init_data *);
int ethr_install_exit_handler(void (*funcp)(void));
int ethr_thr_create(ethr_tid *, void * (*)(void *), void *, ethr_thr_opts *);
int ethr_thr_join(ethr_tid, void **);
@@ -854,65 +396,6 @@ int ethr_thr_detach(ethr_tid);
void ethr_thr_exit(void *);
ethr_tid ethr_self(void);
int ethr_equal_tids(ethr_tid, ethr_tid);
-int ethr_mutex_init(ethr_mutex *);
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
-int ethr_rec_mutex_init(ethr_mutex *);
-#endif
-int ethr_mutex_destroy(ethr_mutex *);
-int ethr_mutex_set_forksafe(ethr_mutex *);
-int ethr_mutex_unset_forksafe(ethr_mutex *);
-#ifdef ETHR_NEED_MTX_PROTOTYPES__
-int ethr_mutex_trylock(ethr_mutex *);
-int ethr_mutex_lock(ethr_mutex *);
-int ethr_mutex_unlock(ethr_mutex *);
-#endif
-int ethr_cond_init(ethr_cond *);
-int ethr_cond_destroy(ethr_cond *);
-int ethr_cond_signal(ethr_cond *);
-int ethr_cond_broadcast(ethr_cond *);
-int ethr_cond_wait(ethr_cond *, ethr_mutex *);
-int ethr_cond_timedwait(ethr_cond *, ethr_mutex *, ethr_timeval *);
-
-int ethr_rwmutex_init(ethr_rwmutex *);
-int ethr_rwmutex_destroy(ethr_rwmutex *);
-#ifdef ETHR_NEED_RWMTX_PROTOTYPES__
-int ethr_rwmutex_tryrlock(ethr_rwmutex *);
-int ethr_rwmutex_rlock(ethr_rwmutex *);
-int ethr_rwmutex_runlock(ethr_rwmutex *);
-int ethr_rwmutex_tryrwlock(ethr_rwmutex *);
-int ethr_rwmutex_rwlock(ethr_rwmutex *);
-int ethr_rwmutex_rwunlock(ethr_rwmutex *);
-#endif
-
-#ifdef ETHR_NEED_ATOMIC_PROTOTYPES__
-int ethr_atomic_init(ethr_atomic_t *, long);
-int ethr_atomic_set(ethr_atomic_t *, long);
-int ethr_atomic_read(ethr_atomic_t *, long *);
-int ethr_atomic_inctest(ethr_atomic_t *, long *);
-int ethr_atomic_dectest(ethr_atomic_t *, long *);
-int ethr_atomic_inc(ethr_atomic_t *);
-int ethr_atomic_dec(ethr_atomic_t *);
-int ethr_atomic_addtest(ethr_atomic_t *, long, long *);
-int ethr_atomic_add(ethr_atomic_t *, long);
-int ethr_atomic_and_old(ethr_atomic_t *, long, long *);
-int ethr_atomic_or_old(ethr_atomic_t *, long, long *);
-int ethr_atomic_xchg(ethr_atomic_t *, long, long *);
-int ethr_atomic_cmpxchg(ethr_atomic_t *, long, long, long *);
-#endif
-
-#ifdef ETHR_NEED_SPINLOCK_PROTOTYPES__
-int ethr_spinlock_init(ethr_spinlock_t *);
-int ethr_spinlock_destroy(ethr_spinlock_t *);
-int ethr_spin_unlock(ethr_spinlock_t *);
-int ethr_spin_lock(ethr_spinlock_t *);
-
-int ethr_rwlock_init(ethr_rwlock_t *);
-int ethr_rwlock_destroy(ethr_rwlock_t *);
-int ethr_read_unlock(ethr_rwlock_t *);
-int ethr_read_lock(ethr_rwlock_t *);
-int ethr_write_unlock(ethr_rwlock_t *);
-int ethr_write_lock(ethr_rwlock_t *);
-#endif
int ethr_time_now(ethr_timeval *);
int ethr_tsd_key_create(ethr_tsd_key *);
@@ -920,13 +403,6 @@ int ethr_tsd_key_delete(ethr_tsd_key);
int ethr_tsd_set(ethr_tsd_key, void *);
void *ethr_tsd_get(ethr_tsd_key);
-int ethr_gate_init(ethr_gate *);
-int ethr_gate_destroy(ethr_gate *);
-int ethr_gate_close(ethr_gate *);
-int ethr_gate_let_through(ethr_gate *, unsigned);
-int ethr_gate_wait(ethr_gate *);
-int ethr_gate_swait(ethr_gate *, int);
-
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
#include <signal.h>
int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset);
@@ -935,534 +411,579 @@ int ethr_sigwait(const sigset_t *set, int *sig);
void ethr_compiler_barrier(void);
-#ifdef ETHR_TRY_INLINE_FUNCS
-
-#ifdef ETHR_HAVE_NATIVE_ATOMICS
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
-{
- ethr_native_atomic_init(var, i);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
-{
- ethr_native_atomic_set(var, i);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
-{
- *i = ethr_native_atomic_read(var);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
-{
- ethr_native_atomic_add(var, incr);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *var,
- long i,
- long *testp)
-{
- *testp = ethr_native_atomic_add_return(var, i);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *var)
-{
- ethr_native_atomic_inc(var);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *var)
-{
- ethr_native_atomic_dec(var);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *var, long *testp)
-{
- *testp = ethr_native_atomic_inc_return(var);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *var, long *testp)
-{
- *testp = ethr_native_atomic_dec_return(var);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
- long mask,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- *old = ethr_native_atomic_and_retold(var, mask);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
- long mask,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- *old = ethr_native_atomic_or_retold(var, mask);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
- long new,
- long *old)
-{
- *old = ethr_native_atomic_xchg(var, new);
- return 0;
-}
-
-/*
- * If *var == *old, replace *old with new, else do nothing.
- * In any case return the original value of *var in *old.
- */
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
- long new,
- long expected,
- long *old)
-{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- *old = ethr_native_atomic_cmpxchg(var, new, expected);
- return 0;
-}
+#if defined(ETHR_HAVE_NATIVE_SPINLOCKS)
+typedef ethr_native_spinlock_t ethr_spinlock_t;
+#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
+typedef ethr_opt_spinlock_t ethr_spinlock_t;
+#elif defined(__WIN32__)
+typedef CRITICAL_SECTION ethr_spinlock_t;
+#else
+typedef pthread_mutex_t ethr_spinlock_t;
+#endif
-#endif /* ETHR_HAVE_NATIVE_ATOMICS */
+#ifdef ETHR_NEED_SPINLOCK_PROTOTYPES__
+int ethr_spinlock_init(ethr_spinlock_t *);
+int ethr_spinlock_destroy(ethr_spinlock_t *);
+void ethr_spin_unlock(ethr_spinlock_t *);
+void ethr_spin_lock(ethr_spinlock_t *);
+#endif
-#ifdef ETHR_HAVE_NATIVE_LOCKS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE int
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
{
+#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
ethr_native_spinlock_init(lock);
return 0;
+#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
+ return ethr_opt_spinlock_init((ethr_opt_spinlock_t *) lock);
+#elif defined(__WIN32__)
+ if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, INT_MAX))
+ return ethr_win_get_errno__();
+ return 0;
+#else
+ return pthread_mutex_init((pthread_mutex_t *) lock, NULL);
+#endif
}
static ETHR_INLINE int
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
{
+#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
return 0;
+#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
+ return ethr_opt_spinlock_destroy((ethr_opt_spinlock_t *) lock);
+#elif defined(__WIN32__)
+ DeleteCriticalSection((CRITICAL_SECTION *) lock);
+ return 0;
+#else
+ return pthread_mutex_destroy((pthread_mutex_t *) lock);
+#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
{
+#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
ethr_native_spin_unlock(lock);
- return 0;
+#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
+ int err = ethr_opt_spin_unlock((ethr_opt_spinlock_t *) lock);
+ if (err)
+ ETHR_FATAL_ERROR__(err);
+#elif defined(__WIN32__)
+ LeaveCriticalSection((CRITICAL_SECTION *) lock);
+#else
+ int err = pthread_mutex_unlock((pthread_mutex_t *) lock);
+ if (err)
+ ETHR_FATAL_ERROR__(err);
+#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
{
+#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
ethr_native_spin_lock(lock);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
-{
- ethr_native_rwlock_init(lock);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
-{
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
-{
- ethr_native_read_unlock(lock);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
-{
- ethr_native_read_lock(lock);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
-{
- ethr_native_write_unlock(lock);
- return 0;
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
-{
- ethr_native_write_lock(lock);
- return 0;
+#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
+ int err = ethr_opt_spin_lock((ethr_opt_spinlock_t *) lock);
+ if (err)
+ ETHR_FATAL_ERROR__(err);
+#elif defined(__WIN32__)
+ EnterCriticalSection((CRITICAL_SECTION *) lock);
+#else
+ int err = pthread_mutex_lock((pthread_mutex_t *) lock);
+ if (err)
+ ETHR_FATAL_ERROR__(err);
+#endif
}
-#endif /* ETHR_HAVE_NATIVE_LOCKS */
-
#endif /* ETHR_TRY_INLINE_FUNCS */
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
/*
- * Fallbacks for atomics used in absence of optimized implementation.
+ * Map ethread native atomics to ethread API atomics.
*/
-#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
+typedef ethr_native_atomic_t ethr_atomic_t;
+#else
+typedef long ethr_atomic_t;
+#endif
+#ifdef ETHR_NEED_ATOMIC_PROTOTYPES__
+void ethr_atomic_init(ethr_atomic_t *, long);
+void ethr_atomic_set(ethr_atomic_t *, long);
+long ethr_atomic_read(ethr_atomic_t *);
+long ethr_atomic_inc_read(ethr_atomic_t *);
+long ethr_atomic_dec_read(ethr_atomic_t *);
+void ethr_atomic_inc(ethr_atomic_t *);
+void ethr_atomic_dec(ethr_atomic_t *);
+long ethr_atomic_add_read(ethr_atomic_t *, long);
+void ethr_atomic_add(ethr_atomic_t *, long);
+long ethr_atomic_read_band(ethr_atomic_t *, long);
+long ethr_atomic_read_bor(ethr_atomic_t *, long);
+long ethr_atomic_xchg(ethr_atomic_t *, long);
+long ethr_atomic_cmpxchg(ethr_atomic_t *, long, long);
+long ethr_atomic_read_acqb(ethr_atomic_t *);
+long ethr_atomic_inc_read_acqb(ethr_atomic_t *);
+void ethr_atomic_set_relb(ethr_atomic_t *, long);
+void ethr_atomic_dec_relb(ethr_atomic_t *);
+long ethr_atomic_dec_read_relb(ethr_atomic_t *);
+long ethr_atomic_cmpxchg_acqb(ethr_atomic_t *, long, long);
+long ethr_atomic_cmpxchg_relb(ethr_atomic_t *, long, long);
+#endif
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+#ifndef ETHR_HAVE_NATIVE_ATOMICS
/*
- * ETHR_MEMORY_BARRIER orders between locked and atomic accesses only,
- * i.e. when this atomic fallback is used a noop is sufficient.
+ * Fallbacks for atomics used in absence of a native implementation.
*/
-#define ETHR_MEMORY_BARRIER
#define ETHR_ATOMIC_ADDR_BITS 10
#define ETHR_ATOMIC_ADDR_SHIFT 6
typedef struct {
union {
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- pthread_spinlock_t spnlck;
-#else
- ethr_mutex mtx;
-#endif
+ ethr_spinlock_t lck;
char buf[ETHR_CACHE_LINE_SIZE];
} u;
} ethr_atomic_protection_t;
extern ethr_atomic_protection_t ethr_atomic_protection__[1 << ETHR_ATOMIC_ADDR_BITS];
-
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
-
#define ETHR_ATOMIC_PTR2LCK__(PTR) \
(&ethr_atomic_protection__[((((unsigned long) (PTR)) >> ETHR_ATOMIC_ADDR_SHIFT) \
- & ((1 << ETHR_ATOMIC_ADDR_BITS) - 1))].u.spnlck)
+ & ((1 << ETHR_ATOMIC_ADDR_BITS) - 1))].u.lck)
#define ETHR_ATOMIC_OP_FALLBACK_IMPL__(AP, EXPS) \
do { \
- pthread_spinlock_t *slp__ = ETHR_ATOMIC_PTR2LCK__((AP)); \
- int res__ = pthread_spin_lock(slp__); \
- if (res__ != 0) \
- return res__; \
+ ethr_spinlock_t *slp__ = ETHR_ATOMIC_PTR2LCK__((AP)); \
+ ethr_spin_lock(slp__); \
{ EXPS; } \
- return pthread_spin_unlock(slp__); \
+ ethr_spin_unlock(slp__); \
} while (0)
-#else /* ethread mutex */
-
-#define ETHR_ATOMIC_PTR2LCK__(PTR) \
-(&ethr_atomic_protection__[((((unsigned long) (PTR)) >> ETHR_ATOMIC_ADDR_SHIFT) \
- & ((1 << ETHR_ATOMIC_ADDR_BITS) - 1))].u.mtx)
-
-#define ETHR_ATOMIC_OP_FALLBACK_IMPL__(AP, EXPS) \
-do { \
- ethr_mutex *mtxp__ = ETHR_ATOMIC_PTR2LCK__((AP)); \
- int res__ = ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(mtxp__); \
- if (res__ != 0) \
- return res__; \
- { EXPS; } \
- return ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(mtxp__); \
-} while (0)
-
-#endif /* end ethread mutex */
-
-#ifdef ETHR_TRY_INLINE_FUNCS
+#endif
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = (ethr_atomic_t) i);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_init(var, i);
+#else
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = i);
+#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = (ethr_atomic_t) i);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_set(var, i);
+#else
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = i);
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *i = (long) *var);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_read(var);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = (long) *var);
+ return res;
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *incp, long *testp)
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, *testp = (long) ++(*incp));
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_add(var, incr);
+#else
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var += incr);
+#endif
+}
+
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_add_read)(ethr_atomic_t *var, long i)
+{
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_add_return(var, i);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var += i; res = *var);
+ return res;
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *decp, long *testp)
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *var)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(decp, *testp = (long) --(*decp));
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_inc(var);
+#else
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, ++(*var));
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
-{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var += incr);
-}
-
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *incp,
- long i,
- long *testp)
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *var)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, *incp += i; *testp = *incp);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_dec(var);
+#else
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, --(*var));
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *incp)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc_read)(ethr_atomic_t *var)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, ++(*incp));
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_inc_return(var);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = (long) ++(*var));
+ return res;
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *decp)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec_read)(ethr_atomic_t *var)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(decp, --(*decp));
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_dec_return(var);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = (long) --(*var));
+ return res;
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
- long mask,
- long *old)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_read_band)(ethr_atomic_t *var,
+ long mask)
{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var &= mask);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_and_retold(var, mask);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = *var; *var &= mask);
+ return res;
+#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
- long mask,
- long *old)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_read_bor)(ethr_atomic_t *var,
+ long mask)
{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var |= mask);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_or_retold(var, mask);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = *var; *var |= mask);
+ return res;
+#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE long
ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
- long new,
- long *old)
+ long new)
{
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var = new);
-}
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_xchg(var, new);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, res = *var; *var = new);
+ return res;
+#endif
+}
-/*
- * If *var == *old, replace *old with new, else do nothing.
- * In any case return the original value of *var in *old.
- */
-static ETHR_INLINE int
+static ETHR_INLINE long
ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
long new,
- long expected,
- long *old)
+ long exp)
{
- /*
- * See "Extra memory barrier requirements" note at the top
- * of the file.
- */
- ETHR_ATOMIC_OP_FALLBACK_IMPL__(
- var,
- long old_val = *var;
- *old = old_val;
- if (__builtin_expect(old_val == expected, 1))
- *var = new;
- );
- return 0;
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_cmpxchg(var, new, exp);
+#else
+ long res;
+ ETHR_ATOMIC_OP_FALLBACK_IMPL__(var,
+ {
+ res = *var;
+ if (__builtin_expect(res == exp, 1))
+ *var = new;
+ });
+ return res;
+#endif
}
-#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
-#endif /* #ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS */
-
/*
- * Fallbacks for spin locks, and rw spin locks used in absence of
- * optimized implementation.
+ * Important memory barrier requirements.
+ *
+ * The following atomic operations *must* supply a memory barrier of
+ * at least the type specified by its suffix:
+ * _acqb = acquire barrier
+ * _relb = release barrier
*/
-#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
-#ifdef ETHR_TRY_INLINE_FUNCS
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_read_acqb)(ethr_atomic_t *var)
+{
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_read_acqb(var);
+#else
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(var);
+#endif
+}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc_read_acqb)(ethr_atomic_t *var)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- return pthread_spin_init(&lock->spnlck, 0);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_inc_return_acqb(var);
#else
- return ethr_mutex_init(&lock->mtx);
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc_read)(var);
#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_set_relb)(ethr_atomic_t *var, long val)
+{
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_set_relb(var, val);
+#else
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(var, val);
+#endif
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec_relb)(ethr_atomic_t *var)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- return pthread_spin_destroy(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ ethr_native_atomic_dec_relb(var);
#else
- return ethr_mutex_destroy(&lock->mtx);
+ ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(var);
#endif
}
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec_read_relb)(ethr_atomic_t *var)
+{
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_dec_return_relb(var);
+#else
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec_read)(var);
+#endif
+}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg_acqb)(ethr_atomic_t *var,
+ long new,
+ long exp)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- return pthread_spin_unlock(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_cmpxchg_acqb(var, new, exp);
#else
- return ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(&lock->mtx);
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(var, new, exp);
#endif
}
-static ETHR_INLINE int
-ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
+static ETHR_INLINE long
+ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg_relb)(ethr_atomic_t *var,
+ long new,
+ long exp)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- return pthread_spin_lock(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_ATOMICS
+ return ethr_native_atomic_cmpxchg_relb(var, new, exp);
#else
- return ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(&lock->mtx);
+ return ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(var, new, exp);
#endif
}
-#ifdef ETHR_USE_RWMTX_FALLBACK
-#define ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(X) X
+#endif /* ETHR_TRY_INLINE_FUNCS */
+
+typedef struct ethr_ts_event_ ethr_ts_event; /* Needed by ethr_mutex.h */
+
+#if defined(ETHR_WIN32_THREADS)
+# include "win/ethr_event.h"
#else
-#define ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(X) ETHR_INLINE_FUNC_NAME_(X)
+# include "pthread/ethr_event.h"
+#endif
+
+int ethr_set_main_thr_status(int, int);
+int ethr_get_main_thr_status(int *);
+
+struct ethr_ts_event_ {
+ ethr_ts_event *next;
+ ethr_ts_event *prev;
+ ethr_event event;
+ void *udata;
+ ethr_atomic_t uaflgs;
+ unsigned uflgs;
+ unsigned iflgs; /* for ethr lib only */
+ short rgix; /* for ethr lib only */
+ short mtix; /* for ethr lib only */
+};
+
+#define ETHR_TS_EV_ETHREAD (((unsigned) 1) << 0)
+#define ETHR_TS_EV_INITED (((unsigned) 1) << 1)
+#define ETHR_TS_EV_TMP (((unsigned) 1) << 2)
+#define ETHR_TS_EV_MAIN_THR (((unsigned) 1) << 3)
+
+int ethr_get_tmp_ts_event__(ethr_ts_event **tsepp);
+int ethr_free_ts_event__(ethr_ts_event *tsep);
+int ethr_make_ts_event__(ethr_ts_event **tsepp);
+
+#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
+ethr_ts_event *ethr_get_ts_event(void);
+void ethr_leave_ts_event(ethr_ts_event *);
+#endif
+
+#if defined(ETHR_PTHREADS)
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
+
+extern pthread_key_t ethr_ts_event_key__;
+
+static ETHR_INLINE ethr_ts_event *
+ETHR_INLINE_FUNC_NAME_(ethr_get_ts_event)(void)
+{
+ ethr_ts_event *tsep = pthread_getspecific(ethr_ts_event_key__);
+ if (!tsep) {
+ int res = ethr_make_ts_event__(&tsep);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ ETHR_ASSERT(tsep);
+ }
+ return tsep;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep)
+{
+
+}
+
#endif
+#elif defined(ETHR_WIN32_THREADS)
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
+
+extern DWORD ethr_ts_event_key__;
+
+static ETHR_INLINE ethr_ts_event *
+ETHR_INLINE_FUNC_NAME_(ethr_get_ts_event)(void)
+{
+ ethr_ts_event *tsep = TlsGetValue(ethr_ts_event_key__);
+ if (!tsep) {
+ int res = ethr_get_tmp_ts_event__(&tsep);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ ETHR_ASSERT(tsep);
+ }
+ return tsep;
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep)
+{
+ if (tsep->iflgs & ETHR_TS_EV_TMP) {
+ int res = ethr_free_ts_event__(tsep);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+}
+
+#endif
+
+#endif
+
+#include "ethr_mutex.h" /* Need atomic declarations and tse */
+
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+typedef ethr_native_rwlock_t ethr_rwlock_t;
+#else
+typedef ethr_rwmutex ethr_rwlock_t;
+#endif
+
+#ifdef ETHR_NEED_RWSPINLOCK_PROTOTYPES__
+int ethr_rwlock_init(ethr_rwlock_t *);
+int ethr_rwlock_destroy(ethr_rwlock_t *);
+void ethr_read_unlock(ethr_rwlock_t *);
+void ethr_read_lock(ethr_rwlock_t *);
+void ethr_write_unlock(ethr_rwlock_t *);
+void ethr_write_lock(ethr_rwlock_t *);
+#endif
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
static ETHR_INLINE int
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- lock->counter = 0;
- return pthread_spin_init(&lock->spnlck, 0);
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ ethr_native_rwlock_init(lock);
+ return 0;
#else
- return ethr_rwmutex_init(&lock->rwmtx);
+ return ethr_rwmutex_init_opt((ethr_rwmutex *) lock, NULL);
#endif
}
static ETHR_INLINE int
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- return pthread_spin_destroy(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ return 0;
#else
- return ethr_rwmutex_destroy(&lock->rwmtx);
+ return ethr_rwmutex_destroy((ethr_rwmutex *) lock);
#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- int res = pthread_spin_lock(&lock->spnlck);
- if (res != 0)
- return res;
- lock->counter--;
- return pthread_spin_unlock(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ ethr_native_read_unlock(lock);
#else
- return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_runlock)(&lock->rwmtx);
+ ethr_rwmutex_runlock((ethr_rwmutex *) lock);
#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- int locked = 0;
- do {
- int res = pthread_spin_lock(&lock->spnlck);
- if (res != 0)
- return res;
- if ((lock->counter & ETHR_RWLOCK_WRITERS) == 0) {
- lock->counter++;
- locked = 1;
- }
- res = pthread_spin_unlock(&lock->spnlck);
- if (res != 0)
- return res;
- } while (!locked);
- return 0;
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ ethr_native_read_lock(lock);
#else
- return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rlock)(&lock->rwmtx);
+ ethr_rwmutex_rlock((ethr_rwmutex *) lock);
#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- lock->counter = 0;
- return pthread_spin_unlock(&lock->spnlck);
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ ethr_native_write_unlock(lock);
#else
- return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rwunlock)(&lock->rwmtx);
+ ethr_rwmutex_rwunlock((ethr_rwmutex *) lock);
#endif
}
-static ETHR_INLINE int
+static ETHR_INLINE void
ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
{
-#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
- while (1) {
- int res = pthread_spin_lock(&lock->spnlck);
- if (res != 0)
- return res;
- lock->counter |= ETHR_RWLOCK_WRITERS;
- if (lock->counter == ETHR_RWLOCK_WRITERS)
- return 0;
- res = pthread_spin_unlock(&lock->spnlck);
- if (res != 0)
- return res;
- }
+#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
+ ethr_native_write_lock(lock);
#else
- return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rwlock)(&lock->rwmtx);
+ ethr_rwmutex_rwlock((ethr_rwmutex *) lock);
#endif
}
-#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
-
-#endif /* ETHR_HAVE_OPTIMIZED_LOCKS */
-
-#if defined(ETHR_HAVE_OPTIMIZED_LOCKS) || defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
-# define ETHR_HAVE_OPTIMIZED_SPINLOCK
-#endif
+#endif /* ETHR_TRY_INLINE_FUNCS */
#endif /* #ifndef ETHREAD_H__ */
diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in
index c9fd87c2f6..5debb44756 100644
--- a/erts/include/internal/ethread_header_config.h.in
+++ b/erts/include/internal/ethread_header_config.h.in
@@ -29,26 +29,54 @@
/* Define if you have pthreads */
#undef ETHR_PTHREADS
+/* Define if you need the <nptl/pthread.h> header file. */
+#undef ETHR_NEED_NPTL_PTHREAD_H
+
/* Define if you have the <pthread.h> header file. */
#undef ETHR_HAVE_PTHREAD_H
/* Define if the pthread.h header file is in pthread/mit directory. */
#undef ETHR_HAVE_MIT_PTHREAD_H
-/* Define if you have the pthread_mutexattr_settype function. */
-#undef ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE
+/* Define if you have the pthread_spin_lock function. */
+#undef ETHR_HAVE_PTHREAD_SPIN_LOCK
-/* Define if you have the pthread_mutexattr_setkind_np function. */
-#undef ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
+/* Define if you want to force usage of pthread rwlocks */
+#undef ETHR_FORCE_PTHREAD_RWLOCK
-/* Define if you have the pthread_atfork function. */
-#undef ETHR_HAVE_PTHREAD_ATFORK
+/* Define if you have the pthread_rwlockattr_setkind_np() function. */
+#undef ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
-/* Define if you have the pthread_spin_lock function. */
-#undef ETHR_HAVE_PTHREAD_SPIN_LOCK
+/* Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock
+ attribute. */
+#undef ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
-/* Define if you have a pthread_rwlock implementation that can be used */
-#undef ETHR_HAVE_PTHREAD_RWLOCK_INIT
+/* Define if you have a linux futex implementation. */
+#undef ETHR_HAVE_LINUX_FUTEX
+
+/* Define if you have gcc atomic operations */
+#undef ETHR_HAVE_GCC_ATOMIC_OPS
+
+/* Define if you prefer gcc native ethread implementations */
+#undef ETHR_PREFER_GCC_NATIVE_IMPLS
+
+/* Define if you have the <sched.h> header file. */
+#undef ETHR_HAVE_SCHED_H
+
+/* Define if you have the sched_yield() function. */
+#undef ETHR_HAVE_SCHED_YIELD
+
+/* Define if you have the pthread_yield() function. */
+#undef ETHR_HAVE_PTHREAD_YIELD
+
+/* Define if pthread_yield() returns an int. */
+#undef ETHR_PTHREAD_YIELD_RET_INT
+
+/* Define if sched_yield() returns an int. */
+#undef ETHR_SCHED_YIELD_RET_INT
+
+/* Define if you want compatibilty with x86 processors before pentium4. */
+#undef ETHR_PRE_PENTIUM4_COMPAT
/* Define if you have the pthread_rwlockattr_setkind_np() function. */
#undef ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
@@ -63,6 +91,15 @@
/* Define if you prefer gcc native ethread implementations */
#undef ETHR_PREFER_GCC_NATIVE_IMPLS
+/* Define if you have libatomic_ops atomic operations */
+#undef ETHR_HAVE_LIBATOMIC_OPS
+
+/* Define if you prefer libatomic_ops native ethread implementations */
+#undef ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS
+
+/* Define to the size of AO_t if libatomic_ops is used */
+#undef ETHR_SIZEOF_AO_T
+
/* Define if you want to turn on extra sanity checking in the ethread library */
#undef ETHR_XCHK
diff --git a/erts/include/internal/gcc/ethr_atomic.h b/erts/include/internal/gcc/ethr_atomic.h
index 775030c8d5..5fe6e23477 100644
--- a/erts/include/internal/gcc/ethr_atomic.h
+++ b/erts/include/internal/gcc/ethr_atomic.h
@@ -55,6 +55,7 @@ do { \
volatile long x___ = 0; \
(void) __sync_val_compare_and_swap(&x___, (long) 0, (long) 1); \
} while (0)
+#define ETHR_READ_DEPEND_MEMORY_BARRIER ETHR_MEMORY_BARRIER
#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
@@ -157,6 +158,24 @@ ethr_native_atomic_xchg(ethr_native_atomic_t *var, long new)
return act;
}
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+ return __sync_add_and_fetch(&var->counter, (long) 0);
+}
+
+#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
+#define ethr_native_atomic_set_relb ethr_native_atomic_xchg
+#define ethr_native_atomic_dec_relb ethr_native_atomic_dec_return
+#define ethr_native_atomic_dec_return_relb ethr_native_atomic_dec_return
+
+#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
+#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
+
#endif
#endif
diff --git a/erts/include/internal/i386/atomic.h b/erts/include/internal/i386/atomic.h
index 90b4c5f773..f28258059f 100644
--- a/erts/include/internal/i386/atomic.h
+++ b/erts/include/internal/i386/atomic.h
@@ -32,8 +32,11 @@ typedef struct {
volatile long counter;
} ethr_native_atomic_t;
-#ifdef __x86_64__
+#if defined(__x86_64__) || !defined(ETHR_PRE_PENTIUM4_COMPAT)
#define ETHR_MEMORY_BARRIER __asm__ __volatile__("mfence" : : : "memory")
+#define ETHR_WRITE_MEMORY_BARRIER __asm__ __volatile__("sfence" : : : "memory")
+#define ETHR_READ_MEMORY_BARRIER __asm__ __volatile__("lfence" : : : "memory")
+#define ETHR_READ_DEPEND_MEMORY_BARRIER __asm__ __volatile__("" : : : "memory")
#else
#define ETHR_MEMORY_BARRIER \
do { \
@@ -42,7 +45,9 @@ do { \
} while (0)
#endif
-#ifdef ETHR_TRY_INLINE_FUNCS
+#define ETHR_ATOMIC_HAVE_INC_DEC_INSTRUCTIONS 1
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
#ifdef __x86_64__
#define LONG_SUFFIX "q"
@@ -158,6 +163,22 @@ ethr_native_atomic_xchg(ethr_native_atomic_t *var, long val)
return tmp;
}
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+#define ethr_native_atomic_read_acqb ethr_native_atomic_read
+#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
+#if defined(__x86_64__) || !defined(ETHR_PRE_PENTIUM4_COMPAT)
+#define ethr_native_atomic_set_relb ethr_native_atomic_set
+#else
+#define ethr_native_atomic_set_relb ethr_native_atomic_xchg
+#endif
+#define ethr_native_atomic_dec_relb ethr_native_atomic_dec
+#define ethr_native_atomic_dec_return_relb ethr_native_atomic_dec_return
+#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
+#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
+
#undef LONG_SUFFIX
#endif /* ETHR_TRY_INLINE_FUNCS */
diff --git a/erts/include/internal/i386/ethread.h b/erts/include/internal/i386/ethread.h
index fad8b108fa..ed43e77279 100644
--- a/erts/include/internal/i386/ethread.h
+++ b/erts/include/internal/i386/ethread.h
@@ -29,6 +29,7 @@
#include "rwlock.h"
#define ETHR_HAVE_NATIVE_ATOMICS 1
-#define ETHR_HAVE_NATIVE_LOCKS 1
+#define ETHR_HAVE_NATIVE_SPINLOCKS 1
+#define ETHR_HAVE_NATIVE_RWSPINLOCKS 1
#endif /* ETHREAD_I386_ETHREAD_H */
diff --git a/erts/include/internal/i386/rwlock.h b/erts/include/internal/i386/rwlock.h
index c009be8ef1..be47f459ce 100644
--- a/erts/include/internal/i386/rwlock.h
+++ b/erts/include/internal/i386/rwlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -31,7 +31,7 @@ typedef struct {
volatile int lock;
} ethr_native_rwlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
#define ETHR_RWLOCK_OFFSET (1<<24)
diff --git a/erts/include/internal/i386/spinlock.h b/erts/include/internal/i386/spinlock.h
index 2b4832e26a..0325324895 100644
--- a/erts/include/internal/i386/spinlock.h
+++ b/erts/include/internal/i386/spinlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -31,7 +31,7 @@ typedef struct {
volatile unsigned int lock;
} ethr_native_spinlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
@@ -46,7 +46,7 @@ ethr_native_spin_unlock(ethr_native_spinlock_t *lock)
* On i386 this needs to be a locked operation
* to avoid Pentium Pro errata 66 and 92.
*/
-#if defined(__x86_64__)
+#if defined(__x86_64__) || !defined(ETHR_PRE_PENTIUM4_COMPAT)
__asm__ __volatile__("" : : : "memory");
*(unsigned char*)&lock->lock = 0;
#else
diff --git a/erts/include/internal/libatomic_ops/ethr_atomic.h b/erts/include/internal/libatomic_ops/ethr_atomic.h
new file mode 100644
index 0000000000..a6eb43a0bd
--- /dev/null
+++ b/erts/include/internal/libatomic_ops/ethr_atomic.h
@@ -0,0 +1,292 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Native atomics ethread support using libatomic_ops
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_LIBATOMIC_OPS_ATOMIC_H__
+#define ETHR_LIBATOMIC_OPS_ATOMIC_H__
+
+#if !defined(ETHR_HAVE_NATIVE_ATOMICS) && defined(ETHR_HAVE_LIBATOMIC_OPS)
+#define ETHR_HAVE_NATIVE_ATOMICS 1
+
+#if (defined(__i386__) && !defined(ETHR_PRE_PENTIUM4_COMPAT)) \
+ || defined(__x86_64__)
+#define AO_USE_PENTIUM4_INSTRS
+#endif
+
+#include "atomic_ops.h"
+
+/*
+ * libatomic_ops can be downloaded from:
+ * http://www.hpl.hp.com/research/linux/atomic_ops/
+ *
+ * These operations need to be defined by libatomic_ops;
+ * otherwise, we won't compile:
+ * - AO_nop_full()
+ * - AO_load()
+ * - AO_store()
+ * - AO_compare_and_swap()
+ *
+ * The `AO_t' type also have to be at least as large as
+ * `void *' and `long' types.
+ */
+
+#if ETHR_SIZEOF_AO_T < ETHR_SIZEOF_PTR
+#error The AO_t type is too small
+#endif
+
+typedef struct {
+ volatile AO_t counter;
+} ethr_native_atomic_t;
+
+#define ETHR_MEMORY_BARRIER AO_nop_full()
+#ifdef AO_HAVE_nop_write
+# define ETHR_WRITE_MEMORY_BARRIER AO_nop_write()
+#else
+# define ETHR_WRITE_MEMORY_BARRIER ETHR_MEMORY_BARRIER
+#endif
+#ifdef AO_HAVE_nop_read
+# define ETHR_READ_MEMORY_BARRIER AO_nop_read()
+#else
+# define ETHR_READ_MEMORY_BARRIER ETHR_MEMORY_BARRIER
+#endif
+#ifdef AO_NO_DD_ORDERING
+# define ETHR_READ_DEPEND_MEMORY_BARRIER ETHR_READ_MEMORY_BARRIER
+#else
+# define ETHR_READ_DEPEND_MEMORY_BARRIER __asm__ __volatile__("":::"memory")
+#endif
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+static ETHR_INLINE void
+ethr_native_atomic_set(ethr_native_atomic_t *var, long value)
+{
+ AO_store(&var->counter, (AO_t) value);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_init(ethr_native_atomic_t *var, long value)
+{
+ ethr_native_atomic_set(var, value);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_read(ethr_native_atomic_t *var)
+{
+ return (long) AO_load(&var->counter);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_add_return(ethr_native_atomic_t *var, long incr)
+{
+#ifdef AO_HAVE_fetch_and_add
+ return ((long) AO_fetch_and_add(&var->counter, (AO_t) incr)) + incr;
+#else
+ while (1) {
+ AO_t exp = AO_load(&var->counter);
+ AO_t new = exp + (AO_t) incr;
+ if (AO_compare_and_swap(&var->counter, exp, new))
+ return (long) new;
+ }
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_add(ethr_native_atomic_t *var, long incr)
+{
+ (void) ethr_native_atomic_add_return(var, incr);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return(ethr_native_atomic_t *var)
+{
+#ifdef AO_HAVE_fetch_and_add1
+ return ((long) AO_fetch_and_add1(&var->counter)) + 1;
+#else
+ return ethr_native_atomic_add_return(var, 1);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_inc(ethr_native_atomic_t *var)
+{
+ (void) ethr_native_atomic_inc_return(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return(ethr_native_atomic_t *var)
+{
+#ifdef AO_HAVE_fetch_and_sub1
+ return ((long) AO_fetch_and_sub1(&var->counter)) - 1;
+#else
+ return ethr_native_atomic_add_return(var, -1);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec(ethr_native_atomic_t *var)
+{
+ (void) ethr_native_atomic_dec_return(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_and_retold(ethr_native_atomic_t *var, long mask)
+{
+ while (1) {
+ AO_t exp = AO_load(&var->counter);
+ AO_t new = exp & ((AO_t) mask);
+ if (AO_compare_and_swap(&var->counter, exp, new))
+ return (long) exp;
+ }
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_or_retold(ethr_native_atomic_t *var, long mask)
+{
+ while (1) {
+ AO_t exp = AO_load(&var->counter);
+ AO_t new = exp | ((AO_t) mask);
+ if (AO_compare_and_swap(&var->counter, exp, new))
+ return (long) exp;
+ }
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long exp)
+{
+ long act;
+ do {
+ if (AO_compare_and_swap(&var->counter, (AO_t) exp, (AO_t) new))
+ return exp;
+ act = (long) AO_load(&var->counter);
+ } while (act == exp);
+ return act;
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_xchg(ethr_native_atomic_t *var, long new)
+{
+ while (1) {
+ AO_t exp = AO_load(&var->counter);
+ if (AO_compare_and_swap(&var->counter, exp, (AO_t) new))
+ return (long) exp;
+ }
+}
+
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+#ifdef AO_HAVE_load_acquire
+ return (long) AO_load_acquire(&var->counter);
+#else
+ long res = ethr_native_atomic_read(var);
+ ETHR_MEMORY_BARRIER;
+ return res;
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return_acqb(ethr_native_atomic_t *var)
+{
+#ifdef AO_HAVE_fetch_and_add1_acquire
+ return ((long) AO_fetch_and_add1_acquire(&var->counter)) + 1;
+#else
+ long res = ethr_native_atomic_add_return(var, 1);
+ ETHR_MEMORY_BARRIER;
+ return res;
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long value)
+{
+#ifdef AO_HAVE_store_release
+ AO_store_release(&var->counter, (AO_t) value);
+#else
+ ETHR_MEMORY_BARRIER;
+ ethr_native_atomic_set(var, value);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
+{
+#ifdef AO_HAVE_fetch_and_sub1_release
+ return ((long) AO_fetch_and_sub1_release(&var->counter)) - 1;
+#else
+ ETHR_MEMORY_BARRIER;
+ return ethr_native_atomic_dec_return(var);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
+{
+ (void) ethr_native_atomic_dec_return_relb(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_acqb(ethr_native_atomic_t *var, long new, long exp)
+{
+#ifdef AO_HAVE_compare_and_swap_acquire
+ long act;
+ do {
+ if (AO_compare_and_swap_acquire(&var->counter, (AO_t) exp, (AO_t) new))
+ return exp;
+ act = (long) AO_load(&var->counter);
+ } while (act == exp);
+ AO_nop_full();
+ return act;
+#else
+ long act = ethr_native_atomic_cmpxchg(var, new, exp);
+ ETHR_MEMORY_BARRIER;
+ return act;
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_relb(ethr_native_atomic_t *var, long new, long exp)
+{
+#ifdef AO_HAVE_compare_and_swap_release
+ long act;
+ do {
+ if (AO_compare_and_swap_release(&var->counter, (AO_t) exp, (AO_t) new))
+ return exp;
+ act = (long) AO_load(&var->counter);
+ } while (act == exp);
+ return act;
+#else
+ ETHR_MEMORY_BARRIER;
+ return ethr_native_atomic_cmpxchg(var, new, exp);
+#endif
+}
+
+
+#endif
+
+#endif
+
+#endif
diff --git a/erts/include/internal/libatomic_ops/ethread.h b/erts/include/internal/libatomic_ops/ethread.h
new file mode 100644
index 0000000000..ee73ba73bc
--- /dev/null
+++ b/erts/include/internal/libatomic_ops/ethread.h
@@ -0,0 +1,30 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Native atomics ethread support using libatomic_ops
+ * Author: Rickard Green
+ */
+
+#ifndef ETHREAD_LIBATOMIC_OPS_H__
+#define ETHREAD_LIBATOMIC_OPS_H__
+
+#include "ethr_atomic.h"
+
+#endif
diff --git a/erts/include/internal/ppc32/atomic.h b/erts/include/internal/ppc32/atomic.h
index 105d874995..f21f7c9588 100644
--- a/erts/include/internal/ppc32/atomic.h
+++ b/erts/include/internal/ppc32/atomic.h
@@ -34,7 +34,7 @@ typedef struct {
#define ETHR_MEMORY_BARRIER __asm__ __volatile__("sync" : : : "memory")
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_atomic_init(ethr_native_atomic_t *var, int i)
@@ -205,6 +205,26 @@ ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, int new, int expected)
return old;
}
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_read(var);
+ ETHR_MEMORY_BARRIER;
+ return res;
+}
+
+#define ethr_native_atomic_set_relb ethr_native_atomic_xchg
+#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
+#define ethr_native_atomic_dec_relb ethr_native_atomic_dec_return
+#define ethr_native_atomic_dec_return_relb ethr_native_atomic_dec_return
+
+#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
+#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
+
#endif /* ETHR_TRY_INLINE_FUNCS */
#endif /* ETHREAD_PPC_ATOMIC_H */
diff --git a/erts/include/internal/ppc32/ethread.h b/erts/include/internal/ppc32/ethread.h
index d2a72c3dc1..12efc1b653 100644
--- a/erts/include/internal/ppc32/ethread.h
+++ b/erts/include/internal/ppc32/ethread.h
@@ -29,6 +29,7 @@
#include "rwlock.h"
#define ETHR_HAVE_NATIVE_ATOMICS 1
-#define ETHR_HAVE_NATIVE_LOCKS 1
+#define ETHR_HAVE_NATIVE_SPINLOCKS 1
+#define ETHR_HAVE_NATIVE_RWSPINLOCKS 1
#endif /* ETHREAD_PPC32_ETHREAD_H */
diff --git a/erts/include/internal/ppc32/rwlock.h b/erts/include/internal/ppc32/rwlock.h
index 9bdab12826..19ec26ab68 100644
--- a/erts/include/internal/ppc32/rwlock.h
+++ b/erts/include/internal/ppc32/rwlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -34,7 +34,7 @@ typedef struct {
volatile int lock;
} ethr_native_rwlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_rwlock_init(ethr_native_rwlock_t *lock)
diff --git a/erts/include/internal/ppc32/spinlock.h b/erts/include/internal/ppc32/spinlock.h
index 034c20c143..c8460a3e8a 100644
--- a/erts/include/internal/ppc32/spinlock.h
+++ b/erts/include/internal/ppc32/spinlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -34,7 +34,7 @@ typedef struct {
volatile unsigned int lock;
} ethr_native_spinlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
diff --git a/erts/include/internal/pthread/ethr_event.h b/erts/include/internal/pthread/ethr_event.h
new file mode 100644
index 0000000000..104ec287e0
--- /dev/null
+++ b/erts/include/internal/pthread/ethr_event.h
@@ -0,0 +1,151 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Author: Rickard Green
+ */
+
+#if defined(ETHR_HAVE_LINUX_FUTEX) && defined(ETHR_HAVE_NATIVE_ATOMICS)
+/* --- Linux futex implementation of ethread events ------------------------- */
+#define ETHR_LINUX_FUTEX_IMPL__
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/futex.h>
+#include <sys/time.h>
+
+/*
+ * Note: Linux futexes operate on 32-bit integers, but
+ * ethr_native_atomic_t are 64-bits on 64-bit
+ * platforms. This has to be taken into account.
+ * Therefore, in each individual value used each
+ * byte look the same.
+ */
+
+#if ETHR_SIZEOF_PTR == 8
+
+#define ETHR_EVENT_OFF_WAITER__ 0xffffffffffffffffL
+#define ETHR_EVENT_OFF__ 0x7777777777777777L
+#define ETHR_EVENT_ON__ 0L
+
+#elif ETHR_SIZEOF_PTR == 4
+
+#define ETHR_EVENT_OFF_WAITER__ 0xffffffffL
+#define ETHR_EVENT_OFF__ 0x77777777L
+#define ETHR_EVENT_ON__ 0L
+
+#else
+
+#error ehrm...
+
+#endif
+
+#if defined(FUTEX_WAIT_PRIVATE) && defined(FUTEX_WAKE_PRIVATE)
+# define ETHR_FUTEX_WAIT__ FUTEX_WAIT_PRIVATE
+# define ETHR_FUTEX_WAKE__ FUTEX_WAKE_PRIVATE
+#else
+# define ETHR_FUTEX_WAIT__ FUTEX_WAIT
+# define ETHR_FUTEX_WAKE__ FUTEX_WAKE
+#endif
+
+typedef struct {
+ ethr_atomic_t futex;
+} ethr_event;
+
+#define ETHR_FUTEX__(FTX, OP, VAL) \
+ (-1 == syscall(__NR_futex, (void *) (FTX), (OP), (int) (VAL), NULL, NULL, 0)\
+ ? errno : 0)
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__)
+
+static void ETHR_INLINE
+ETHR_INLINE_FUNC_NAME_(ethr_event_set)(ethr_event *e)
+{
+ long val;
+ ETHR_WRITE_MEMORY_BARRIER;
+ val = ethr_atomic_xchg(&e->futex, ETHR_EVENT_ON__);
+ if (val == ETHR_EVENT_OFF_WAITER__) {
+ int res = ETHR_FUTEX__(&e->futex, ETHR_FUTEX_WAKE__, 1);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+}
+
+static void ETHR_INLINE
+ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e)
+{
+ ethr_atomic_set(&e->futex, ETHR_EVENT_OFF__);
+ ETHR_MEMORY_BARRIER;
+}
+
+#endif
+
+#elif defined(ETHR_PTHREADS)
+/* --- Posix mutex/cond implementation of events ---------------------------- */
+
+typedef struct {
+ ethr_atomic_t state;
+ pthread_mutex_t mtx;
+ pthread_cond_t cnd;
+} ethr_event;
+
+#define ETHR_EVENT_OFF_WAITER__ -1L
+#define ETHR_EVENT_OFF__ 1L
+#define ETHR_EVENT_ON__ 0L
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__)
+
+static void ETHR_INLINE
+ETHR_INLINE_FUNC_NAME_(ethr_event_set)(ethr_event *e)
+{
+ long val;
+ ETHR_WRITE_MEMORY_BARRIER;
+ val = ethr_atomic_xchg(&e->state, ETHR_EVENT_ON__);
+ if (val == ETHR_EVENT_OFF_WAITER__) {
+ int res = pthread_mutex_lock(&e->mtx);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ res = pthread_cond_signal(&e->cnd);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ res = pthread_mutex_unlock(&e->mtx);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+}
+
+static void ETHR_INLINE
+ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e)
+{
+ ethr_atomic_set(&e->state, ETHR_EVENT_OFF__);
+ ETHR_MEMORY_BARRIER;
+}
+
+#endif
+
+#endif
+
+int ethr_event_init(ethr_event *e);
+int ethr_event_destroy(ethr_event *e);
+int ethr_event_wait(ethr_event *e);
+int ethr_event_swait(ethr_event *e, int spincount);
+#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__)
+void ethr_event_set(ethr_event *e);
+void ethr_event_reset(ethr_event *e);
+#endif
diff --git a/erts/include/internal/sparc32/atomic.h b/erts/include/internal/sparc32/atomic.h
index 8fde449a52..2a995d4465 100644
--- a/erts/include/internal/sparc32/atomic.h
+++ b/erts/include/internal/sparc32/atomic.h
@@ -32,7 +32,7 @@ typedef struct {
__asm__ __volatile__("membar #LoadLoad|#LoadStore|#StoreLoad|#StoreStore\n" \
: : : "memory")
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
#if defined(__arch64__)
#define CASX "casx"
@@ -172,6 +172,43 @@ ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long old)
return new;
}
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_read(var);
+ __asm__ __volatile__("membar #StoreLoad|#StoreStore");
+ return res;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long i)
+{
+ __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ ethr_native_atomic_set(var, i);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
+{
+ __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ ethr_native_atomic_dec(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
+{
+ __asm__ __volatile__("membar #LoadStore|#StoreStore");
+ return ethr_native_atomic_dec_return(var);
+}
+
+#define ethr_native_atomic_inc_return_acqb ethr_native_atomic_inc_return
+#define ethr_native_atomic_cmpxchg_acqb ethr_native_atomic_cmpxchg
+#define ethr_native_atomic_cmpxchg_relb ethr_native_atomic_cmpxchg
+
#endif /* ETHR_TRY_INLINE_FUNCS */
#endif /* ETHR_SPARC32_ATOMIC_H */
diff --git a/erts/include/internal/sparc32/ethread.h b/erts/include/internal/sparc32/ethread.h
index 1d55399640..dca113b4d6 100644
--- a/erts/include/internal/sparc32/ethread.h
+++ b/erts/include/internal/sparc32/ethread.h
@@ -29,6 +29,7 @@
#include "rwlock.h"
#define ETHR_HAVE_NATIVE_ATOMICS 1
-#define ETHR_HAVE_NATIVE_LOCKS 1
+#define ETHR_HAVE_NATIVE_SPINLOCKS 1
+#define ETHR_HAVE_NATIVE_RWSPINLOCKS 1
#endif /* ETHREAD_SPARC32_ETHREAD_H */
diff --git a/erts/include/internal/sparc32/rwlock.h b/erts/include/internal/sparc32/rwlock.h
index 12448e0b06..465ec96866 100644
--- a/erts/include/internal/sparc32/rwlock.h
+++ b/erts/include/internal/sparc32/rwlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -29,7 +29,7 @@ typedef struct {
volatile int lock;
} ethr_native_rwlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_rwlock_init(ethr_native_rwlock_t *lock)
diff --git a/erts/include/internal/sparc32/spinlock.h b/erts/include/internal/sparc32/spinlock.h
index b4fe48b714..493d514210 100644
--- a/erts/include/internal/sparc32/spinlock.h
+++ b/erts/include/internal/sparc32/spinlock.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -29,7 +29,7 @@ typedef struct {
volatile unsigned char lock;
} ethr_native_spinlock_t;
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
diff --git a/erts/include/internal/tile/atomic.h b/erts/include/internal/tile/atomic.h
index 5e4c7ac9fe..69569d82d1 100644
--- a/erts/include/internal/tile/atomic.h
+++ b/erts/include/internal/tile/atomic.h
@@ -34,7 +34,7 @@ typedef struct {
#define ETHR_MEMORY_BARRIER __insn_mf()
-#ifdef ETHR_TRY_INLINE_FUNCS
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
static ETHR_INLINE void
ethr_native_atomic_init(ethr_native_atomic_t *var, long i)
@@ -45,7 +45,6 @@ ethr_native_atomic_init(ethr_native_atomic_t *var, long i)
static ETHR_INLINE void
ethr_native_atomic_set(ethr_native_atomic_t *var, long i)
{
- __insn_mf();
atomic_exchange_acq(&var->counter, i);
}
@@ -58,28 +57,24 @@ ethr_native_atomic_read(ethr_native_atomic_t *var)
static ETHR_INLINE void
ethr_native_atomic_add(ethr_native_atomic_t *var, long incr)
{
- __insn_mf();
atomic_add(&var->counter, incr);
}
static ETHR_INLINE void
ethr_native_atomic_inc(ethr_native_atomic_t *var)
{
- __insn_mf();
atomic_increment(&var->counter);
}
static ETHR_INLINE void
ethr_native_atomic_dec(ethr_native_atomic_t *var)
{
- __insn_mf();
atomic_decrement(&var->counter);
}
static ETHR_INLINE long
ethr_native_atomic_add_return(ethr_native_atomic_t *var, long incr)
{
- __insn_mf();
return atomic_exchange_and_add(&var->counter, incr) + incr;
}
@@ -98,33 +93,81 @@ ethr_native_atomic_dec_return(ethr_native_atomic_t *var)
static ETHR_INLINE long
ethr_native_atomic_and_retold(ethr_native_atomic_t *var, long mask)
{
- /* Implement a barrier suitable for a mutex unlock. */
- __insn_mf();
return atomic_and_val(&var->counter, mask);
}
static ETHR_INLINE long
ethr_native_atomic_or_retold(ethr_native_atomic_t *var, long mask)
{
- __insn_mf();
return atomic_or_val(&var->counter, mask);
}
static ETHR_INLINE long
ethr_native_atomic_xchg(ethr_native_atomic_t *var, long val)
{
- __insn_mf();
return atomic_exchange_acq(&var->counter, val);
}
static ETHR_INLINE long
ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long expected)
{
- /* Implement a barrier suitable for a mutex unlock. */
- __insn_mf();
return atomic_compare_and_exchange_val_acq(&var->counter, new, expected);
}
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_read(var);
+ ETHR_MEMORY_BARRIER;
+ return res;
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return_acqb(ethr_native_atomic_t *var)
+{
+ long res = ethr_native_atomic_inc_return(var);
+ ETHR_MEMORY_BARRIER;
+ return res;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long val)
+{
+ ETHR_MEMORY_BARRIER;
+ ethr_native_atomic_set(var, val);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
+{
+ ETHR_MEMORY_BARRIER;
+ ethr_native_atomic_dec(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
+{
+ ETHR_MEMORY_BARRIER;
+ return ethr_native_atomic_dec_return(var);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_acqb(ethr_native_atomic_t *var, long new, long exp)
+{
+ return ethr_native_atomic_cmpxchg(var, new, exp);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_relb(ethr_native_atomic_t *var, long new, long exp)
+{
+ ETHR_MEMORY_BARRIER;
+ return ethr_native_atomic_cmpxchg(var, new, exp);
+}
+
#endif /* ETHR_TRY_INLINE_FUNCS */
#endif /* ETHREAD_TILE_ATOMIC_H */
diff --git a/erts/include/internal/win/ethr_atomic.h b/erts/include/internal/win/ethr_atomic.h
new file mode 100644
index 0000000000..500459dd6c
--- /dev/null
+++ b/erts/include/internal/win/ethr_atomic.h
@@ -0,0 +1,244 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Native atomics ethread support when using VC++
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_WIN_ATOMIC_H__
+#define ETHR_WIN_ATOMIC_H__
+
+#ifdef _MSC_VER
+# if _MSC_VER < 1300
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0 /* Dont trust really old compilers */
+# else
+# if defined(_M_IX86)
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
+# else /* I.e. IA64 */
+# if _MSC_VER >= 1400
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
+# else
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0
+# endif
+# endif
+# endif
+# if _MSC_VER >= 1400
+# include <intrin.h>
+# undef ETHR_COMPILER_BARRIER
+# define ETHR_COMPILER_BARRIER _ReadWriteBarrier()
+# endif
+#pragma intrinsic(_ReadWriteBarrier)
+#pragma intrinsic(_InterlockedAnd)
+#pragma intrinsic(_InterlockedOr)
+#else
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0
+#endif
+
+/*
+ * No configure test checking for _Interlocked*_{acq,rel} and
+ * Interlocked*{Acquire,Release} have been written yet...
+ *
+ * Note, that these are pure optimizations for the itanium
+ * processor.
+ */
+
+#ifdef ETHR_HAVE_INTERLOCKEDCOMPAREEXCHANGE_ACQ
+#pragma intrinsic(_InterlockedCompareExchange_acq)
+#endif
+#ifdef ETHR_HAVE_INTERLOCKEDCOMPAREEXCHANGE_REL
+#pragma intrinsic(_InterlockedCompareExchange_rel)
+#endif
+
+
+typedef struct {
+ volatile LONG value;
+} ethr_native_atomic_t;
+
+#define ETHR_MEMORY_BARRIER \
+do { \
+ volatile LONG x___ = 0; \
+ _InterlockedCompareExchange(&x___, (LONG) 1, (LONG) 0); \
+} while (0)
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+static ETHR_INLINE void
+ethr_native_atomic_init(ethr_native_atomic_t *var, long i)
+{
+ var->value = (LONG) i;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set(ethr_native_atomic_t *var, long i)
+{
+#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+ var->value = (LONG) i;
+#else
+ (void) InterlockedExchange(&var->value, (LONG) i);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_read(ethr_native_atomic_t *var)
+{
+#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+ return var->value;
+#else
+ return InterlockedExchangeAdd(&var->value, (LONG) 0);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_add(ethr_native_atomic_t *var, long incr)
+{
+ (void) InterlockedExchangeAdd(&var->value, (LONG) incr);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_add_return(ethr_native_atomic_t *var, long i)
+{
+ LONG tmp = InterlockedExchangeAdd(&var->value, (LONG) i);
+ return tmp + i;
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_inc(ethr_native_atomic_t *var)
+{
+ (void) InterlockedIncrement(&var->value);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec(ethr_native_atomic_t *var)
+{
+ (void) InterlockedDecrement(&var->value);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return(ethr_native_atomic_t *var)
+{
+ return (long) InterlockedIncrement(&var->value);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return(ethr_native_atomic_t *var)
+{
+ return (long) InterlockedDecrement(&var->value);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_and_retold(ethr_native_atomic_t *var, long mask)
+{
+ return (long) _InterlockedAnd(&var->value, mask);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_or_retold(ethr_native_atomic_t *var, long mask)
+{
+ return (long) _InterlockedOr(&var->value, mask);
+}
+
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long old)
+{
+ return (long) _InterlockedCompareExchange(&var->value, (LONG) new, (LONG) old);
+}
+
+
+static ETHR_INLINE long
+ethr_native_atomic_xchg(ethr_native_atomic_t *var, long new)
+{
+ return (long) InterlockedExchange(&var->value, (LONG) new);
+}
+
+/*
+ * Atomic ops with at least specified barriers.
+ */
+
+static ETHR_INLINE long
+ethr_native_atomic_read_acqb(ethr_native_atomic_t *var)
+{
+#ifdef ETHR_HAVE_INTERLOCKEDEXCHANGEADDACQUIRE
+ return (long) InterlockedExchangeAddAcquire(&var->value, (LONG) 0);
+#else
+ return (long) InterlockedExchangeAdd(&var->value, (LONG) 0);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return_acqb(ethr_native_atomic_t *var)
+{
+#ifdef ETHR_HAVE_INTERLOCKEDINCREMENTACQUIRE
+ return (long) InterlockedIncrementAcquire(&var->value);
+#else
+ return (long) InterlockedIncrement(&var->value);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_set_relb(ethr_native_atomic_t *var, long i)
+{
+ (void) InterlockedExchange(&var->value, (LONG) i);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec_relb(ethr_native_atomic_t *var)
+{
+#ifdef ETHR_HAVE_INTERLOCKEDDECREMENTRELEASE
+ (void) InterlockedDecrementRelease(&var->value);
+#else
+ (void) InterlockedDecrement(&var->value);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return_relb(ethr_native_atomic_t *var)
+{
+#ifdef ETHR_HAVE_INTERLOCKEDDECREMENTRELEASE
+ return (long) InterlockedDecrementRelease(&var->value);
+#else
+ return (long) InterlockedDecrement(&var->value);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_acqb(ethr_native_atomic_t *var, long new, long old)
+{
+#ifdef ETHR_HAVE_INTERLOCKEDCOMPAREEXCHANGE_ACQ
+ return (long) _InterlockedCompareExchange_acq(&var->value, (LONG) new, (LONG) old);
+#else
+ return (long) _InterlockedCompareExchange(&var->value, (LONG) new, (LONG) old);
+#endif
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg_relb(ethr_native_atomic_t *var, long new, long old)
+{
+
+#ifdef ETHR_HAVE_INTERLOCKEDCOMPAREEXCHANGE_REL
+ return (long) _InterlockedCompareExchange_rel(&var->value, (LONG) new, (LONG) old);
+#else
+ return (long) _InterlockedCompareExchange(&var->value, (LONG) new, (LONG) old);
+#endif
+}
+
+#endif
+
+#endif
diff --git a/erts/include/internal/win/ethr_event.h b/erts/include/internal/win/ethr_event.h
new file mode 100644
index 0000000000..af57c20f91
--- /dev/null
+++ b/erts/include/internal/win/ethr_event.h
@@ -0,0 +1,62 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Author: Rickard Green
+ */
+
+#define ETHR_EVENT_OFF_WAITER__ ((LONG) -1)
+#define ETHR_EVENT_OFF__ ((LONG) 1)
+#define ETHR_EVENT_ON__ ((LONG) 0)
+
+typedef struct {
+ volatile LONG state;
+ HANDLE handle;
+} ethr_event;
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__)
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_event_set)(ethr_event *e)
+{
+ /* InterlockedExchange() imply a full memory barrier which is important */
+ LONG state = InterlockedExchange(&e->state, ETHR_EVENT_ON__);
+ if (state == ETHR_EVENT_OFF_WAITER__) {
+ if (!SetEvent(e->handle))
+ ETHR_FATAL_ERROR__(ethr_win_get_errno__());
+ }
+}
+
+static ETHR_INLINE void
+ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e)
+{
+ /* InterlockedExchange() imply a full memory barrier which is important */
+ InterlockedExchange(&e->state, ETHR_EVENT_OFF__);
+}
+
+#endif
+
+int ethr_event_init(ethr_event *e);
+int ethr_event_destroy(ethr_event *e);
+int ethr_event_wait(ethr_event *e);
+int ethr_event_swait(ethr_event *e, int spincount);
+#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__)
+void ethr_event_set(ethr_event *e);
+void ethr_event_reset(ethr_event *e);
+#endif
diff --git a/erts/include/internal/win/ethread.h b/erts/include/internal/win/ethread.h
new file mode 100644
index 0000000000..b52710f6a3
--- /dev/null
+++ b/erts/include/internal/win/ethread.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Native atomic and spinlock ethread support when using VC++
+ * Author: Rickard Green
+ */
+
+#ifndef ETHREAD_WIN_H__
+#define ETHREAD_WIN_H__
+
+#include "ethr_atomic.h"
+#define ETHR_HAVE_NATIVE_ATOMICS 1
+
+#endif
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index e7caac8072..0d3181cace 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -280,8 +280,13 @@ endif
#
# ethread library
#
+ETHR_THR_LIB_BASE_DIR=@ETHR_THR_LIB_BASE_DIR@
ifneq ($(strip $(ETHR_LIB_NAME)),)
-ETHREAD_LIB_SRC=common/ethread.c
+ETHREAD_LIB_SRC=common/ethr_aux.c \
+ common/ethr_mutex.c \
+ common/ethr_cbf.c \
+ $(ETHR_THR_LIB_BASE_DIR)/ethread.c \
+ $(ETHR_THR_LIB_BASE_DIR)/ethr_event.c
ETHREAD_LIB_NAME=ethread$(TYPE_SUFFIX)
ifeq ($(USING_VC),yes)
@@ -379,13 +384,13 @@ $(ERTS_LIB): $(ERTS_LIB_OBJS)
$(r_OBJ_DIR)/%.o: common/%.c
$(CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
-$(r_OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(r_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(THR_DEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(OBJ_DIR)/%.o: common/%.c
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
-$(OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
# Win32 specific
@@ -393,25 +398,25 @@ $(OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
$(MD_OBJ_DIR)/%.o: common/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
-$(MD_OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(MD_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MD $(INCLUDES) -c $< -o $@
$(MDd_OBJ_DIR)/%.o: common/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
-$(MDd_OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(MDd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MDd $(INCLUDES) -c $< -o $@
$(MT_OBJ_DIR)/%.o: common/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
-$(MT_OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(MT_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MT $(INCLUDES) -c $< -o $@
$(MTd_OBJ_DIR)/%.o: common/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
-$(MTd_OBJ_DIR)/%.o: $(ERLANG_OSTYPE)/%.c
+$(MTd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c
$(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@
#
@@ -438,6 +443,8 @@ RELEASE_LIBS=$(ERTS_LIBS)
INTERNAL_RELEASE_INCLUDES= \
$(ERTS_INCL_INT)/README \
$(ERTS_INCL_INT)/ethread.h \
+ $(ERTS_INCL_INT)/ethr_mutex.h \
+ $(ERTS_INCL_INT)/ethr_optimized_fallbacks.h \
$(ERTS_INCL_INT)/$(TARGET)/ethread.mk \
$(ERTS_INCL_INT)/$(TARGET)/erts_internal.mk \
$(ERTS_INCL_INT)/$(TARGET)/ethread_header_config.h \
@@ -447,7 +454,8 @@ INTERNAL_RELEASE_INCLUDES= \
$(ERTS_INCL_INT)/erl_misc_utils.h \
$(ERTS_INCL_INT)/erl_errno.h
-INTERNAL_X_RELEASE_INCLUDE_DIRS= i386 x86_64 ppc32 sparc32 sparc64 tile gcc
+INTERNAL_X_RELEASE_INCLUDE_DIRS= \
+ i386 x86_64 ppc32 sparc32 sparc64 tile gcc pthread win libatomic_ops
INTERNAL_RELEASE_LIBS= \
../lib/internal/README \
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c
index f70db86960..116c9886d8 100644
--- a/erts/lib_src/common/erl_misc_utils.c
+++ b/erts/lib_src/common/erl_misc_utils.c
@@ -21,10 +21,13 @@
#include "config.h"
#endif
+#if defined(__WIN32__)
+# include <windows.h>
+#endif
+
#include "erl_misc_utils.h"
#if defined(__WIN32__)
-# include <windows.h>
#elif defined(VXWORKS)
# include <selectLib.h>
#else /* UNIX */
@@ -59,8 +62,25 @@
# endif
#endif
-#ifdef HAVE_SCHED_xETAFFINITY
+#if defined(HAVE_SCHED_xETAFFINITY)
# include <sched.h>
+# define ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__
+#define ERTS_MU_GET_PROC_AFFINITY__(CPUINFOP, CPUSET) \
+ (sched_getaffinity((CPUINFOP)->pid, \
+ sizeof(cpu_set_t), \
+ (CPUSET)) != 0 ? -errno : 0)
+#define ERTS_MU_SET_THR_AFFINITY__(SETP) \
+ (sched_setaffinity(0, sizeof(cpu_set_t), (SETP)) != 0 ? -errno : 0)
+#elif defined(__WIN32__)
+# define ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__
+# define cpu_set_t DWORD
+# define CPU_SETSIZE (sizeof(DWORD)*8)
+# define CPU_ZERO(SETP) (*(SETP) = (DWORD) 0)
+# define CPU_SET(CPU, SETP) (*(SETP) |= (((DWORD) 1) << (CPU)))
+# define CPU_CLR(CPU, SETP) (*(SETP) &= ~(((DWORD) 1) << (CPU)))
+# define CPU_ISSET(CPU, SETP) ((*(SETP) & (((DWORD) 1) << (CPU))) != (DWORD) 0)
+#define ERTS_MU_GET_PROC_AFFINITY__ get_proc_affinity
+#define ERTS_MU_SET_THR_AFFINITY__ set_thr_affinity
#endif
#ifdef HAVE_PSET_INFO
# include <sys/pset.h>
@@ -82,6 +102,26 @@
static int read_topology(erts_cpu_info_t *cpuinfo);
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
+static int
+cpu_sets_are_eq(cpu_set_t *x, cpu_set_t *y)
+{
+ int i;
+ for (i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, x)) {
+ if (!CPU_ISSET(i, y))
+ return 0;
+ }
+ else {
+ if (CPU_ISSET(i, y))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif
+
int
erts_milli_sleep(long ms)
{
@@ -105,30 +145,66 @@ struct erts_cpu_info_t_ {
int available;
int topology_size;
erts_cpu_topology_t *topology;
-#if defined(HAVE_SCHED_xETAFFINITY)
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
char *affinity_str;
char affinity_str_buf[CPU_SETSIZE/4+2];
cpu_set_t cpuset;
+#if defined(HAVE_SCHED_xETAFFINITY)
pid_t pid;
+#endif
#elif defined(HAVE_PSET_INFO)
processorid_t *cpuids;
#endif
};
+#if defined(__WIN32__)
+
+static __forceinline int
+get_proc_affinity(erts_cpu_info_t *cpuinfo, cpu_set_t *cpuset)
+{
+ DWORD pamask, samask;
+ if (GetProcessAffinityMask(GetCurrentProcess(), &pamask, &samask)) {
+ *cpuset = (cpu_set_t) pamask;
+ return 0;
+ }
+ else {
+ *cpuset = (cpu_set_t) 0;
+ return -erts_get_last_win_errno();
+ }
+}
+
+static __forceinline int
+set_thr_affinity(cpu_set_t *set)
+{
+ if (*set == (cpu_set_t) 0)
+ return -ENOTSUP;
+ if (SetThreadAffinityMask(GetCurrentThread(), *set) == 0)
+ return -erts_get_last_win_errno();
+ else
+ return 0;
+}
+
+#endif
+
erts_cpu_info_t *
erts_cpu_info_create(void)
{
erts_cpu_info_t *cpuinfo = malloc(sizeof(erts_cpu_info_t));
if (!cpuinfo)
return NULL;
-#if defined(HAVE_SCHED_xETAFFINITY)
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
cpuinfo->affinity_str = NULL;
+#if defined(HAVE_SCHED_xETAFFINITY)
cpuinfo->pid = getpid();
+#endif
#elif defined(HAVE_PSET_INFO)
cpuinfo->cpuids = NULL;
#endif
cpuinfo->topology_size = 0;
cpuinfo->topology = NULL;
+ cpuinfo->configured = -1;
+ cpuinfo->online = -1;
+ cpuinfo->available = -1;
erts_cpu_info_update(cpuinfo);
return cpuinfo;
}
@@ -153,31 +229,40 @@ erts_cpu_info_destroy(erts_cpu_info_t *cpuinfo)
}
}
-void
+int
erts_cpu_info_update(erts_cpu_info_t *cpuinfo)
{
- cpuinfo->configured = 0;
- cpuinfo->online = 0;
- cpuinfo->available = 0;
+ int changed = 0;
+ int configured = 0;
+ int online = 0;
+ int available = 0;
+ erts_cpu_topology_t *old_topology;
+ int old_topology_size;
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
+ cpu_set_t cpuset;
+#endif
#ifdef __WIN32__
{
+ int i;
SYSTEM_INFO sys_info;
GetSystemInfo(&sys_info);
- cpuinfo->configured = (int) sys_info.dwNumberOfProcessors;
-
+ configured = (int) sys_info.dwNumberOfProcessors;
+ for (i = 0; i < sizeof(DWORD)*8; i++)
+ if (sys_info.dwActiveProcessorMask & (((DWORD) 1) << i))
+ online++;
}
#elif !defined(NO_SYSCONF) && (defined(_SC_NPROCESSORS_CONF) \
|| defined(_SC_NPROCESSORS_ONLN))
#ifdef _SC_NPROCESSORS_CONF
- cpuinfo->configured = (int) sysconf(_SC_NPROCESSORS_CONF);
- if (cpuinfo->configured < 0)
- cpuinfo->configured = 0;
+ configured = (int) sysconf(_SC_NPROCESSORS_CONF);
+ if (configured < 0)
+ configured = 0;
#endif
#ifdef _SC_NPROCESSORS_ONLN
- cpuinfo->online = (int) sysconf(_SC_NPROCESSORS_ONLN);
- if (cpuinfo->online < 0)
- cpuinfo->online = 0;
+ online = (int) sysconf(_SC_NPROCESSORS_ONLN);
+ if (online < 0)
+ online = 0;
#endif
#elif defined(HAVE_SYS_SYSCTL_H) && defined(CTL_HW) && (defined(HW_NCPU) \
|| defined(HW_AVAILCPU))
@@ -189,71 +274,138 @@ erts_cpu_info_update(erts_cpu_info_t *cpuinfo)
len = sizeof(int);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
- if (sysctl(&mib[0], 2, &cpuinfo->configured, &len, NULL, 0) < 0)
- cpuinfo->configured = 0;
+ if (sysctl(&mib[0], 2, &configured, &len, NULL, 0) < 0)
+ configured = 0;
#endif
#ifdef HW_AVAILCPU
len = sizeof(int);
mib[0] = CTL_HW;
mib[1] = HW_AVAILCPU;
- if (sysctl(&mib[0], 2, &cpuinfo->online, &len, NULL, 0) < 0)
- cpuinfo->online = 0;
+ if (sysctl(&mib[0], 2, &online, &len, NULL, 0) < 0)
+ online = 0;
#endif
}
#endif
- if (cpuinfo->online > cpuinfo->configured)
- cpuinfo->online = cpuinfo->configured;
+ if (online > configured)
+ online = configured;
-#ifdef HAVE_SCHED_xETAFFINITY
- if (sched_getaffinity(cpuinfo->pid, sizeof(cpu_set_t), &cpuinfo->cpuset) == 0) {
- int i, c, cn, si;
- c = cn = 0;
- si = sizeof(cpuinfo->affinity_str_buf) - 1;
- cpuinfo->affinity_str_buf[si] = '\0';
- for (i = 0; i < CPU_SETSIZE; i++) {
- if (CPU_ISSET(i, &cpuinfo->cpuset)) {
- c |= 1 << cn;
- cpuinfo->available++;
+ if (cpuinfo->configured != configured)
+ changed = 1;
+ if (cpuinfo->online != online)
+ changed = 1;
+
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
+ if (ERTS_MU_GET_PROC_AFFINITY__(cpuinfo, &cpuset) == 0) {
+ if (!changed && !cpu_sets_are_eq(&cpuset, &cpuinfo->cpuset))
+ changed = 1;
+
+ if (!changed)
+ available = cpuinfo->available;
+ else {
+ int i, c, cn, si;
+
+ memcpy((void *) &cpuinfo->cpuset,
+ (void *) &cpuset,
+ sizeof(cpu_set_t));
+
+ c = cn = 0;
+ si = sizeof(cpuinfo->affinity_str_buf) - 1;
+ cpuinfo->affinity_str_buf[si] = '\0';
+ for (i = 0; i < CPU_SETSIZE; i++) {
+ if (CPU_ISSET(i, &cpuinfo->cpuset)) {
+ c |= 1 << cn;
+ available++;
+ }
+ cn++;
+ if (cn == 4) {
+ cpuinfo->affinity_str_buf[--si] = (c < 10
+ ? '0' + c
+ : 'A' + c - 10);
+ c = cn = 0;
+ }
}
- cn++;
- if (cn == 4) {
+ if (c)
cpuinfo->affinity_str_buf[--si] = (c < 10
? '0' + c
: 'A' + c - 10);
- c = cn = 0;
- }
+ while (cpuinfo->affinity_str_buf[si] == '0')
+ si++;
+ cpuinfo->affinity_str = &cpuinfo->affinity_str_buf[si];
}
- if (c)
- cpuinfo->affinity_str_buf[--si] = (c < 10
- ? '0' + c
- : 'A' + c - 10);
- while (cpuinfo->affinity_str_buf[si] == '0')
- si++;
- cpuinfo->affinity_str = &cpuinfo->affinity_str_buf[si];
}
#elif defined(HAVE_PSET_INFO)
{
- uint_t numcpus = cpuinfo->configured;
- if (cpuinfo->cpuids)
- free(cpuinfo->cpuids);
- cpuinfo->cpuids = malloc(sizeof(processorid_t)*numcpus);
- if (cpuinfo->cpuids) {
- if (pset_info(PS_MYID, NULL, &numcpus, &cpuinfo->cpuids) == 0)
- cpuinfo->available = (int) numcpus;
- if (cpuinfo->available < 0) {
- free(cpuinfo->cpuid);
- cpuinfo->available = 0;
+ processorid_t *cpuids;
+ uint_t numcpus = configured;
+ cpuids = malloc(sizeof(processorid_t)*numcpus);
+ if (cpuids) {
+ if (pset_info(PS_MYID, NULL, &numcpus, &cpuids) == 0)
+ available = (int) numcpus;
+ if (available < 0) {
+ free(cpuids);
+ cpuids = NULL;
+ available = 0;
}
}
+ if (!cpuids) {
+ if (cpuinfo->cpuids)
+ changed = 1;
+ }
+ else {
+ if (cpuinfo->cpuids)
+ changed = 1;
+ if (memcmp((void *) cpuinfo->cpuids,
+ (void *) cpuids,
+ sizeof(processorid_t)*numcpus) != 0)
+ changed = 1;
+
+ }
+ if (!changed) {
+ if (cpuids)
+ free(cpuids);
+ }
+ else {
+ if (cpuinfo->cpuids)
+ free(cpuinfo->cpuids);
+ cpuinfo->cpuids = cpuids;
+ }
}
#endif
- if (cpuinfo->available > cpuinfo->online)
- cpuinfo->available = cpuinfo->online;
+ if (available > online)
+ available = online;
+
+ if (cpuinfo->available != available)
+ changed = 1;
+
+ cpuinfo->configured = configured;
+ cpuinfo->online = online;
+ cpuinfo->available = available;
+
+ old_topology = cpuinfo->topology;
+ old_topology_size = cpuinfo->topology_size;
+ cpuinfo->topology = NULL;
read_topology(cpuinfo);
+ if (cpuinfo->topology_size != old_topology_size
+ || (old_topology_size != 0
+ && memcmp((void *) cpuinfo->topology,
+ (void *) old_topology,
+ (sizeof(erts_cpu_topology_t)
+ * old_topology_size)) != 0)) {
+ changed = 1;
+ if (old_topology)
+ free(old_topology);
+ }
+ else {
+ if (cpuinfo->topology)
+ free(cpuinfo->topology);
+ cpuinfo->topology = old_topology;
+ }
+
+ return changed;
}
int
@@ -289,7 +441,7 @@ erts_get_cpu_available(erts_cpu_info_t *cpuinfo)
char *
erts_get_unbind_from_cpu_str(erts_cpu_info_t *cpuinfo)
{
-#if defined(HAVE_SCHED_xETAFFINITY)
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
if (!cpuinfo)
return "false";
return cpuinfo->affinity_str;
@@ -303,7 +455,7 @@ erts_get_available_cpu(erts_cpu_info_t *cpuinfo, int no)
{
if (!cpuinfo || no < 1 || cpuinfo->available < no)
return -EINVAL;
-#ifdef HAVE_SCHED_xETAFFINITY
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
{
cpu_set_t *allowed = &cpuinfo->cpuset;
int ix, n;
@@ -335,8 +487,8 @@ int
erts_is_cpu_available(erts_cpu_info_t *cpuinfo, int id)
{
if (cpuinfo && 0 <= id) {
-#ifdef HAVE_SCHED_xETAFFINITY
- if (id <= CPU_SETSIZE)
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
+ if (id < CPU_SETSIZE)
return CPU_ISSET(id, &cpuinfo->cpuset);
#elif defined(HAVE_PROCESSOR_BIND)
int no;
@@ -388,7 +540,7 @@ erts_bind_to_cpu(erts_cpu_info_t *cpuinfo, int cpu)
*/
if (!cpuinfo)
return -EINVAL;
-#ifdef HAVE_SCHED_xETAFFINITY
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
{
cpu_set_t bind_set;
if (cpu < 0)
@@ -398,9 +550,7 @@ erts_bind_to_cpu(erts_cpu_info_t *cpuinfo, int cpu)
CPU_ZERO(&bind_set);
CPU_SET(cpu, &bind_set);
- if (sched_setaffinity(0, sizeof(cpu_set_t), &bind_set) != 0)
- return -errno;
- return 0;
+ return ERTS_MU_SET_THR_AFFINITY__(&bind_set);
}
#elif defined(HAVE_PROCESSOR_BIND)
if (cpu < 0)
@@ -418,10 +568,8 @@ erts_unbind_from_cpu(erts_cpu_info_t *cpuinfo)
{
if (!cpuinfo)
return -EINVAL;
-#if defined(HAVE_SCHED_xETAFFINITY)
- if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuinfo->cpuset) != 0)
- return -errno;
- return 0;
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
+ return ERTS_MU_SET_THR_AFFINITY__(&cpuinfo->cpuset);
#elif defined(HAVE_PROCESSOR_BIND)
if (processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL) != 0)
return -errno;
@@ -434,7 +582,7 @@ erts_unbind_from_cpu(erts_cpu_info_t *cpuinfo)
int
erts_unbind_from_cpu_str(char *str)
{
-#if defined(HAVE_SCHED_xETAFFINITY)
+#if defined(ERTS_HAVE_MISC_UTIL_AFFINITY_MASK__)
char *c = str;
int cpus = 0;
int shft = 0;
@@ -486,9 +634,7 @@ erts_unbind_from_cpu_str(char *str)
if (!cpus)
return -EINVAL;
- if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) != 0)
- return -errno;
- return 0;
+ return ERTS_MU_SET_THR_AFFINITY__(&cpuset);
#elif defined(HAVE_PROCESSOR_BIND)
if (processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL) != 0)
return -errno;
@@ -541,6 +687,56 @@ cpu_cmp(const void *vx, const void *vy)
return 0;
}
+static void
+adjust_processor_nodes(erts_cpu_info_t *cpuinfo, int no_nodes)
+{
+ erts_cpu_topology_t *prev, *this, *last;
+ if (no_nodes > 1) {
+ int processor = -1;
+ int processor_node = 0;
+ int node = -1;
+
+ qsort(cpuinfo->topology,
+ cpuinfo->topology_size,
+ sizeof(erts_cpu_topology_t),
+ pn_cmp);
+
+ prev = NULL;
+ this = &cpuinfo->topology[0];
+ last = &cpuinfo->topology[cpuinfo->configured-1];
+ while (1) {
+ if (processor == this->processor) {
+ if (node != this->node)
+ processor_node = 1;
+ }
+ else {
+ if (processor_node) {
+ make_processor_node:
+ while (prev->processor == processor) {
+ prev->processor_node = prev->node;
+ prev->node = -1;
+ if (prev == &cpuinfo->topology[0])
+ break;
+ prev--;
+ }
+ processor_node = 0;
+ }
+ processor = this->processor;
+ node = this->node;
+ }
+ if (this == last) {
+ if (processor_node) {
+ prev = this;
+ goto make_processor_node;
+ }
+ break;
+ }
+ prev = this++;
+ }
+ }
+}
+
+
#ifdef __linux__
static int
@@ -594,9 +790,6 @@ read_topology(erts_cpu_info_t *cpuinfo)
errno = 0;
- if (cpuinfo->topology)
- free(cpuinfo->topology);
-
if (cpuinfo->configured < 1)
goto error;
@@ -710,49 +903,7 @@ read_topology(erts_cpu_info_t *cpuinfo)
cpuinfo->topology = t;
}
- if (no_nodes > 1) {
- int processor = -1;
- int processor_node = 0;
- int node = -1;
-
- qsort(cpuinfo->topology,
- cpuinfo->topology_size,
- sizeof(erts_cpu_topology_t),
- pn_cmp);
-
- prev = NULL;
- this = &cpuinfo->topology[0];
- last = &cpuinfo->topology[cpuinfo->configured-1];
- while (1) {
- if (processor == this->processor) {
- if (node != this->node)
- processor_node = 1;
- }
- else {
- if (processor_node) {
- make_processor_node:
- while (prev->processor == processor) {
- prev->processor_node = prev->node;
- prev->node = -1;
- if (prev == &cpuinfo->topology[0])
- break;
- prev--;
- }
- processor_node = 0;
- }
- processor = this->processor;
- node = this->node;
- }
- if (this == last) {
- if (processor_node) {
- prev = this;
- goto make_processor_node;
- }
- break;
- }
- prev = this++;
- }
- }
+ adjust_processor_nodes(cpuinfo, no_nodes);
qsort(cpuinfo->topology,
cpuinfo->topology_size,
@@ -849,9 +1000,6 @@ read_topology(erts_cpu_info_t *cpuinfo)
errno = 0;
- if (cpuinfo->topology)
- free(cpuinfo->topology);
-
if (cpuinfo->configured < 1)
goto error;
@@ -938,6 +1086,8 @@ read_topology(erts_cpu_info_t *cpuinfo)
}
}
+ adjust_processor_nodes(cpuinfo, 1);
+
error:
if (res == 0) {
@@ -956,6 +1106,275 @@ read_topology(erts_cpu_info_t *cpuinfo)
}
+#elif defined(__WIN32__)
+
+/*
+ * We cannot use Relation* out of the box since all of them are not
+ * always part of the LOGICAL_PROCESSOR_RELATIONSHIP enum. They are
+ * however documented as follows...
+ */
+#define ERTS_MU_RELATION_PROCESSOR_CORE 0 /* RelationProcessorCore */
+#define ERTS_MU_RELATION_NUMA_NODE 1 /* RelationNumaNode */
+#define ERTS_MU_RELATION_CACHE 2 /* RelationCache */
+#define ERTS_MU_RELATION_PROCESSOR_PACKAGE 3 /* RelationProcessorPackage */
+
+static __forceinline int
+rel_cmp_val(int r)
+{
+ switch (r) {
+ case ERTS_MU_RELATION_NUMA_NODE: return 0;
+ case ERTS_MU_RELATION_PROCESSOR_PACKAGE: return 1;
+ case ERTS_MU_RELATION_PROCESSOR_CORE: return 2;
+ default: /* currently not used */ return 3;
+ }
+}
+
+static int
+slpi_cmp(const void *vx, const void *vy)
+{
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION x, y;
+ x = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) vx;
+ y = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION) vy;
+
+ if ((int) x->Relationship != (int) y->Relationship)
+ return (rel_cmp_val((int) x->Relationship)
+ - rel_cmp_val((int) y->Relationship));
+
+ switch ((int) x->Relationship) {
+ case ERTS_MU_RELATION_NUMA_NODE:
+ if (x->NumaNode.NodeNumber == y->NumaNode.NodeNumber)
+ break;
+ return ((int) x->NumaNode.NodeNumber) - ((int) y->NumaNode.NodeNumber);
+ case ERTS_MU_RELATION_PROCESSOR_CORE:
+ case ERTS_MU_RELATION_PROCESSOR_PACKAGE:
+ default:
+ break;
+ }
+
+ if (x->ProcessorMask == y->ProcessorMask)
+ return 0;
+ return x->ProcessorMask < y->ProcessorMask ? -1 : 1;
+}
+
+typedef BOOL (WINAPI *glpi_t)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
+
+static int
+read_topology(erts_cpu_info_t *cpuinfo)
+{
+ int res = 0;
+ glpi_t glpi;
+ int *core_id = NULL;
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION slpip = NULL;
+ int wix, rix, max_l, l, packages, nodes, no_slpi;
+ DWORD slpi_size = 0;
+
+
+ glpi = (glpi_t) GetProcAddress(GetModuleHandle("kernel32"),
+ "GetLogicalProcessorInformation");
+ if (!glpi)
+ return -ENOTSUP;
+
+ cpuinfo->topology = NULL;
+
+ if (cpuinfo->configured < 1 || sizeof(ULONG_PTR)*8 < cpuinfo->configured)
+ goto error;
+
+ while (1) {
+ DWORD werr;
+ if (TRUE == glpi(slpip, &slpi_size))
+ break;
+ werr = GetLastError();
+ if (werr != ERROR_INSUFFICIENT_BUFFER) {
+ res = -erts_map_win_error_to_errno(werr);
+ goto error;
+ }
+ if (slpip)
+ free(slpip);
+ slpip = malloc(slpi_size);
+ if (!slpip) {
+ res = -ENOMEM;
+ goto error;
+ }
+ }
+
+ no_slpi = (int) slpi_size/sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
+
+ qsort(slpip,
+ no_slpi,
+ sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION),
+ slpi_cmp);
+
+ /*
+ * Now numa node relations appear before package relations which
+ * appear before core relations which appear before relations
+ * we aren't interested in...
+ */
+
+ max_l = 0;
+ packages = 0;
+ nodes = 0;
+ for (rix = 0; rix < no_slpi; rix++) {
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION this = &slpip[rix];
+ for (l = sizeof(ULONG_PTR)*8 - 1; l > 0; l--) {
+ if (slpip[rix].ProcessorMask & (((ULONG_PTR) 1) << l)) {
+ if (max_l < l)
+ max_l = l;
+ break;
+ }
+ }
+ if ((int) slpip[rix].Relationship == ERTS_MU_RELATION_PROCESSOR_PACKAGE)
+ packages++;
+ if ((int) slpip[rix].Relationship == ERTS_MU_RELATION_NUMA_NODE)
+ nodes++;
+ }
+
+ core_id = malloc(sizeof(int)*(packages ? packages : 1));
+ if (!core_id) {
+ res = -ENOMEM;
+ goto error;
+ }
+
+ for (rix = 0; rix < packages; rix++)
+ core_id[rix] = 0;
+
+ cpuinfo->topology_size = max_l + 1;
+ cpuinfo->topology = malloc(sizeof(erts_cpu_topology_t)
+ * cpuinfo->topology_size);
+ if (!cpuinfo->topology) {
+ res = -ENOMEM;
+ goto error;
+ }
+
+ for (wix = 0; wix < cpuinfo->topology_size; wix++) {
+ cpuinfo->topology[wix].node = -1;
+ cpuinfo->topology[wix].processor = -1;
+ cpuinfo->topology[wix].processor_node = -1;
+ cpuinfo->topology[wix].core = -1;
+ cpuinfo->topology[wix].thread = -1;
+ cpuinfo->topology[wix].logical = -1;
+ }
+
+ nodes = 0;
+ packages = 0;
+
+ for (rix = 0; rix < no_slpi; rix++) {
+
+ switch ((int) slpip[rix].Relationship) {
+ case ERTS_MU_RELATION_NUMA_NODE:
+ for (l = 0; l < sizeof(ULONG_PTR)*8; l++) {
+ if (slpip[rix].ProcessorMask & (((ULONG_PTR) 1) << l)) {
+ cpuinfo->topology[l].logical = l;
+ cpuinfo->topology[l].node = slpip[rix].NumaNode.NodeNumber;
+ }
+ }
+ nodes++;
+ break;
+ case ERTS_MU_RELATION_PROCESSOR_PACKAGE:
+ for (l = 0; l < sizeof(ULONG_PTR)*8; l++) {
+ if (slpip[rix].ProcessorMask & (((ULONG_PTR) 1) << l)) {
+ cpuinfo->topology[l].logical = l;
+ cpuinfo->topology[l].processor = packages;
+ }
+ }
+ packages++;
+ break;
+ case ERTS_MU_RELATION_PROCESSOR_CORE: {
+ int thread = 0;
+ int processor = -1;
+ for (l = 0; l < sizeof(ULONG_PTR)*8; l++) {
+ /*
+ * Nodes and packages may not be supported; pretend
+ * that there are one if this is the case...
+ */
+ if (!nodes)
+ cpuinfo->topology[l].node = 0;
+ if (!packages)
+ cpuinfo->topology[l].processor = 0;
+ if (slpip[rix].ProcessorMask & (((ULONG_PTR) 1) << l)) {
+ if (processor < 0) {
+ processor = cpuinfo->topology[l].processor;
+ if (processor < 0) {
+ res = -EINVAL;
+ goto error;
+ }
+ }
+ else if (processor != cpuinfo->topology[l].processor) {
+ res = -EINVAL;
+ goto error;
+ }
+ cpuinfo->topology[l].logical = l;
+ cpuinfo->topology[l].thread = thread;
+ cpuinfo->topology[l].core = core_id[processor];
+ thread++;
+ }
+ }
+ core_id[processor]++;
+ break;
+ }
+ default:
+ /*
+ * We have reached the end of the relationships
+ * that we (currently) are interested in...
+ */
+ goto relationships_done;
+ }
+ }
+
+ relationships_done:
+
+ /*
+ * There may be unused entries; remove them...
+ */
+ for (rix = wix = 0; rix < cpuinfo->topology_size; rix++) {
+ if (cpuinfo->topology[rix].logical >= 0) {
+ if (wix != rix)
+ cpuinfo->topology[wix] = cpuinfo->topology[rix];
+ wix++;
+ }
+ }
+
+ if (cpuinfo->topology_size != wix) {
+ erts_cpu_topology_t *new = cpuinfo->topology;
+ new = realloc(cpuinfo->topology,
+ sizeof(erts_cpu_topology_t)*wix);
+ if (!new) {
+ res = -ENOMEM;
+ goto error;
+ }
+ cpuinfo->topology = new;
+ cpuinfo->topology_size = wix;
+ }
+
+ res = wix;
+
+ adjust_processor_nodes(cpuinfo, nodes);
+
+ qsort(cpuinfo->topology,
+ cpuinfo->topology_size,
+ sizeof(erts_cpu_topology_t),
+ cpu_cmp);
+
+ if (res < cpuinfo->online)
+ res = -EINVAL;
+
+ error:
+
+ if (res <= 0) {
+ cpuinfo->topology_size = 0;
+ if (cpuinfo->topology) {
+ free(cpuinfo->topology);
+ cpuinfo->topology = NULL;
+ }
+ }
+
+ if (slpip)
+ free(slpip);
+ if (core_id)
+ free(core_id);
+
+ return res;
+}
+
#else
static int
@@ -965,3 +1384,98 @@ read_topology(erts_cpu_info_t *cpuinfo)
}
#endif
+
+#if defined(__WIN32__)
+
+int
+erts_map_win_error_to_errno(DWORD win_error)
+{
+ switch (win_error) {
+ case ERROR_INVALID_FUNCTION: return EINVAL; /* 1 */
+ case ERROR_FILE_NOT_FOUND: return ENOENT; /* 2 */
+ case ERROR_PATH_NOT_FOUND: return ENOENT; /* 3 */
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; /* 4 */
+ case ERROR_ACCESS_DENIED: return EACCES; /* 5 */
+ case ERROR_INVALID_HANDLE: return EBADF; /* 6 */
+ case ERROR_ARENA_TRASHED: return ENOMEM; /* 7 */
+ case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; /* 8 */
+ case ERROR_INVALID_BLOCK: return ENOMEM; /* 9 */
+ case ERROR_BAD_ENVIRONMENT: return E2BIG; /* 10 */
+ case ERROR_BAD_FORMAT: return ENOEXEC; /* 11 */
+ case ERROR_INVALID_ACCESS: return EINVAL; /* 12 */
+ case ERROR_INVALID_DATA: return EINVAL; /* 13 */
+ case ERROR_OUTOFMEMORY: return ENOMEM; /* 14 */
+ case ERROR_INVALID_DRIVE: return ENOENT; /* 15 */
+ case ERROR_CURRENT_DIRECTORY: return EACCES; /* 16 */
+ case ERROR_NOT_SAME_DEVICE: return EXDEV; /* 17 */
+ case ERROR_NO_MORE_FILES: return ENOENT; /* 18 */
+ case ERROR_WRITE_PROTECT: return EACCES; /* 19 */
+ case ERROR_BAD_UNIT: return EACCES; /* 20 */
+ case ERROR_NOT_READY: return EACCES; /* 21 */
+ case ERROR_BAD_COMMAND: return EACCES; /* 22 */
+ case ERROR_CRC: return EACCES; /* 23 */
+ case ERROR_BAD_LENGTH: return EACCES; /* 24 */
+ case ERROR_SEEK: return EACCES; /* 25 */
+ case ERROR_NOT_DOS_DISK: return EACCES; /* 26 */
+ case ERROR_SECTOR_NOT_FOUND: return EACCES; /* 27 */
+ case ERROR_OUT_OF_PAPER: return EACCES; /* 28 */
+ case ERROR_WRITE_FAULT: return EACCES; /* 29 */
+ case ERROR_READ_FAULT: return EACCES; /* 30 */
+ case ERROR_GEN_FAILURE: return EACCES; /* 31 */
+ case ERROR_SHARING_VIOLATION: return EACCES; /* 32 */
+ case ERROR_LOCK_VIOLATION: return EACCES; /* 33 */
+ case ERROR_WRONG_DISK: return EACCES; /* 34 */
+ case ERROR_SHARING_BUFFER_EXCEEDED: return EACCES; /* 36 */
+ case ERROR_BAD_NETPATH: return ENOENT; /* 53 */
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES; /* 65 */
+ case ERROR_BAD_NET_NAME: return ENOENT; /* 67 */
+ case ERROR_FILE_EXISTS: return EEXIST; /* 80 */
+ case ERROR_CANNOT_MAKE: return EACCES; /* 82 */
+ case ERROR_FAIL_I24: return EACCES; /* 83 */
+ case ERROR_INVALID_PARAMETER: return EINVAL; /* 87 */
+ case ERROR_NO_PROC_SLOTS: return EAGAIN; /* 89 */
+ case ERROR_DRIVE_LOCKED: return EACCES; /* 108 */
+ case ERROR_BROKEN_PIPE: return EPIPE; /* 109 */
+ case ERROR_DISK_FULL: return ENOSPC; /* 112 */
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF; /* 114 */
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD; /* 128 */
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD; /* 129 */
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; /* 130 */
+ case ERROR_NEGATIVE_SEEK: return EINVAL; /* 131 */
+ case ERROR_SEEK_ON_DEVICE: return EACCES; /* 132 */
+ case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY;/* 145 */
+ case ERROR_NOT_LOCKED: return EACCES; /* 158 */
+ case ERROR_BAD_PATHNAME: return ENOENT; /* 161 */
+ case ERROR_MAX_THRDS_REACHED: return EAGAIN; /* 164 */
+ case ERROR_LOCK_FAILED: return EACCES; /* 167 */
+ case ERROR_ALREADY_EXISTS: return EEXIST; /* 183 */
+ case ERROR_INVALID_STARTING_CODESEG: return ENOEXEC; /* 188 */
+ case ERROR_INVALID_STACKSEG: return ENOEXEC; /* 189 */
+ case ERROR_INVALID_MODULETYPE: return ENOEXEC; /* 190 */
+ case ERROR_INVALID_EXE_SIGNATURE: return ENOEXEC; /* 191 */
+ case ERROR_EXE_MARKED_INVALID: return ENOEXEC; /* 192 */
+ case ERROR_BAD_EXE_FORMAT: return ENOEXEC; /* 193 */
+ case ERROR_ITERATED_DATA_EXCEEDS_64k: return ENOEXEC; /* 194 */
+ case ERROR_INVALID_MINALLOCSIZE: return ENOEXEC; /* 195 */
+ case ERROR_DYNLINK_FROM_INVALID_RING: return ENOEXEC; /* 196 */
+ case ERROR_IOPL_NOT_ENABLED: return ENOEXEC; /* 197 */
+ case ERROR_INVALID_SEGDPL: return ENOEXEC; /* 198 */
+ case ERROR_AUTODATASEG_EXCEEDS_64k: return ENOEXEC; /* 199 */
+ case ERROR_RING2SEG_MUST_BE_MOVABLE: return ENOEXEC; /* 200 */
+ case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: return ENOEXEC; /* 201 */
+ case ERROR_INFLOOP_IN_RELOC_CHAIN: return ENOEXEC; /* 202 */
+ case ERROR_FILENAME_EXCED_RANGE: return ENOENT; /* 206 */
+ case ERROR_NESTING_NOT_ALLOWED: return EAGAIN; /* 215 */
+ case ERROR_NOT_ENOUGH_QUOTA: return ENOMEM; /* 1816 */
+ default: return EINVAL;
+ }
+}
+
+int
+erts_get_last_win_errno(void)
+{
+ return erts_map_win_error_to_errno(GetLastError());
+}
+
+
+#endif
diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c
new file mode 100644
index 0000000000..4db4cffd3a
--- /dev/null
+++ b/erts/lib_src/common/ethr_aux.c
@@ -0,0 +1,762 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: A Thread library for use in the ERTS and other OTP
+ * applications.
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHR_AUX_IMPL__
+
+#include "ethread.h"
+#include "ethr_internal.h"
+#include <string.h>
+#include <limits.h>
+
+#ifndef __WIN32__
+#include <unistd.h>
+#endif
+
+#define ERTS_TS_EV_ALLOC_DEFAULT_POOL_SIZE 100
+#define ERTS_TS_EV_ALLOC_POOL_SIZE 25
+
+erts_cpu_info_t *ethr_cpu_info__;
+
+int ethr_not_completely_inited__ = 1;
+int ethr_not_inited__ = 1;
+
+ethr_memory_allocators ethr_mem__ = ETHR_MEM_ALLOCS_DEF_INITER__;
+
+#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
+ethr_atomic_protection_t ethr_atomic_protection__[1 << ETHR_ATOMIC_ADDR_BITS];
+#endif
+
+void *(*ethr_thr_prepare_func__)(void) = NULL;
+void (*ethr_thr_parent_func__)(void *) = NULL;
+void (*ethr_thr_child_func__)(void *) = NULL;
+
+typedef struct ethr_xhndl_list_ ethr_xhndl_list;
+struct ethr_xhndl_list_ {
+ ethr_xhndl_list *next;
+ void (*funcp)(void);
+};
+
+size_t ethr_pagesize__;
+size_t ethr_min_stack_size__; /* kilo words */
+size_t ethr_max_stack_size__; /* kilo words */
+
+ethr_rwmutex xhndl_rwmtx;
+ethr_xhndl_list *xhndl_list;
+
+static int main_threads;
+
+static int init_ts_event_alloc(void);
+
+int
+ethr_init_common__(ethr_init_data *id)
+{
+ int res;
+ if (id) {
+ ethr_thr_prepare_func__ = id->thread_create_prepare_func;
+ ethr_thr_parent_func__ = id->thread_create_parent_func;
+ ethr_thr_child_func__ = id->thread_create_child_func;
+ }
+
+ ethr_cpu_info__ = erts_cpu_info_create();
+ if (!ethr_cpu_info__)
+ return ENOMEM;
+
+#ifdef _SC_PAGESIZE
+ ethr_pagesize__ = (size_t) sysconf(_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ ethr_pagesize__ = (size_t) getpagesize();
+#else
+ ethr_pagesize__ = (size_t) 4*1024; /* Guess 4 KB */
+#endif
+
+ /* User needs at least 4 KB */
+ ethr_min_stack_size__ = 4*1024;
+#if SIZEOF_VOID_P == 8
+ /* Double that on 64-bit archs */
+ ethr_min_stack_size__ *= 2;
+#endif
+ /* On some systems as much as about 4 KB is used by the system */
+ ethr_min_stack_size__ += 4*1024;
+ /* There should be room for signal handlers */
+#ifdef SIGSTKSZ
+ ethr_min_stack_size__ += SIGSTKSZ;
+#else
+ ethr_min_stack_size__ += ethr_pagesize__;
+#endif
+ /* The system may think that we need more stack */
+#if defined(PTHREAD_STACK_MIN)
+ if (ethr_min_stack_size__ < PTHREAD_STACK_MIN)
+ ethr_min_stack_size__ = PTHREAD_STACK_MIN;
+#elif defined(_SC_THREAD_STACK_MIN)
+ {
+ size_t thr_min_stk_sz = (size_t) sysconf(_SC_THREAD_STACK_MIN);
+ if (ethr_min_stack_size__ < thr_min_stk_sz)
+ ethr_min_stack_size__ = thr_min_stk_sz;
+ }
+#endif
+ /* The guard is at least on some platforms included in the stack size
+ passed when creating threads */
+#ifdef ETHR_STACK_GUARD_SIZE
+ ethr_min_stack_size__ += ETHR_STACK_GUARD_SIZE;
+#endif
+ ethr_min_stack_size__ = ETHR_PAGE_ALIGN(ethr_min_stack_size__);
+
+ ethr_min_stack_size__ = ETHR_B2KW(ethr_min_stack_size__);
+
+ ethr_max_stack_size__ = 32*1024*1024;
+#if SIZEOF_VOID_P == 8
+ ethr_max_stack_size__ *= 2;
+#endif
+ ethr_max_stack_size__ = ETHR_B2KW(ethr_max_stack_size__);
+
+#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
+ {
+ int i;
+ for (i = 0; i < (1 << ETHR_ATOMIC_ADDR_BITS); i++) {
+ res = ethr_spinlock_init(&ethr_atomic_protection__[i].u.lck);
+ if (res != 0)
+ return res;
+ }
+ }
+#endif
+
+ res = ethr_mutex_lib_init(erts_get_cpu_configured(ethr_cpu_info__));
+ if (res != 0)
+ return res;
+
+ xhndl_list = NULL;
+
+ return 0;
+}
+
+int
+ethr_late_init_common__(ethr_late_init_data *lid)
+{
+ ethr_ts_event *tsep = NULL;
+ int reader_groups;
+ int res;
+ int i;
+ ethr_memory_allocator *m[] = {&ethr_mem__.std,
+ &ethr_mem__.sl,
+ &ethr_mem__.ll};
+ if (lid)
+ ethr_mem__ = lid->mem;
+ if (!ethr_mem__.std.alloc
+ || !ethr_mem__.std.realloc
+ || !ethr_mem__.std.free) {
+ ethr_mem__.std.alloc = malloc;
+ ethr_mem__.std.realloc = realloc;
+ ethr_mem__.std.free = free;
+ }
+ for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
+ if (!m[i]->alloc || !m[i]->realloc || !m[i]->free) {
+ m[i]->alloc = ethr_mem__.std.alloc;
+ m[i]->realloc = ethr_mem__.std.realloc;
+ m[i]->free = ethr_mem__.std.free;
+ }
+
+ }
+ res = init_ts_event_alloc();
+ if (res != 0)
+ return res;
+ res = ethr_make_ts_event__(&tsep);
+ if (res == 0)
+ tsep->iflgs |= ETHR_TS_EV_ETHREAD;
+ if (!lid) {
+ main_threads = 0;
+ reader_groups = 0;
+ }
+ else {
+ if (lid->main_threads < 0 || USHRT_MAX < lid->main_threads)
+ return res;
+ main_threads = lid->main_threads;
+ reader_groups = lid->reader_groups;
+ }
+ res = ethr_mutex_lib_late_init(reader_groups, main_threads);
+ if (res != 0)
+ return res;
+ ethr_not_completely_inited__ = 0; /* Need it for
+ rwmutex_init */
+ res = ethr_rwmutex_init(&xhndl_rwmtx);
+ ethr_not_completely_inited__ = 1;
+ if (res != 0)
+ return res;
+ return 0;
+}
+
+int
+ethr_install_exit_handler(void (*funcp)(void))
+{
+ ethr_xhndl_list *xhp;
+
+#if ETHR_XCHK
+ if (ethr_not_completely_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+
+ if (!funcp)
+ return EINVAL;
+
+ xhp = (ethr_xhndl_list *) ethr_mem__.std.alloc(sizeof(ethr_xhndl_list));
+ if (!xhp)
+ return ENOMEM;
+
+ ethr_rwmutex_rwlock(&xhndl_rwmtx);
+
+ xhp->funcp = funcp;
+ xhp->next = xhndl_list;
+ xhndl_list = xhp;
+
+ ethr_rwmutex_rwunlock(&xhndl_rwmtx);
+
+ return 0;
+}
+
+void
+ethr_run_exit_handlers__(void)
+{
+ ethr_xhndl_list *xhp;
+
+ ethr_rwmutex_rlock(&xhndl_rwmtx);
+
+ xhp = xhndl_list;
+
+ ethr_rwmutex_runlock(&xhndl_rwmtx);
+
+ for (; xhp; xhp = xhp->next)
+ (*xhp->funcp)();
+}
+
+/*
+ * Thread specific event alloc, etc.
+ *
+ * Note that we don't know when it is safe to destroy an event, but
+ * we know when it is safe to reuse it. ts_event_free() therefore
+ * never destroys an event (but makes freed events available for
+ * reuse).
+ *
+ * We could easily keep track of the usage of events, and by this
+ * make it possible to destroy events. We would however suffer a
+ * performance penalty for this and save very little memory.
+ */
+
+typedef union {
+ ethr_ts_event ts_ev;
+ char align[ETHR_CACHE_LINE_ALIGN_SIZE(sizeof(ethr_ts_event))];
+} ethr_aligned_ts_event;
+
+static ethr_spinlock_t ts_ev_alloc_lock;
+static ethr_ts_event *free_ts_ev;
+
+#if SIZEOF_VOID_P == SIZEOF_INT
+typedef unsigned int EthrPtrSzUInt;
+#elif SIZEOF_VOID_P == SIZEOF_LONG
+typedef unsigned long EthrPtrSzUInt;
+#else
+#error No pointer sized integer type
+#endif
+
+static ethr_ts_event *ts_event_pool(int size, ethr_ts_event **endpp)
+{
+ int i;
+ ethr_aligned_ts_event *atsev;
+ atsev = ethr_mem__.std.alloc(sizeof(ethr_aligned_ts_event) * size
+ + ETHR_CACHE_LINE_SIZE);
+ if (!atsev)
+ return NULL;
+ if ((((EthrPtrSzUInt) atsev) & ETHR_CACHE_LINE_MASK) == 0)
+ atsev = ((ethr_aligned_ts_event *)
+ ((((EthrPtrSzUInt) atsev) & ~ETHR_CACHE_LINE_MASK)
+ + ETHR_CACHE_LINE_SIZE));
+ for (i = 1; i < size; i++) {
+ atsev[i-1].ts_ev.next = &atsev[i].ts_ev;
+ ethr_atomic_init(&atsev[i-1].ts_ev.uaflgs, 0);
+ atsev[i-1].ts_ev.iflgs = 0;
+ }
+ ethr_atomic_init(&atsev[size-1].ts_ev.uaflgs, 0);
+ atsev[size-1].ts_ev.iflgs = 0;
+ atsev[size-1].ts_ev.next = NULL;
+ if (endpp)
+ *endpp = &atsev[size-1].ts_ev;
+ return &atsev[0].ts_ev;
+}
+
+static int init_ts_event_alloc(void)
+{
+ free_ts_ev = ts_event_pool(ERTS_TS_EV_ALLOC_DEFAULT_POOL_SIZE,
+ NULL);
+ if (!free_ts_ev)
+ return ENOMEM;
+ return ethr_spinlock_init(&ts_ev_alloc_lock);
+}
+
+static ethr_ts_event *ts_event_alloc(void)
+{
+ ethr_ts_event *ts_ev;
+ ethr_spin_lock(&ts_ev_alloc_lock);
+ if (free_ts_ev) {
+ ts_ev = free_ts_ev;
+ free_ts_ev = ts_ev->next;
+ ethr_spin_unlock(&ts_ev_alloc_lock);
+ }
+ else {
+ ethr_ts_event *ts_ev_pool_end;
+ ethr_spin_unlock(&ts_ev_alloc_lock);
+
+ ts_ev = ts_event_pool(ERTS_TS_EV_ALLOC_POOL_SIZE, &ts_ev_pool_end);
+ if (!ts_ev)
+ return NULL;
+
+ ethr_spin_lock(&ts_ev_alloc_lock);
+ ts_ev_pool_end->next = free_ts_ev;
+ free_ts_ev = ts_ev->next;
+ ethr_spin_unlock(&ts_ev_alloc_lock);
+ }
+ return ts_ev;
+}
+
+static void ts_event_free(ethr_ts_event *ts_ev)
+{
+ ETHR_ASSERT(!ts_ev->udata);
+ ethr_spin_lock(&ts_ev_alloc_lock);
+ ts_ev->next = free_ts_ev;
+ free_ts_ev = ts_ev;
+ ethr_spin_unlock(&ts_ev_alloc_lock);
+}
+
+int ethr_make_ts_event__(ethr_ts_event **tsepp)
+{
+ int res;
+ ethr_ts_event *tsep = *tsepp;
+
+ if (!tsep) {
+ tsep = ts_event_alloc();
+ if (!tsep)
+ return ENOMEM;
+ }
+
+ if ((tsep->iflgs & ETHR_TS_EV_INITED) == 0) {
+ res = ethr_event_init(&tsep->event);
+ if (res != 0) {
+ ts_event_free(tsep);
+ return res;
+ }
+ }
+
+ tsep->iflgs = ETHR_TS_EV_INITED;
+ tsep->udata = NULL;
+ tsep->rgix = 0;
+ tsep->mtix = 0;
+
+ res = ethr_set_tse__(tsep);
+ if (res != 0 && tsepp && *tsepp) {
+ ts_event_free(tsep);
+ return res;
+ }
+
+ if (tsepp)
+ *tsepp = tsep;
+
+ return 0;
+}
+
+int ethr_get_tmp_ts_event__(ethr_ts_event **tsepp)
+{
+ int res;
+ ethr_ts_event *tsep = *tsepp;
+
+ if (!tsep) {
+ tsep = ts_event_alloc();
+ if (!tsep)
+ return ENOMEM;
+ }
+
+ if ((tsep->iflgs & ETHR_TS_EV_INITED) == 0) {
+ res = ethr_event_init(&tsep->event);
+ if (res != 0) {
+ ts_event_free(tsep);
+ return res;
+ }
+ }
+
+ tsep->iflgs = ETHR_TS_EV_INITED|ETHR_TS_EV_TMP;
+ tsep->udata = NULL;
+
+ if (tsepp)
+ *tsepp = tsep;
+
+ return 0;
+}
+
+int ethr_free_ts_event__(ethr_ts_event *tsep)
+{
+ ts_event_free(tsep);
+ return 0;
+}
+
+void ethr_ts_event_destructor__(void *vtsep)
+{
+ if (vtsep) {
+ ethr_ts_event *tsep = (ethr_ts_event *) vtsep;
+ ts_event_free(tsep);
+ ethr_set_tse__(NULL);
+ }
+}
+
+int ethr_set_main_thr_status(int on, int no)
+{
+ ethr_ts_event *tsep = ethr_get_tse__();
+ if (!tsep)
+ return EINVAL;
+ if (on) {
+ if (no < 1 || main_threads < no)
+ return EINVAL;
+ tsep->mtix = (unsigned short) no;
+ tsep->iflgs |= ETHR_TS_EV_MAIN_THR;
+ }
+ else {
+ tsep->iflgs &= ~ETHR_TS_EV_MAIN_THR;
+ tsep->mtix = (unsigned short) 0;
+ }
+ return 0;
+}
+
+int ethr_get_main_thr_status(int *on)
+{
+ ethr_ts_event *tsep = ethr_get_tse__();
+ if (!tsep)
+ *on = 0;
+ else {
+ if (tsep->iflgs & ETHR_TS_EV_MAIN_THR)
+ *on = 1;
+ else
+ *on = 0;
+ }
+ return 0;
+}
+
+
+/* Atomics */
+
+void
+ethr_atomic_init(ethr_atomic_t *var, long i)
+{
+ ETHR_ASSERT(var);
+ ethr_atomic_init__(var, i);
+}
+
+void
+ethr_atomic_set(ethr_atomic_t *var, long i)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_set__(var, i);
+}
+
+long
+ethr_atomic_read(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_read__(var);
+}
+
+
+long
+ethr_atomic_add_read(ethr_atomic_t *var, long incr)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_add_read__(var, incr);
+}
+
+long
+ethr_atomic_inc_read(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_inc_read__(var);
+}
+
+long
+ethr_atomic_dec_read(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_dec_read__(var);
+}
+
+void
+ethr_atomic_add(ethr_atomic_t *var, long incr)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_add__(var, incr);
+}
+
+void
+ethr_atomic_inc(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_inc__(var);
+}
+
+void
+ethr_atomic_dec(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_dec__(var);
+}
+
+long
+ethr_atomic_read_band(ethr_atomic_t *var, long mask)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_read_band__(var, mask);
+}
+
+long
+ethr_atomic_read_bor(ethr_atomic_t *var, long mask)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_read_bor__(var, mask);
+}
+
+long
+ethr_atomic_xchg(ethr_atomic_t *var, long new)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_xchg__(var, new);
+}
+
+long
+ethr_atomic_cmpxchg(ethr_atomic_t *var, long new, long expected)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_cmpxchg__(var, new, expected);
+}
+
+long
+ethr_atomic_read_acqb(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_read_acqb__(var);
+}
+
+long
+ethr_atomic_inc_read_acqb(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_inc_read_acqb__(var);
+}
+
+void
+ethr_atomic_set_relb(ethr_atomic_t *var, long i)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_set_relb__(var, i);
+}
+
+void
+ethr_atomic_dec_relb(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ ethr_atomic_dec_relb__(var);
+}
+
+long
+ethr_atomic_dec_read_relb(ethr_atomic_t *var)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_dec_read_relb__(var);
+}
+
+long
+ethr_atomic_cmpxchg_acqb(ethr_atomic_t *var, long new, long exp)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_cmpxchg_acqb__(var, new, exp);
+}
+
+long
+ethr_atomic_cmpxchg_relb(ethr_atomic_t *var, long new, long exp)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(var);
+ return ethr_atomic_cmpxchg_relb__(var, new, exp);
+}
+
+
+/* Spinlocks and rwspinlocks */
+
+int
+ethr_spinlock_init(ethr_spinlock_t *lock)
+{
+#if ETHR_XCHK
+ if (!lock) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return ethr_spinlock_init__(lock);
+}
+
+int
+ethr_spinlock_destroy(ethr_spinlock_t *lock)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!lock) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return ethr_spinlock_destroy__(lock);
+}
+
+void
+ethr_spin_unlock(ethr_spinlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_spin_unlock__(lock);
+}
+
+void
+ethr_spin_lock(ethr_spinlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_spin_lock__(lock);
+}
+
+int
+ethr_rwlock_init(ethr_rwlock_t *lock)
+{
+#if ETHR_XCHK
+ if (!lock) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return ethr_rwlock_init__(lock);
+}
+
+int
+ethr_rwlock_destroy(ethr_rwlock_t *lock)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!lock) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return ethr_rwlock_destroy__(lock);
+}
+
+void
+ethr_read_unlock(ethr_rwlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_read_unlock__(lock);
+}
+
+void
+ethr_read_lock(ethr_rwlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_read_lock__(lock);
+}
+
+void
+ethr_write_unlock(ethr_rwlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_write_unlock__(lock);
+}
+
+void
+ethr_write_lock(ethr_rwlock_t *lock)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(lock);
+ ethr_write_lock__(lock);
+}
+
+ETHR_IMPL_NORETURN__ ethr_fatal_error__(const char *file,
+ int line,
+ const char *func,
+ int err)
+{
+ char *errstr;
+ if (err == ENOTSUP)
+ errstr = "Operation not supported";
+ else {
+ errstr = strerror(err);
+ if (!errstr)
+ errstr = "Unknown error";
+ }
+ fprintf(stderr, "%s:%d: Fatal error in %s(): %s (%d)\n",
+ file, line, func, errstr, err);
+ ethr_abort__();
+}
+
+int ethr_assert_failed(const char *file, int line, const char *func, char *a)
+{
+ fprintf(stderr, "%s:%d: %s(): Assertion failed: %s\n", file, line, func, a);
+ ethr_abort__();
+ return 0;
+}
diff --git a/erts/lib_src/common/ethr_cbf.c b/erts/lib_src/common/ethr_cbf.c
new file mode 100644
index 0000000000..04feceec89
--- /dev/null
+++ b/erts/lib_src/common/ethr_cbf.c
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+
+/*
+ * We keep this function alone in a separate file so the
+ * compiler wont optimize it away.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ethread.h"
+
+void
+ethr_compiler_barrier_fallback(void)
+{
+
+}
diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c
new file mode 100644
index 0000000000..aac0d44a32
--- /dev/null
+++ b/erts/lib_src/common/ethr_mutex.c
@@ -0,0 +1,2758 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Mutex, rwmutex and condition variable implementation
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHR_MUTEX_IMPL__
+
+#include <limits.h>
+#include "ethread.h"
+#include "ethr_internal.h"
+
+#define ETHR_SPIN_WITH_WAITERS 1
+
+#define ETHR_MTX_MAX_FLGS_SPIN 1000
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+static int default_rwmtx_main_spincount;
+static int default_rwmtx_aux_spincount;
+#endif
+#ifdef ETHR_USE_OWN_MTX_IMPL__
+static int default_mtx_main_spincount;
+static int default_mtx_aux_spincount;
+static int default_cnd_main_spincount;
+static int default_cnd_aux_spincount;
+#endif
+
+static int no_spin;
+
+#ifndef ETHR_USE_OWN_RWMTX_IMPL__
+static pthread_rwlockattr_t write_pref_attr_data;
+static pthread_rwlockattr_t *write_pref_attr;
+#endif
+
+#if defined(ETHR_MTX_Q_LOCK_SPINLOCK__)
+# define ETHR_MTX_QLOCK_INIT ethr_spinlock_init
+# define ETHR_MTX_QLOCK_DESTROY ethr_spinlock_destroy
+# define ETHR_MTX_Q_LOCK ethr_spin_lock
+# define ETHR_MTX_Q_UNLOCK ethr_spin_unlock
+#elif defined(ETHR_MTX_Q_LOCK_PTHREAD_MUTEX__)
+# define ETHR_MTX_QLOCK_INIT(QL) pthread_mutex_init((QL), NULL)
+# define ETHR_MTX_QLOCK_DESTROY pthread_mutex_destroy
+# define ETHR_MTX_Q_LOCK(L) \
+do { \
+ int res__ = pthread_mutex_lock(L); \
+ if (res__ != 0) \
+ ETHR_FATAL_ERROR__(res__); \
+} while (0)
+# define ETHR_MTX_Q_UNLOCK(L) \
+do { \
+ int res__ = pthread_mutex_unlock(L); \
+ if (res__ != 0) \
+ ETHR_FATAL_ERROR__(res__); \
+} while (0)
+#elif defined(ETHR_MTX_Q_LOCK_CRITICAL_SECTION__)
+# define ETHR_MTX_QLOCK_INIT(QL) (InitializeCriticalSection((QL)), 0)
+# define ETHR_MTX_QLOCK_DESTROY(QL) (DeleteCriticalSection((QL)), 0)
+# define ETHR_MTX_Q_LOCK(QL) EnterCriticalSection((QL))
+# define ETHR_MTX_Q_UNLOCK(QL) LeaveCriticalSection((QL))
+#endif
+
+int
+ethr_mutex_lib_init(int cpu_conf)
+{
+ int res = 0;
+
+ no_spin = cpu_conf == 1;
+
+#ifdef ETHR_USE_OWN_MTX_IMPL__
+ default_mtx_main_spincount = ETHR_MTX_DEFAULT_MAIN_SPINCOUNT;
+ default_mtx_aux_spincount = ETHR_MTX_DEFAULT_AUX_SPINCOUNT;
+ default_cnd_main_spincount = ETHR_CND_DEFAULT_MAIN_SPINCOUNT;
+ default_cnd_aux_spincount = ETHR_CND_DEFAULT_AUX_SPINCOUNT;
+#endif
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+
+ default_rwmtx_main_spincount = ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT;
+ default_rwmtx_aux_spincount = ETHR_RWMTX_DEFAULT_AUX_SPINCOUNT;
+
+#else
+
+#if defined(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) \
+ && defined(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
+ res = pthread_rwlockattr_init(&write_pref_attr_data);
+ if (res != 0)
+ return res;
+ res = pthread_rwlockattr_setkind_np(
+ &write_pref_attr_data,
+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ write_pref_attr = &write_pref_attr_data;
+#else
+ write_pref_attr = NULL;
+#endif
+
+#endif
+
+ return res;
+}
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+
+#ifdef ETHR_ATOMIC_HAVE_INC_DEC_INSTRUCTIONS
+#if 0 /*
+ * When inc and dec are real atomic instructions as on x86, the
+ * ETHR_RLOCK_WITH_INC_DEC implementations performs better with
+ * lots of read locks compared to the cmpxchg based implementation.
+ * It, however, performs worse with lots of mixed reads and writes.
+ * It could be used for rwlocks that are known to be read locked
+ * much, but the readers array based implementation outperforms it
+ * by far. Therefore, it has been disabled, and will probably be
+ * removed some time in the future.
+ */
+# define ETHR_RLOCK_WITH_INC_DEC
+#endif
+#endif
+
+static int reader_groups_array_size = 0;
+static int main_threads_array_size = 0;
+
+#endif
+
+int
+ethr_mutex_lib_late_init(int no_reader_groups, int no_main_threads)
+{
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+ reader_groups_array_size = (no_reader_groups <= 1
+ ? 1
+ : no_reader_groups + 1);
+ main_threads_array_size = (no_main_threads <= 1
+ ? 1
+ : no_main_threads + 1);
+#endif
+ return 0;
+}
+
+int
+ethr_rwmutex_set_reader_group(int ix)
+{
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+ ethr_ts_event *tse;
+
+ if (ix < 0 || reader_groups_array_size <= ix)
+ return EINVAL;
+
+ tse = ethr_get_ts_event();
+
+ if ((tse->iflgs & ETHR_TS_EV_ETHREAD) == 0) {
+ ethr_leave_ts_event(tse);
+ return EINVAL;
+ }
+
+ tse->rgix = ix;
+
+ ethr_leave_ts_event(tse);
+#endif
+ return 0;
+}
+
+#if defined(ETHR_MTX_HARD_DEBUG_Q) || defined(ETHR_MTX_HARD_DEBUG_WSQ)
+static void hard_debug_chk_q__(struct ethr_mutex_base_ *, int);
+#define ETHR_RWMTX_HARD_DEBUG_CHK_Q(RWMTX) hard_debug_chk_q__(&(RWMTX)->mtxb,1)
+#define ETHR_MTX_HARD_DEBUG_CHK_Q(MTX) hard_debug_chk_q__(&(MTX)->mtxb, 0)
+#else
+#define ETHR_RWMTX_HARD_DEBUG_CHK_Q(RWMTX)
+#define ETHR_MTX_HARD_DEBUG_CHK_Q(MTX)
+#endif
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+static void
+rwmutex_unlock_wake(ethr_rwmutex *rwmtx,
+ int have_w,
+ long initial);
+static int
+rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
+ long initial,
+ ethr_ts_event *tse,
+ int start_next_ix,
+ int check_before_try,
+ int try_write_lock);
+#endif
+
+#if defined(ETHR_USE_OWN_RWMTX_IMPL__) || defined(ETHR_USE_OWN_MTX_IMPL__)
+
+/* -- Utilities operating both on ordinary mutexes and read write mutexes -- */
+
+static ETHR_INLINE void
+rwmutex_freqread_wtng_rdrs_inc(ethr_rwmutex *rwmtx, ethr_ts_event *tse)
+{
+ int ix = (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ
+ ? tse->rgix
+ : tse->mtix);
+ rwmtx->tdata.ra[ix].data.waiting_readers++;
+}
+
+static ETHR_INLINE void
+rwmutex_freqread_rdrs_add(ethr_rwmutex *rwmtx,
+ ethr_rwmutex_type type,
+ int ix,
+ int inc)
+{
+ if (type == ETHR_RWMUTEX_TYPE_FREQUENT_READ || ix == 0)
+ ethr_atomic_add(&rwmtx->tdata.ra[ix].data.readers, inc);
+ else {
+ ETHR_ASSERT(type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ);
+ ETHR_ASSERT(ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers) == 0);
+ ETHR_ASSERT(inc == 1);
+ ethr_atomic_set(&rwmtx->tdata.ra[ix].data.readers, (long) 1);
+ }
+}
+
+static ETHR_INLINE void
+rwmutex_freqread_rdrs_inc(ethr_rwmutex *rwmtx, ethr_ts_event *tse)
+{
+ int ix;
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ ix = tse->rgix;
+ atomic_inc:
+ ethr_atomic_inc(&rwmtx->tdata.ra[ix].data.readers);
+ }
+ else {
+ ix = tse->mtix;
+ if (ix == 0)
+ goto atomic_inc;
+ ETHR_ASSERT(rwmtx->type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ);
+ ETHR_ASSERT(ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers) == 0);
+ ethr_atomic_set(&rwmtx->tdata.ra[ix].data.readers, (long) 1);
+ }
+}
+
+static ETHR_INLINE void
+rwmutex_freqread_rdrs_dec(ethr_rwmutex *rwmtx, ethr_ts_event *tse)
+{
+ int ix;
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ ix = tse->rgix;
+ atomic_dec:
+ ethr_atomic_dec(&rwmtx->tdata.ra[ix].data.readers);
+ }
+ else {
+ ix = tse->mtix;
+ if (ix == 0)
+ goto atomic_dec;
+ ETHR_ASSERT(rwmtx->type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ);
+ ETHR_ASSERT(ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers) == 1);
+ ethr_atomic_set(&rwmtx->tdata.ra[ix].data.readers, (long) 0);
+ }
+}
+
+static ETHR_INLINE long
+rwmutex_freqread_rdrs_dec_read(ethr_rwmutex *rwmtx, ethr_ts_event *tse)
+{
+ int ix;
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ ix = tse->rgix;
+ atomic_dec_read:
+ return ethr_atomic_dec_read(&rwmtx->tdata.ra[ix].data.readers);
+ }
+ else {
+ ix = tse->mtix;
+ if (ix == 0)
+ goto atomic_dec_read;
+ ETHR_ASSERT(rwmtx->type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ);
+ ETHR_ASSERT(ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers) == 1);
+ ethr_atomic_set(&rwmtx->tdata.ra[ix].data.readers, (long) 0);
+ return (long) 0;
+ }
+}
+
+static ETHR_INLINE long
+rwmutex_freqread_rdrs_dec_read_relb(ethr_rwmutex *rwmtx, ethr_ts_event *tse)
+{
+ int ix;
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ ix = tse->rgix;
+ atomic_dec_read:
+ return ethr_atomic_dec_read_relb(&rwmtx->tdata.ra[ix].data.readers);
+ }
+ else {
+ ix = tse->mtix;
+ if (ix == 0)
+ goto atomic_dec_read;
+ ETHR_ASSERT(rwmtx->type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ);
+ ETHR_ASSERT(ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers) == 1);
+ ethr_atomic_set_relb(&rwmtx->tdata.ra[ix].data.readers, (long) 0);
+ return (long) 0;
+ }
+}
+
+static ETHR_INLINE long
+rwmutex_freqread_rdrs_read(ethr_rwmutex *rwmtx, int ix)
+{
+ long res = ethr_atomic_read(&rwmtx->tdata.ra[ix].data.readers);
+#ifdef ETHR_DEBUG
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ ETHR_ASSERT(res >= 0);
+ break;
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ:
+ ETHR_ASSERT(res == 0 || res == 1);
+ break;
+ default:
+ ETHR_ASSERT(0);
+ break;
+ }
+#endif
+ return res;
+}
+
+
+static ETHR_INLINE void
+enqueue(ethr_ts_event **queue,
+ ethr_ts_event *tse_start,
+ ethr_ts_event *tse_end)
+{
+ if (!*queue) {
+ *queue = tse_start;
+ tse_start->prev = tse_end;
+ tse_end->next = tse_start;
+ }
+ else {
+ tse_end->next = *queue;
+ tse_start->prev = (*queue)->prev;
+ (*queue)->prev->next = tse_start;
+ (*queue)->prev = tse_end;
+ }
+}
+
+static ETHR_INLINE void
+insert(ethr_ts_event *tse_pred, ethr_ts_event *tse)
+{
+ tse->next = tse_pred->next;
+ tse->prev = tse_pred;
+ tse_pred->next->prev = tse;
+ tse_pred->next = tse;
+}
+
+static ETHR_INLINE void
+dequeue(ethr_ts_event **queue,
+ ethr_ts_event *tse_start,
+ ethr_ts_event *tse_end)
+{
+ if (tse_start->prev == tse_end) {
+ ETHR_ASSERT(*queue == tse_start && tse_end->next == tse_start);
+ *queue = NULL;
+ }
+ else {
+ if (*queue == tse_start)
+ *queue = tse_end->next;
+ tse_end->next->prev = tse_start->prev;
+ tse_start->prev->next = tse_end->next;
+ }
+}
+
+static void
+event_wait(struct ethr_mutex_base_ *mtxb,
+ ethr_ts_event *tse,
+ int spincount,
+ long type,
+ int is_rwmtx,
+ int is_freq_read)
+{
+ int locked = 0;
+ long act;
+ int need_try_complete_runlock = 0;
+
+ /* Need to enqueue and wait... */
+
+ tse->uflgs = type;
+ ethr_atomic_set(&tse->uaflgs, type);
+
+ ETHR_MTX_Q_LOCK(&mtxb->qlck);
+ locked = 1;
+
+#ifdef ETHR_MTX_HARD_DEBUG_Q
+ hard_debug_chk_q__(mtxb, is_rwmtx);
+#endif
+
+ act = ethr_atomic_read(&mtxb->flgs);
+
+ if (act & type) {
+
+ /* Wait bit already there; enqueue... */
+
+ ETHR_ASSERT(mtxb->q);
+ if (type == ETHR_RWMTX_W_WAIT_FLG__) {
+ enqueue(&mtxb->q, tse, tse);
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ mtxb->ws++;
+#endif
+ }
+ else {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_ASSERT(is_rwmtx);
+ ETHR_ASSERT(rwmtx->rq_end);
+ insert(rwmtx->rq_end, tse);
+ rwmtx->rq_end = tse;
+ if (is_freq_read)
+ rwmutex_freqread_wtng_rdrs_inc(rwmtx, tse);
+ else
+ rwmtx->tdata.rs++;
+ }
+ }
+ else {
+
+ /* Set wait bit */
+
+ while (1) {
+ long new, exp = act;
+ int freqread_tryrlock = 0;
+ need_try_complete_runlock = 0;
+
+ if (type == ETHR_RWMTX_W_WAIT_FLG__) {
+ if (is_freq_read && act == ETHR_RWMTX_R_FLG__)
+ need_try_complete_runlock = 1;
+ if (act != 0)
+ new = act | ETHR_RWMTX_W_WAIT_FLG__;
+ else
+ new = ETHR_RWMTX_W_FLG__; /* Try to get it */
+ }
+ else {
+ ETHR_ASSERT(is_rwmtx);
+
+ if (!is_freq_read) {
+ if (act & (ETHR_RWMTX_W_FLG__| ETHR_RWMTX_W_WAIT_FLG__))
+ new = act | ETHR_RWMTX_R_WAIT_FLG__;
+ else
+ new = act + 1; /* Try to get it */
+ }
+ else {
+ if (act & ~ETHR_RWMTX_R_FLG__)
+ new = act | ETHR_RWMTX_R_WAIT_FLG__;
+ else { /* Try to get it */
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ rwmutex_freqread_rdrs_inc(rwmtx, tse);
+ ETHR_MEMORY_BARRIER;
+ new = act | ETHR_RWMTX_R_FLG__;
+ freqread_tryrlock = 1;
+ }
+ }
+ }
+
+ act = ethr_atomic_cmpxchg_acqb(&mtxb->flgs, new, exp);
+ if (exp == act) {
+ if (new & type) {
+ act = new;
+ break;
+ }
+ else {
+ /* Got it */
+ goto done;
+ }
+ }
+
+ if (freqread_tryrlock) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+
+ /* We didn't set ETHR_RWMTX_R_FLG__, however someone
+ else might have */
+ if (act == ETHR_RWMTX_R_FLG__)
+ goto done; /* Got it by help from someone else */
+
+ ETHR_ASSERT((act & ETHR_RWMTX_WAIT_FLGS__) == 0);
+ /*
+ * We know that no waiter flags have been set, i.e.,
+ * we cannot get into a situation where we need to wake
+ * someone up here. Just restore the readers counter
+ * and do it over again...
+ */
+ rwmutex_freqread_rdrs_dec(rwmtx, tse);
+ }
+ }
+
+ /* Enqueue */
+
+ if (type == ETHR_RWMTX_R_WAIT_FLG__) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_ASSERT(is_rwmtx);
+ ETHR_ASSERT(!rwmtx->rq_end);
+ rwmtx->rq_end = tse;
+ if (is_freq_read)
+ rwmutex_freqread_wtng_rdrs_inc(rwmtx, tse);
+ else
+ rwmtx->tdata.rs++;
+ }
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ else {
+ mtxb->ws++;
+ }
+#endif
+
+ enqueue(&mtxb->q, tse, tse);
+ }
+
+#ifdef ETHR_MTX_HARD_DEBUG_Q
+ hard_debug_chk_q__(mtxb, is_rwmtx);
+#endif
+
+ /* Wait */
+ locked = 0;
+ ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
+
+ if (need_try_complete_runlock) {
+ ETHR_ASSERT(((ethr_rwmutex *) mtxb)->type
+ != ETHR_RWMUTEX_TYPE_NORMAL);
+ /*
+ * We were the only one in queue when we enqueued, and it
+ * was seemingly read locked. We need to try to complete a
+ * runlock otherwise we might be hanging forever. If the
+ * runlock could be completed we will be dequeued and
+ * woken by ourselves.
+ */
+ rwmutex_try_complete_runlock((ethr_rwmutex *) mtxb,
+ act, tse, 0, 1, 0);
+ }
+
+ while (1) {
+ ethr_event_reset(&tse->event);
+
+ act = ethr_atomic_read_acqb(&tse->uaflgs);
+ if (!act)
+ goto done; /* Got it */
+
+ ETHR_ASSERT(act == type);
+ ethr_event_swait(&tse->event, spincount);
+ /* swait result: 0 || EINTR */
+
+ act = ethr_atomic_read_acqb(&tse->uaflgs);
+ if (!act)
+ goto done; /* Got it */
+ }
+
+ done:
+ if (locked)
+ ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
+}
+
+static void
+wake_writer(struct ethr_mutex_base_ *mtxb, int is_rwmtx)
+{
+ ethr_ts_event *tse;
+
+ tse = mtxb->q;
+ ETHR_ASSERT(tse);
+ dequeue(&mtxb->q, tse, tse);
+
+ ETHR_ASSERT(tse->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+ ETHR_ASSERT(ethr_atomic_read(&tse->uaflgs) == ETHR_RWMTX_W_WAIT_FLG__);
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ mtxb->ws--;
+#endif
+#if defined(ETHR_MTX_HARD_DEBUG_Q) || defined(ETHR_MTX_HARD_DEBUG_WSQ)
+ hard_debug_chk_q__(mtxb, is_rwmtx);
+#endif
+
+ ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
+
+ ethr_atomic_set(&tse->uaflgs, 0);
+ ethr_event_set(&tse->event);
+}
+
+static ETHR_INLINE int
+initial_spincount(struct ethr_mutex_base_ *mtxb)
+{
+ return (mtxb->aux_scnt < ETHR_MTX_MAX_FLGS_SPIN
+ ? mtxb->aux_scnt
+ : ETHR_MTX_MAX_FLGS_SPIN);
+}
+
+static ETHR_INLINE int
+update_spincount(struct ethr_mutex_base_ *mtxb,
+ ethr_ts_event *tse,
+ int *start_scnt,
+ int *scnt)
+{
+ int sscnt = *start_scnt;
+ if (sscnt < 0) {
+ *scnt = ((tse->iflgs & ETHR_TS_EV_MAIN_THR)
+ ? mtxb->main_scnt
+ : mtxb->aux_scnt);
+ *scnt -= ETHR_MTX_MAX_FLGS_SPIN;
+ }
+ else {
+ *scnt = ((tse->iflgs & ETHR_TS_EV_MAIN_THR)
+ ? mtxb->main_scnt
+ : mtxb->aux_scnt);
+ *scnt -= sscnt;
+ if (*scnt > 0 && sscnt < ETHR_MTX_MAX_FLGS_SPIN) {
+ *scnt = ETHR_MTX_MAX_FLGS_SPIN - sscnt;
+ *start_scnt = -1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int check_readers_array(ethr_rwmutex *rwmtx,
+ int start_rix,
+ int length,
+ int pre_check);
+
+static ETHR_INLINE void
+write_lock_wait(struct ethr_mutex_base_ *mtxb,
+ long initial,
+ int is_rwmtx,
+ int is_freq_read)
+{
+ long act = initial;
+ int scnt, start_scnt;
+ ethr_ts_event *tse = NULL;
+ int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ int res;
+ int freq_read_size = -1;
+ int freq_read_start_ix = -1;
+
+ ETHR_ASSERT(!is_freq_read || is_rwmtx);
+
+ start_scnt = scnt = initial_spincount(mtxb);
+
+ /*
+ * Spin trying to write lock for a while. If unsuccessful,
+ * wait on event.
+ */
+
+ while (1) {
+ long exp;
+
+ while (act != 0) {
+
+ if (is_freq_read && act == ETHR_RWMTX_R_FLG__) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ if (!tse)
+ tse = ethr_get_ts_event();
+ if (freq_read_size < 0) {
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ freq_read_size = reader_groups_array_size;
+ freq_read_start_ix = tse->rgix;
+ }
+ else {
+ freq_read_size = main_threads_array_size;
+ freq_read_start_ix = tse->mtix;
+ }
+ }
+ res = check_readers_array(rwmtx,
+ freq_read_start_ix,
+ freq_read_size,
+ 1);
+ scnt--;
+ if (res == 0) {
+ act = ethr_atomic_read(&mtxb->flgs);
+ if (act & ETHR_RWMTX_R_MASK__) {
+ res = rwmutex_try_complete_runlock(rwmtx, act,
+ tse, 0, 0,
+ 1);
+ if (res != EBUSY)
+ goto done; /* Got it */
+ }
+ if (scnt <= 0)
+ goto chk_spin;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ ETHR_YIELD();
+ }
+ continue;
+ }
+ }
+
+ if (scnt <= 0) {
+ chk_spin:
+ scnt = 0;
+
+ if (!tse)
+ tse = ethr_get_ts_event();
+ if (update_spincount(mtxb, tse, &start_scnt, &scnt)) {
+ event_wait(mtxb, tse, scnt, ETHR_RWMTX_W_WAIT_FLG__,
+ is_rwmtx, is_freq_read);
+ goto done;
+ }
+ }
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ ETHR_YIELD();
+ }
+ act = ethr_atomic_read(&mtxb->flgs);
+ scnt--;
+ }
+ ETHR_ASSERT(scnt >= 0);
+
+ exp = act;
+
+ act = ethr_atomic_cmpxchg_acqb(&mtxb->flgs,
+ ETHR_RWMTX_W_FLG__,
+ exp);
+ if (act == 0)
+ goto done; /* Got it */
+ }
+
+ done:
+ if (tse)
+ ethr_leave_ts_event(tse);
+}
+
+static int
+mtxb_init(struct ethr_mutex_base_ *mtxb,
+ int def_main_scnt,
+ int main_scnt,
+ int def_aux_scnt,
+ int aux_scnt)
+{
+ ETHR_MTX_HARD_DEBUG_LFS_INIT(mtxb);
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ mtxb->ws = 0;
+#endif
+ if (no_spin) {
+ mtxb->main_scnt = 0;
+ mtxb->aux_scnt = 0;
+ }
+ else {
+ if (main_scnt > SHRT_MAX)
+ mtxb->main_scnt = SHRT_MAX;
+ else if (main_scnt < 0)
+ mtxb->main_scnt = def_main_scnt;
+ else
+ mtxb->main_scnt = (short) main_scnt;
+ if (aux_scnt > SHRT_MAX)
+ mtxb->aux_scnt = SHRT_MAX;
+ else if (aux_scnt < 0)
+ mtxb->aux_scnt = def_aux_scnt;
+ else
+ mtxb->aux_scnt = (short) aux_scnt;
+ if (mtxb->main_scnt < mtxb->aux_scnt)
+ mtxb->main_scnt = mtxb->aux_scnt;
+
+ }
+ mtxb->q = NULL;
+ ethr_atomic_init(&mtxb->flgs, 0);
+ return ETHR_MTX_QLOCK_INIT(&mtxb->qlck);
+}
+
+static int
+mtxb_destroy(struct ethr_mutex_base_ *mtxb)
+{
+ long act;
+ ETHR_MTX_Q_LOCK(&mtxb->qlck);
+ act = ethr_atomic_read(&mtxb->flgs);
+ ETHR_MTX_Q_UNLOCK(&mtxb->qlck);
+ if (act != 0)
+ return EINVAL;
+ return ETHR_MTX_QLOCK_DESTROY(&mtxb->qlck);
+}
+
+
+#endif /* ETHR_USE_OWN_RWMTX_IMPL__ || ETHR_USE_OWN_MTX_IMPL__ */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Mutex and condition variable implementation *
+\* */
+
+#ifdef ETHR_USE_OWN_MTX_IMPL__
+
+/* -- Mutex ---------------------------------------------------------------- */
+
+int
+ethr_mutex_init_opt(ethr_mutex *mtx, ethr_mutex_opt *opt)
+{
+ int res;
+#if ETHR_XCHK
+ if (!mtx) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ mtx->initialized = ETHR_MUTEX_INITIALIZED;
+#endif
+ ETHR_MTX_HARD_DEBUG_FENCE_INIT(mtx);
+ res = mtxb_init(&mtx->mtxb,
+ default_mtx_main_spincount,
+ opt ? opt->main_spincount : -1,
+ default_mtx_aux_spincount,
+ opt ? opt->aux_spincount : -1);
+#if ETHR_XCHK
+ if (res != 0)
+ mtx->initialized = 0;
+#endif
+ return res;
+}
+
+int
+ethr_mutex_init(ethr_mutex *mtx)
+{
+ return ethr_mutex_init_opt(mtx, NULL);
+}
+
+int
+ethr_mutex_destroy(ethr_mutex *mtx)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!mtx) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ mtx->initialized = 0;
+#endif
+ return mtxb_destroy(&mtx->mtxb);
+}
+
+void
+ethr_mutex_lock_wait__(ethr_mutex *mtx, long initial)
+{
+ write_lock_wait(&mtx->mtxb, initial, 0, 0);
+}
+
+void
+ethr_mutex_unlock_wake__(ethr_mutex *mtx, long initial)
+{
+ ethr_ts_event *tse;
+
+ ETHR_MTX_Q_LOCK(&mtx->mtxb.qlck);
+ tse = mtx->mtxb.q;
+
+ ETHR_ASSERT(tse);
+ ETHR_ASSERT(ethr_atomic_read(&mtx->mtxb.flgs)
+ == (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__));
+ ETHR_ASSERT(initial & ETHR_RWMTX_W_WAIT_FLG__);
+ ETHR_MTX_HARD_DEBUG_CHK_Q(mtx);
+
+ /*
+ * If we have multiple waiters, there is no need to modify
+ * mtxb->flgs; otherwise, we need to clear the write wait bit...
+ */
+ if (tse->next == mtx->mtxb.q)
+ ethr_atomic_set(&mtx->mtxb.flgs, ETHR_RWMTX_W_FLG__);
+
+ wake_writer(&mtx->mtxb, 0);
+}
+
+/* -- Condition variables -------------------------------------------------- */
+
+static void
+enqueue_mtx(ethr_mutex *mtx, ethr_ts_event *tse_start, ethr_ts_event *tse_end)
+{
+ long act;
+
+ /*
+ * `ethr_cond_signal()' and `ethr_cond_broadcast()' end up here. If `mtx'
+ * is not currently locked by current thread, we almost certainly have a
+ * hard to debug race condition. There might however be some (strange)
+ * use for it. POSIX also allow a call to `pthread_cond_signal' or
+ * `pthread_cond_broadcast' even though the the associated mutex isn't
+ * locked by the caller. Therefore, we also allow this kind of strange
+ * usage, but optimize for the case where the mutex is locked by the
+ * calling thread.
+ */
+
+ ETHR_MTX_Q_LOCK(&mtx->mtxb.qlck);
+
+ ETHR_MTX_HARD_DEBUG_CHK_Q(mtx);
+
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ {
+ int dbg_nws__ = 0;
+ ethr_ts_event *dbg_tse__;
+ for (dbg_tse__ = tse_start;
+ dbg_tse__ != tse_end;
+ dbg_tse__ = dbg_tse__->next)
+ dbg_nws__++;
+ mtx->mtxb.ws += dbg_nws__ + 1;
+ }
+#endif
+
+ act = ethr_atomic_read(&mtx->mtxb.flgs);
+ ETHR_ASSERT(act == 0
+ || act == ETHR_RWMTX_W_FLG__
+ || act == (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__));
+ if (act & ETHR_RWMTX_W_FLG__) {
+ /* The normal sane case */
+ if (!(act & ETHR_RWMTX_W_WAIT_FLG__)) {
+ ETHR_ASSERT(!mtx->mtxb.q);
+ act = ethr_atomic_cmpxchg(&mtx->mtxb.flgs,
+ (ETHR_RWMTX_W_FLG__
+ | ETHR_RWMTX_W_WAIT_FLG__),
+ ETHR_RWMTX_W_FLG__);
+ if (act != ETHR_RWMTX_W_FLG__) {
+ /*
+ * Sigh... this wasn't so sane after all since, the mutex was
+ * obviously not locked by the current thread....
+ */
+ ETHR_ASSERT(act == 0);
+ goto mtx_unlocked;
+ }
+ }
+
+#ifdef ETHR_DEBUG
+ if (act & ETHR_RWMTX_W_WAIT_FLG__)
+ ETHR_ASSERT(mtx->mtxb.q);
+ else
+ ETHR_ASSERT(!mtx->mtxb.q);
+#endif
+
+ enqueue(&mtx->mtxb.q, tse_start, tse_end);
+
+ ETHR_MTX_HARD_DEBUG_CHK_Q(mtx);
+ ETHR_MTX_Q_UNLOCK(&mtx->mtxb.qlck);
+
+ }
+ else {
+ int multi;
+ mtx_unlocked:
+ /* Sigh... mutex isn't locked... */
+
+ multi = tse_start != tse_end;
+
+ while (1) {
+ long new, exp = act;
+
+ if (multi || (act & ETHR_RWMTX_W_FLG__))
+ new = ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__;
+ else
+ new = ETHR_RWMTX_W_FLG__;
+
+ act = ethr_atomic_cmpxchg(&mtx->mtxb.flgs, new, exp);
+ if (exp == act) {
+ ETHR_ASSERT(!mtx->mtxb.q);
+ if (act & ETHR_RWMTX_W_FLG__) {
+ enqueue(&mtx->mtxb.q, tse_start, tse_end);
+
+ ETHR_MTX_HARD_DEBUG_CHK_Q(mtx);
+ ETHR_MTX_Q_UNLOCK(&mtx->mtxb.qlck);
+
+ }
+ else {
+ ETHR_ASSERT(!mtx->mtxb.q);
+ /*
+ * Acquired the mutex on behalf of the
+ * first thread in the queue; wake
+ * it and enqueue the rest...
+ */
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ mtx->mtxb.ws--;
+#endif
+ if (multi) {
+ enqueue(&mtx->mtxb.q, tse_start->next, tse_end);
+ ETHR_ASSERT(mtx->mtxb.q);
+ }
+
+ ETHR_MTX_HARD_DEBUG_CHK_Q(mtx);
+ ETHR_MTX_Q_UNLOCK(&mtx->mtxb.qlck);
+
+ ethr_atomic_set(&tse_start->uaflgs, 0);
+ ethr_event_set(&tse_start->event);
+ }
+ break;
+ }
+ }
+ }
+}
+
+int
+ethr_cond_init_opt(ethr_cond *cnd, ethr_cond_opt *opt)
+{
+ int res;
+#if ETHR_XCHK
+ if (!cnd) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ cnd->initialized = ETHR_COND_INITIALIZED;
+#endif
+ ETHR_MTX_HARD_DEBUG_FENCE_INIT(cnd);
+ cnd->q = NULL;
+ if (no_spin) {
+ cnd->main_scnt = 0;
+ cnd->aux_scnt = 0;
+ }
+ else {
+ if (!opt || opt->main_spincount < 0)
+ cnd->main_scnt = default_cnd_main_spincount;
+ else if (opt->main_spincount > SHRT_MAX)
+ cnd->main_scnt = SHRT_MAX;
+ else
+ cnd->main_scnt = (short) opt->main_spincount;
+ if (!opt || opt->aux_spincount < 0)
+ cnd->aux_scnt = default_cnd_aux_spincount;
+ else if (opt->aux_spincount > SHRT_MAX)
+ cnd->aux_scnt = SHRT_MAX;
+ else
+ cnd->aux_scnt = (short) opt->aux_spincount;
+ if (cnd->main_scnt < cnd->aux_scnt)
+ cnd->main_scnt = cnd->aux_scnt;
+ }
+ ETHR_MTX_QLOCK_INIT(&cnd->qlck);
+ return 0;
+}
+
+int
+ethr_cond_init(ethr_cond *cnd)
+{
+ return ethr_cond_init_opt(cnd, NULL);
+}
+
+int
+ethr_cond_destroy(ethr_cond *cnd)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ cnd->initialized = 0;
+#endif
+ return ETHR_MTX_QLOCK_DESTROY(&cnd->qlck);
+}
+
+void
+ethr_cond_signal(ethr_cond *cnd)
+{
+ ethr_ts_event *tse;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+
+ ETHR_MTX_Q_LOCK(&cnd->qlck);
+
+ tse = cnd->q;
+
+ if (!tse) {
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+ }
+ else {
+ ethr_mutex *mtx = (ethr_mutex *) tse->udata;
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+ ETHR_ASSERT(tse->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+ ETHR_ASSERT(ethr_atomic_read(&tse->uaflgs) == ETHR_CND_WAIT_FLG__);
+
+ ethr_atomic_set(&tse->uaflgs, ETHR_RWMTX_W_WAIT_FLG__);
+
+ dequeue(&cnd->q, tse, tse);
+
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+
+ tse->next = tse->prev = NULL;
+
+ enqueue_mtx(mtx, tse, tse);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+ }
+}
+
+void
+ethr_cond_broadcast(ethr_cond *cnd)
+{
+ int res;
+ int got_all;
+ ethr_ts_event *tse;
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ do {
+ got_all = 1;
+
+ ETHR_MTX_Q_LOCK(&cnd->qlck);
+
+ tse = cnd->q;
+
+ if (!tse) {
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+ }
+ else {
+ ethr_mutex *mtx = (ethr_mutex *) tse->udata;
+ ethr_ts_event *tse_tmp, *tse_end;
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+ tse_end = cnd->q->prev;
+
+ tse_tmp = tse;
+
+ do {
+
+ if (mtx == (ethr_mutex *) tse_tmp->udata) {
+ /* The normal case */
+
+ ETHR_ASSERT(tse_tmp->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+ ETHR_ASSERT(ethr_atomic_read(&tse_tmp->uaflgs)
+ == ETHR_CND_WAIT_FLG__);
+
+ ethr_atomic_set(&tse_tmp->uaflgs, ETHR_RWMTX_W_WAIT_FLG__);
+ }
+ else {
+ /* Should be very unusual */
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+ tse_end = tse_tmp->prev;
+ got_all = 0;
+ break;
+ }
+
+ tse_tmp = tse_tmp->next;
+
+ } while (tse_tmp != cnd->q);
+
+ dequeue(&cnd->q, tse, tse_end);
+
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+
+ enqueue_mtx(mtx, tse, tse_end);
+ }
+
+ } while (!got_all);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+}
+
+int
+ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
+{
+ int woken;
+ int scnt;
+ int res;
+ void *udata = NULL;
+ ethr_ts_event *tse;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+ ETHR_ASSERT(mtx);
+ ETHR_ASSERT(mtx->initialized == ETHR_MUTEX_INITIALIZED);
+
+ tse = ethr_get_ts_event();
+
+ scnt = ((tse->iflgs & ETHR_TS_EV_MAIN_THR)
+ ? cnd->main_scnt
+ : cnd->aux_scnt);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ udata = tse->udata; /* Got to restore udata before returning */
+ tse->udata = (void *) mtx;
+
+ tse->uflgs = ETHR_RWMTX_W_WAIT_FLG__; /* Prep for mutex lock op */
+ ethr_atomic_set(&tse->uaflgs, ETHR_CND_WAIT_FLG__);
+
+ ETHR_MTX_Q_LOCK(&cnd->qlck);
+
+ enqueue(&cnd->q, tse, tse);
+
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+
+ ethr_mutex_unlock(mtx);
+
+ /* Wait */
+ woken = 0;
+ while (1) {
+ long act;
+
+ ethr_event_reset(&tse->event);
+
+ act = ethr_atomic_read_acqb(&tse->uaflgs);
+ if (!act)
+ break; /* Mtx locked */
+
+ /* First time, got EINTR, or spurious wakeup... */
+
+ ETHR_ASSERT(act == ETHR_CND_WAIT_FLG__
+ || act == ETHR_RWMTX_W_WAIT_FLG__);
+
+ if (woken) {
+ /*
+ * If act == ETHR_RWMTX_W_WAIT_FLG__, we have already been enqueued
+ * on the mutex; continue wait until locked...
+ */
+ if (act == ETHR_CND_WAIT_FLG__) {
+ ETHR_MTX_Q_LOCK(&cnd->qlck);
+ act = ethr_atomic_read(&tse->uaflgs);
+ ETHR_ASSERT(act == ETHR_CND_WAIT_FLG__
+ || act == ETHR_RWMTX_W_WAIT_FLG__);
+ /*
+ * If act == ETHR_RWMTX_W_WAIT_FLG__, we have already
+ * enqueued on the mutex; continue wait until locked...
+ */
+ if (act == ETHR_CND_WAIT_FLG__)
+ dequeue(&cnd->q, tse, tse);
+
+ ETHR_MTX_Q_UNLOCK(&cnd->qlck);
+
+ if (act == ETHR_CND_WAIT_FLG__) {
+ tse->udata = udata;
+ ethr_leave_ts_event(tse);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ethr_mutex_lock(mtx);
+ return EINTR;
+ }
+ }
+ ETHR_ASSERT(act == ETHR_RWMTX_W_WAIT_FLG__);
+ }
+ ethr_event_swait(&tse->event, scnt);
+ /* swait result: 0 || EINTR */
+ woken = 1;
+ }
+
+ ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&mtx->mtxb);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(cnd);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(mtx);
+
+ tse->udata = udata;
+ ethr_leave_ts_event(tse);
+ return 0;
+}
+
+#else
+/* -- pthread mutex and condition variables -------------------------------- */
+
+int
+ethr_mutex_init(ethr_mutex *mtx)
+{
+#if ETHR_XCHK
+ if (!mtx) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ mtx->initialized = ETHR_MUTEX_INITIALIZED;
+#endif
+ return pthread_mutex_init(&mtx->pt_mtx, NULL);
+}
+
+int
+ethr_mutex_destroy(ethr_mutex *mtx)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+#if ETHR_XCHK
+ mtx->initialized = 0;
+#endif
+ return pthread_mutex_destroy(&mtx->pt_mtx);
+}
+
+int
+ethr_cond_init(ethr_cond *cnd)
+{
+#if ETHR_XCHK
+ if (!cnd) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ cnd->initialized = ETHR_COND_INITIALIZED;
+#endif
+ return pthread_cond_init(&cnd->pt_cnd, NULL);
+}
+
+int
+ethr_cond_destroy(ethr_cond *cnd)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ cnd->initialized = 0;
+#endif
+ return pthread_cond_destroy(&cnd->pt_cnd);
+}
+
+void
+ethr_cond_signal(ethr_cond *cnd)
+{
+ int res;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+
+ res = pthread_cond_signal(&cnd->pt_cnd);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+void
+ethr_cond_broadcast(ethr_cond *cnd)
+{
+ int res;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+
+ res = pthread_cond_broadcast(&cnd->pt_cnd);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+}
+
+int
+ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
+{
+ int res;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(cnd);
+ ETHR_ASSERT(cnd->initialized == ETHR_COND_INITIALIZED);
+ ETHR_ASSERT(mtx);
+ ETHR_ASSERT(mtx->initialized == ETHR_MUTEX_INITIALIZED);
+
+ res = pthread_cond_wait(&cnd->pt_cnd, &mtx->pt_mtx);
+ if (res != 0 && res != EINTR)
+ ETHR_FATAL_ERROR__(res);
+ return res;
+}
+
+#endif /* pthread_mutex */
+
+/* -- Exported symbols of inline functions --------------------------------- */
+
+int
+ethr_mutex_trylock(ethr_mutex *mtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(mtx);
+ ETHR_ASSERT(mtx->initialized == ETHR_MUTEX_INITIALIZED);
+
+ return ethr_mutex_trylock__(mtx);
+}
+
+void
+ethr_mutex_lock(ethr_mutex *mtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(mtx);
+ ETHR_ASSERT(mtx->initialized == ETHR_MUTEX_INITIALIZED);
+
+ ethr_mutex_lock__(mtx);
+}
+
+void
+ethr_mutex_unlock(ethr_mutex *mtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(mtx);
+ ETHR_ASSERT(mtx->initialized == ETHR_MUTEX_INITIALIZED);
+
+ ethr_mutex_unlock__(mtx);
+}
+
+
+#ifdef ETHR_USE_OWN_RWMTX_IMPL__
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Read/Write Mutex *
+\* */
+
+static void
+wake_readers(ethr_rwmutex *rwmtx, int rs)
+{
+ ethr_ts_event *tse;
+#ifdef ETHR_DEBUG
+ int drs = 0;
+#endif
+
+ tse = rwmtx->mtxb.q;
+ ETHR_ASSERT(tse);
+ ETHR_ASSERT(rwmtx->rq_end);
+ dequeue(&rwmtx->mtxb.q, tse, rwmtx->rq_end);
+ rwmtx->rq_end->next = NULL;
+ rwmtx->rq_end = NULL;
+
+ ETHR_ASSERT(!rwmtx->mtxb.q
+ || (ethr_atomic_read(&rwmtx->mtxb.q->uaflgs)
+ == ETHR_RWMTX_W_WAIT_FLG__));
+
+ ETHR_RWMTX_HARD_DEBUG_CHK_Q(rwmtx);
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+
+ while (tse) {
+ ethr_ts_event *tse_next;
+
+#ifdef ETHR_DEBUG
+ ETHR_ASSERT(tse->uflgs == ETHR_RWMTX_R_WAIT_FLG__);
+ ETHR_ASSERT(ethr_atomic_read(&tse->uaflgs)
+ == ETHR_RWMTX_R_WAIT_FLG__);
+ drs++;
+#endif
+
+ tse_next = tse->next; /* we aren't allowed to read tse->next
+ after we have reset uaflgs */
+
+ ethr_atomic_set(&tse->uaflgs, 0);
+ ethr_event_set(&tse->event);
+ tse = tse_next;
+ }
+
+ ETHR_ASSERT(rs == drs);
+}
+
+static ETHR_INLINE int
+is_w_waiter(ethr_ts_event *tse)
+{
+ ETHR_ASSERT(tse->uflgs == ETHR_RWMTX_W_WAIT_FLG__
+ || tse->uflgs == ETHR_RWMTX_R_WAIT_FLG__);
+ return tse->uflgs == ETHR_RWMTX_W_WAIT_FLG__;
+}
+
+static ETHR_INLINE int
+multiple_w_waiters(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(rwmtx->mtxb.q);
+ ETHR_ASSERT(rwmtx->mtxb.q->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+
+ if (!rwmtx->rq_end)
+ return rwmtx->mtxb.q->next != rwmtx->mtxb.q;
+ else {
+ ETHR_ASSERT(rwmtx->mtxb.q->next != rwmtx->mtxb.q);
+ if (rwmtx->mtxb.q->next->uflgs == ETHR_RWMTX_W_WAIT_FLG__)
+ return 1;
+ ETHR_ASSERT(rwmtx->rq_end->next == rwmtx->mtxb.q
+ || rwmtx->rq_end->next->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+ return rwmtx->rq_end->next != rwmtx->mtxb.q;
+ }
+}
+
+int check_readers_array(ethr_rwmutex *rwmtx,
+ int start_rix,
+ int length,
+ int pre_check)
+{
+ int ix = start_rix;
+
+#ifndef ETHR_READ_MEMORY_BARRIER_IS_FULL
+ if (pre_check)
+ ETHR_READ_MEMORY_BARRIER;
+ else
+#endif
+ ETHR_MEMORY_BARRIER;
+
+ do {
+ long act = rwmutex_freqread_rdrs_read(rwmtx, ix);
+ if (act != 0)
+ return EBUSY;
+ ix++;
+ if (ix == length)
+ ix = 0;
+ } while (ix != start_rix);
+
+ return 0;
+}
+
+static ETHR_INLINE void
+rwmutex_freqread_restore_failed_tryrlock(ethr_rwmutex *rwmtx,
+ ethr_ts_event *tse)
+{
+ long act;
+ /*
+ * Restore failed increment
+ */
+ act = rwmutex_freqread_rdrs_dec_read(rwmtx, tse);
+
+ ETHR_WRITE_MEMORY_BARRIER;
+
+ if (act == 0) {
+
+#ifndef ETHR_WRITE_MEMORY_BARRIER_IS_FULL
+ ETHR_READ_MEMORY_BARRIER;
+#endif
+
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ if ((act & ETHR_RWMTX_W_FLG__) == 0
+ && act & (ETHR_RWMTX_WAIT_FLGS__|ETHR_RWMTX_R_PEND_UNLCK_MASK__)) {
+ /*
+ * We either got waiters, or someone else trying
+ * to read unlock which we might have to help.
+ */
+ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 1, 0);
+ }
+ }
+}
+
+static int
+rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx,
+ long initial,
+ ethr_ts_event *tse,
+ int start_next_ix,
+ int check_before_try,
+ int try_write_lock)
+{
+ ethr_ts_event *tse_tmp;
+ long act = initial;
+ int six, res, length;
+
+ tse_tmp = tse;
+ if (!tse_tmp)
+ tse_tmp = ethr_get_ts_event();
+
+ if ((act & ETHR_RWMTX_WAIT_FLGS__)
+ && (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0)
+ goto check_waiters;
+
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_FREQUENT_READ) {
+ length = reader_groups_array_size;
+ six = tse_tmp->rgix;
+ }
+ else {
+ length = main_threads_array_size;
+ six = tse_tmp->mtix;
+ }
+ if (start_next_ix) {
+ six++;
+ if (six >= length)
+ six = 0;
+ }
+
+ if (!tse)
+ ethr_leave_ts_event(tse_tmp);
+
+ if (check_before_try) {
+ res = check_readers_array(rwmtx, six, length, 1);
+ if (res == EBUSY)
+ return try_write_lock ? EBUSY : 0;
+ }
+
+ while (1) {
+ long exp = act;
+ long new = act+1;
+
+ ETHR_ASSERT((act & ETHR_RWMTX_R_PEND_UNLCK_MASK__)
+ < ETHR_RWMTX_R_PEND_UNLCK_MASK__);
+
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (exp == act) {
+ act = new;
+ break;
+ }
+ if (!try_write_lock) {
+ if (act == ETHR_RWMTX_W_FLG__ || act == 0)
+ return 0;
+ if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ if ((act & ETHR_RWMTX_R_FLG__) == 0)
+ return 0;
+ }
+ else if ((act & ETHR_RWMTX_R_FLG__) == 0) {
+ if (act & ETHR_RWMTX_R_PEND_UNLCK_MASK__)
+ return 0;
+ goto check_waiters;
+ }
+ }
+ else {
+ if (act == 0)
+ goto tryrwlock;
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_WAIT_FLGS__))
+ return EBUSY;
+ }
+ }
+
+ res = check_readers_array(rwmtx, six, length, 0);
+ if (res == EBUSY) {
+ act = ethr_atomic_dec_read(&rwmtx->mtxb.flgs);
+ if (act & ETHR_RWMTX_R_MASK__)
+ return try_write_lock ? EBUSY : 0;
+ }
+ else {
+ while (1) {
+ long exp = act;
+ long new = act;
+ new &= ~ETHR_RWMTX_R_FLG__;
+ new--;
+
+ ETHR_ASSERT(act & ETHR_RWMTX_R_PEND_UNLCK_MASK__);
+
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (exp == act) {
+ if (new & ETHR_RWMTX_R_PEND_UNLCK_MASK__)
+ return try_write_lock ? EBUSY : 0;
+ act = new;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Read unlock completed, but we have to check if
+ * threads have to be woken (or if we should try
+ * to write lock it).
+ */
+
+ if (act & ETHR_RWMTX_W_FLG__)
+ return try_write_lock ? EBUSY : 0;
+
+ if (act & ETHR_RWMTX_WAIT_FLGS__) {
+ check_waiters:
+ rwmutex_unlock_wake(rwmtx, 0, act);
+ return try_write_lock ? EBUSY : 0;
+ }
+
+ if (!try_write_lock)
+ return 0;
+
+ tryrwlock:
+ /* Try to write lock it */
+
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__,
+ 0);
+ return act == 0 ? 0 : EBUSY;
+}
+
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+
+static ETHR_INLINE void
+rwmutex_incdec_restore_failed_tryrlock(ethr_rwmutex *rwmtx)
+{
+ long act;
+ /*
+ * Restore failed increment
+ */
+ act = ethr_atomic_dec_read(&rwmtx->mtxb.flgs);
+ if ((act & ETHR_RWMTX_WAIT_FLGS__)
+ && (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ rwmutex_unlock_wake(rwmtx, 0, act);
+ }
+}
+
+#endif
+
+static void
+rwmutex_normal_rlock_wait(ethr_rwmutex *rwmtx,
+ long initial)
+{
+ long act = initial, exp;
+ int scnt, start_scnt;
+ ethr_ts_event *tse = NULL;
+ int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+
+ start_scnt = scnt = initial_spincount(&rwmtx->mtxb);
+
+ /*
+ * Spin trying to read lock for a while. If unsuccessful,
+ * wait on event.
+ */
+
+ while (1) {
+
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ rwmutex_incdec_restore_failed_tryrlock(rwmtx);
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+#endif
+
+ while (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
+ if (scnt == 0) {
+ tse = ethr_get_ts_event();
+ if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) {
+ event_wait(&rwmtx->mtxb, tse, scnt,
+ ETHR_RWMTX_R_WAIT_FLG__, 1, 0);
+ goto done;
+ }
+ }
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ ETHR_YIELD();
+ }
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ scnt--;
+ }
+ exp = act;
+ ETHR_ASSERT(scnt >= 0);
+
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ act = ethr_atomic_inc_read(&rwmtx->mtxb.flgs);
+ if ((act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) == 0)
+ goto done; /* Got it */
+#else
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, exp+1, exp);
+ if (act == exp)
+ goto done; /* Got it */
+#endif
+ }
+
+ done:
+ if (tse)
+ ethr_leave_ts_event(tse);
+}
+
+static void
+rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx,
+ ethr_ts_event *tse,
+ long initial)
+{
+ long act = initial;
+ int scnt, start_scnt;
+ int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+
+ start_scnt = scnt = initial_spincount(&rwmtx->mtxb);
+
+ /*
+ * Spin trying to read lock for a while. If unsuccessful,
+ * wait on event.
+ */
+
+ while (1) {
+
+ rwmutex_freqread_restore_failed_tryrlock(rwmtx, tse);
+
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ while (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
+ if (scnt == 0) {
+ if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) {
+ event_wait(&rwmtx->mtxb, tse, scnt,
+ ETHR_RWMTX_R_WAIT_FLG__, 1, 1);
+ return; /* Got it */
+ }
+ }
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ ETHR_YIELD();
+ }
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ scnt--;
+ }
+
+ ETHR_ASSERT(scnt >= 0);
+
+ rwmutex_freqread_rdrs_inc(rwmtx, tse);
+
+ ETHR_MEMORY_BARRIER;
+
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ if (act == ETHR_RWMTX_R_FLG__)
+ return; /* Got it */
+
+ while (1) {
+ long exp, new;
+
+ if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__))
+ break; /* Busy (need to restore inc) */
+
+ if (act & ETHR_RWMTX_R_FLG__)
+ return; /* Got it */
+
+ exp = act;
+ new = act | ETHR_RWMTX_R_FLG__;
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ return; /* Got it */
+ }
+ }
+}
+
+static void
+rwmutex_normal_rwlock_wait(ethr_rwmutex *rwmtx, long initial)
+{
+ write_lock_wait(&rwmtx->mtxb, initial, 1, 0);
+}
+
+static void
+rwmutex_freqread_rwlock_wait(ethr_rwmutex *rwmtx, long initial)
+{
+ write_lock_wait(&rwmtx->mtxb, initial, 1, 1);
+}
+
+static ETHR_INLINE void
+rwlock_wake_set_flags(ethr_rwmutex *rwmtx, long new_initial, int act_initial)
+{
+ long act, act_mask;
+ if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL) {
+ /* r pend unlock mask may vary and must be retained */
+ act_mask = ETHR_RWMTX_R_PEND_UNLCK_MASK__;
+ }
+ else {
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ /* rs mask may vary and must be retained */
+ act_mask = ETHR_RWMTX_RS_MASK__;
+#else
+ /* rs mask always zero */
+ ETHR_ASSERT((act_initial & ETHR_RWMTX_RS_MASK__) == 0);
+ ethr_atomic_set(&rwmtx->mtxb.flgs, new_initial);
+ return;
+#endif
+ }
+
+ act = act_initial;
+ while (1) {
+ long exp = act;
+ long new = new_initial + (act & act_mask);
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ break;
+ exp = act;
+ }
+}
+
+#ifdef ETHR_DEBUG
+
+static void
+dbg_unlock_wake(ethr_rwmutex *rwmtx,
+ int have_w,
+ ethr_ts_event *tse)
+{
+ long exp, act, imask;
+
+ exp = have_w ? ETHR_RWMTX_W_FLG__ : 0;
+
+ if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL)
+ imask = ETHR_RWMTX_R_PEND_UNLCK_MASK__;
+ else {
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ imask = ETHR_RWMTX_RS_MASK__;
+#else
+ imask = 0;
+#endif
+ }
+
+ ETHR_ASSERT(tse);
+
+ if (is_w_waiter(tse)) {
+
+ exp |= ETHR_RWMTX_W_WAIT_FLG__;
+ if (rwmtx->rq_end) {
+ exp |= ETHR_RWMTX_R_WAIT_FLG__;
+ }
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ ETHR_ASSERT((exp & ~imask) == (act & ~imask));
+
+ ETHR_RWMTX_HARD_DEBUG_CHK_Q(rwmtx);
+
+ }
+ else {
+
+ exp |= ETHR_RWMTX_R_WAIT_FLG__;
+ if (rwmtx->rq_end->next != rwmtx->mtxb.q)
+ exp |= ETHR_RWMTX_W_WAIT_FLG__;
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ ETHR_ASSERT((exp & ~imask) == (act & ~imask));
+
+ ETHR_RWMTX_HARD_DEBUG_CHK_Q(rwmtx);
+
+ }
+}
+
+#endif
+
+static void
+rwmutex_unlock_wake(ethr_rwmutex *rwmtx, int have_w, long initial)
+{
+ long new, act = initial;
+ ethr_ts_event *tse;
+
+ if ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ if (!have_w)
+ return;
+ else {
+ while ((act & ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ long exp = act;
+ new = exp & ~ETHR_RWMTX_W_FLG__;
+ act = ethr_atomic_cmpxchg(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ return;
+ }
+ }
+ }
+
+ ETHR_MTX_Q_LOCK(&rwmtx->mtxb.qlck);
+ tse = rwmtx->mtxb.q;
+
+ if (!have_w) {
+ if (!tse) {
+#ifdef ETHR_DEBUG
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ ETHR_ASSERT((act & ETHR_RWMTX_WAIT_FLGS__) == 0);
+#endif
+ goto already_served;
+ }
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ if (act & ~ETHR_RWMTX_WAIT_FLGS__) {
+ already_served:
+ ETHR_MTX_Q_UNLOCK(&rwmtx->mtxb.qlck);
+ return;
+ }
+ }
+
+#ifdef ETHR_DEBUG
+ dbg_unlock_wake(rwmtx, have_w, tse);
+#endif
+
+ if (is_w_waiter(tse)) {
+
+ if (!have_w) {
+ act = ethr_atomic_read_bor(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__);
+ ETHR_ASSERT((act & ~ETHR_RWMTX_WAIT_FLGS__) == 0);
+ ETHR_ASSERT(act & ETHR_RWMTX_W_WAIT_FLG__);
+ act |= ETHR_RWMTX_W_FLG__;
+ }
+
+ /*
+ * If we have multiple write waiters, there
+ * is no need to modify mtxb->flgs; otherwise,
+ * we need to clear the write wait bit...
+ */
+ if (!multiple_w_waiters(rwmtx)) {
+ new = ETHR_RWMTX_W_FLG__;
+ if (tse->next != rwmtx->mtxb.q) {
+ ETHR_ASSERT(tse->next->uflgs == ETHR_RWMTX_R_WAIT_FLG__);
+ new |= ETHR_RWMTX_R_WAIT_FLG__;
+ }
+
+ rwlock_wake_set_flags(rwmtx, new, act);
+ }
+
+ wake_writer(&rwmtx->mtxb, 1);
+ }
+ else {
+ int rs;
+
+ if (rwmtx->type == ETHR_RWMUTEX_TYPE_NORMAL) {
+ rs = rwmtx->tdata.rs;
+ new = (long) rs;
+ rwmtx->tdata.rs = 0;
+ }
+ else {
+ ethr_rwmutex_type type = rwmtx->type;
+ int length = (type == ETHR_RWMUTEX_TYPE_FREQUENT_READ
+ ? reader_groups_array_size
+ : main_threads_array_size);
+ int ix;
+
+ rs = 0;
+ for (ix = 0; ix < length; ix++) {
+ int wrs = rwmtx->tdata.ra[ix].data.waiting_readers;
+ rwmtx->tdata.ra[ix].data.waiting_readers = 0;
+ ETHR_ASSERT(wrs >= 0);
+ if (wrs) {
+ rs += wrs;
+ rwmutex_freqread_rdrs_add(rwmtx, type, ix, wrs);
+ }
+ }
+ new = ETHR_RWMTX_R_FLG__;
+ }
+
+ if (rwmtx->rq_end->next != rwmtx->mtxb.q)
+ new |= ETHR_RWMTX_W_WAIT_FLG__;
+
+ rwlock_wake_set_flags(rwmtx, new, act);
+ wake_readers(rwmtx, rs);
+ }
+}
+
+static ethr_rwmtx_readers_array__ *
+alloc_readers_array(int length, ethr_rwmutex_lived lived)
+{
+ ethr_rwmtx_readers_array__ *ra;
+ size_t sz;
+ void *mem;
+
+ sz = sizeof(ethr_rwmtx_readers_array__) * (length + 1);
+
+ switch (lived) {
+ case ETHR_RWMUTEX_LONG_LIVED:
+ mem = ethr_mem__.ll.alloc(sz);
+ break;
+ case ETHR_RWMUTEX_SHORT_LIVED:
+ mem = ethr_mem__.sl.alloc(sz);
+ break;
+ default:
+ mem = ethr_mem__.std.alloc(sz);
+ break;
+ }
+ if (!mem)
+ return NULL;
+
+ if ((((unsigned long) mem) & ETHR_CACHE_LINE_MASK) == 0) {
+ ra = (ethr_rwmtx_readers_array__ *) mem;
+ ra->data.byte_offset = 0;
+ }
+ else {
+ ra = ((ethr_rwmtx_readers_array__ *)
+ ((((unsigned long) mem) & ~ETHR_CACHE_LINE_MASK)
+ + ETHR_CACHE_LINE_SIZE));
+ ra->data.byte_offset = (int) ((unsigned long) ra
+ - (unsigned long) mem);
+ }
+ ra->data.lived = lived;
+ return ra;
+}
+
+static void
+free_readers_array(ethr_rwmtx_readers_array__ *ra)
+{
+ void *ptr = (void *) (((char *) ra) - ra->data.byte_offset);
+ switch (ra->data.lived) {
+ case ETHR_RWMUTEX_LONG_LIVED:
+ ethr_mem__.ll.free(ptr);
+ break;
+ case ETHR_RWMUTEX_SHORT_LIVED:
+ ethr_mem__.sl.free(ptr);
+ break;
+ default:
+ ethr_mem__.std.free(ptr);
+ break;
+ }
+}
+
+int
+ethr_rwmutex_init_opt(ethr_rwmutex *rwmtx, ethr_rwmutex_opt *opt)
+{
+ int res;
+ ethr_rwmtx_readers_array__ *ra = NULL;
+#if ETHR_XCHK
+ if (ethr_not_completely_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!rwmtx) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
+#endif
+ ETHR_MTX_HARD_DEBUG_FENCE_INIT(rwmtx);
+ rwmtx->rq_end = NULL;
+ rwmtx->type = opt ? opt->type : ETHR_RWMUTEX_TYPE_NORMAL;
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ if (main_threads_array_size <= reader_groups_array_size) {
+ /* No point using reader groups... */
+ rwmtx->type = ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ;
+ }
+ /* Fall through */
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
+ int length;
+
+ length = (rwmtx->type == ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ
+ ? main_threads_array_size
+ : reader_groups_array_size);
+
+ if (length == 1) {
+ /* No point using a frequent reader type... */
+ rwmtx->type = ETHR_RWMUTEX_TYPE_NORMAL;
+ }
+ else {
+ int ix;
+ ra = alloc_readers_array(length,
+ (opt
+ ? opt->lived
+ : ETHR_RWMUTEX_UNKNOWN_LIVED));
+ if (!ra) {
+ res = ENOMEM;
+ goto error;
+ }
+
+ rwmtx->tdata.ra = ra;
+
+ for (ix = 0; ix < length; ix++) {
+ ethr_atomic_init(&rwmtx->tdata.ra[ix].data.readers, 0);
+ rwmtx->tdata.ra[ix].data.waiting_readers = 0;
+ }
+ break;
+ }
+ }
+ case ETHR_RWMUTEX_TYPE_NORMAL:
+ rwmtx->tdata.rs = 0;
+ break;
+ default:
+ res = EINVAL;
+ goto error;
+ }
+ res = mtxb_init(&rwmtx->mtxb,
+ default_rwmtx_main_spincount,
+ opt ? opt->main_spincount : -1,
+ default_rwmtx_aux_spincount,
+ opt ? opt->aux_spincount : -1);
+ if (res == 0)
+ return 0;
+
+ error:
+
+ if (ra)
+ free_readers_array(ra);
+
+#if ETHR_XCHK
+ rwmtx->initialized = 0;
+#endif
+ return res;
+}
+
+int
+ethr_rwmutex_init(ethr_rwmutex *rwmtx)
+{
+ return ethr_rwmutex_init_opt(rwmtx, NULL);
+}
+
+int
+ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
+{
+ int res;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL) {
+ long act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ if (act == ETHR_RWMTX_R_FLG__)
+ rwmutex_try_complete_runlock(rwmtx, act, NULL, 0, 0, 0);
+ }
+ res = mtxb_destroy(&rwmtx->mtxb);
+ if (res != 0)
+ return res;
+ if (rwmtx->type != ETHR_RWMUTEX_TYPE_NORMAL)
+ free_readers_array(rwmtx->tdata.ra);
+#if ETHR_XCHK
+ rwmtx->initialized = 0;
+#endif
+ return 0;
+}
+
+#define ETHR_MAX_TRYRLOCK_TRIES 5
+
+int
+ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
+{
+ int res = 0;
+ long act;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL: {
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__))
+ res = EBUSY;
+ else {
+ act = ethr_atomic_inc_read_acqb(&rwmtx->mtxb.flgs);
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
+ rwmutex_incdec_restore_failed_tryrlock(rwmtx);
+ res = EBUSY;
+ }
+ }
+#else
+ long exp = 0;
+ int tries = 0;
+
+ while (1) {
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, exp+1, exp);
+ if (act == exp) {
+ res = 0;
+ break;
+ }
+ if (tries > ETHR_MAX_TRYRLOCK_TRIES
+ || (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__))) {
+ res = EBUSY;
+ break;
+ }
+ tries++;
+ exp = act;
+ }
+#endif
+ break;
+ }
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
+ ethr_ts_event *tse = ethr_get_ts_event();
+
+ rwmutex_freqread_rdrs_inc(rwmtx, tse);
+
+ ETHR_MEMORY_BARRIER;
+
+ act = ethr_atomic_read_acqb(&rwmtx->mtxb.flgs);
+
+ if (act != ETHR_RWMTX_R_FLG__) {
+ while (1) {
+ long exp, new;
+
+ if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
+ rwmutex_freqread_restore_failed_tryrlock(rwmtx, tse);
+ res = EBUSY;
+ break;
+ }
+
+ if (act & ETHR_RWMTX_R_FLG__)
+ break;
+
+ exp = act;
+ new = act | ETHR_RWMTX_R_FLG__;
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ break;
+ }
+ }
+
+ ethr_leave_ts_event(tse);
+ break;
+ }
+ }
+
+ ETHR_MTX_HARD_DEBUG_LFS_TRYRLOCK(&rwmtx->mtxb, res);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ return res;
+}
+
+void
+ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
+{
+ long act;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL: {
+#ifdef ETHR_RLOCK_WITH_INC_DEC
+ act = ethr_atomic_inc_read_acqb(&rwmtx->mtxb.flgs);
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__))
+ rwmutex_normal_rlock_wait(rwmtx, act);
+#else
+ long exp = 0;
+
+ while (1) {
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, exp+1, exp);
+ if (act == exp) {
+ break;
+ }
+
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) {
+ rwmutex_normal_rlock_wait(rwmtx, act);
+ break;
+ }
+ exp = act;
+ }
+#endif
+ break;
+ }
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
+ ethr_ts_event *tse = ethr_get_ts_event();
+
+ rwmutex_freqread_rdrs_inc(rwmtx, tse);
+
+ ETHR_MEMORY_BARRIER;
+
+ act = ethr_atomic_read_acqb(&rwmtx->mtxb.flgs);
+
+ if (act != ETHR_RWMTX_R_FLG__) {
+ while (1) {
+ long exp, new;
+
+ if (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) {
+ rwmutex_freqread_rlock_wait(rwmtx, tse, act);
+ break;
+ }
+
+ if (act & ETHR_RWMTX_R_FLG__)
+ break;
+
+ exp = act;
+ new = act | ETHR_RWMTX_R_FLG__;
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs, new, exp);
+ if (act == exp)
+ break;
+ }
+ }
+
+ ethr_leave_ts_event(tse);
+ break;
+ }
+ }
+
+ ETHR_MTX_HARD_DEBUG_LFS_RLOCK(&rwmtx->mtxb);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+}
+
+void
+ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
+{
+ long act;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+ ETHR_MTX_HARD_DEBUG_LFS_RUNLOCK(&rwmtx->mtxb);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL:
+ act = ethr_atomic_dec_read_relb(&rwmtx->mtxb.flgs);
+ if ((act & ETHR_RWMTX_WAIT_FLGS__)
+ && (act & ~ETHR_RWMTX_WAIT_FLGS__) == 0) {
+ ETHR_ASSERT((act & ETHR_RWMTX_W_FLG__) == 0);
+ rwmutex_unlock_wake(rwmtx, 0, act);
+ }
+ break;
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ: {
+ ethr_ts_event *tse = ethr_get_ts_event();
+
+ act = rwmutex_freqread_rdrs_dec_read_relb(rwmtx, tse);
+
+ ETHR_ASSERT(act >= 0);
+
+ ETHR_WRITE_MEMORY_BARRIER;
+
+ if (act == 0) {
+
+#ifndef ETHR_WRITE_MEMORY_BARRIER_IS_FULL
+ ETHR_READ_MEMORY_BARRIER;
+#endif
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ if ((act & ETHR_RWMTX_W_FLG__) == 0
+ && (act & (ETHR_RWMTX_WAIT_FLGS__
+ | ETHR_RWMTX_R_PEND_UNLCK_MASK__))) {
+ rwmutex_try_complete_runlock(rwmtx, act, tse, 1, 0, 0);
+ }
+
+ }
+
+ ethr_leave_ts_event(tse);
+ break;
+ }
+ }
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+}
+
+int
+ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
+{
+ int res = 0;
+ long act;
+
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL:
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__, 0);
+ if (act != 0)
+ res = EBUSY;
+ break;
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ:
+
+ res = 0;
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ do {
+
+ if (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_WAIT_FLGS__)) {
+ res = EBUSY;
+ break;
+ }
+
+ if (act & ETHR_RWMTX_R_MASK__) {
+ res = rwmutex_try_complete_runlock(rwmtx, act, NULL,
+ 0, 1, 1);
+ break;
+ }
+
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__, 0);
+
+ } while (act != 0);
+
+ break;
+ }
+
+ ETHR_MTX_HARD_DEBUG_LFS_TRYRWLOCK(&rwmtx->mtxb, res);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ return res;
+}
+
+void
+ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
+{
+ long act;
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL:
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__, 0);
+ if (act != 0)
+ rwmutex_normal_rwlock_wait(rwmtx, act);
+ break;
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ:
+
+ act = ethr_atomic_read(&rwmtx->mtxb.flgs);
+
+ do {
+
+ if (act != 0) {
+ rwmutex_freqread_rwlock_wait(rwmtx, act);
+ break;
+ }
+
+ act = ethr_atomic_cmpxchg_acqb(&rwmtx->mtxb.flgs,
+ ETHR_RWMTX_W_FLG__, 0);
+
+ } while (act != 0);
+
+ break;
+ }
+
+ ETHR_MTX_HARD_DEBUG_LFS_RWLOCK(&rwmtx->mtxb);
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+
+}
+
+void
+ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
+{
+ long act;
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+ ETHR_MTX_HARD_DEBUG_LFS_RWUNLOCK(&rwmtx->mtxb);
+
+ switch (rwmtx->type) {
+ case ETHR_RWMUTEX_TYPE_NORMAL:
+ act = ethr_atomic_cmpxchg_relb(&rwmtx->mtxb.flgs,
+ 0, ETHR_RWMTX_W_FLG__);
+ if (act != ETHR_RWMTX_W_FLG__)
+ rwmutex_unlock_wake(rwmtx, 1, act);
+ break;
+
+ case ETHR_RWMUTEX_TYPE_FREQUENT_READ:
+ case ETHR_RWMUTEX_TYPE_EXTREMELY_FREQUENT_READ:
+ act = ethr_atomic_cmpxchg_relb(&rwmtx->mtxb.flgs, 0,
+ ETHR_RWMTX_W_FLG__);
+ if (act != ETHR_RWMTX_W_FLG__)
+ rwmutex_unlock_wake(rwmtx, 1, act);
+ break;
+ }
+
+ ETHR_MTX_HARD_DEBUG_FENCE_CHK(rwmtx);
+}
+
+#else
+/* -- pthread read/write mutex --------------------------------------------- */
+
+int
+ethr_rwmutex_init(ethr_rwmutex *rwmtx)
+{
+#if ETHR_XCHK
+ if (!rwmtx) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+ rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
+#endif
+ return pthread_rwlock_init(&rwmtx->pt_rwlock, write_pref_attr);
+}
+
+int
+ethr_rwmutex_init_opt(ethr_rwmutex *rwmtx, ethr_rwmutex_opt *opt)
+{
+ return ethr_rwmutex_init(rwmtx);
+}
+
+int
+ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
+{
+ int res;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ res = pthread_rwlock_destroy(&rwmtx->pt_rwlock);
+#if ETHR_XCHK
+ rwmtx->initialized = 0;
+#endif
+ return res;
+}
+
+/* -- Exported symbols of inline functions --------------------------------- */
+
+int
+ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ return ethr_rwmutex_tryrlock__(rwmtx);
+}
+
+void
+ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ethr_rwmutex_rlock__(rwmtx);
+}
+
+void
+ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ethr_rwmutex_runlock__(rwmtx);
+}
+
+int
+ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ return ethr_rwmutex_tryrwlock__(rwmtx);
+}
+
+void
+ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ return ethr_rwmutex_rwlock__(rwmtx);
+}
+
+void
+ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
+{
+ ETHR_ASSERT(!ethr_not_inited__);
+ ETHR_ASSERT(rwmtx);
+ ETHR_ASSERT(rwmtx->initialized == ETHR_RWMUTEX_INITIALIZED);
+
+ ethr_rwmutex_rwunlock__(rwmtx);
+}
+
+#endif /* pthread */
+
+
+#if defined(ETHR_USE_OWN_RWMTX_IMPL__) || defined(ETHR_USE_OWN_MTX_IMPL__)
+
+#ifdef ETHR_MTX_HARD_DEBUG_Q
+static void
+hard_debug_chk_q__(struct ethr_mutex_base_ *mtxb, int is_rwmtx)
+{
+ int res;
+ long flgs = ethr_atomic_read(&mtxb->flgs);
+
+ ETHR_MTX_HARD_ASSERT(res == 0);
+
+ ETHR_MTX_HARD_ASSERT(!(flgs & ETHR_RWMTX_R_WAIT_FLG__) || is_rwmtx);
+
+ if (!(flgs & ETHR_RWMTX_WAIT_FLGS__)) {
+ ETHR_MTX_HARD_ASSERT(!mtxb->q);
+ if (is_rwmtx) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(!rwmtx->rq_end);
+ ETHR_MTX_HARD_ASSERT(!rwmtx->rs);
+ }
+ }
+ else {
+ ethr_ts_event *tse;
+ int ws = 0, rs = 0, rsf = 0, ref = 0;
+
+ ETHR_MTX_HARD_ASSERT(mtxb->q);
+
+ tse = mtxb->q;
+
+ do {
+ long type;
+
+ ETHR_MTX_HARD_ASSERT(tse->next->prev == tse);
+ ETHR_MTX_HARD_ASSERT(tse->prev->next == tse);
+
+ type = ethr_atomic_read(&tse->uaflgs);
+ ETHR_MTX_HARD_ASSERT(type == tse->uflgs);
+ switch (type) {
+ case ETHR_RWMTX_W_WAIT_FLG__:
+ ws++;
+ break;
+ case ETHR_RWMTX_R_WAIT_FLG__: {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(is_rwmtx);
+ if (!rsf)
+ rsf = 1;
+ ETHR_MTX_HARD_ASSERT(!ref);
+ if (rwmtx->rq_end == tse) {
+ ETHR_MTX_HARD_ASSERT(
+ tse->next == rwmtx->mtxb.q
+ || tse->next->uflgs == ETHR_RWMTX_W_WAIT_FLG__);
+ ref = 1;
+ }
+ rs++;
+ break;
+ }
+ default:
+ ETHR_MTX_HARD_ASSERT(! "invalid wait type found");
+ }
+
+ tse = tse->next;
+ } while (tse != mtxb->q);
+
+ if (is_rwmtx) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(rs == rwmtx->rs);
+ }
+
+#ifdef ETHR_MTX_HARD_DEBUG_WSQ
+ ETHR_MTX_HARD_ASSERT(ws == mtxb->ws);
+#endif
+
+ if (flgs & ETHR_RWMTX_W_WAIT_FLG__)
+ ETHR_MTX_HARD_ASSERT(ws);
+ else
+ ETHR_MTX_HARD_ASSERT(!ws);
+
+ if (flgs & ETHR_RWMTX_R_WAIT_FLG__) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(is_rwmtx);
+ ETHR_MTX_HARD_ASSERT(rwmtx->rq_end);
+ ETHR_MTX_HARD_ASSERT(rsf);
+ ETHR_MTX_HARD_ASSERT(ref);
+ ETHR_MTX_HARD_ASSERT(rs);
+ }
+ else {
+ if (is_rwmtx) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(!rwmtx->rq_end);
+ }
+ ETHR_MTX_HARD_ASSERT(!rsf);
+ ETHR_MTX_HARD_ASSERT(!ref);
+ ETHR_MTX_HARD_ASSERT(!rs);
+ }
+ }
+}
+
+#elif defined(ETHR_MTX_HARD_DEBUG_WSQ)
+
+static void
+hard_debug_chk_q__(struct ethr_mutex_base_ *mtxb, int is_rwmtx)
+{
+ int ws = 0;
+ int rs = 0;
+
+ if (mtxb->q) {
+ ethr_ts_event *tse = mtxb->q;
+ do {
+ switch (tse->uflgs) {
+ case ETHR_RWMTX_W_WAIT_FLG__:
+ ws++;
+ break;
+ case ETHR_RWMTX_R_WAIT_FLG__:
+ rs++;
+ break;
+ default:
+ ETHR_MTX_HARD_ASSERT(0);
+ break;
+ }
+ tse = tse->next;
+ } while (tse != mtxb->q);
+ }
+
+ ETHR_MTX_HARD_ASSERT(mtxb->ws == ws);
+ if (is_rwmtx) {
+ ethr_rwmutex *rwmtx = (ethr_rwmutex *) mtxb;
+ ETHR_MTX_HARD_ASSERT(rwmtx->rs == rs);
+ }
+}
+
+#endif
+
+#endif
diff --git a/erts/lib_src/common/ethread.c b/erts/lib_src/common/ethread.c
deleted file mode 100644
index 9c88233934..0000000000
--- a/erts/lib_src/common/ethread.c
+++ /dev/null
@@ -1,3369 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2010. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * Description: A Thread library for use in the ERTS and other OTP
- * applications.
- * Author: Rickard Green
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#undef ETHR_STACK_GUARD_SIZE
-
-#if defined(ETHR_PTHREADS)
-
-#ifdef ETHR_TIME_WITH_SYS_TIME
-# include <time.h>
-# include <sys/time.h>
-#else
-# ifdef ETHR_HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#include <sys/types.h>
-#include <unistd.h>
-#include <signal.h>
-
-#ifdef ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE
-# define ETHR_STACK_GUARD_SIZE (pagesize)
-#endif
-
-#elif defined(ETHR_WIN32_THREADS)
-
-#undef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <process.h>
-#include <winerror.h>
-
-#else
-#error "Missing thread implementation"
-#endif
-
-#include <limits.h>
-
-#define ETHR_FORCE_INLINE_FUNCS
-#define ETHR_INLINE_FUNC_NAME_(X) X ## __
-#include "ethread.h"
-
-#ifndef ETHR_HAVE_ETHREAD_DEFINES
-#error Missing configure defines
-#endif
-
-/*
- * ----------------------------------------------------------------------------
- * Common stuff
- * ----------------------------------------------------------------------------
- */
-
-#define ETHR_MAX_THREADS 2048 /* Has to be an even power of 2 */
-
-static int ethr_not_inited = 1;
-
-#define ASSERT(A) ETHR_ASSERT((A))
-
-static void *(*allocp)(size_t) = malloc;
-static void *(*reallocp)(void *, size_t) = realloc;
-static void (*freep)(void *) = free;
-
-#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
-ethr_atomic_protection_t ethr_atomic_protection__[1 << ETHR_ATOMIC_ADDR_BITS];
-#endif
-
-void *(*thread_create_prepare_func)(void) = NULL;
-void (*thread_create_parent_func)(void *) = NULL;
-void (*thread_create_child_func)(void *) = NULL;
-
-typedef struct ethr_xhndl_list_ ethr_xhndl_list;
-struct ethr_xhndl_list_ {
- ethr_xhndl_list *next;
- void (*funcp)(void);
-};
-
-static size_t pagesize;
-#define ETHR_PAGE_ALIGN(SZ) (((((size_t) (SZ)) - 1)/pagesize + 1)*pagesize)
-static size_t min_stack_size; /* kilo words */
-static size_t max_stack_size; /* kilo words */
-#define ETHR_B2KW(B) ((((size_t) (B)) - 1)/(sizeof(void *)*1024) + 1)
-#define ETHR_KW2B(KW) (((size_t) (KW))*sizeof(void *)*1024)
-
-ethr_mutex xhndl_mtx;
-ethr_xhndl_list *xhndl_list;
-
-static int
-init_common(ethr_init_data *id)
-{
- int res;
- if (id) {
- allocp = id->alloc;
- reallocp = id->realloc;
- freep = id->free;
- thread_create_prepare_func = id->thread_create_prepare_func;
- thread_create_parent_func = id->thread_create_parent_func;
- thread_create_child_func = id->thread_create_child_func;
- }
- if (!allocp || !reallocp || !freep)
- return EINVAL;
-
-#ifdef _SC_PAGESIZE
- pagesize = (size_t) sysconf(_SC_PAGESIZE);
-#elif defined(HAVE_GETPAGESIZE)
- pagesize = (size_t) getpagesize();
-#else
- pagesize = (size_t) 4*1024; /* Guess 4 KB */
-#endif
-
- /* User needs at least 4 KB */
- min_stack_size = 4*1024;
-#if SIZEOF_VOID_P == 8
- /* Double that on 64-bit archs */
- min_stack_size *= 2;
-#endif
- /* On some systems as much as about 4 KB is used by the system */
- min_stack_size += 4*1024;
- /* There should be room for signal handlers */
-#ifdef SIGSTKSZ
- min_stack_size += SIGSTKSZ;
-#else
- min_stack_size += pagesize;
-#endif
- /* The system may think that we need more stack */
-#if defined(PTHREAD_STACK_MIN)
- if (min_stack_size < PTHREAD_STACK_MIN)
- min_stack_size = PTHREAD_STACK_MIN;
-#elif defined(_SC_THREAD_STACK_MIN)
- {
- size_t thr_min_stk_sz = (size_t) sysconf(_SC_THREAD_STACK_MIN);
- if (min_stack_size < thr_min_stk_sz)
- min_stack_size = thr_min_stk_sz;
- }
-#endif
- /* The guard is at least on some platforms included in the stack size
- passed when creating threads */
-#ifdef ETHR_STACK_GUARD_SIZE
- min_stack_size += ETHR_STACK_GUARD_SIZE;
-#endif
- min_stack_size = ETHR_PAGE_ALIGN(min_stack_size);
-
- min_stack_size = ETHR_B2KW(min_stack_size);
-
- max_stack_size = 32*1024*1024;
-#if SIZEOF_VOID_P == 8
- max_stack_size *= 2;
-#endif
- max_stack_size = ETHR_B2KW(max_stack_size);
-
- xhndl_list = NULL;
-
- res = ethr_mutex_init(&xhndl_mtx);
- if (res != 0)
- return res;
-
- res = ethr_mutex_set_forksafe(&xhndl_mtx);
- if (res != 0 && res != ENOTSUP)
- return res;
-
- return 0;
-}
-
-int
-ethr_install_exit_handler(void (*funcp)(void))
-{
- ethr_xhndl_list *xhp;
- int res;
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
-
- if (!funcp)
- return EINVAL;
-
- xhp = (ethr_xhndl_list *) (*allocp)(sizeof(ethr_xhndl_list));
- if (!xhp)
- return ENOMEM;
-
- res = ethr_mutex_lock__(&xhndl_mtx);
- if (res != 0) {
- (*freep)((void *) xhp);
- return res;
- }
-
- xhp->funcp = funcp;
- xhp->next = xhndl_list;
- xhndl_list = xhp;
-
- res = ethr_mutex_unlock__(&xhndl_mtx);
- if (res != 0)
- abort();
-
- return res;
-}
-
-static void
-run_exit_handlers(void)
-{
- int res;
- ethr_xhndl_list *xhp;
-
- res = ethr_mutex_lock__(&xhndl_mtx);
- if (res != 0)
- abort();
-
- xhp = xhndl_list;
-
- res = ethr_mutex_unlock__(&xhndl_mtx);
- if (res != 0)
- abort();
-
- for (; xhp; xhp = xhp->next)
- (*xhp->funcp)();
-}
-
-#if defined(ETHR_PTHREADS)
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * pthread implementation *
-\* */
-
-typedef struct {
- pthread_mutex_t mtx;
- pthread_cond_t cnd;
- int initialized;
- void *(*thr_func)(void *);
- void *arg;
- void *prep_func_res;
-} thr_wrap_data_;
-
-static int no_ethreads;
-static ethr_mutex no_ethrs_mtx;
-
-#ifndef ETHR_HAVE_PTHREAD_ATFORK
-#define ETHR_HAVE_PTHREAD_ATFORK 0
-#endif
-
-#if !ETHR_HAVE_PTHREAD_ATFORK
-#warning "Cannot enforce fork-safety"
-#endif
-
-#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
-static pthread_rwlockattr_t write_pref_attr_data;
-static pthread_rwlockattr_t *write_pref_attr;
-#endif
-
-/*
- * ----------------------------------------------------------------------------
- * Static functions
- * ----------------------------------------------------------------------------
- */
-
-/*
- * Functions with safe_ prefix aborts on failure. To be used when
- * we cannot recover after failure.
- */
-
-static ETHR_INLINE void
-safe_mutex_lock(pthread_mutex_t *mtxp)
-{
- int res = pthread_mutex_lock(mtxp);
- if (res != 0)
- abort();
-}
-
-static ETHR_INLINE void
-safe_mutex_unlock(pthread_mutex_t *mtxp)
-{
- int res = pthread_mutex_unlock(mtxp);
- if (res != 0)
- abort();
-}
-
-static ETHR_INLINE void
-safe_cond_signal(pthread_cond_t *cndp)
-{
- int res = pthread_cond_signal(cndp);
- if (res != 0)
- abort();
-}
-
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
-
-static volatile int rec_mtx_attr_need_init = 1;
-static pthread_mutexattr_t rec_mtx_attr;
-
-static int init_rec_mtx_attr(void);
-
-#endif
-
-#if ETHR_HAVE_PTHREAD_ATFORK
-
-static ethr_mutex forksafe_mtx = ETHR_MUTEX_INITER;
-
-static void lock_mutexes(void)
-{
- ethr_mutex *m = &forksafe_mtx;
- do {
-
- safe_mutex_lock(&m->pt_mtx);
-
- m = m->next;
-
- } while (m != &forksafe_mtx);
-}
-
-static void unlock_mutexes(void)
-{
- ethr_mutex *m = forksafe_mtx.prev;
- do {
-
- safe_mutex_unlock(&m->pt_mtx);
-
- m = m->prev;
-
- } while (m->next != &forksafe_mtx);
-}
-
-#if ETHR_INIT_MUTEX_IN_CHILD_AT_FORK
-
-static void reinit_mutexes(void)
-{
- ethr_mutex *m = forksafe_mtx.prev;
- do {
- pthread_mutexattr_t *attrp = NULL;
-
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
- if (m->is_rec_mtx) {
- if (rec_mtx_attr_need_init) {
- int res = init_rec_mtx_attr();
- if (res != 0)
- abort();
- }
- attrp = &rec_mtx_attr;
- }
-#endif
- if (pthread_mutex_init(&m->pt_mtx, attrp) != 0)
- abort();
-
- m = m->prev;
-
- } while (m->next != &forksafe_mtx);
-}
-
-#endif
-
-static int
-init_forksafe(void)
-{
- static int init_done = 0;
- int res = 0;
-
- if (init_done)
- return res;
-
- forksafe_mtx.prev = &forksafe_mtx;
- forksafe_mtx.next = &forksafe_mtx;
-
- res = pthread_atfork(lock_mutexes,
- unlock_mutexes,
-#if ETHR_INIT_MUTEX_IN_CHILD_AT_FORK
- reinit_mutexes
-#else
- unlock_mutexes
-#endif
- );
-
- init_done = 1;
- return res;
-}
-
-#endif
-
-
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
-
-#if defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE)
-
-#define SET_REC_MUTEX_ATTR(AP) \
- pthread_mutexattr_settype((AP), PTHREAD_MUTEX_RECURSIVE);
-
-#elif defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
-
-#define SET_REC_MUTEX_ATTR(AP) \
- pthread_mutexattr_setkind_np((AP), PTHREAD_MUTEX_RECURSIVE_NP);
-
-#else
-
-#error "Don't know how to set recursive mutex attributes"
-
-#endif
-
-static int
-init_rec_mtx_attr(void)
-{
- int res, mres;
- static pthread_mutex_t attrinit_mtx = PTHREAD_MUTEX_INITIALIZER;
-
- mres = pthread_mutex_lock(&attrinit_mtx);
- if (mres != 0)
- return mres;
- /* Got here under race conditions; check again ... */
- if (!rec_mtx_attr_need_init)
- res = 0;
- else {
- res = pthread_mutexattr_init(&rec_mtx_attr);
- if (res == 0) {
- res = SET_REC_MUTEX_ATTR(&rec_mtx_attr);
- if (res == 0)
- rec_mtx_attr_need_init = 0;
- else
- (void) pthread_mutexattr_destroy(&rec_mtx_attr);
- }
- }
-
- mres = pthread_mutex_unlock(&attrinit_mtx);
- if (mres != 0)
- return mres;
- return res;
-}
-
-#endif /* #if ETHR_HAVE_ETHR_REC_MUTEX_INIT */
-
-static ETHR_INLINE void thr_exit_cleanup(void)
-{
- run_exit_handlers();
- safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
- ASSERT(no_ethreads > 0);
- no_ethreads--;
- safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
-}
-
-static void *thr_wrapper(void *vtwd)
-{
- void *res;
- thr_wrap_data_ *twd = (thr_wrap_data_ *) vtwd;
- void *(*thr_func)(void *) = twd->thr_func;
- void *arg = twd->arg;
-
- safe_mutex_lock(&twd->mtx);
-
- if (thread_create_child_func)
- (*thread_create_child_func)(twd->prep_func_res);
-
- twd->initialized = 1;
-
- safe_cond_signal(&twd->cnd);
- safe_mutex_unlock(&twd->mtx);
-
- res = (*thr_func)(arg);
- thr_exit_cleanup();
- return res;
-}
-
-
-/*
- * ----------------------------------------------------------------------------
- * Exported functions
- * ----------------------------------------------------------------------------
- */
-
-int
-ethr_init(ethr_init_data *id)
-{
- int res;
-
- if (!ethr_not_inited)
- return EINVAL;
-
- ethr_not_inited = 0;
-
- res = init_common(id);
- if (res != 0)
- goto error;
-
-#if ETHR_HAVE_PTHREAD_ATFORK
- init_forksafe();
-#endif
-
- no_ethreads = 1;
- res = ethr_mutex_init(&no_ethrs_mtx);
- if (res != 0)
- goto error;
- res = ethr_mutex_set_forksafe(&no_ethrs_mtx);
- if (res != 0 && res != ENOTSUP)
- goto error;
-
-#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
- {
- int i;
- for (i = 0; i < (1 << ETHR_ATOMIC_ADDR_BITS); i++) {
-#ifdef ETHR_HAVE_PTHREAD_SPIN_LOCK
- res = pthread_spin_init(&ethr_atomic_protection__[i].u.spnlck, 0);
-#else
- res = ethr_mutex_init(&ethr_atomic_protection__[i].u.mtx);
-#endif
- if (res != 0)
- goto error;
- }
- }
-#endif
-
-#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
-#if defined(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) \
- && defined(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
- res = pthread_rwlockattr_init(&write_pref_attr_data);
- if (res != 0)
- goto error;
- res = pthread_rwlockattr_setkind_np(
- &write_pref_attr_data,
- PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
- if (res != 0)
- goto error;
- write_pref_attr = &write_pref_attr_data;
-#else
- write_pref_attr = NULL;
-#endif
-#endif
-
-
- return 0;
-
- error:
- ethr_not_inited = 1;
- return res;
-
-}
-
-int
-ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
- ethr_thr_opts *opts)
-{
- thr_wrap_data_ twd;
- pthread_attr_t attr;
- int res, dres;
- int use_stack_size = (opts && opts->suggested_stack_size >= 0
- ? opts->suggested_stack_size
- : -1 /* Use system default */);
-
-#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
- if (use_stack_size < 0)
- use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
-#endif
-
- twd.initialized = 0;
- twd.thr_func = func;
- twd.arg = arg;
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!tid || !func) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-
- /* Call prepare func if it exist */
- if (thread_create_prepare_func)
- twd.prep_func_res = (*thread_create_prepare_func)();
- else
- twd.prep_func_res = NULL;
-
- /* Set som thread attributes */
- res = pthread_attr_init(&attr);
- if (res != 0)
- goto cleanup_parent_func;
- res = pthread_mutex_init(&twd.mtx, NULL);
- if (res != 0)
- goto cleanup_attr_destroy;
- res = pthread_cond_init(&twd.cnd, NULL);
- if (res != 0)
- goto cleanup_mutex_destroy;
-
- /* Schedule child thread in system scope (if possible) ... */
- res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
- if (res != 0 && res != ENOTSUP)
- goto cleanup_cond_destroy;
-
- if (use_stack_size >= 0) {
- size_t suggested_stack_size = (size_t) use_stack_size;
- size_t stack_size;
-#ifdef DEBUG
- suggested_stack_size /= 2; /* Make sure we got margin */
-#endif
-#ifdef ETHR_STACK_GUARD_SIZE
- /* The guard is at least on some platforms included in the stack size
- passed when creating threads */
- suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE);
-#endif
- if (suggested_stack_size < min_stack_size)
- stack_size = ETHR_KW2B(min_stack_size);
- else if (suggested_stack_size > max_stack_size)
- stack_size = ETHR_KW2B(max_stack_size);
- else
- stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
- (void) pthread_attr_setstacksize(&attr, stack_size);
- }
-
-#ifdef ETHR_STACK_GUARD_SIZE
- (void) pthread_attr_setguardsize(&attr, ETHR_STACK_GUARD_SIZE);
-#endif
-
- /* Detached or joinable... */
- res = pthread_attr_setdetachstate(&attr,
- (opts && opts->detached
- ? PTHREAD_CREATE_DETACHED
- : PTHREAD_CREATE_JOINABLE));
- if (res != 0)
- goto cleanup_cond_destroy;
-
- res = pthread_mutex_lock(&twd.mtx);
-
- if (res != 0)
- goto cleanup_cond_destroy;
-
- safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
- if (no_ethreads < ETHR_MAX_THREADS) {
- no_ethreads++;
- safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
- }
- else {
- res = EAGAIN;
- safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
- goto cleanup_mutex_unlock;
- }
-
- res = pthread_create((pthread_t *) tid, &attr, thr_wrapper, (void *) &twd);
-
- if (res != 0) {
- safe_mutex_lock(&no_ethrs_mtx.pt_mtx);
- ASSERT(no_ethreads > 0);
- no_ethreads--;
- safe_mutex_unlock(&no_ethrs_mtx.pt_mtx);
- }
- else {
-
- /* Wait for child to initialize... */
- while (!twd.initialized) {
- res = pthread_cond_wait(&twd.cnd, &twd.mtx);
- if (res != 0 && res != EINTR)
- break;
- }
-
- }
-
- /* Cleanup... */
- cleanup_mutex_unlock:
- dres = pthread_mutex_unlock(&twd.mtx);
- if (res == 0)
- res = dres;
- cleanup_cond_destroy:
- dres = pthread_cond_destroy(&twd.cnd);
- if (res == 0)
- res = dres;
- cleanup_mutex_destroy:
- dres = pthread_mutex_destroy(&twd.mtx);
- if (res == 0)
- res = dres;
- cleanup_attr_destroy:
- dres = pthread_attr_destroy(&attr);
- if (res == 0)
- res = dres;
- cleanup_parent_func:
- if (thread_create_parent_func)
- (*thread_create_parent_func)(twd.prep_func_res);
-
- return res;
-}
-
-int
-ethr_thr_join(ethr_tid tid, void **res)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return pthread_join((pthread_t) tid, res);
-}
-
-int
-ethr_thr_detach(ethr_tid tid)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return pthread_detach((pthread_t) tid);
-}
-
-void
-ethr_thr_exit(void *res)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return;
- }
-#endif
- thr_exit_cleanup();
- pthread_exit(res);
-}
-
-ethr_tid
-ethr_self(void)
-{
- return (ethr_tid) pthread_self();
-}
-
-int
-ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
-{
- return pthread_equal((pthread_t) tid1, (pthread_t) tid2);
-}
-
-
-/*
- * Mutex functions
- */
-
-
-int
-ethr_mutex_init(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx) {
- ASSERT(0);
- return EINVAL;
- }
- mtx->initialized = ETHR_MUTEX_INITIALIZED;
-#endif
- mtx->prev = NULL;
- mtx->next = NULL;
- mtx->is_rec_mtx = 0;
- return pthread_mutex_init(&mtx->pt_mtx, NULL);
-}
-
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
-
-int
-ethr_rec_mutex_init(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx) {
- ASSERT(0);
- return EINVAL;
- }
- mtx->initialized = ETHR_MUTEX_INITIALIZED;
-#endif
- if (rec_mtx_attr_need_init)
- init_rec_mtx_attr();
-
- mtx->prev = NULL;
- mtx->next = NULL;
- mtx->is_rec_mtx = 1;
- return pthread_mutex_init(&mtx->pt_mtx, &rec_mtx_attr);
-}
-
-#endif /* #if ETHR_HAVE_ETHR_REC_MUTEX_INIT */
-
-int
-ethr_mutex_destroy(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (mtx->next) {
- ASSERT(mtx->prev);
- ethr_mutex_unset_forksafe(mtx);
- }
-#if ETHR_XCHK
- mtx->initialized = 0;
-#endif
- return pthread_mutex_destroy(&mtx->pt_mtx);
-}
-
-int ethr_mutex_set_forksafe(ethr_mutex *mtx)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-#if ETHR_HAVE_PTHREAD_ATFORK
- res = pthread_mutex_lock(&forksafe_mtx.pt_mtx);
- if (res != 0)
- return res;
- if (!forksafe_mtx.next) {
- ASSERT(!forksafe_mtx.prev);
- init_forksafe();
- }
- if (mtx->next) {
- /* forksafe already set for this mutex */
- ASSERT(mtx->prev);
- }
- else {
- mtx->next = forksafe_mtx.next;
- mtx->prev = &forksafe_mtx;
- forksafe_mtx.next->prev = mtx;
- forksafe_mtx.next = mtx;
- }
-
- res = pthread_mutex_unlock(&forksafe_mtx.pt_mtx);
-
-#else /* #if ETHR_HAVE_PTHREAD_ATFORK */
- res = ENOTSUP;
-#endif /* #if ETHR_HAVE_PTHREAD_ATFORK */
- return res;
-}
-
-int ethr_mutex_unset_forksafe(ethr_mutex *mtx)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-#if ETHR_HAVE_PTHREAD_ATFORK
- res = pthread_mutex_lock(&forksafe_mtx.pt_mtx);
- if (res != 0)
- return res;
- if (!forksafe_mtx.next) {
- ASSERT(!forksafe_mtx.prev);
- init_forksafe();
- }
- if (!mtx->next) {
- /* forksafe already unset for this mutex */
- ASSERT(!mtx->prev);
- }
- else {
- mtx->prev->next = mtx->next;
- mtx->next->prev = mtx->prev;
- mtx->next = NULL;
- mtx->prev = NULL;
- }
- res = pthread_mutex_unlock(&forksafe_mtx.pt_mtx);
-
-#else /* #if ETHR_HAVE_PTHREAD_ATFORK */
- res = ENOTSUP;
-#endif /* #if ETHR_HAVE_PTHREAD_ATFORK */
- return res;
-}
-
-int
-ethr_mutex_trylock(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_mutex_trylock__(mtx);
-}
-
-int
-ethr_mutex_lock(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_mutex_lock__(mtx);
-}
-
-int
-ethr_mutex_unlock(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_mutex_unlock__(mtx);
-}
-
-/*
- * Condition variable functions
- */
-
-int
-ethr_cond_init(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd) {
- ASSERT(0);
- return EINVAL;
- }
- cnd->initialized = ETHR_COND_INITIALIZED;
-#endif
- return pthread_cond_init(&cnd->pt_cnd, NULL);
-}
-
-int
-ethr_cond_destroy(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
- cnd->initialized = 0;
-#endif
- return pthread_cond_destroy(&cnd->pt_cnd);
-}
-
-int
-ethr_cond_signal(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return pthread_cond_signal(&cnd->pt_cnd);
-}
-
-int
-ethr_cond_broadcast(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd || cnd->initialized != ETHR_COND_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return pthread_cond_broadcast(&cnd->pt_cnd);
-}
-
-int
-ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd
- || cnd->initialized != ETHR_COND_INITIALIZED
- || !mtx
- || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return pthread_cond_wait(&cnd->pt_cnd, &mtx->pt_mtx);
-}
-
-int
-ethr_cond_timedwait(ethr_cond *cnd, ethr_mutex *mtx, ethr_timeval *timeout)
-{
- struct timespec to;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd
- || cnd->initialized != ETHR_COND_INITIALIZED
- || !mtx
- || mtx->initialized != ETHR_MUTEX_INITIALIZED
- || !timeout) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-
- to.tv_sec = timeout->tv_sec;
- to.tv_nsec = timeout->tv_nsec;
-
- return pthread_cond_timedwait(&cnd->pt_cnd, &mtx->pt_mtx, &to);
-}
-
-
-#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
-
-int
-ethr_rwmutex_init(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx) {
- ASSERT(0);
- return EINVAL;
- }
- rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
-#endif
- return pthread_rwlock_init(&rwmtx->pt_rwlock, write_pref_attr);
-}
-
-int
-ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = pthread_rwlock_destroy(&rwmtx->pt_rwlock);
-#if ETHR_XCHK
- rwmtx->initialized = 0;
-#endif
- return res;
-}
-
-int
-ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_tryrlock__(rwmtx);
-}
-
-int
-ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_rlock__(rwmtx);
-}
-
-int
-ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_runlock__(rwmtx);
-}
-
-int
-ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_tryrwlock__(rwmtx);
-}
-
-int
-ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_rwlock__(rwmtx);
-}
-
-int
-ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwmutex_rwunlock__(rwmtx);
-}
-
-#endif /* #ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT */
-
-/*
- * Current time
- */
-
-int
-ethr_time_now(ethr_timeval *time)
-{
- int res;
- struct timeval tv;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!time) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-
- res = gettimeofday(&tv, NULL);
- time->tv_sec = (long) tv.tv_sec;
- time->tv_nsec = ((long) tv.tv_usec)*1000;
- return res;
-}
-
-/*
- * Thread specific data
- */
-
-int
-ethr_tsd_key_create(ethr_tsd_key *keyp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!keyp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return pthread_key_create((pthread_key_t *) keyp, NULL);
-}
-
-int
-ethr_tsd_key_delete(ethr_tsd_key key)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return pthread_key_delete((pthread_key_t) key);
-}
-
-int
-ethr_tsd_set(ethr_tsd_key key, void *value)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return pthread_setspecific((pthread_key_t) key, value);
-}
-
-void *
-ethr_tsd_get(ethr_tsd_key key)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return NULL;
- }
-#endif
- return pthread_getspecific((pthread_key_t) key);
-}
-
-/*
- * Signal functions
- */
-
-#if ETHR_HAVE_ETHR_SIG_FUNCS
-
-int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!set && !oset) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return pthread_sigmask(how, set, oset);
-}
-
-int ethr_sigwait(const sigset_t *set, int *sig)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!set || !sig) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (sigwait(set, sig) < 0)
- return errno;
- return 0;
-}
-
-#endif /* #if ETHR_HAVE_ETHR_SIG_FUNCS */
-
-#elif defined(ETHR_WIN32_THREADS)
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
- * Native win32 threads implementation *
-\* */
-
-#define INVALID_TID -1
-
-/* The spin count values are more or less taken out of the blue */
-#define ETHR_MUTEX_SPIN_COUNT 5000
-#define ETHR_COND_SPIN_COUNT 1000
-
-ethr_tid serial_shift; /* Bits to shift serial when constructing a tid */
-ethr_tid last_serial; /* Last thread table serial used */
-ethr_tid last_ix; /* Last thread table index used */
-ethr_tid thr_ix_mask; /* Mask used to mask out thread table index from a tid */
-
-/* Event used for conditional variables. On per thread. */
-/*typedef struct cnd_wait_event__ cnd_wait_event_;*/
-struct cnd_wait_event__ {
- HANDLE handle;
- cnd_wait_event_ *prev;
- cnd_wait_event_ *next;
- int in_queue;
-};
-
-/* Thread specific data. Stored in the thread table */
-typedef struct {
- ethr_tid thr_id;
- HANDLE thr_handle;
- ethr_tid joiner;
- void *result;
- cnd_wait_event_ wait_event;
-} thr_data_;
-
-/* Argument passed to thr_wrapper() */
-typedef struct {
- void * (*func)(void *);
- void * arg;
- thr_data_ *ptd;
- thr_data_ *td;
- int res;
- void *prep_func_res;
-} thr_wrap_data_;
-
-
-static CRITICAL_SECTION thr_table_cs; /* Critical section used to protect
- the thread table from concurrent
- accesses. */
-static CRITICAL_SECTION fake_static_init_cs; /* Critical section used to protect
- initialazition of 'statically
- initialized' mutexes */
-static thr_data_ * thr_table[ETHR_MAX_THREADS]; /* The thread table */
-
-static DWORD tls_own_thr_data;
-
-static thr_data_ main_thr_data;
-
-#define THR_IX(TID) ((TID) & thr_ix_mask)
-#define OWN_THR_DATA ((thr_data_ *) TlsGetValue(tls_own_thr_data))
-
-/*
- * ----------------------------------------------------------------------------
- * Static functions
- * ----------------------------------------------------------------------------
- */
-
-static int
-get_errno(void)
-{
- switch (GetLastError()) {
- case ERROR_INVALID_FUNCTION: return EINVAL; /* 1 */
- case ERROR_FILE_NOT_FOUND: return ENOENT; /* 2 */
- case ERROR_PATH_NOT_FOUND: return ENOENT; /* 3 */
- case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; /* 4 */
- case ERROR_ACCESS_DENIED: return EACCES; /* 5 */
- case ERROR_INVALID_HANDLE: return EBADF; /* 6 */
- case ERROR_ARENA_TRASHED: return ENOMEM; /* 7 */
- case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; /* 8 */
- case ERROR_INVALID_BLOCK: return ENOMEM; /* 9 */
- case ERROR_BAD_ENVIRONMENT: return E2BIG; /* 10 */
- case ERROR_BAD_FORMAT: return ENOEXEC; /* 11 */
- case ERROR_INVALID_ACCESS: return EINVAL; /* 12 */
- case ERROR_INVALID_DATA: return EINVAL; /* 13 */
- case ERROR_OUTOFMEMORY: return ENOMEM; /* 14 */
- case ERROR_INVALID_DRIVE: return ENOENT; /* 15 */
- case ERROR_CURRENT_DIRECTORY: return EACCES; /* 16 */
- case ERROR_NOT_SAME_DEVICE: return EXDEV; /* 17 */
- case ERROR_NO_MORE_FILES: return ENOENT; /* 18 */
- case ERROR_WRITE_PROTECT: return EACCES; /* 19 */
- case ERROR_BAD_UNIT: return EACCES; /* 20 */
- case ERROR_NOT_READY: return EACCES; /* 21 */
- case ERROR_BAD_COMMAND: return EACCES; /* 22 */
- case ERROR_CRC: return EACCES; /* 23 */
- case ERROR_BAD_LENGTH: return EACCES; /* 24 */
- case ERROR_SEEK: return EACCES; /* 25 */
- case ERROR_NOT_DOS_DISK: return EACCES; /* 26 */
- case ERROR_SECTOR_NOT_FOUND: return EACCES; /* 27 */
- case ERROR_OUT_OF_PAPER: return EACCES; /* 28 */
- case ERROR_WRITE_FAULT: return EACCES; /* 29 */
- case ERROR_READ_FAULT: return EACCES; /* 30 */
- case ERROR_GEN_FAILURE: return EACCES; /* 31 */
- case ERROR_SHARING_VIOLATION: return EACCES; /* 32 */
- case ERROR_LOCK_VIOLATION: return EACCES; /* 33 */
- case ERROR_WRONG_DISK: return EACCES; /* 34 */
- case ERROR_SHARING_BUFFER_EXCEEDED: return EACCES; /* 36 */
- case ERROR_BAD_NETPATH: return ENOENT; /* 53 */
- case ERROR_NETWORK_ACCESS_DENIED: return EACCES; /* 65 */
- case ERROR_BAD_NET_NAME: return ENOENT; /* 67 */
- case ERROR_FILE_EXISTS: return EEXIST; /* 80 */
- case ERROR_CANNOT_MAKE: return EACCES; /* 82 */
- case ERROR_FAIL_I24: return EACCES; /* 83 */
- case ERROR_INVALID_PARAMETER: return EINVAL; /* 87 */
- case ERROR_NO_PROC_SLOTS: return EAGAIN; /* 89 */
- case ERROR_DRIVE_LOCKED: return EACCES; /* 108 */
- case ERROR_BROKEN_PIPE: return EPIPE; /* 109 */
- case ERROR_DISK_FULL: return ENOSPC; /* 112 */
- case ERROR_INVALID_TARGET_HANDLE: return EBADF; /* 114 */
- case ERROR_WAIT_NO_CHILDREN: return ECHILD; /* 128 */
- case ERROR_CHILD_NOT_COMPLETE: return ECHILD; /* 129 */
- case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; /* 130 */
- case ERROR_NEGATIVE_SEEK: return EINVAL; /* 131 */
- case ERROR_SEEK_ON_DEVICE: return EACCES; /* 132 */
- case ERROR_DIR_NOT_EMPTY: return ENOTEMPTY;/* 145 */
- case ERROR_NOT_LOCKED: return EACCES; /* 158 */
- case ERROR_BAD_PATHNAME: return ENOENT; /* 161 */
- case ERROR_MAX_THRDS_REACHED: return EAGAIN; /* 164 */
- case ERROR_LOCK_FAILED: return EACCES; /* 167 */
- case ERROR_ALREADY_EXISTS: return EEXIST; /* 183 */
- case ERROR_INVALID_STARTING_CODESEG: return ENOEXEC; /* 188 */
- case ERROR_INVALID_STACKSEG: return ENOEXEC; /* 189 */
- case ERROR_INVALID_MODULETYPE: return ENOEXEC; /* 190 */
- case ERROR_INVALID_EXE_SIGNATURE: return ENOEXEC; /* 191 */
- case ERROR_EXE_MARKED_INVALID: return ENOEXEC; /* 192 */
- case ERROR_BAD_EXE_FORMAT: return ENOEXEC; /* 193 */
- case ERROR_ITERATED_DATA_EXCEEDS_64k: return ENOEXEC; /* 194 */
- case ERROR_INVALID_MINALLOCSIZE: return ENOEXEC; /* 195 */
- case ERROR_DYNLINK_FROM_INVALID_RING: return ENOEXEC; /* 196 */
- case ERROR_IOPL_NOT_ENABLED: return ENOEXEC; /* 197 */
- case ERROR_INVALID_SEGDPL: return ENOEXEC; /* 198 */
- case ERROR_AUTODATASEG_EXCEEDS_64k: return ENOEXEC; /* 199 */
- case ERROR_RING2SEG_MUST_BE_MOVABLE: return ENOEXEC; /* 200 */
- case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: return ENOEXEC; /* 201 */
- case ERROR_INFLOOP_IN_RELOC_CHAIN: return ENOEXEC; /* 202 */
- case ERROR_FILENAME_EXCED_RANGE: return ENOENT; /* 206 */
- case ERROR_NESTING_NOT_ALLOWED: return EAGAIN; /* 215 */
- case ERROR_NOT_ENOUGH_QUOTA: return ENOMEM; /* 1816 */
- default: return EINVAL;
- }
-}
-
-static ETHR_INLINE thr_data_ *
-tid2thr(ethr_tid tid)
-{
- ethr_tid ix;
- thr_data_ *td;
-
- if (tid < 0)
- return NULL;
- ix = THR_IX(tid);
- if (ix >= ETHR_MAX_THREADS)
- return NULL;
- td = thr_table[ix];
- if (!td)
- return NULL;
- if (td->thr_id != tid)
- return NULL;
- return td;
-}
-
-static ETHR_INLINE void
-new_tid(ethr_tid *new_tid, ethr_tid *new_serial, ethr_tid *new_ix)
-{
- ethr_tid tmp_serial = last_serial;
- ethr_tid tmp_ix = last_ix + 1;
- ethr_tid start_ix = tmp_ix;
-
-
- do {
- if (tmp_ix >= ETHR_MAX_THREADS) {
- tmp_serial++;
- if ((tmp_serial << serial_shift) < 0)
- tmp_serial = 0;
- tmp_ix = 0;
- }
- if (!thr_table[tmp_ix]) {
- *new_tid = (tmp_serial << serial_shift) | tmp_ix;
- *new_serial = tmp_serial;
- *new_ix = tmp_ix;
- return;
- }
- tmp_ix++;
- } while (tmp_ix != start_ix);
-
- *new_tid = INVALID_TID;
- *new_serial = INVALID_TID;
- *new_ix = INVALID_TID;
-
-}
-
-
-static void thr_exit_cleanup(thr_data_ *td, void *res)
-{
-
- ASSERT(td == OWN_THR_DATA);
-
- run_exit_handlers();
-
- EnterCriticalSection(&thr_table_cs);
- CloseHandle(td->wait_event.handle);
- if (td->thr_handle == INVALID_HANDLE_VALUE) {
- /* We are detached; cleanup thread table */
- ASSERT(td->joiner == INVALID_TID);
- ASSERT(td == thr_table[THR_IX(td->thr_id)]);
- thr_table[THR_IX(td->thr_id)] = NULL;
- if (td != &main_thr_data)
- (*freep)((void *) td);
- }
- else {
- /* Save result and let joining thread cleanup */
- td->result = res;
- }
- LeaveCriticalSection(&thr_table_cs);
-}
-
-static unsigned __stdcall thr_wrapper(LPVOID args)
-{
- void *(*func)(void*) = ((thr_wrap_data_ *) args)->func;
- void *arg = ((thr_wrap_data_ *) args)->arg;
- thr_data_ *td = ((thr_wrap_data_ *) args)->td;
-
- td->wait_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (td->wait_event.handle == INVALID_HANDLE_VALUE
- || !TlsSetValue(tls_own_thr_data, (LPVOID) td)) {
- ((thr_wrap_data_ *) args)->res = get_errno();
- if (td->wait_event.handle != INVALID_HANDLE_VALUE)
- CloseHandle(td->wait_event.handle);
- SetEvent(((thr_wrap_data_ *) args)->ptd->wait_event.handle);
- _endthreadex((unsigned) 0);
- ASSERT(0);
- }
-
- td->wait_event.prev = NULL;
- td->wait_event.next = NULL;
- td->wait_event.in_queue = 0;
-
- if (thread_create_child_func)
- (*thread_create_child_func)(((thr_wrap_data_ *) args)->prep_func_res);
-
- ASSERT(td == OWN_THR_DATA);
-
- ((thr_wrap_data_ *) args)->res = 0;
- SetEvent(((thr_wrap_data_ *) args)->ptd->wait_event.handle);
-
- thr_exit_cleanup(td, (*func)(arg));
- return 0;
-}
-
-int
-ethr_fake_static_mutex_init(ethr_mutex *mtx)
-{
- EnterCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
- /* Got here under race conditions; check again... */
- if (!mtx->initialized) {
- if (!InitializeCriticalSectionAndSpinCount(&mtx->cs,
- ETHR_MUTEX_SPIN_COUNT))
- return get_errno();
- mtx->initialized = ETHR_MUTEX_INITIALIZED;
- }
- LeaveCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
- return 0;
-}
-
-static int
-fake_static_cond_init(ethr_cond *cnd)
-{
- EnterCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
- /* Got here under race conditions; check again... */
- if (!cnd->initialized) {
- if (!InitializeCriticalSectionAndSpinCount(&cnd->cs,
- ETHR_COND_SPIN_COUNT))
- return get_errno();
- cnd->queue = NULL;
- cnd->queue_end = NULL;
- cnd->initialized = ETHR_COND_INITIALIZED;
- }
- LeaveCriticalSection((CRITICAL_SECTION *) &fake_static_init_cs);
- return 0;
-}
-
-#ifdef __GNUC__
-#define LL_LITERAL(X) X##LL
-#else
-#define LL_LITERAL(X) X##i64
-#endif
-
-#define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600)
-
-static ETHR_INLINE void
-get_curr_time(long *sec, long *nsec)
-{
- SYSTEMTIME t;
- FILETIME ft;
- LONGLONG lft;
-
- GetSystemTime(&t);
- SystemTimeToFileTime(&t, &ft);
- memcpy(&lft, &ft, sizeof(lft));
- *nsec = ((long) (lft % LL_LITERAL(10000000)))*100;
- *sec = (long) ((lft / LL_LITERAL(10000000)) - EPOCH_JULIAN_DIFF);
-}
-
-static cnd_wait_event_ *cwe_freelist;
-static CRITICAL_SECTION cwe_cs;
-
-static int
-alloc_cwe(cnd_wait_event_ **cwe_res)
-{
- cnd_wait_event_ *cwe;
- EnterCriticalSection(&cwe_cs);
- cwe = cwe_freelist;
- if (cwe) {
- cwe_freelist = cwe->next;
- LeaveCriticalSection(&cwe_cs);
- }
- else {
- LeaveCriticalSection(&cwe_cs);
- cwe = (*allocp)(sizeof(cnd_wait_event_));
- if (!cwe)
- return ENOMEM;
- cwe->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (cwe->handle == INVALID_HANDLE_VALUE) {
- int res = get_errno();
- (*freep)(cwe);
- return res;
- }
- }
- *cwe_res = cwe;
- return 0;
-}
-
-static
-free_cwe(cnd_wait_event_ *cwe)
-{
- EnterCriticalSection(&cwe_cs);
- cwe->next = cwe_freelist;
- cwe_freelist = cwe;
- LeaveCriticalSection(&cwe_cs);
-}
-
-static ETHR_INLINE int
-condwait(ethr_cond *cnd,
- ethr_mutex *mtx,
- int with_timeout,
- ethr_timeval *timeout)
-{
- int res;
- thr_data_ *td;
- cnd_wait_event_ *cwe;
- DWORD code;
- long time; /* time until timeout in milli seconds */
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-
- if (!mtx
- || mtx->initialized != ETHR_MUTEX_INITIALIZED
- || !cnd
- || (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)
- || (with_timeout && !timeout)) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-
- td = OWN_THR_DATA;
- if (td)
- cwe = &td->wait_event;
- else { /* A non-ethread thread */
- res = alloc_cwe(&cwe);
- if (res != 0)
- return res;
- }
-
- if (!cnd->initialized)
- fake_static_cond_init(cnd);
- EnterCriticalSection(&cnd->cs);
-
- ASSERT(!cwe->in_queue);
- if (cnd->queue_end) {
- ASSERT(cnd->queue);
- cwe->prev = cnd->queue_end;
- cwe->next = NULL;
- cnd->queue_end->next = cwe;
- cnd->queue_end = cwe;
- }
- else {
- ASSERT(!cnd->queue);
- cwe->prev = NULL;
- cwe->next = NULL;
- cnd->queue = cwe;
- cnd->queue_end = cwe;
- }
- cwe->in_queue = 1;
-
- LeaveCriticalSection(&cnd->cs);
-
- LeaveCriticalSection(&mtx->cs);
-
- if (!with_timeout)
- time = INFINITE;
- else {
- long sec, nsec;
- ASSERT(timeout);
- get_curr_time(&sec, &nsec);
- time = (timeout->tv_sec - sec)*1000;
- time += (timeout->tv_nsec - nsec + 500)/1000000;
- if (time < 0)
- time = 0;
- }
-
- /* wait for event to signal */
- code = WaitForSingleObject(cwe->handle, time);
-
- EnterCriticalSection(&mtx->cs);
-
- if (code == WAIT_OBJECT_0) {
- /* We were woken by a signal or a broadcast ... */
- res = 0;
-
- /* ... no need to remove event from wait queue since this was
- taken care of by the signal or broadcast */
-#ifdef DEBUG
- EnterCriticalSection(&cnd->cs);
- ASSERT(!cwe->in_queue);
- LeaveCriticalSection(&cnd->cs);
-#endif
-
- }
- else {
- /* We timed out... */
- res = ETIMEDOUT;
-
- /* ... probably have to remove event from wait queue ... */
- EnterCriticalSection(&cnd->cs);
-
- if (cwe->in_queue) { /* ... but we must check that we are in queue
- since a signal or broadcast after timeout
- may have removed us from the queue */
- if (cwe->prev) {
- cwe->prev->next = cwe->next;
- }
- else {
- ASSERT(cnd->queue == cwe);
- cnd->queue = cwe->next;
- }
-
- if (cwe->next) {
- cwe->next->prev = cwe->prev;
- }
- else {
- ASSERT(cnd->queue_end == cwe);
- cnd->queue_end = cwe->prev;
- }
- cwe->in_queue = 0;
- }
-
- LeaveCriticalSection(&cnd->cs);
-
- }
-
- if (!td)
- free_cwe(cwe);
-
- return res;
-
-}
-
-
-/*
- * ----------------------------------------------------------------------------
- * Exported functions
- * ----------------------------------------------------------------------------
- */
-
-int
-ethr_init(ethr_init_data *id)
-{
-#ifdef _WIN32_WINNT
- DWORD major = (_WIN32_WINNT >> 8) & 0xff;
- DWORD minor = _WIN32_WINNT & 0xff;
- OSVERSIONINFO os_version;
-#endif
- int err = 0;
- thr_data_ *td = &main_thr_data;
- unsigned long i;
-
- if (!ethr_not_inited)
- return EINVAL;
-
-#ifdef _WIN32_WINNT
- os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx(&os_version);
- if (os_version.dwPlatformId != VER_PLATFORM_WIN32_NT
- || os_version.dwMajorVersion < major
- || (os_version.dwMajorVersion == major
- && os_version.dwMinorVersion < minor))
- return ENOTSUP;
-#endif
-
- ASSERT(ETHR_MAX_THREADS > 0);
- for (i = ETHR_MAX_THREADS - 1, serial_shift = 0;
- i;
- serial_shift++, i >>= 1);
- thr_ix_mask = ~(~((ethr_tid) 0) << serial_shift);
-
- tls_own_thr_data = TlsAlloc();
- if (tls_own_thr_data == TLS_OUT_OF_INDEXES)
- goto error;
-
- last_serial = 0;
- last_ix = 0;
-
- td->thr_id = 0;
- td->thr_handle = GetCurrentThread();
- td->joiner = INVALID_TID;
- td->result = NULL;
- td->wait_event.handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (td->wait_event.handle == INVALID_HANDLE_VALUE)
- goto error;
- td->wait_event.prev = NULL;
- td->wait_event.next = NULL;
- td->wait_event.in_queue = 0;
- thr_table[0] = td;
-
- if (!TlsSetValue(tls_own_thr_data, (LPVOID) td))
- goto error;
-
- ASSERT(td == OWN_THR_DATA);
-
-
- cwe_freelist = NULL;
- if (!InitializeCriticalSectionAndSpinCount(&cwe_cs,
- ETHR_MUTEX_SPIN_COUNT))
- goto error;
-
- for (i = 1; i < ETHR_MAX_THREADS; i++)
- thr_table[i] = NULL;
-
- if (!InitializeCriticalSectionAndSpinCount(&thr_table_cs,
- ETHR_MUTEX_SPIN_COUNT))
- goto error;
- if (!InitializeCriticalSectionAndSpinCount(&fake_static_init_cs,
- ETHR_MUTEX_SPIN_COUNT))
- goto error;
- ethr_not_inited = 0;
-
- err = init_common(id);
- if (err)
- goto error;
-
- return 0;
-
- error:
- ethr_not_inited = 1;
- if (err == 0)
- err = get_errno();
- ASSERT(err != 0);
- if (td->thr_handle != INVALID_HANDLE_VALUE)
- CloseHandle(td->thr_handle);
- if (td->wait_event.handle != INVALID_HANDLE_VALUE)
- CloseHandle(td->wait_event.handle);
- return err;
-}
-
-/*
- * Thread functions.
- */
-
-int
-ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
- ethr_thr_opts *opts)
-{
- int err = 0;
- thr_wrap_data_ twd;
- thr_data_ *my_td, *child_td = NULL;
- ethr_tid child_tid, child_serial, child_ix;
- DWORD code;
- unsigned ID;
- unsigned stack_size = 0; /* 0 = system default */
- int use_stack_size = (opts && opts->suggested_stack_size >= 0
- ? opts->suggested_stack_size
- : -1 /* Use system default */);
-
-#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
- if (use_stack_size < 0)
- use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
-#endif
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!tid || !func) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
-
- my_td = OWN_THR_DATA;
- if (!my_td) {
- /* Only ethreads are allowed to call this function */
- ASSERT(0);
- return EACCES;
- }
-
- if (use_stack_size >= 0) {
- size_t suggested_stack_size = (size_t) use_stack_size;
-#ifdef DEBUG
- suggested_stack_size /= 2; /* Make sure we got margin */
-#endif
- if (suggested_stack_size < min_stack_size)
- stack_size = (unsigned) ETHR_KW2B(min_stack_size);
- else if (suggested_stack_size > max_stack_size)
- stack_size = (unsigned) ETHR_KW2B(max_stack_size);
- else
- stack_size =
- (unsigned) ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
- }
-
- EnterCriticalSection(&thr_table_cs);
-
- /* Call prepare func if it exist */
- if (thread_create_prepare_func)
- twd.prep_func_res = (*thread_create_prepare_func)();
- else
- twd.prep_func_res = NULL;
-
- /* Find a new thread id to use */
- new_tid(&child_tid, &child_serial, &child_ix);
- if (child_tid == INVALID_TID) {
- err = EAGAIN;
- goto error;
- }
-
- ASSERT(child_ix == THR_IX(child_tid));
-
- *tid = child_tid;
-
- ASSERT(!thr_table[child_ix]);
-
- /* Alloc thread data */
- thr_table[child_ix] = child_td = (thr_data_ *) (*allocp)(sizeof(thr_data_));
- if (!child_td) {
- err = ENOMEM;
- goto error;
- }
-
- /* Init thread data */
-
- child_td->thr_id = child_tid;
- child_td->thr_handle = INVALID_HANDLE_VALUE;
- child_td->joiner = INVALID_TID;
- child_td->result = NULL;
- /* 'child_td->wait_event' is initialized by child thread */
-
-
- /* Init thread wrapper data */
-
- twd.func = func;
- twd.arg = arg;
- twd.ptd = my_td;
- twd.td = child_td;
- twd.res = 0;
-
- ASSERT(!my_td->wait_event.in_queue);
-
- /* spawn the thr_wrapper function */
- child_td->thr_handle = (HANDLE) _beginthreadex(NULL,
- stack_size,
- thr_wrapper,
- (LPVOID) &twd,
- 0,
- &ID);
- if (child_td->thr_handle == (HANDLE) 0) {
- child_td->thr_handle = INVALID_HANDLE_VALUE;
- goto error;
- }
-
- ASSERT(child_td->thr_handle != INVALID_HANDLE_VALUE);
-
- /* Wait for child to finish initialization */
- code = WaitForSingleObject(my_td->wait_event.handle, INFINITE);
- if (twd.res || code != WAIT_OBJECT_0) {
- err = twd.res;
- goto error;
- }
-
- if (opts && opts->detached) {
- CloseHandle(child_td->thr_handle);
- child_td->thr_handle = INVALID_HANDLE_VALUE;
- }
-
- last_serial = child_serial;
- last_ix = child_ix;
-
- ASSERT(thr_table[child_ix] == child_td);
-
- if (thread_create_parent_func)
- (*thread_create_parent_func)(twd.prep_func_res);
-
- LeaveCriticalSection(&thr_table_cs);
-
- return 0;
-
- error:
-
- if (err == 0)
- err = get_errno();
- ASSERT(err != 0);
-
- if (thread_create_parent_func)
- (*thread_create_parent_func)(twd.prep_func_res);
-
- if (child_ix != INVALID_TID) {
-
- if (child_td) {
- ASSERT(thr_table[child_ix] == child_td);
-
- if (child_td->thr_handle != INVALID_HANDLE_VALUE) {
- WaitForSingleObject(child_td->thr_handle, INFINITE);
- CloseHandle(child_td->thr_handle);
- }
-
- (*freep)((void *) child_td);
- thr_table[child_ix] = NULL;
- }
- }
-
- *tid = INVALID_TID;
-
- LeaveCriticalSection(&thr_table_cs);
- return err;
-}
-
-int ethr_thr_join(ethr_tid tid, void **res)
-{
- int err = 0;
- DWORD code;
- thr_data_ *td;
- thr_data_ *my_td;
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
-
- my_td = OWN_THR_DATA;
-
- if (!my_td) {
- /* Only ethreads are allowed to call this function */
- ASSERT(0);
- return EACCES;
- }
-
- EnterCriticalSection(&thr_table_cs);
-
- td = tid2thr(tid);
- if (!td)
- err = ESRCH;
- else if (td->thr_handle == INVALID_HANDLE_VALUE /* i.e. detached */
- || td->joiner != INVALID_TID) /* i.e. someone else is joining */
- err = EINVAL;
- else if (my_td == td)
- err = EDEADLK;
- else
- td->joiner = my_td->thr_id;
-
- LeaveCriticalSection(&thr_table_cs);
-
- if (err)
- goto error;
-
- /* Wait for thread to terminate */
- code = WaitForSingleObject(td->thr_handle, INFINITE);
- if (code != WAIT_OBJECT_0)
- goto error;
-
- EnterCriticalSection(&thr_table_cs);
-
- ASSERT(td == tid2thr(tid));
- ASSERT(td->thr_handle != INVALID_HANDLE_VALUE);
- ASSERT(td->joiner == my_td->thr_id);
-
- if (res)
- *res = td->result;
-
- CloseHandle(td->thr_handle);
- ASSERT(td == thr_table[THR_IX(td->thr_id)]);
- thr_table[THR_IX(td->thr_id)] = NULL;
- if (td != &main_thr_data)
- (*freep)((void *) td);
-
- LeaveCriticalSection(&thr_table_cs);
-
- return 0;
-
- error:
- if (err == 0)
- err = get_errno();
- ASSERT(err != 0);
- return err;
-}
-
-
-int
-ethr_thr_detach(ethr_tid tid)
-{
- int res;
- DWORD code;
- thr_data_ *td;
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
-
- if (!OWN_THR_DATA) {
- /* Only ethreads are allowed to call this function */
- ASSERT(0);
- return EACCES;
- }
-
- EnterCriticalSection(&thr_table_cs);
-
- td = tid2thr(tid);
- if (!td)
- res = ESRCH;
- if (td->thr_handle == INVALID_HANDLE_VALUE /* i.e. detached */
- || td->joiner != INVALID_TID) /* i.e. someone is joining */
- res = EINVAL;
- else {
- res = 0;
- CloseHandle(td->thr_handle);
- td->thr_handle = INVALID_HANDLE_VALUE;
- }
-
- LeaveCriticalSection(&thr_table_cs);
-
- return res;
-}
-
-
-void
-ethr_thr_exit(void *res)
-{
- thr_data_ *td;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return;
- }
-#endif
- td = OWN_THR_DATA;
- if (!td) {
- /* Only ethreads are allowed to call this function */
- ASSERT(0);
- return;
- }
- thr_exit_cleanup(td, res);
- _endthreadex((unsigned) 0);
-}
-
-ethr_tid
-ethr_self(void)
-{
- thr_data_ *td;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return INVALID_TID;
- }
-#endif
- /* It is okay for non-ethreads (i.e. native win32 threads) to call
- ethr_self(). They will however be returned the INVALID_TID. */
- td = OWN_THR_DATA;
- if (!td)
- return INVALID_TID;
- return td->thr_id;
-}
-
-int
-ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
-{
- /* INVALID_TID does not equal any tid, not even the INVALID_TID */
- return tid1 == tid2 && tid1 != INVALID_TID;
-}
-
-/*
- * Mutex functions.
- */
-
-int
-ethr_mutex_init(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (!InitializeCriticalSectionAndSpinCount(&mtx->cs, ETHR_MUTEX_SPIN_COUNT))
- return get_errno();
- mtx->initialized = ETHR_MUTEX_INITIALIZED;
-#if ETHR_XCHK
- mtx->is_rec_mtx = 0;
-#endif
- return 0;
-}
-
-int
-ethr_rec_mutex_init(ethr_mutex *mtx)
-{
- int res;
- res = ethr_mutex_init(mtx);
-#if ETHR_XCHK
- mtx->is_rec_mtx = 1;
-#endif
- return res;
-}
-
-int
-ethr_mutex_destroy(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- DeleteCriticalSection(&mtx->cs);
- mtx->initialized = 0;
- return 0;
-}
-
-int ethr_mutex_set_forksafe(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return 0; /* No fork() */
-}
-
-int ethr_mutex_unset_forksafe(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- return 0; /* No fork() */
-}
-
-int
-ethr_mutex_trylock(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx
- || (mtx->initialized && mtx->initialized != ETHR_MUTEX_INITIALIZED)) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (!mtx->initialized) {
- int res = ethr_fake_static_mutex_init(mtx);
- if (res != 0)
- return res;
- }
- return ethr_mutex_trylock__(mtx);
-}
-
-int
-ethr_mutex_lock(ethr_mutex *mtx)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx
- || (mtx->initialized && mtx->initialized != ETHR_MUTEX_INITIALIZED)) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_mutex_lock__(mtx);
-}
-
-int
-ethr_mutex_unlock(ethr_mutex *mtx)
-{
-#if ETHR_XCHK
- int res;
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!mtx || mtx->initialized != ETHR_MUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_mutex_unlock__(mtx);
-}
-
-/*
- * Condition variable functions.
- */
-
-int
-ethr_cond_init(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (!InitializeCriticalSectionAndSpinCount(&cnd->cs, ETHR_COND_SPIN_COUNT))
- return get_errno();
- cnd->queue = NULL;
- cnd->queue_end = NULL;
- cnd->initialized = ETHR_COND_INITIALIZED;
- return 0;
-}
-
-int
-ethr_cond_destroy(ethr_cond *cnd)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd
- || (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)
- || cnd->queue) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- DeleteCriticalSection(&cnd->cs);
- cnd->initialized = 0;
- return 0;
-}
-
-int
-ethr_cond_signal(ethr_cond *cnd)
-{
- cnd_wait_event_ *cwe;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd
- || (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (!cnd->initialized) {
- int res = fake_static_cond_init(cnd);
- if (res != 0)
- return res;
- }
- EnterCriticalSection(&cnd->cs);
- cwe = cnd->queue;
- if (cwe) {
- ASSERT(cwe->in_queue);
- SetEvent(cnd->queue->handle);
- if (cwe->next)
- cwe->next->prev = NULL;
- else {
- ASSERT(cnd->queue_end == cnd->queue);
- cnd->queue_end = NULL;
- }
- cnd->queue = cwe->next;
- cwe->in_queue = 0;
- }
- LeaveCriticalSection(&cnd->cs);
- return 0;
-}
-
-int
-ethr_cond_broadcast(ethr_cond *cnd)
-{
- cnd_wait_event_ *cwe;
-
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!cnd
- || (cnd->initialized && cnd->initialized != ETHR_COND_INITIALIZED)) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (!cnd->initialized) {
- int res = fake_static_cond_init(cnd);
- if (res != 0)
- return res;
- }
- EnterCriticalSection(&cnd->cs);
- for (cwe = cnd->queue; cwe; cwe = cwe->next) {
- ASSERT(cwe->in_queue);
- SetEvent(cwe->handle);
- cwe->in_queue = 0;
- }
- cnd->queue = NULL;
- cnd->queue_end = NULL;
- LeaveCriticalSection(&cnd->cs);
- return 0;
-
-}
-
-int
-ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
-{
- return condwait(cnd, mtx, 0, NULL);
-}
-
-int
-ethr_cond_timedwait(ethr_cond *cnd, ethr_mutex *mtx, ethr_timeval *timeout)
-{
- return condwait(cnd, mtx, 1, timeout);
-}
-
-int
-ethr_time_now(ethr_timeval *time)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!time) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- get_curr_time(&time->tv_sec, &time->tv_nsec);
- return 0;
-}
-
-/*
- * Thread specific data
- */
-
-int
-ethr_tsd_key_create(ethr_tsd_key *keyp)
-{
- DWORD key;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!keyp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- key = TlsAlloc();
- if (key == TLS_OUT_OF_INDEXES)
- return get_errno();
- *keyp = (ethr_tsd_key) key;
- return 0;
-}
-
-int
-ethr_tsd_key_delete(ethr_tsd_key key)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- if (!TlsFree((DWORD) key))
- return get_errno();
- return 0;
-}
-
-int
-ethr_tsd_set(ethr_tsd_key key, void *value)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
-#endif
- if (!TlsSetValue((DWORD) key, (LPVOID) value))
- return get_errno();
- return 0;
-}
-
-void *
-ethr_tsd_get(ethr_tsd_key key)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return NULL;
- }
-#endif
- return (void *) TlsGetValue((DWORD) key);
-}
-
-/* Misc */
-
-#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
-
-int
-ethr_do_spinlock_init(ethr_spinlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- if (InitializeCriticalSectionAndSpinCount(&lock->cs, INT_MAX))
- return 0;
- else
- return get_errno();
-}
-
-int
-ethr_do_rwlock_init(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- lock->counter = 0;
- if (InitializeCriticalSectionAndSpinCount(&lock->cs, INT_MAX))
- return 0;
- else
- return get_errno();
-}
-
-#endif /* #ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS */
-
-#else
-#error "Missing thread implementation"
-#endif
-
-/* Atomics */
-
-int
-ethr_atomic_init(ethr_atomic_t *var, long i)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_init__(var, i);
-}
-
-int
-ethr_atomic_set(ethr_atomic_t *var, long i)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_set__(var, i);
-}
-
-int
-ethr_atomic_read(ethr_atomic_t *var, long *i)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !i) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_read__(var, i);
-}
-
-
-int
-ethr_atomic_addtest(ethr_atomic_t *var, long incr, long *testp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !testp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_addtest__(var, incr, testp);
-}
-
-int
-ethr_atomic_inctest(ethr_atomic_t *incp, long *testp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!incp || !testp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_inctest__(incp, testp);
-}
-
-int
-ethr_atomic_dectest(ethr_atomic_t *decp, long *testp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!decp || !testp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_dectest__(decp, testp);
-}
-
-int
-ethr_atomic_add(ethr_atomic_t *var, long incr)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_add__(var, incr);
-}
-
-int
-ethr_atomic_inc(ethr_atomic_t *incp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!incp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_inc__(incp);
-}
-
-int
-ethr_atomic_dec(ethr_atomic_t *decp)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!decp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_dec__(decp);
-}
-
-int
-ethr_atomic_and_old(ethr_atomic_t *var, long mask, long *old)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !old) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_and_old__(var, mask, old);
-}
-
-int
-ethr_atomic_or_old(ethr_atomic_t *var, long mask, long *old)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !old) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_or_old__(var, mask, old);
-}
-
-int
-ethr_atomic_xchg(ethr_atomic_t *var, long new, long *old)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !old) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_xchg__(var, new, old);
-}
-
-int
-ethr_atomic_cmpxchg(ethr_atomic_t *var, long new, long expected, long *old)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!var || !old) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_atomic_cmpxchg__(var, new, expected, old);
-}
-
-/* Spinlocks and rwspinlocks */
-
-int
-ethr_spinlock_init(ethr_spinlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_spinlock_init__(lock);
-}
-
-int
-ethr_spinlock_destroy(ethr_spinlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_spinlock_destroy__(lock);
-}
-
-
-int
-ethr_spin_unlock(ethr_spinlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_spin_unlock__(lock);
-}
-
-int
-ethr_spin_lock(ethr_spinlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_spin_lock__(lock);
-}
-
-int
-ethr_rwlock_init(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwlock_init__(lock);
-}
-
-int
-ethr_rwlock_destroy(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_rwlock_destroy__(lock);
-}
-
-int
-ethr_read_unlock(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_read_unlock__(lock);
-}
-
-int
-ethr_read_lock(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_read_lock__(lock);
-}
-
-int
-ethr_write_unlock(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_write_unlock__(lock);
-}
-
-int
-ethr_write_lock(ethr_rwlock_t *lock)
-{
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!lock) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- return ethr_write_lock__(lock);
-}
-
-
-int
-ethr_gate_init(ethr_gate *gp)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!gp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_init(&gp->mtx);
- if (res != 0)
- return res;
- res = ethr_cond_init(&gp->cnd);
- if (res != 0) {
- ethr_mutex_destroy(&gp->mtx);
- return res;
- }
- gp->open = 0;
- return 0;
-}
-
-int
-ethr_gate_destroy(ethr_gate *gp)
-{
- int res, dres;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!gp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_destroy(&gp->mtx);
- dres = ethr_cond_destroy(&gp->cnd);
- if (res == 0)
- res = dres;
- gp->open = 0;
- return res;
-}
-
-int
-ethr_gate_close(ethr_gate *gp)
-{
- int res;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!gp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_lock__(&gp->mtx);
- if (res != 0)
- return res;
- gp->open = 0;
- res = ethr_mutex_unlock__(&gp->mtx);
- return res;
-}
-
-int
-ethr_gate_let_through(ethr_gate *gp, unsigned no)
-{
- int res, ures;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!gp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_lock__(&gp->mtx);
- if (res != 0)
- return res;
- gp->open += no;
- res = (gp->open == 1
- ? ethr_cond_signal(&gp->cnd)
- : ethr_cond_broadcast(&gp->cnd));
- ures = ethr_mutex_unlock__(&gp->mtx);
- if (res != 0)
- res = ures;
- return res;
-}
-
-int
-ethr_gate_swait(ethr_gate *gp, int spincount)
-{
- int res, ures, n;
-#if ETHR_XCHK
- if (ethr_not_inited) {
- ASSERT(0);
- return EACCES;
- }
- if (!gp) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- n = spincount;
- res = ethr_mutex_lock__(&gp->mtx);
- if (res != 0)
- return res;
- while (n >= 0 && !gp->open) {
- res = ethr_mutex_unlock__(&gp->mtx);
- if (res != 0)
- return res;
- res = ethr_mutex_lock__(&gp->mtx);
- if (res != 0)
- return res;
- n--;
- }
- while (!gp->open) {
- res = ethr_cond_wait(&gp->cnd, &gp->mtx);
- if (res != 0 && res != EINTR)
- goto done;
- }
- gp->open--;
- done:
- ures = ethr_mutex_unlock__(&gp->mtx);
- if (res == 0)
- res = ures;
- return res;
-}
-
-
-int
-ethr_gate_wait(ethr_gate *gp)
-{
- return ethr_gate_swait(gp, 0);
-}
-
-
-/* rwmutex fallback */
-#ifdef ETHR_USE_RWMTX_FALLBACK
-
-int
-ethr_rwmutex_init(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (!rwmtx) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_init(&rwmtx->mtx);
- if (res != 0)
- return res;
- ethr_cond_init(&rwmtx->rcnd);
- if (res != 0)
- goto error_cleanup1;
- res = ethr_cond_init(&rwmtx->wcnd);
- if (res != 0)
- goto error_cleanup2;
- rwmtx->readers = 0;
- rwmtx->waiting_readers = 0;
- rwmtx->waiting_writers = 0;
-#if ETHR_XCHK
- rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
-#endif
- return 0;
- error_cleanup2:
- ethr_cond_destroy(&rwmtx->rcnd);
- error_cleanup1:
- ethr_mutex_destroy(&rwmtx->mtx);
- return res;
-}
-
-int
-ethr_rwmutex_destroy(ethr_rwmutex *rwmtx)
-{
- int res, pres;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
- rwmtx->initialized = 0;
-#endif
- res = ethr_mutex_destroy(&rwmtx->mtx);
- pres = ethr_cond_destroy(&rwmtx->rcnd);
- if (res == 0)
- res = pres;
- pres = ethr_cond_destroy(&rwmtx->wcnd);
- if (res == 0)
- res = pres;
- return res;
-}
-
-int
-ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_trylock__(&rwmtx->mtx);
- if (res != 0)
- return res;
- if (rwmtx->waiting_writers) {
- res = ethr_mutex_unlock__(&rwmtx->mtx);
- if (res == 0)
- return EBUSY;
- return res;
- }
- rwmtx->readers++;
- return ethr_mutex_unlock__(&rwmtx->mtx);
-}
-
-int
-ethr_rwmutex_rlock(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_lock__(&rwmtx->mtx);
- if (res != 0)
- return res;
- while (rwmtx->waiting_writers) {
- rwmtx->waiting_readers++;
- res = ethr_cond_wait(&rwmtx->rcnd, &rwmtx->mtx);
- rwmtx->waiting_readers--;
- if (res != 0 && res != EINTR) {
- (void) ethr_mutex_unlock__(&rwmtx->mtx);
- return res;
- }
- }
- rwmtx->readers++;
- return ethr_mutex_unlock__(&rwmtx->mtx);
-}
-
-int
-ethr_rwmutex_runlock(ethr_rwmutex *rwmtx)
-{
- int res, ures;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_lock__(&rwmtx->mtx);
- if (res != 0)
- return res;
- rwmtx->readers--;
- if (!rwmtx->readers && rwmtx->waiting_writers)
- res = ethr_cond_signal(&rwmtx->wcnd);
- ures = ethr_mutex_unlock__(&rwmtx->mtx);
- if (res == 0)
- res = ures;
- return res;
-}
-
-int
-ethr_rwmutex_tryrwlock(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_trylock__(&rwmtx->mtx);
- if (res != 0)
- return res;
- if (!rwmtx->readers && !rwmtx->waiting_writers)
- return 0;
- else {
- res = ethr_mutex_unlock__(&rwmtx->mtx);
- if (res == 0)
- return EBUSY;
- return res;
- }
-}
-
-int
-ethr_rwmutex_rwlock(ethr_rwmutex *rwmtx)
-{
- int res;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = ethr_mutex_lock__(&rwmtx->mtx);
- if (res != 0)
- return res;
- if (!rwmtx->readers && !rwmtx->waiting_writers)
- return 0;
-
- while (rwmtx->readers) {
- rwmtx->waiting_writers++;
- res = ethr_cond_wait(&rwmtx->wcnd, &rwmtx->mtx);
- rwmtx->waiting_writers--;
- if (res != 0 && res != EINTR) {
- (void) ethr_rwmutex_rwunlock(rwmtx);
- return res;
- }
- }
- return 0;
-}
-
-int
-ethr_rwmutex_rwunlock(ethr_rwmutex *rwmtx)
-{
- int res, ures;
-#if ETHR_XCHK
- if (!rwmtx || rwmtx->initialized != ETHR_RWMUTEX_INITIALIZED) {
- ASSERT(0);
- return EINVAL;
- }
-#endif
- res = 0;
- if (rwmtx->waiting_writers)
- res = ethr_cond_signal(&rwmtx->wcnd);
- else if (rwmtx->waiting_readers)
- res = ethr_cond_broadcast(&rwmtx->rcnd);
- ures = ethr_mutex_unlock__(&rwmtx->mtx);
- if (res == 0)
- res = ures;
- return res;
-}
-
-#endif /* #ifdef ETHR_USE_RWMTX_FALLBACK */
-
-void
-ethr_compiler_barrier(void)
-{
-
-}
-
-#ifdef DEBUG
-
-#include <stdio.h>
-int ethr_assert_failed(char *f, int l, char *a)
-{
- fprintf(stderr, "%s:%d: Assertion failed: %s\n", f, l, a);
- abort();
- return 0;
-}
-
-#endif
-
-
diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c
new file mode 100644
index 0000000000..6731c0eb46
--- /dev/null
+++ b/erts/lib_src/pthread/ethr_event.c
@@ -0,0 +1,219 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Author: Rickard Green
+ */
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHR_EVENT_IMPL__
+
+#include "ethread.h"
+
+#if defined(ETHR_LINUX_FUTEX_IMPL__)
+/* --- Linux futex implementation of ethread events ------------------------- */
+
+#include <sched.h>
+#include <errno.h>
+
+#define ETHR_YIELD_AFTER_BUSY_LOOPS 50
+
+int
+ethr_event_init(ethr_event *e)
+{
+ ethr_atomic_init(&e->futex, ETHR_EVENT_OFF__);
+ return 0;
+}
+
+int
+ethr_event_destroy(ethr_event *e)
+{
+ return 0;
+}
+
+static ETHR_INLINE int
+wait__(ethr_event *e, int spincount)
+{
+ unsigned sc = spincount;
+ int res;
+ long val;
+ int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+
+ if (spincount < 0)
+ ETHR_FATAL_ERROR__(EINVAL);
+
+ while (1) {
+ while (1) {
+ val = ethr_atomic_read(&e->futex);
+ if (val == ETHR_EVENT_ON__)
+ return 0;
+ if (sc == 0)
+ break;
+ sc--;
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ res = ETHR_YIELD();
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+ }
+
+ if (val != ETHR_EVENT_OFF_WAITER__) {
+ val = ethr_atomic_cmpxchg(&e->futex,
+ ETHR_EVENT_OFF_WAITER__,
+ ETHR_EVENT_OFF__);
+
+ if (val == ETHR_EVENT_ON__)
+ return 0;
+ ETHR_ASSERT(val == ETHR_EVENT_OFF__);
+ }
+
+ res = ETHR_FUTEX__(&e->futex, ETHR_FUTEX_WAIT__, ETHR_EVENT_OFF_WAITER__);
+ if (res == EINTR)
+ break;
+ if (res != 0 && res != EWOULDBLOCK)
+ ETHR_FATAL_ERROR__(res);
+ }
+
+ return res;
+}
+
+#elif defined(ETHR_PTHREADS)
+/* --- Posix mutex/cond implementation of events ---------------------------- */
+
+int
+ethr_event_init(ethr_event *e)
+{
+ int res;
+ ethr_atomic_init(&e->state, ETHR_EVENT_OFF__);
+ res = pthread_mutex_init(&e->mtx, NULL);
+ if (res != 0)
+ return res;
+ res = pthread_cond_init(&e->cnd, NULL);
+ if (res != 0) {
+ pthread_mutex_destroy(&e->mtx);
+ return res;
+ }
+ return 0;
+}
+
+int
+ethr_event_destroy(ethr_event *e)
+{
+ int res;
+ res = pthread_mutex_destroy(&e->mtx);
+ if (res != 0)
+ return res;
+ res = pthread_cond_destroy(&e->cnd);
+ if (res != 0)
+ return res;
+ return 0;
+}
+
+static ETHR_INLINE int
+wait__(ethr_event *e, int spincount)
+{
+ int sc = spincount;
+ long val;
+ int res, ulres;
+ int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+
+ if (spincount < 0)
+ ETHR_FATAL_ERROR__(EINVAL);
+
+ while (1) {
+ val = ethr_atomic_read(&e->state);
+ if (val == ETHR_EVENT_ON__)
+ return 0;
+ if (sc == 0)
+ break;
+ sc--;
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ res = ETHR_YIELD();
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+ }
+
+ if (val != ETHR_EVENT_OFF_WAITER__) {
+ val = ethr_atomic_cmpxchg(&e->state,
+ ETHR_EVENT_OFF_WAITER__,
+ ETHR_EVENT_OFF__);
+ if (val == ETHR_EVENT_ON__)
+ return 0;
+ ETHR_ASSERT(val == ETHR_EVENT_OFF__);
+ }
+
+ ETHR_ASSERT(val == ETHR_EVENT_OFF_WAITER__
+ || val == ETHR_EVENT_OFF__);
+
+ res = pthread_mutex_lock(&e->mtx);
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+
+ while (1) {
+
+ val = ethr_atomic_read(&e->state);
+ if (val == ETHR_EVENT_ON__)
+ break;
+
+ res = pthread_cond_wait(&e->cnd, &e->mtx);
+ if (res == EINTR)
+ break;
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+
+ ulres = pthread_mutex_unlock(&e->mtx);
+ if (ulres != 0)
+ ETHR_FATAL_ERROR__(ulres);
+
+ return res; /* 0 || EINTR */
+}
+
+#else
+#error No ethread event implementation
+#endif
+
+void
+ethr_event_reset(ethr_event *e)
+{
+ ethr_event_reset__(e);
+}
+
+void
+ethr_event_set(ethr_event *e)
+{
+ ethr_event_set__(e);
+}
+
+int
+ethr_event_wait(ethr_event *e)
+{
+ return wait__(e, 0);
+}
+
+int
+ethr_event_swait(ethr_event *e, int spincount)
+{
+ return wait__(e, spincount);
+}
diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c
new file mode 100644
index 0000000000..ea1d9d43f0
--- /dev/null
+++ b/erts/lib_src/pthread/ethread.c
@@ -0,0 +1,477 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Pthread implementation of the ethread library
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ETHR_CHILD_WAIT_SPIN_COUNT 4000
+
+#include <stdio.h>
+#ifdef ETHR_TIME_WITH_SYS_TIME
+# include <time.h>
+# include <sys/time.h>
+#else
+# ifdef ETHR_HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <limits.h>
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHREAD_IMPL__
+
+#include "ethread.h"
+#include "ethr_internal.h"
+
+#ifndef ETHR_HAVE_ETHREAD_DEFINES
+#error Missing configure defines
+#endif
+
+pthread_key_t ethr_ts_event_key__;
+static int child_wait_spin_count;
+
+/*
+ * --------------------------------------------------------------------------
+ * Static functions
+ * --------------------------------------------------------------------------
+ */
+
+static void thr_exit_cleanup(void)
+{
+ ethr_run_exit_handlers__();
+}
+
+
+/* Argument passed to thr_wrapper() */
+typedef struct {
+ ethr_atomic_t result;
+ ethr_ts_event *tse;
+ void *(*thr_func)(void *);
+ void *arg;
+ void *prep_func_res;
+} ethr_thr_wrap_data__;
+
+static void *thr_wrapper(void *vtwd)
+{
+ long result;
+ void *res;
+ ethr_thr_wrap_data__ *twd = (ethr_thr_wrap_data__ *) vtwd;
+ void *(*thr_func)(void *) = twd->thr_func;
+ void *arg = twd->arg;
+ ethr_ts_event *tsep = NULL;
+
+ result = (long) ethr_make_ts_event__(&tsep);
+
+ if (result == 0) {
+ tsep->iflgs |= ETHR_TS_EV_ETHREAD;
+ if (ethr_thr_child_func__)
+ ethr_thr_child_func__(twd->prep_func_res);
+ }
+
+ tsep = twd->tse; /* We aren't allowed to follow twd after
+ result has been set! */
+
+ ethr_atomic_set(&twd->result, result);
+
+ ethr_event_set(&tsep->event);
+
+ res = result == 0 ? (*thr_func)(arg) : NULL;
+
+ thr_exit_cleanup();
+ return res;
+}
+
+/* internal exports */
+
+int ethr_set_tse__(ethr_ts_event *tsep)
+{
+ return pthread_setspecific(ethr_ts_event_key__, (void *) tsep);
+}
+
+ethr_ts_event *ethr_get_tse__(void)
+{
+ return pthread_getspecific(ethr_ts_event_key__);
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * Exported functions
+ * --------------------------------------------------------------------------
+ */
+
+int
+ethr_init(ethr_init_data *id)
+{
+ int res;
+
+ if (!ethr_not_inited__)
+ return EINVAL;
+
+ ethr_not_inited__ = 0;
+
+ res = ethr_init_common__(id);
+ if (res != 0)
+ goto error;
+
+ child_wait_spin_count = ETHR_CHILD_WAIT_SPIN_COUNT;
+ if (erts_get_cpu_configured(ethr_cpu_info__) == 1)
+ child_wait_spin_count = 0;
+
+ res = pthread_key_create(&ethr_ts_event_key__, ethr_ts_event_destructor__);
+
+ return 0;
+ error:
+ ethr_not_inited__ = 1;
+ return res;
+
+}
+
+int
+ethr_late_init(ethr_late_init_data *id)
+{
+ int res = ethr_late_init_common__(id);
+ if (res != 0)
+ return res;
+ ethr_not_completely_inited__ = 0;
+ return res;
+}
+
+int
+ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
+ ethr_thr_opts *opts)
+{
+ ethr_thr_wrap_data__ twd;
+ pthread_attr_t attr;
+ int res, dres;
+ int use_stack_size = (opts && opts->suggested_stack_size >= 0
+ ? opts->suggested_stack_size
+ : -1 /* Use system default */);
+
+#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
+ if (use_stack_size < 0)
+ use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
+#endif
+
+#if ETHR_XCHK
+ if (ethr_not_completely_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!tid || !func) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+
+ ethr_atomic_init(&twd.result, -1);
+ twd.tse = ethr_get_ts_event();
+ twd.thr_func = func;
+ twd.arg = arg;
+
+ res = pthread_attr_init(&attr);
+ if (res != 0)
+ return res;
+
+ /* Error cleanup needed after this point */
+
+ /* Schedule child thread in system scope (if possible) ... */
+ res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ if (res != 0 && res != ENOTSUP)
+ goto error;
+
+ if (use_stack_size >= 0) {
+ size_t suggested_stack_size = (size_t) use_stack_size;
+ size_t stack_size;
+#ifdef ETHR_DEBUG
+ suggested_stack_size /= 2; /* Make sure we got margin */
+#endif
+#ifdef ETHR_STACK_GUARD_SIZE
+ /* The guard is at least on some platforms included in the stack size
+ passed when creating threads */
+ suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE);
+#endif
+ if (suggested_stack_size < ethr_min_stack_size__)
+ stack_size = ETHR_KW2B(ethr_min_stack_size__);
+ else if (suggested_stack_size > ethr_max_stack_size__)
+ stack_size = ETHR_KW2B(ethr_max_stack_size__);
+ else
+ stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
+ (void) pthread_attr_setstacksize(&attr, stack_size);
+ }
+
+#ifdef ETHR_STACK_GUARD_SIZE
+ (void) pthread_attr_setguardsize(&attr, ETHR_STACK_GUARD_SIZE);
+#endif
+
+ /* Detached or joinable... */
+ res = pthread_attr_setdetachstate(&attr,
+ (opts && opts->detached
+ ? PTHREAD_CREATE_DETACHED
+ : PTHREAD_CREATE_JOINABLE));
+ if (res != 0)
+ goto error;
+
+ /* Call prepare func if it exist */
+ if (ethr_thr_prepare_func__)
+ twd.prep_func_res = ethr_thr_prepare_func__();
+ else
+ twd.prep_func_res = NULL;
+
+ res = pthread_create((pthread_t *) tid, &attr, thr_wrapper, (void*) &twd);
+
+ if (res == 0) {
+ int spin_count = child_wait_spin_count;
+
+ /* Wait for child to initialize... */
+ while (1) {
+ long result;
+ ethr_event_reset(&twd.tse->event);
+
+ result = ethr_atomic_read(&twd.result);
+ if (result == 0)
+ break;
+
+ if (result > 0) {
+ res = (int) result;
+ goto error;
+ }
+
+ res = ethr_event_swait(&twd.tse->event, spin_count);
+ if (res != 0 && res != EINTR)
+ goto error;
+ spin_count = 0;
+ }
+ }
+
+ /* Cleanup... */
+
+ error:
+ dres = pthread_attr_destroy(&attr);
+ if (res == 0)
+ res = dres;
+ if (ethr_thr_parent_func__)
+ ethr_thr_parent_func__(twd.prep_func_res);
+ return res;
+}
+
+int
+ethr_thr_join(ethr_tid tid, void **res)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ return pthread_join((pthread_t) tid, res);
+}
+
+int
+ethr_thr_detach(ethr_tid tid)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ return pthread_detach((pthread_t) tid);
+}
+
+void
+ethr_thr_exit(void *res)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return;
+ }
+#endif
+ thr_exit_cleanup();
+ pthread_exit(res);
+}
+
+ethr_tid
+ethr_self(void)
+{
+ return (ethr_tid) pthread_self();
+}
+
+int
+ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
+{
+ return pthread_equal((pthread_t) tid1, (pthread_t) tid2);
+}
+
+
+/*
+ * Thread specific events
+ */
+
+ethr_ts_event *
+ethr_get_ts_event(void)
+{
+ return ethr_get_ts_event__();
+}
+
+void
+ethr_leave_ts_event(ethr_ts_event *tsep)
+{
+ ethr_leave_ts_event__(tsep);
+}
+
+/*
+ * Current time
+ */
+
+int
+ethr_time_now(ethr_timeval *time)
+{
+ int res;
+ struct timeval tv;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!time) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+
+ res = gettimeofday(&tv, NULL);
+ time->tv_sec = (long) tv.tv_sec;
+ time->tv_nsec = ((long) tv.tv_usec)*1000;
+ return res;
+}
+
+/*
+ * Thread specific data
+ */
+
+int
+ethr_tsd_key_create(ethr_tsd_key *keyp)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!keyp) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return pthread_key_create((pthread_key_t *) keyp, NULL);
+}
+
+int
+ethr_tsd_key_delete(ethr_tsd_key key)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ return pthread_key_delete((pthread_key_t) key);
+}
+
+int
+ethr_tsd_set(ethr_tsd_key key, void *value)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ return pthread_setspecific((pthread_key_t) key, value);
+}
+
+void *
+ethr_tsd_get(ethr_tsd_key key)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return NULL;
+ }
+#endif
+ return pthread_getspecific((pthread_key_t) key);
+}
+
+/*
+ * Signal functions
+ */
+
+#if ETHR_HAVE_ETHR_SIG_FUNCS
+
+int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!set && !oset) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ return pthread_sigmask(how, set, oset);
+}
+
+int ethr_sigwait(const sigset_t *set, int *sig)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!set || !sig) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ if (sigwait(set, sig) < 0)
+ return errno;
+ return 0;
+}
+
+#endif /* #if ETHR_HAVE_ETHR_SIG_FUNCS */
+
+ETHR_IMPL_NORETURN__
+ethr_abort__(void)
+{
+ abort();
+}
diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c
new file mode 100644
index 0000000000..ddb4780ff1
--- /dev/null
+++ b/erts/lib_src/win/ethr_event.c
@@ -0,0 +1,120 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Author: Rickard Green
+ */
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHR_EVENT_IMPL__
+
+#include "ethread.h"
+
+/* --- Windows implementation of thread events ------------------------------ */
+
+int
+ethr_event_init(ethr_event *e)
+{
+ e->state = ETHR_EVENT_OFF__;
+ e->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (e->handle == INVALID_HANDLE_VALUE)
+ return ethr_win_get_errno__();
+ return 0;
+}
+
+int
+ethr_event_destroy(ethr_event *e)
+{
+ BOOL res = CloseHandle(e->handle);
+ return res == 0 ? ethr_win_get_errno__() : 0;
+}
+
+void
+ethr_event_set(ethr_event *e)
+{
+ ethr_event_set__(e);
+}
+
+void
+ethr_event_reset(ethr_event *e)
+{
+ ethr_event_reset__(e);
+}
+
+static ETHR_INLINE int
+wait(ethr_event *e, int spincount)
+{
+ LONG state;
+ DWORD code;
+ int sc, res, until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+
+ if (spincount < 0)
+ ETHR_FATAL_ERROR__(EINVAL);
+
+ sc = spincount;
+
+ while (1) {
+ long on;
+ while (1) {
+#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+ state = e->state;
+#else
+ state = InterlockedExchangeAdd(&e->state, (LONG) 0);
+#endif
+ if (state == ETHR_EVENT_ON__)
+ return 0;
+ if (sc == 0)
+ break;
+ sc--;
+ ETHR_SPIN_BODY;
+ if (--until_yield == 0) {
+ until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS;
+ res = ETHR_YIELD();
+ if (res != 0)
+ ETHR_FATAL_ERROR__(res);
+ }
+ }
+
+ if (state != ETHR_EVENT_OFF_WAITER__) {
+ state = _InterlockedCompareExchange(&e->state,
+ ETHR_EVENT_OFF_WAITER__,
+ ETHR_EVENT_OFF__);
+ if (state == ETHR_EVENT_ON__)
+ return 0;
+ ETHR_ASSERT(state == ETHR_EVENT_OFF__);
+ }
+
+ code = WaitForSingleObject(e->handle, INFINITE);
+ if (code != WAIT_OBJECT_0)
+ ETHR_FATAL_ERROR__(ethr_win_get_errno__());
+ }
+
+}
+
+int
+ethr_event_wait(ethr_event *e)
+{
+ return wait(e, 0);
+}
+
+int
+ethr_event_swait(ethr_event *e, int spincount)
+{
+ return wait(e, spincount);
+}
diff --git a/erts/lib_src/win/ethread.c b/erts/lib_src/win/ethread.c
new file mode 100644
index 0000000000..69523edf94
--- /dev/null
+++ b/erts/lib_src/win/ethread.c
@@ -0,0 +1,625 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Windows native threads implementation of the ethread library
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ETHR_CHILD_WAIT_SPIN_COUNT 4000
+
+#undef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#include <winerror.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define ETHR_INLINE_FUNC_NAME_(X) X ## __
+#define ETHREAD_IMPL__
+
+#include "ethread.h"
+#include "ethr_internal.h"
+
+#ifndef ETHR_HAVE_ETHREAD_DEFINES
+#error Missing configure defines
+#endif
+
+/* Argument passed to thr_wrapper() */
+typedef struct {
+ ethr_tid *tid;
+ ethr_atomic_t result;
+ ethr_ts_event *tse;
+ void *(*thr_func)(void *);
+ void *arg;
+ void *prep_func_res;
+} ethr_thr_wrap_data__;
+
+#define ETHR_INVALID_TID_ID -1
+
+struct ethr_join_data_ {
+ HANDLE handle;
+ void *res;
+};
+
+static ethr_atomic_t thread_id_counter;
+static DWORD own_tid_key;
+static ethr_tid main_thr_tid;
+static int child_wait_spin_count;
+
+DWORD ethr_ts_event_key__;
+
+#define ETHR_GET_OWN_TID__ ((ethr_tid *) TlsGetValue(own_tid_key))
+
+/*
+ * --------------------------------------------------------------------------
+ * Static functions
+ * --------------------------------------------------------------------------
+ */
+
+static void thr_exit_cleanup(ethr_tid *tid, void *res)
+{
+
+ ETHR_ASSERT(tid == ETHR_GET_OWN_TID__);
+
+ if (tid->jdata)
+ tid->jdata->res = res;
+
+ ethr_run_exit_handlers__();
+ ethr_ts_event_destructor__((void *) ethr_get_tse__());
+}
+
+static unsigned __stdcall thr_wrapper(LPVOID vtwd)
+{
+ ethr_tid my_tid;
+ long result;
+ void *res;
+ ethr_thr_wrap_data__ *twd = (ethr_thr_wrap_data__ *) vtwd;
+ void *(*thr_func)(void *) = twd->thr_func;
+ void *arg = twd->arg;
+ ethr_ts_event *tsep = NULL;
+
+ result = (long) ethr_make_ts_event__(&tsep);
+
+ if (result == 0) {
+ tsep->iflgs |= ETHR_TS_EV_ETHREAD;
+ my_tid = *twd->tid;
+ if (!TlsSetValue(own_tid_key, (LPVOID) &my_tid)) {
+ result = (long) ethr_win_get_errno__();
+ ethr_free_ts_event__(tsep);
+ }
+ else {
+ if (ethr_thr_child_func__)
+ ethr_thr_child_func__(twd->prep_func_res);
+ }
+ }
+
+ tsep = twd->tse; /* We aren't allowed to follow twd after
+ result has been set! */
+
+ ethr_atomic_set(&twd->result, result);
+
+ ethr_event_set(&tsep->event);
+
+ res = result == 0 ? (*thr_func)(arg) : NULL;
+
+ thr_exit_cleanup(&my_tid, res);
+ return 0;
+}
+
+#ifdef __GNUC__
+#define LL_LITERAL(X) X##LL
+#else
+#define LL_LITERAL(X) X##i64
+#endif
+
+#define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600)
+
+static ETHR_INLINE void
+get_curr_time(long *sec, long *nsec)
+{
+ SYSTEMTIME t;
+ FILETIME ft;
+ LONGLONG lft;
+
+ GetSystemTime(&t);
+ SystemTimeToFileTime(&t, &ft);
+ memcpy(&lft, &ft, sizeof(lft));
+ *nsec = ((long) (lft % LL_LITERAL(10000000)))*100;
+ *sec = (long) ((lft / LL_LITERAL(10000000)) - EPOCH_JULIAN_DIFF);
+}
+
+/* internal exports */
+
+int
+ethr_win_get_errno__(void)
+{
+ return erts_get_last_win_errno();
+}
+
+int ethr_set_tse__(ethr_ts_event *tsep)
+{
+ return (TlsSetValue(ethr_ts_event_key__, (LPVOID) tsep)
+ ? 0
+ : ethr_win_get_errno__());
+}
+
+ethr_ts_event *ethr_get_tse__(void)
+{
+ return (ethr_ts_event *) TlsGetValue(ethr_ts_event_key__);
+}
+
+ETHR_IMPL_NORETURN__
+ethr_abort__(void)
+{
+#if 1
+ DebugBreak();
+#else
+ abort();
+#endif
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Exported functions
+ * ----------------------------------------------------------------------------
+ */
+
+int
+ethr_init(ethr_init_data *id)
+{
+#ifdef _WIN32_WINNT
+ DWORD major = (_WIN32_WINNT >> 8) & 0xff;
+ DWORD minor = _WIN32_WINNT & 0xff;
+ OSVERSIONINFO os_version;
+#endif
+ int err = 0;
+ unsigned long i;
+
+ if (!ethr_not_inited__)
+ return EINVAL;
+
+#ifdef _WIN32_WINNT
+ os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&os_version);
+ if (os_version.dwPlatformId != VER_PLATFORM_WIN32_NT
+ || os_version.dwMajorVersion < major
+ || (os_version.dwMajorVersion == major
+ && os_version.dwMinorVersion < minor))
+ return ENOTSUP;
+#endif
+ err = ethr_init_common__(id);
+ if (err)
+ goto error;
+
+ own_tid_key = TlsAlloc();
+ if (own_tid_key == TLS_OUT_OF_INDEXES)
+ goto error;
+
+ ethr_atomic_init(&thread_id_counter, 0);
+
+ main_thr_tid.id = 0;
+ main_thr_tid.jdata = NULL;
+
+ if (!TlsSetValue(own_tid_key, (LPVOID) &main_thr_tid))
+ goto error;
+
+ ETHR_ASSERT(&main_thr_tid == ETHR_GET_OWN_TID__);
+
+ ethr_ts_event_key__ = TlsAlloc();
+ if (ethr_ts_event_key__ == TLS_OUT_OF_INDEXES)
+ goto error;
+
+ child_wait_spin_count = ETHR_CHILD_WAIT_SPIN_COUNT;
+ if (erts_get_cpu_configured(ethr_cpu_info__) == 1)
+ child_wait_spin_count = 0;
+
+ ethr_not_inited__ = 0;
+
+ return 0;
+
+ error:
+ ethr_not_inited__ = 1;
+ if (err == 0)
+ err = ethr_win_get_errno__();
+ ETHR_ASSERT(err != 0);
+ return err;
+}
+
+int
+ethr_late_init(ethr_late_init_data *id)
+{
+ int res = ethr_late_init_common__(id);
+ if (res != 0)
+ return res;
+ ethr_not_completely_inited__ = 0;
+ return res;
+}
+
+
+/*
+ * Thread functions.
+ */
+
+int
+ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg,
+ ethr_thr_opts *opts)
+{
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ int err = 0;
+ ethr_thr_wrap_data__ twd;
+ DWORD code;
+ unsigned ID;
+ unsigned stack_size = 0; /* 0 = system default */
+ int use_stack_size = (opts && opts->suggested_stack_size >= 0
+ ? opts->suggested_stack_size
+ : -1 /* Use system default */);
+
+#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
+ if (use_stack_size < 0)
+ use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
+#endif
+
+#if ETHR_XCHK
+ if (ethr_not_completely_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!tid || !func) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+
+ do {
+ tid->id = ethr_atomic_inc_read(&thread_id_counter);
+ } while (tid->id == ETHR_INVALID_TID_ID);
+
+ if (opts && opts->detached)
+ tid->jdata = NULL;
+ else {
+ tid->jdata = ethr_mem__.std.alloc(sizeof(struct ethr_join_data_));
+ if (!tid->jdata)
+ return ENOMEM;
+ tid->jdata->handle = INVALID_HANDLE_VALUE;
+ tid->jdata->res = NULL;
+ }
+
+ if (use_stack_size >= 0) {
+ size_t suggested_stack_size = (size_t) use_stack_size;
+#ifdef ETHR_DEBUG
+ suggested_stack_size /= 2; /* Make sure we got margin */
+#endif
+ if (suggested_stack_size < ethr_min_stack_size__)
+ stack_size = (unsigned) ETHR_KW2B(ethr_min_stack_size__);
+ else if (suggested_stack_size > ethr_max_stack_size__)
+ stack_size = (unsigned) ETHR_KW2B(ethr_max_stack_size__);
+ else
+ stack_size = (unsigned)
+ ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
+ }
+
+ ethr_atomic_init(&twd.result, -1);
+
+ twd.tid = tid;
+ twd.thr_func = func;
+ twd.arg = arg;
+ twd.tse = ethr_get_ts_event();
+
+ /* Call prepare func if it exist */
+ if (ethr_thr_prepare_func__)
+ twd.prep_func_res = ethr_thr_prepare_func__();
+ else
+ twd.prep_func_res = NULL;
+
+ /* spawn the thr_wrapper function */
+ handle = (HANDLE) _beginthreadex(NULL, stack_size, thr_wrapper,
+ (LPVOID) &twd, 0, &ID);
+ if (handle == (HANDLE) 0) {
+ handle = INVALID_HANDLE_VALUE;
+ goto error;
+ }
+ else {
+ int spin_count = child_wait_spin_count;
+
+ ETHR_ASSERT(handle != INVALID_HANDLE_VALUE);
+
+ if (!tid->jdata)
+ CloseHandle(handle);
+ else
+ tid->jdata->handle = handle;
+
+ /* Wait for child to initialize... */
+ while (1) {
+ long result;
+ int err;
+ ethr_event_reset(&twd.tse->event);
+
+ result = ethr_atomic_read(&twd.result);
+ if (result == 0)
+ break;
+
+ if (result > 0) {
+ err = (int) result;
+ goto error;
+ }
+
+ err = ethr_event_swait(&twd.tse->event, spin_count);
+ if (err && err != EINTR)
+ goto error;
+ spin_count = 0;
+ }
+ }
+
+ if (ethr_thr_parent_func__)
+ ethr_thr_parent_func__(twd.prep_func_res);
+
+ if (twd.tse)
+ ethr_leave_ts_event(twd.tse);
+
+ return 0;
+
+ error:
+
+ if (err == 0)
+ err = ethr_win_get_errno__();
+ ETHR_ASSERT(err != 0);
+
+ if (ethr_thr_parent_func__)
+ ethr_thr_parent_func__(twd.prep_func_res);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ WaitForSingleObject(handle, INFINITE);
+ CloseHandle(handle);
+ }
+
+ if (tid->jdata) {
+ ethr_mem__.std.free(tid->jdata);
+ tid->jdata = NULL;
+ }
+
+ tid->id = ETHR_INVALID_TID_ID;
+
+ if (twd.tse)
+ ethr_leave_ts_event(twd.tse);
+
+ return err;
+}
+
+int ethr_thr_join(ethr_tid tid, void **res)
+{
+ DWORD code;
+
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+
+ if (tid.id == ETHR_INVALID_TID_ID || !tid.jdata)
+ return EINVAL;
+
+ /* Wait for thread to terminate */
+ code = WaitForSingleObject(tid.jdata->handle, INFINITE);
+ if (code != WAIT_OBJECT_0)
+ return ethr_win_get_errno__();
+
+ CloseHandle(tid.jdata->handle);
+ tid.jdata->handle = INVALID_HANDLE_VALUE;
+
+ if (res)
+ *res = tid.jdata->res;
+
+ /*
+ * User better not try to join or detach again; or
+ * bad things will happen... (users responsibility)
+ */
+
+ ethr_mem__.std.free(tid.jdata);
+
+ return 0;
+}
+
+
+int
+ethr_thr_detach(ethr_tid tid)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+
+ if (tid.id == ETHR_INVALID_TID_ID || !tid.jdata)
+ return EINVAL;
+
+ CloseHandle(tid.jdata->handle);
+ tid.jdata->handle = INVALID_HANDLE_VALUE;
+
+ /*
+ * User better not try to join or detach again; or
+ * bad things will happen... (users responsibility)
+ */
+
+ ethr_mem__.std.free(tid.jdata);
+
+ return 0;
+}
+
+
+void
+ethr_thr_exit(void *res)
+{
+ ethr_tid *tid;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return;
+ }
+#endif
+ tid = ETHR_GET_OWN_TID__;
+ if (!tid) {
+ ETHR_ASSERT(0);
+ _endthreadex((unsigned) 0);
+ }
+ thr_exit_cleanup(tid, res);
+ _endthreadex((unsigned) 0);
+}
+
+ethr_tid
+ethr_self(void)
+{
+ ethr_tid *tid;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ethr_tid dummy_tid = {ETHR_INVALID_TID_ID, NULL};
+ ETHR_ASSERT(0);
+ return dummy_tid;
+ }
+#endif
+ /* It is okay for non-ethreads (i.e. native win32 threads) to call
+ ethr_self(). They will however be returned an invalid tid. */
+ tid = ETHR_GET_OWN_TID__;
+ if (!tid) {
+ ethr_tid dummy_tid = {ETHR_INVALID_TID_ID, NULL};
+ return dummy_tid;
+ }
+ return *tid;
+}
+
+int
+ethr_equal_tids(ethr_tid tid1, ethr_tid tid2)
+{
+ /* An invalid tid does not equal any tid, not even an invalid tid */
+ return tid1.id == tid2.id && tid1.id != ETHR_INVALID_TID_ID;
+}
+
+int
+ethr_time_now(ethr_timeval *time)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!time) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ get_curr_time(&time->tv_sec, &time->tv_nsec);
+ return 0;
+}
+
+/*
+ * Thread specific data
+ */
+
+int
+ethr_tsd_key_create(ethr_tsd_key *keyp)
+{
+ DWORD key;
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+ if (!keyp) {
+ ETHR_ASSERT(0);
+ return EINVAL;
+ }
+#endif
+ key = TlsAlloc();
+ if (key == TLS_OUT_OF_INDEXES)
+ return ethr_win_get_errno__();
+ *keyp = (ethr_tsd_key) key;
+ return 0;
+}
+
+int
+ethr_tsd_key_delete(ethr_tsd_key key)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ if (!TlsFree((DWORD) key))
+ return ethr_win_get_errno__();
+ return 0;
+}
+
+int
+ethr_tsd_set(ethr_tsd_key key, void *value)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ if (!TlsSetValue((DWORD) key, (LPVOID) value))
+ return ethr_win_get_errno__();
+ return 0;
+}
+
+void *
+ethr_tsd_get(ethr_tsd_key key)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return NULL;
+ }
+#endif
+ return (void *) TlsGetValue((DWORD) key);
+}
+
+
+/*
+ * Thread specific events
+ */
+
+ethr_ts_event *
+ethr_get_ts_event(void)
+{
+ return ethr_get_ts_event__();
+}
+
+void
+ethr_leave_ts_event(ethr_ts_event *tsep)
+{
+ ethr_leave_ts_event__(tsep);
+}
+
+ethr_ts_event *
+ethr_create_ts_event__(void)
+{
+ ethr_ts_event *tsep;
+ ethr_make_ts_event__(&tsep);
+ return tsep;
+}
diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl
index bbc79e9381..0cc315e9be 100644
--- a/erts/test/ethread_SUITE.erl
+++ b/erts/test/ethread_SUITE.erl
@@ -37,21 +37,16 @@
equal_tids/1,
mutex/1,
try_lock_mutex/1,
- recursive_mutex/1,
time_now/1,
cond_wait/1,
- cond_timedwait/1,
broadcast/1,
detached_thread/1,
max_threads/1,
- forksafety/1,
- vfork/1,
tsd/1,
spinlock/1,
rwspinlock/1,
rwmutex/1,
- atomic/1,
- gate/1]).
+ atomic/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -60,21 +55,16 @@ tests() ->
equal_tids,
mutex,
try_lock_mutex,
- recursive_mutex,
time_now,
cond_wait,
- cond_timedwait,
broadcast,
detached_thread,
max_threads,
- forksafety,
- vfork,
tsd,
spinlock,
rwspinlock,
rwmutex,
- atomic,
- gate].
+ atomic].
all(doc) -> [];
all(suite) -> tests().
@@ -114,13 +104,6 @@ try_lock_mutex(suite) ->
try_lock_mutex(Config) ->
run_case(Config, "try_lock_mutex", "").
-recursive_mutex(doc) ->
- ["Tests recursive mutexes."];
-recursive_mutex(suite) ->
- [];
-recursive_mutex(Config) ->
- run_case(Config, "recursive_mutex", "").
-
time_now(doc) ->
["Tests ethr_time_now by comparing time values with Erlang."];
time_now(suite) ->
@@ -169,13 +152,6 @@ cond_wait(suite) ->
cond_wait(Config) ->
run_case(Config, "cond_wait", "").
-cond_timedwait(doc) ->
- ["Tests ethr_cond_timedwait with ethr_cond_signal and ethr_cond_broadcast."];
-cond_timedwait(suite) ->
- [];
-cond_timedwait(Config) ->
- run_case(Config, "cond_timedwait", "").
-
broadcast(doc) ->
["Tests that a ethr_cond_broadcast really wakes up all waiting threads"];
broadcast(suite) ->
@@ -197,25 +173,6 @@ max_threads(suite) ->
max_threads(Config) ->
run_case(Config, "max_threads", "").
-forksafety(doc) ->
- ["Tests forksafety."];
-forksafety(suite) ->
- [];
-forksafety(Config) ->
- run_case(Config, "forksafety", "").
-
-vfork(doc) ->
- ["Tests vfork with threads."];
-vfork(suite) ->
- case ?t:os_type() of
- {unix, osf1} ->
- {skip, "vfork() known to hang multi-threaded applications on osf1"};
- _ ->
- []
- end;
-vfork(Config) ->
- run_case(Config, "vfork", "").
-
tsd(doc) ->
["Tests thread specific data."];
tsd(suite) ->
@@ -251,13 +208,6 @@ atomic(suite) ->
atomic(Config) ->
run_case(Config, "atomic", "").
-gate(doc) ->
- ["Tests gates."];
-gate(suite) ->
- [];
-gate(Config) ->
- run_case(Config, "gate", "").
-
%%
%%
%% Auxiliary functions
diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c
index f779f13c51..7fc71d8047 100644
--- a/erts/test/ethread_SUITE_data/ethread_tests.c
+++ b/erts/test/ethread_SUITE_data/ethread_tests.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
- *
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
+ *
* %CopyrightEnd%
*/
@@ -90,10 +90,12 @@ static void print_line(char *frmt,...)
print_eol();
}
+#if 0 /* Currently not used; silence annoying warning... */
static void print(char *frmt,...)
{
PRINT_VA_LIST(frmt);
}
+#endif
static void fail(char *frmt,...)
{
@@ -197,8 +199,8 @@ create_join_thread_test(void)
}
for (i = 1; i <= CJTT_NO_THREADS; i++) {
- int *tres;
- res = ethr_thr_join(cjtt_tids[i], (void **) &tres);
+ void *tres;
+ res = ethr_thr_join(cjtt_tids[i], &tres);
ASSERT(res == 0);
ASSERT(tres == &cjtt_res[i]);
ASSERT(cjtt_res[i] == i);
@@ -216,8 +218,8 @@ create_join_thread_test(void)
#define ETT_THREADS 100000
static ethr_tid ett_tids[3];
-static ethr_mutex ett_mutex = ETHR_MUTEX_INITER;
-static ethr_cond ett_cond = ETHR_COND_INITER;
+static ethr_mutex ett_mutex;
+static ethr_cond ett_cond;
static int ett_terminate;
static void *
@@ -234,14 +236,12 @@ static void *
ett_thread2(void *unused)
{
int res;
- res = ethr_mutex_lock(&ett_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&ett_mutex);
while (!ett_terminate) {
res = ethr_cond_wait(&ett_cond, &ett_mutex);
ASSERT(res == 0);
}
- res = ethr_mutex_unlock(&ett_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&ett_mutex);
return NULL;
}
@@ -250,6 +250,10 @@ equal_tids_test(void)
{
int res, i;
+ res = ethr_mutex_init(&ett_mutex);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&ett_cond);
+ ASSERT(res == 0);
ett_tids[0] = ethr_self();
res = ethr_thr_create(&ett_tids[1], ett_thread, (void *) &ett_tids[1], NULL);
@@ -298,13 +302,10 @@ equal_tids_test(void)
ASSERT(res == 0);
}
- res = ethr_mutex_lock(&ett_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&ett_mutex);
ett_terminate = 1;
- res = ethr_cond_signal(&ett_cond);
- ASSERT(res == 0);
- res = ethr_mutex_unlock(&ett_mutex);
- ASSERT(res == 0);
+ ethr_cond_signal(&ett_cond);
+ ethr_mutex_unlock(&ett_mutex);
res = ethr_thr_join(ett_tids[1], NULL);
ASSERT(res == 0);
@@ -321,17 +322,14 @@ equal_tids_test(void)
* Tests mutexes.
*/
-static ethr_mutex mt_mutex = ETHR_MUTEX_INITER;
+static ethr_mutex mt_mutex;
static int mt_data;
void *
mt_thread(void *unused)
{
- int res;
-
print_line("Aux thread tries to lock mutex");
- res = ethr_mutex_lock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&mt_mutex);
print_line("Aux thread locked mutex");
ASSERT(mt_data == 0);
@@ -345,8 +343,7 @@ mt_thread(void *unused)
ASSERT(mt_data == 1);
- res = ethr_mutex_unlock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&mt_mutex);
print_line("Aux thread unlocked mutex");
return NULL;
@@ -356,18 +353,18 @@ mt_thread(void *unused)
static void
mutex_test(void)
{
- int do_restart = 1;
int res;
ethr_tid tid;
- print_line("Running test with statically initialized mutex");
+ print_line("Trying to initialize mutex");
+ res = ethr_mutex_init(&mt_mutex);
+ ASSERT(res == 0);
+ print_line("Initialized mutex");
- restart:
mt_data = 0;
print_line("Main thread tries to lock mutex");
- res = ethr_mutex_lock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&mt_mutex);
print_line("Main thread locked mutex");
ASSERT(mt_data == 0);
@@ -383,8 +380,7 @@ mutex_test(void)
ASSERT(mt_data == 0);
- res = ethr_mutex_unlock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&mt_mutex);
print_line("Main thread unlocked mutex");
print_line("Main thread goes to sleep for 1 second");
@@ -392,8 +388,7 @@ mutex_test(void)
print_line("Main thread woke up");
print_line("Main thread tries to lock mutex");
- res = ethr_mutex_lock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&mt_mutex);
print_line("Main thread locked mutex");
ASSERT(mt_data == 1);
@@ -404,8 +399,7 @@ mutex_test(void)
ASSERT(mt_data == 1);
- res = ethr_mutex_unlock(&mt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&mt_mutex);
print_line("Main thread unlocked mutex");
res = ethr_thr_join(tid, NULL);
@@ -416,20 +410,6 @@ mutex_test(void)
ASSERT(res == 0);
print_line("Main thread destroyed mutex");
- if (do_restart) {
- do_restart = 0;
-
- print_line("Running test with dynamically initialized mutex");
-
- print_line("Trying to initialize mutex");
- res = ethr_mutex_init(&mt_mutex);
- ASSERT(res == 0);
- print_line("Initialized mutex");
-
- goto restart;
-
- }
-
}
/*
@@ -438,9 +418,9 @@ mutex_test(void)
* Tests try lock mutex operation.
*/
-static ethr_mutex tlmt_mtx1 = ETHR_MUTEX_INITER;
-static ethr_mutex tlmt_mtx2 = ETHR_MUTEX_INITER;
-static ethr_cond tlmt_cnd2 = ETHR_COND_INITER;
+static ethr_mutex tlmt_mtx1;
+static ethr_mutex tlmt_mtx2;
+static ethr_cond tlmt_cnd2;
static int tlmt_mtx1_locked;
static int tlmt_mtx1_do_unlock;
@@ -450,32 +430,24 @@ tlmt_thread(void *unused)
{
int res;
- res = ethr_mutex_lock(&tlmt_mtx1);
- ASSERT(res == 0);
- res = ethr_mutex_lock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_lock(&tlmt_mtx1);
+ ethr_mutex_lock(&tlmt_mtx2);
tlmt_mtx1_locked = 1;
- res = ethr_cond_signal(&tlmt_cnd2);
- ASSERT(res == 0);
+ ethr_cond_signal(&tlmt_cnd2);
while (!tlmt_mtx1_do_unlock) {
res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
ASSERT(res == 0 || res == EINTR);
}
- res = ethr_mutex_unlock(&tlmt_mtx2);
- ASSERT(res == 0);
- res = ethr_mutex_unlock(&tlmt_mtx1);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&tlmt_mtx2);
+ ethr_mutex_unlock(&tlmt_mtx1);
- res = ethr_mutex_lock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_lock(&tlmt_mtx2);
tlmt_mtx1_locked = 0;
- res = ethr_cond_signal(&tlmt_cnd2);
- ASSERT(res == 0);
- res = ethr_mutex_unlock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_cond_signal(&tlmt_cnd2);
+ ethr_mutex_unlock(&tlmt_mtx2);
return NULL;
}
@@ -486,48 +458,49 @@ try_lock_mutex_test(void)
int i, res;
ethr_tid tid;
+ res = ethr_mutex_init(&tlmt_mtx1);
+ ASSERT(res == 0);
+ res = ethr_mutex_init(&tlmt_mtx2);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&tlmt_cnd2);
+ ASSERT(res == 0);
+
tlmt_mtx1_locked = 0;
tlmt_mtx1_do_unlock = 0;
res = ethr_thr_create(&tid, tlmt_thread, NULL, NULL);
ASSERT(res == 0);
- res = ethr_mutex_lock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_lock(&tlmt_mtx2);
while (!tlmt_mtx1_locked) {
res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
ASSERT(res == 0 || res == EINTR);
}
- res = ethr_mutex_unlock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&tlmt_mtx2);
for (i = 0; i < 10; i++) {
res = ethr_mutex_trylock(&tlmt_mtx1);
ASSERT(res == EBUSY);
}
- res = ethr_mutex_lock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_lock(&tlmt_mtx2);
tlmt_mtx1_do_unlock = 1;
- res = ethr_cond_signal(&tlmt_cnd2);
- ASSERT(res == 0);
+ ethr_cond_signal(&tlmt_cnd2);
while (tlmt_mtx1_locked) {
res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2);
ASSERT(res == 0 || res == EINTR);
}
- res = ethr_mutex_unlock(&tlmt_mtx2);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&tlmt_mtx2);
res = ethr_mutex_trylock(&tlmt_mtx1);
ASSERT(res == 0);
- res = ethr_mutex_unlock(&tlmt_mtx1);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&tlmt_mtx1);
res = ethr_thr_join(tid, NULL);
ASSERT(res == 0);
@@ -541,159 +514,6 @@ try_lock_mutex_test(void)
}
/*
- * The recursive mutex test case.
- *
- * Tests recursive mutexes.
- */
-
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
-
-static ethr_mutex rmt_mutex
-#ifdef ETHR_REC_MUTEX_INITER
- = ETHR_REC_MUTEX_INITER
-#endif
- ;
-static int rmt_data;
-
-void *
-rmt_thread(void *unused)
-{
- int res;
-
- print_line("Aux thread tries to lock mutex");
- res = ethr_mutex_lock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Aux thread locked mutex");
-
- ASSERT(rmt_data == 0);
-
- rmt_data = 1;
- print_line("Aux thread wrote");
-
- print_line("Aux thread goes to sleep for 1 second");
- do_sleep(1);
- print_line("Aux thread woke up");
-
- ASSERT(rmt_data == 1);
-
- res = ethr_mutex_unlock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Aux thread unlocked mutex");
-
- return NULL;
-}
-
-#endif
-
-static void
-recursive_mutex_test(void)
-{
-#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
- int do_restart = 1;
- int res;
- ethr_tid tid;
-
-#ifdef ETHR_REC_MUTEX_INITER
- print_line("Running test with statically initialized mutex");
-#else
- goto dynamic_init;
-#endif
-
- restart:
- rmt_data = 0;
-
- print_line("Main thread tries to lock mutex");
- res = ethr_mutex_lock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread locked mutex");
-
- print_line("Main thread tries to lock mutex again");
- res = ethr_mutex_lock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread locked mutex again");
-
- ASSERT(rmt_data == 0);
-
- print_line("Main thread about to create aux thread");
- res = ethr_thr_create(&tid, rmt_thread, NULL, NULL);
- ASSERT(res == 0);
- print_line("Main thread created aux thread");
-
- print_line("Main thread goes to sleep for 1 second");
- do_sleep(1);
- print_line("Main thread woke up");
-
- ASSERT(rmt_data == 0);
-
- res = ethr_mutex_unlock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread unlocked mutex");
-
- print_line("Main thread goes to sleep for 1 second");
- do_sleep(1);
- print_line("Main thread woke up");
-
- ASSERT(rmt_data == 0);
-
- res = ethr_mutex_unlock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread unlocked mutex again");
-
- print_line("Main thread goes to sleep for 1 second");
- do_sleep(1);
- print_line("Main thread woke up");
-
- print_line("Main thread tries to lock mutex");
- res = ethr_mutex_lock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread locked mutex");
-
- ASSERT(rmt_data == 1);
-
- print_line("Main thread goes to sleep for 1 second");
- do_sleep(1);
- print_line("Main thread woke up");
-
- ASSERT(rmt_data == 1);
-
- res = ethr_mutex_unlock(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread unlocked mutex");
-
- res = ethr_thr_join(tid, NULL);
- ASSERT(res == 0);
- print_line("Main thread joined aux thread");
-
- res = ethr_mutex_destroy(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Main thread destroyed mutex");
-
- if (do_restart) {
-#ifndef ETHR_REC_MUTEX_INITER
- dynamic_init:
-#endif
- do_restart = 0;
-
- print_line("Running test with dynamically initialized mutex");
-
- print_line("Trying to initialize mutex");
- res = ethr_rec_mutex_init(&rmt_mutex);
- ASSERT(res == 0);
- print_line("Initialized mutex");
-
- goto restart;
- }
-
-#ifndef ETHR_REC_MUTEX_INITER
- succeed("Static initializer for recursive mutexes not supported");
-#endif
-
-#else /* #ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT */
- skip("Recursive mutexes not supported");
-#endif /* #ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT */
-}
-
-/*
* The time now test.
*
* Tests ethr_time_now by comparing time values with Erlang.
@@ -763,106 +583,82 @@ time_now_test(void)
*/
-static ethr_mutex cwt_mutex = ETHR_MUTEX_INITER;
-static ethr_cond cwt_cond = ETHR_COND_INITER;
+static ethr_mutex cwt_mutex;
+static ethr_cond cwt_cond;
static int cwt_counter;
void *
-cwt_thread(void *is_timedwait_test_ptr)
+cwt_thread(void *unused)
{
- int use_timedwait = *((int *) is_timedwait_test_ptr);
int res;
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
-
- if (use_timedwait) {
- ethr_timeval tv;
- res = ethr_time_now(&tv);
- ASSERT(res == 0);
- tv.tv_sec += 3600; /* Make sure we won't time out */
+ ethr_mutex_lock(&cwt_mutex);
- do {
- res = ethr_cond_timedwait(&cwt_cond, &cwt_mutex, &tv);
- } while (res == EINTR);
- ASSERT(res == 0);
- }
- else {
- do {
- res = ethr_cond_wait(&cwt_cond, &cwt_mutex);
- } while (res == EINTR);
- ASSERT(res == 0);
- }
+ do {
+ res = ethr_cond_wait(&cwt_cond, &cwt_mutex);
+ } while (res == EINTR);
+ ASSERT(res == 0);
cwt_counter++;
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
return NULL;
}
static void
-cond_wait_test(int is_timedwait_test)
+cond_wait_test(void)
{
- int do_restart = !is_timedwait_test;
ethr_tid tid1, tid2;
int res;
- if (!is_timedwait_test)
- print_line("Running test with statically initialized mutex and cond");
+ res = ethr_mutex_init(&cwt_mutex);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&cwt_cond);
+ ASSERT(res == 0);
- restart:
/* Wake with signal */
cwt_counter = 0;
- res = ethr_thr_create(&tid1, cwt_thread, (void *) &is_timedwait_test, NULL);
+ res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL);
ASSERT(res == 0);
- res = ethr_thr_create(&tid2, cwt_thread, (void *) &is_timedwait_test, NULL);
+ res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL);
ASSERT(res == 0);
do_sleep(1); /* Make sure threads waits on cond var */
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&cwt_mutex);
- res = ethr_cond_signal(&cwt_cond); /* Wake one thread */
- ASSERT(res == 0);
+ ethr_cond_signal(&cwt_cond); /* Wake one thread */
do_sleep(1); /* Make sure awakened thread waits on mutex */
ASSERT(cwt_counter == 0);
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
do_sleep(1); /* Let awakened thread proceed */
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&cwt_mutex);
ASSERT(cwt_counter == 1);
- res = ethr_cond_signal(&cwt_cond); /* Wake the other thread */
- ASSERT(res == 0);
+ ethr_cond_signal(&cwt_cond); /* Wake the other thread */
do_sleep(1); /* Make sure awakened thread waits on mutex */
ASSERT(cwt_counter == 1);
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
do_sleep(1); /* Let awakened thread proceed */
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&cwt_mutex);
ASSERT(cwt_counter == 2);
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
res = ethr_thr_join(tid1, NULL);
ASSERT(res == 0);
@@ -875,35 +671,30 @@ cond_wait_test(int is_timedwait_test)
cwt_counter = 0;
- res = ethr_thr_create(&tid1, cwt_thread, (void *) &is_timedwait_test, NULL);
+ res = ethr_thr_create(&tid1, cwt_thread, NULL, NULL);
ASSERT(res == 0);
- res = ethr_thr_create(&tid2, cwt_thread, (void *) &is_timedwait_test, NULL);
+ res = ethr_thr_create(&tid2, cwt_thread, NULL, NULL);
ASSERT(res == 0);
do_sleep(1); /* Make sure threads waits on cond var */
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&cwt_mutex);
- res = ethr_cond_broadcast(&cwt_cond); /* Wake the threads */
- ASSERT(res == 0);
+ ethr_cond_broadcast(&cwt_cond); /* Wake the threads */
do_sleep(1); /* Make sure awakened threads wait on mutex */
ASSERT(cwt_counter == 0);
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
do_sleep(1); /* Let awakened threads proceed */
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&cwt_mutex);
ASSERT(cwt_counter == 2);
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&cwt_mutex);
res = ethr_thr_join(tid1, NULL);
ASSERT(res == 0);
@@ -916,113 +707,6 @@ cond_wait_test(int is_timedwait_test)
res = ethr_cond_destroy(&cwt_cond);
ASSERT(res == 0);
- if (do_restart) {
- do_restart = 0;
- res = ethr_mutex_init(&cwt_mutex);
- ASSERT(res == 0);
- res = ethr_cond_init(&cwt_cond);
- ASSERT(res == 0);
- print_line("Running test with dynamically initialized mutex and cond");
- goto restart;
- }
-}
-
-/*
- * The cond timedwait test case.
- *
- * Tests ethr_cond_timedwait with ethr_cond_signal and ethr_cond_broadcast.
- */
-
-#define CTWT_MAX_TIME_DIFF 100000
-
-static long
-ctwt_check_timeout(long to)
-{
- int res;
- ethr_timeval tva, tvb;
- long diff, abs_diff;
-
- res = ethr_time_now(&tva);
- ASSERT(res == 0);
-
- tva.tv_sec += to / 1000;
- tva.tv_nsec += (to % 1000) * 1000000;
- if (tva.tv_nsec >= 1000000000) {
- tva.tv_sec++;
- tva.tv_nsec -= 1000000000;
- ASSERT(tva.tv_nsec < 1000000000);
- }
-
- do {
- res = ethr_cond_timedwait(&cwt_cond, &cwt_mutex, &tva);
- } while (res == EINTR);
- ASSERT(res == ETIMEDOUT);
-
- res = ethr_time_now(&tvb);
- ASSERT(res == 0);
-
- diff = (tvb.tv_sec - tva.tv_sec) * 1000000;
- diff += (tvb.tv_nsec - tva.tv_nsec)/1000;
-
- print("Timeout=%ld; ", to);
- print("tva.tv_sec=%ld tva.tv_nsec=%ld; ", tva.tv_sec, tva.tv_nsec);
- print("tvb.tv_sec=%ld tvb.tv_nsec=%ld; ", tvb.tv_sec, tvb.tv_nsec);
- print_line("diff (tvb - tva) = %ld us", diff);
-
- abs_diff = (long) abs((int) diff);
-
- ASSERT(CTWT_MAX_TIME_DIFF >= abs_diff);
- return abs_diff;
-}
-
-static void
-cond_timedwait_test(void)
-{
- int do_restart = 1;
- long abs_diff, max_abs_diff = 0;
- int res;
-
-#define CTWT_UPD_MAX_DIFF if (abs_diff > max_abs_diff) max_abs_diff = abs_diff;
-
- print_line("Running test with statically initialized mutex and cond");
-
- print_line("CTWT_MAX_TIME_DIFF=%d", CTWT_MAX_TIME_DIFF);
-
- restart:
-
- res = ethr_mutex_lock(&cwt_mutex);
- ASSERT(res == 0);
-
- abs_diff = ctwt_check_timeout(300);
- CTWT_UPD_MAX_DIFF;
- abs_diff = ctwt_check_timeout(700);
- CTWT_UPD_MAX_DIFF;
- abs_diff = ctwt_check_timeout(1000);
- CTWT_UPD_MAX_DIFF;
- abs_diff = ctwt_check_timeout(2300);
- CTWT_UPD_MAX_DIFF;
- abs_diff = ctwt_check_timeout(5100);
- CTWT_UPD_MAX_DIFF;
-
- res = ethr_mutex_unlock(&cwt_mutex);
- ASSERT(res == 0);
-
- cond_wait_test(1);
-
- if (do_restart) {
- do_restart = 0;
- res = ethr_mutex_init(&cwt_mutex);
- ASSERT(res == 0);
- res = ethr_cond_init(&cwt_cond);
- ASSERT(res == 0);
- print_line("Running test with dynamically initialized mutex and cond");
- goto restart;
- }
-
- print_line("Max absolute diff = %d us", max_abs_diff);
- succeed("Max absolute diff = %d us", max_abs_diff);
-
-#undef CTWT_UPD_MAX_DIFF
}
/*
@@ -1037,9 +721,9 @@ cond_timedwait_test(void)
static int bct_woken = 0;
static int bct_waiting = 0;
static int bct_done = 0;
-static ethr_mutex bct_mutex = ETHR_MUTEX_INITER;
-static ethr_cond bct_cond = ETHR_COND_INITER;
-static ethr_cond bct_cntrl_cond = ETHR_COND_INITER;
+static ethr_mutex bct_mutex;
+static ethr_cond bct_cond;
+static ethr_cond bct_cntrl_cond;
static void *
@@ -1047,30 +731,24 @@ bct_thread(void *unused)
{
int res;
- res = ethr_mutex_lock(&bct_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&bct_mutex);
while (!bct_done) {
bct_waiting++;
- if (bct_waiting == BCT_THREADS) {
- res = ethr_cond_signal(&bct_cntrl_cond);
- ASSERT(res == 0);
- }
+ if (bct_waiting == BCT_THREADS)
+ ethr_cond_signal(&bct_cntrl_cond);
do {
res = ethr_cond_wait(&bct_cond, &bct_mutex);
} while (res == EINTR);
ASSERT(res == 0);
bct_woken++;
- if (bct_woken == BCT_THREADS) {
- res = ethr_cond_signal(&bct_cntrl_cond);
- ASSERT(res == 0);
- }
+ if (bct_woken == BCT_THREADS)
+ ethr_cond_signal(&bct_cntrl_cond);
}
- res = ethr_mutex_unlock(&bct_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&bct_mutex);
return NULL;
}
@@ -1081,14 +759,20 @@ broadcast_test(void)
int res, i;
ethr_tid tid[BCT_THREADS];
+ res = ethr_mutex_init(&bct_mutex);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&bct_cntrl_cond);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&bct_cond);
+ ASSERT(res == 0);
+
for (i = 0; i < BCT_THREADS; i++) {
res = ethr_thr_create(&tid[i], bct_thread, NULL, NULL);
ASSERT(res == 0);
}
- res = ethr_mutex_lock(&bct_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&bct_mutex);
for (i = 0; i < BCT_NO_OF_WAITS; i++) {
@@ -1101,8 +785,7 @@ broadcast_test(void)
bct_woken = 0;
/* Wake all threads */
- res = ethr_cond_broadcast(&bct_cond);
- ASSERT(res == 0);
+ ethr_cond_broadcast(&bct_cond);
while (bct_woken != BCT_THREADS) {
res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex);
@@ -1114,13 +797,11 @@ broadcast_test(void)
bct_done = 1;
/* Wake all threads */
- res = ethr_cond_broadcast(&bct_cond);
- ASSERT(res == 0);
+ ethr_cond_broadcast(&bct_cond);
- res = ethr_mutex_unlock(&bct_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&bct_mutex);
- for (i = 0; i < BCT_THREADS - 1; i++) {
+ for (i = 0; i < BCT_THREADS; i++) {
res = ethr_thr_join(tid[i], NULL);
ASSERT(res == 0);
}
@@ -1143,26 +824,22 @@ broadcast_test(void)
#define DT_THREADS (50*1024)
#define DT_BATCH_SIZE 64
-static ethr_mutex dt_mutex = ETHR_MUTEX_INITER;
-static ethr_cond dt_cond = ETHR_COND_INITER;
+static ethr_mutex dt_mutex;
+static ethr_cond dt_cond;
static int dt_count;
static int dt_limit;
static void *
dt_thread(void *unused)
{
- int res;
-
- res = ethr_mutex_lock(&dt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&dt_mutex);
dt_count++;
if (dt_count >= dt_limit)
ethr_cond_signal(&dt_cond);
- res = ethr_mutex_unlock(&dt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&dt_mutex);
return NULL;
}
@@ -1174,6 +851,11 @@ detached_thread_test(void)
ethr_tid tid[DT_BATCH_SIZE];
int i, j, res;
+ res = ethr_mutex_init(&dt_mutex);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&dt_cond);
+ ASSERT(res == 0);
+
thr_opts.detached = 1;
dt_count = 0;
dt_limit = 0;
@@ -1187,14 +869,12 @@ detached_thread_test(void)
ASSERT(res == 0);
}
- res = ethr_mutex_lock(&dt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&dt_mutex);
while (dt_count < dt_limit) {
res = ethr_cond_wait(&dt_cond, &dt_mutex);
ASSERT(res == 0 || res == EINTR);
}
- res = ethr_mutex_unlock(&dt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&dt_mutex);
print_line("dt_count = %d", dt_count);
}
@@ -1211,8 +891,8 @@ detached_thread_test(void)
#define MTT_TIMES 10
static int mtt_terminate;
-static ethr_mutex mtt_mutex = ETHR_MUTEX_INITER;
-static ethr_cond mtt_cond = ETHR_COND_INITER;
+static ethr_mutex mtt_mutex;
+static ethr_cond mtt_cond;
static char mtt_string[22*MTT_TIMES]; /* 22 is enough for ", %d" */
@@ -1220,16 +900,14 @@ void *mtt_thread(void *unused)
{
int res;
- res = ethr_mutex_lock(&mtt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&mtt_mutex);
while (!mtt_terminate) {
res = ethr_cond_wait(&mtt_cond, &mtt_mutex);
ASSERT(res == 0 || res == EINTR);
}
- res = ethr_mutex_unlock(&mtt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&mtt_mutex);
return NULL;
}
@@ -1265,16 +943,13 @@ mtt_create_join_threads(void)
print_line("%d = ethr_thr_create()", res);
print_line("Number of created threads: %d", no_threads);
- res = ethr_mutex_lock(&mtt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_lock(&mtt_mutex);
mtt_terminate = 1;
- res = ethr_cond_broadcast(&mtt_cond);
- ASSERT(res == 0);
+ ethr_cond_broadcast(&mtt_cond);
- res = ethr_mutex_unlock(&mtt_mutex);
- ASSERT(res == 0);
+ ethr_mutex_unlock(&mtt_mutex);
while (ix) {
res = ethr_thr_join(tids[--ix], NULL);
@@ -1292,9 +967,14 @@ mtt_create_join_threads(void)
static void
max_threads_test(void)
{
- int no_threads[MTT_TIMES], i, up, down, eq;
+ int no_threads[MTT_TIMES], i, up, down, eq, res;
char *str;
+ res = ethr_mutex_init(&mtt_mutex);
+ ASSERT(res == 0);
+ res = ethr_cond_init(&mtt_cond);
+ ASSERT(res == 0);
+
for (i = 0; i < MTT_TIMES; i++) {
no_threads[i] = mtt_create_join_threads();
}
@@ -1326,272 +1006,6 @@ max_threads_test(void)
}
-
-/*
- * The forksafety test case.
- *
- * Tests forksafety.
- */
-#ifdef __WIN32__
-#define NO_FORK_PRESENT
-#endif
-
-#ifndef NO_FORK_PRESENT
-
-static ethr_mutex ft_test_inner_mutex = ETHR_MUTEX_INITER;
-static ethr_mutex ft_test_outer_mutex = ETHR_MUTEX_INITER;
-static ethr_mutex ft_go_mutex = ETHR_MUTEX_INITER;
-static ethr_cond ft_go_cond = ETHR_COND_INITER;
-static int ft_go;
-static int ft_have_forked;
-
-static void *
-ft_thread(void *unused)
-{
- int res;
-
- res = ethr_mutex_lock(&ft_test_outer_mutex);
- ASSERT(res == 0);
-
- res = ethr_mutex_lock(&ft_go_mutex);
- ASSERT(res == 0);
-
- ft_go = 1;
- res = ethr_cond_signal(&ft_go_cond);
- ASSERT(res == 0);
- res = ethr_mutex_unlock(&ft_go_mutex);
- ASSERT(res == 0);
-
- do_sleep(1);
- ASSERT(!ft_have_forked);
-
- res = ethr_mutex_lock(&ft_test_inner_mutex);
- ASSERT(res == 0);
-
- res = ethr_mutex_unlock(&ft_test_inner_mutex);
- ASSERT(res == 0);
-
- do_sleep(1);
- ASSERT(!ft_have_forked);
-
- res = ethr_mutex_unlock(&ft_test_outer_mutex);
- ASSERT(res == 0);
-
- do_sleep(1);
- ASSERT(ft_have_forked);
-
-
- return NULL;
-}
-
-#endif /* #ifndef NO_FORK_PRESENT */
-
-static void
-forksafety_test(void)
-{
-#ifdef NO_FORK_PRESENT
- skip("No fork() present; nothing to test");
-#elif defined(DEBUG)
- skip("Doesn't work in debug build");
-#else
- char snd_msg[] = "ok, bye!";
- char rec_msg[sizeof(snd_msg)*2];
- ethr_tid tid;
- int res;
- int fds[2];
-
-
- res = ethr_mutex_set_forksafe(&ft_test_inner_mutex);
- if (res == ENOTSUP) {
- skip("Forksafety not supported on this platform!");
- }
- ASSERT(res == 0);
- res = ethr_mutex_set_forksafe(&ft_test_outer_mutex);
- ASSERT(res == 0);
-
-
- res = pipe(fds);
- ASSERT(res == 0);
-
- ft_go = 0;
- ft_have_forked = 0;
-
- res = ethr_mutex_lock(&ft_go_mutex);
- ASSERT(res == 0);
-
- res = ethr_thr_create(&tid, ft_thread, NULL, NULL);
- ASSERT(res == 0);
-
- do {
- res = ethr_cond_wait(&ft_go_cond, &ft_go_mutex);
- } while (res == EINTR || !ft_go);
- ASSERT(res == 0);
-
- res = ethr_mutex_unlock(&ft_go_mutex);
- ASSERT(res == 0);
-
- res = fork();
- ft_have_forked = 1;
- if (res == 0) {
- close(fds[0]);
- res = ethr_mutex_lock(&ft_test_outer_mutex);
- if (res != 0)
- _exit(1);
- res = ethr_mutex_lock(&ft_test_inner_mutex);
- if (res != 0)
- _exit(1);
- res = ethr_mutex_unlock(&ft_test_inner_mutex);
- if (res != 0)
- _exit(1);
- res = ethr_mutex_unlock(&ft_test_outer_mutex);
- if (res != 0)
- _exit(1);
-
- res = ethr_mutex_destroy(&ft_test_inner_mutex);
- if (res != 0)
- _exit(1);
- res = ethr_mutex_destroy(&ft_test_outer_mutex);
- if (res != 0)
- _exit(1);
-
- res = (int) write(fds[1], (void *) snd_msg, sizeof(snd_msg));
- if (res != sizeof(snd_msg))
- _exit(1);
- close(fds[1]);
- _exit(0);
- }
- ASSERT(res > 0);
- close(fds[1]);
-
- res = (int) read(fds[0], (void *) rec_msg, sizeof(rec_msg));
- ASSERT(res == (int) sizeof(snd_msg));
- ASSERT(strcmp(snd_msg, rec_msg) == 0);
-
- close(fds[0]);
-#endif
-}
-
-
-/*
- * The vfork test case.
- *
- * Tests vfork with threads.
- */
-
-#ifdef __WIN32__
-#define NO_VFORK_PRESENT
-#endif
-
-#ifndef NO_VFORK_PRESENT
-
-#undef vfork
-
-static ethr_mutex vt_mutex = ETHR_MUTEX_INITER;
-
-static void *
-vt_thread(void *vprog)
-{
- char *prog = (char *) vprog;
- int res;
- char snd_msg[] = "ok, bye!";
- char rec_msg[sizeof(snd_msg)*2];
- int fds[2];
- char closefd[20];
- char writefd[20];
-
- res = pipe(fds);
- ASSERT(res == 0);
-
- res = sprintf(closefd, "%d", fds[0]);
- ASSERT(res <= 20);
- res = sprintf(writefd, "%d", fds[1]);
- ASSERT(res <= 20);
-
- print("parent: About to vfork and execute ");
- print("execlp(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", NULL)",
- prog, prog, "vfork", "exec", snd_msg, closefd, writefd);
- print_line(" in child");
- res = vfork();
- if (res == 0) {
- execlp(prog, prog, "vfork", "exec", snd_msg, closefd, writefd, NULL);
- _exit(1);
- }
- ASSERT(res > 0);
-
- print_line("parent: I'm back");
-
- close(fds[1]);
-
- res = (int) read(fds[0], (void *) rec_msg, sizeof(rec_msg));
- print_line("parent: %d = read()", res);
- print_line("parent: rec_msg=\"%s\"", rec_msg);
- ASSERT(res == (int) sizeof(snd_msg));
- ASSERT(strcmp(snd_msg, rec_msg) == 0);
-
- close(fds[0]);
-
- return NULL;
-}
-
-#endif /* #ifndef NO_VFORK_PRESENT */
-
-static void
-vfork_test(int argc, char *argv[])
-{
-#ifdef NO_VFORK_PRESENT
- skip("No vfork() present; nothing to test");
-#else
- int res;
- ethr_tid tid;
-
- if (argc == 6 && strcmp("exec", argv[2]) == 0) {
- /* We are child after vfork() and execlp() ... */
-
- char *snd_msg;
- int closefd;
- int writefd;
-
- snd_msg = argv[3];
- closefd = atoi(argv[4]);
- writefd = atoi(argv[5]);
-
- print_line("child: snd_msg=\"%s\"; closefd=%d writefd=%d",
- snd_msg, closefd, writefd);
-
- close(closefd);
-
- res = (int) write(writefd, (void *) snd_msg, strlen(snd_msg)+1);
- print_line("child: %d = write()", res);
- if (res != strlen(snd_msg)+1)
- exit(1);
- close(writefd);
- print_line("child: bye");
- exit(0);
- }
- ASSERT(argc == 2);
-
- res = ethr_mutex_set_forksafe(&vt_mutex);
- ASSERT(res == 0 || res == ENOTSUP);
- res = ethr_mutex_lock(&vt_mutex);
- ASSERT(res == 0);
-
- res = ethr_thr_create(&tid, vt_thread, (void *) argv[0], NULL);
- ASSERT(res == 0);
-
- do_sleep(1);
-
- res = ethr_mutex_unlock(&vt_mutex);
- ASSERT(res == 0);
-
- res = ethr_thr_join(tid, NULL);
- ASSERT(res == 0);
-
- res = ethr_mutex_destroy(&vt_mutex);
- ASSERT(res == 0);
-#endif
-}
-
-
/*
* The tsd test case.
*
@@ -1651,11 +1065,8 @@ static int st_data;
void *
st_thread(void *unused)
{
- int res;
-
print_line("Aux thread tries to lock spinlock");
- res = ethr_spin_lock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_lock(&st_spinlock);
print_line("Aux thread locked spinlock");
ASSERT(st_data == 0);
@@ -1669,8 +1080,7 @@ st_thread(void *unused)
ASSERT(st_data == 1);
- res = ethr_spin_unlock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_unlock(&st_spinlock);
print_line("Aux thread unlocked spinlock");
return NULL;
@@ -1691,8 +1101,7 @@ spinlock_test(void)
st_data = 0;
print_line("Main thread tries to lock spinlock");
- res = ethr_spin_lock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_lock(&st_spinlock);
print_line("Main thread locked spinlock");
ASSERT(st_data == 0);
@@ -1708,8 +1117,7 @@ spinlock_test(void)
ASSERT(st_data == 0);
- res = ethr_spin_unlock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_unlock(&st_spinlock);
print_line("Main thread unlocked spinlock");
print_line("Main thread goes to sleep for 1 second");
@@ -1717,8 +1125,7 @@ spinlock_test(void)
print_line("Main thread woke up");
print_line("Main thread tries to lock spinlock");
- res = ethr_spin_lock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_lock(&st_spinlock);
print_line("Main thread locked spinlock");
ASSERT(st_data == 1);
@@ -1729,8 +1136,7 @@ spinlock_test(void)
ASSERT(st_data == 1);
- res = ethr_spin_unlock(&st_spinlock);
- ASSERT(res == 0);
+ ethr_spin_unlock(&st_spinlock);
print_line("Main thread unlocked spinlock");
res = ethr_thr_join(tid, NULL);
@@ -1757,23 +1163,19 @@ void *
rwst_thread(void *unused)
{
int data;
- int res;
print_line("Aux thread tries to read lock rwspinlock");
- res = ethr_read_lock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_read_lock(&rwst_rwspinlock);
print_line("Aux thread read locked rwspinlock");
ASSERT(rwst_data == 4711);
print_line("Aux thread tries to read unlock rwspinlock");
- res = ethr_read_unlock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_read_unlock(&rwst_rwspinlock);
print_line("Aux thread read unlocked rwspinlock");
print_line("Aux thread tries to write lock rwspinlock");
- res = ethr_write_lock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_write_lock(&rwst_rwspinlock);
print_line("Aux thread write locked rwspinlock");
data = ++rwst_data;
@@ -1787,8 +1189,7 @@ rwst_thread(void *unused)
++rwst_data;
print_line("Aux thread tries to write unlock rwspinlock");
- res = ethr_write_unlock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_write_unlock(&rwst_rwspinlock);
print_line("Aux thread write unlocked rwspinlock");
return NULL;
@@ -1810,8 +1211,7 @@ rwspinlock_test(void)
rwst_data = 4711;
print_line("Main thread tries to read lock rwspinlock");
- res = ethr_read_lock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_read_lock(&rwst_rwspinlock);
print_line("Main thread read locked rwspinlock");
ASSERT(rwst_data == 4711);
@@ -1828,13 +1228,11 @@ rwspinlock_test(void)
ASSERT(rwst_data == 4711);
print_line("Main thread tries to read unlock rwspinlock");
- res = ethr_read_unlock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_read_unlock(&rwst_rwspinlock);
print_line("Main thread read unlocked rwspinlock");
print_line("Main thread tries to write lock rwspinlock");
- res = ethr_write_lock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_write_lock(&rwst_rwspinlock);
print_line("Main thread write locked rwspinlock");
data = ++rwst_data;
@@ -1847,8 +1245,7 @@ rwspinlock_test(void)
++rwst_data;
print_line("Main thread tries to write unlock rwspinlock");
- res = ethr_write_unlock(&rwst_rwspinlock);
- ASSERT(res == 0);
+ ethr_write_unlock(&rwst_rwspinlock);
print_line("Main thread write unlocked rwspinlock");
res = ethr_thr_join(tid, NULL);
@@ -1875,23 +1272,19 @@ void *
rwmt_thread(void *unused)
{
int data;
- int res;
print_line("Aux thread tries to read lock rwmutex");
- res = ethr_rwmutex_rlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rlock(&rwmt_rwmutex);
print_line("Aux thread read locked rwmutex");
ASSERT(rwmt_data == 4711);
print_line("Aux thread tries to read unlock rwmutex");
- res = ethr_rwmutex_runlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_runlock(&rwmt_rwmutex);
print_line("Aux thread read unlocked rwmutex");
print_line("Aux thread tries to write lock rwmutex");
- res = ethr_rwmutex_rwlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rwlock(&rwmt_rwmutex);
print_line("Aux thread write locked rwmutex");
data = ++rwmt_data;
@@ -1905,8 +1298,7 @@ rwmt_thread(void *unused)
++rwmt_data;
print_line("Aux thread tries to write unlock rwmutex");
- res = ethr_rwmutex_rwunlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rwunlock(&rwmt_rwmutex);
print_line("Aux thread write unlocked rwmutex");
return NULL;
@@ -1928,8 +1320,7 @@ rwmutex_test(void)
rwmt_data = 4711;
print_line("Main thread tries to read lock rwmutex");
- res = ethr_rwmutex_rlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rlock(&rwmt_rwmutex);
print_line("Main thread read locked rwmutex");
ASSERT(rwmt_data == 4711);
@@ -1946,13 +1337,11 @@ rwmutex_test(void)
ASSERT(rwmt_data == 4711);
print_line("Main thread tries to read unlock rwmutex");
- res = ethr_rwmutex_runlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_runlock(&rwmt_rwmutex);
print_line("Main thread read unlocked rwmutex");
print_line("Main thread tries to write lock rwmutex");
- res = ethr_rwmutex_rwlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rwlock(&rwmt_rwmutex);
print_line("Main thread write locked rwmutex");
data = ++rwmt_data;
@@ -1965,8 +1354,7 @@ rwmutex_test(void)
++rwmt_data;
print_line("Main thread tries to write unlock rwmutex");
- res = ethr_rwmutex_rwunlock(&rwmt_rwmutex);
- ASSERT(res == 0);
+ ethr_rwmutex_rwunlock(&rwmt_rwmutex);
print_line("Main thread write unlocked rwmutex");
res = ethr_thr_join(tid, NULL);
@@ -1998,65 +1386,53 @@ static ethr_atomic_t at_data;
void *
at_thread(void *unused)
{
- int res, i;
+ int i;
long val, go;
- res = ethr_atomic_inctest(&at_ready, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_inc_read(&at_ready);
ASSERT(val > 0);
ASSERT(val <= AT_THREADS);
do {
- res = ethr_atomic_read(&at_go, &go);
- ASSERT(res == 0);
+ go = ethr_atomic_read(&at_go);
} while (!go);
for (i = 0; i < AT_ITER; i++) {
- res = ethr_atomic_or_old(&at_data, at_set_val, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read_bor(&at_data, at_set_val);
ASSERT(val >= (i == 0 ? 0 : at_set_val) + (long) 4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_and_old(&at_data, ~at_rm_val, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read_band(&at_data, ~at_rm_val);
ASSERT(val >= at_set_val + (long) 4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_read(&at_data, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read(&at_data);
ASSERT(val >= at_set_val + (long) 4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_inctest(&at_data, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_inc_read(&at_data);
ASSERT(val > at_set_val + (long) 4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_dectest(&at_data, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_dec_read(&at_data);
ASSERT(val >= at_set_val + (long) 4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_inc(&at_data);
- ASSERT(res == 0);
+ ethr_atomic_inc(&at_data);
- res = ethr_atomic_dec(&at_data);
- ASSERT(res == 0);
+ ethr_atomic_dec(&at_data);
- res = ethr_atomic_addtest(&at_data, (long) 4711, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_add_read(&at_data, (long) 4711);
ASSERT(val >= at_set_val + (long) 2*4711);
ASSERT(val <= at_max_val);
- res = ethr_atomic_add(&at_data, (long) -4711);
- ASSERT(res == 0);
+ ethr_atomic_add(&at_data, (long) -4711);
ASSERT(val >= at_set_val + (long) 4711);
ASSERT(val <= at_max_val);
}
- res = ethr_atomic_inc(&at_done);
- ASSERT(res == 0);
+ ethr_atomic_inc(&at_done);
return NULL;
}
@@ -2069,14 +1445,13 @@ atomic_test(void)
ethr_tid tid[AT_THREADS];
ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER;
- if (sizeof(long) > 4) {
+#if ETHR_SIZEOF_PTR > 4
at_rm_val = ((long) 1) << 57;
at_set_val = ((long) 1) << 60;
- }
- else {
+#else
at_rm_val = ((long) 1) << 27;
at_set_val = ((long) 1) << 30;
- }
+#endif
at_max_val = at_set_val + at_rm_val + ((long) AT_THREADS + 1) * 4711;
data_init = at_rm_val + (long) 4711;
@@ -2085,22 +1460,15 @@ atomic_test(void)
thr_opts.detached = 1;
print_line("Initializing");
- res = ethr_atomic_init(&at_ready, 0);
- ASSERT(res == 0);
- res = ethr_atomic_init(&at_go, 0);
- ASSERT(res == 0);
- res = ethr_atomic_init(&at_done, data_init);
- ASSERT(res == 0);
- res = ethr_atomic_init(&at_data, data_init);
- ASSERT(res == 0);
+ ethr_atomic_init(&at_ready, 0);
+ ethr_atomic_init(&at_go, 0);
+ ethr_atomic_init(&at_done, data_init);
+ ethr_atomic_init(&at_data, data_init);
- res = ethr_atomic_read(&at_data, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read(&at_data);
ASSERT(val == data_init);
- res = ethr_atomic_set(&at_done, 0);
- ASSERT(res == 0);
- res = ethr_atomic_read(&at_done, &val);
- ASSERT(res == 0);
+ ethr_atomic_set(&at_done, 0);
+ val = ethr_atomic_read(&at_done);
ASSERT(val == 0);
print_line("Creating threads");
@@ -2111,31 +1479,27 @@ atomic_test(void)
print_line("Waiting for threads to ready up");
do {
- res = ethr_atomic_read(&at_ready, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read(&at_ready);
ASSERT(val >= 0);
ASSERT(val <= AT_THREADS);
} while (val != AT_THREADS);
print_line("Letting threads loose");
- res = ethr_atomic_xchg(&at_go, 17, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_xchg(&at_go, 17);
ASSERT(val == 0);
- res = ethr_atomic_read(&at_go, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read(&at_go);
ASSERT(val == 17);
print_line("Waiting for threads to finish");
do {
- res = ethr_atomic_read(&at_done, &val);
- ASSERT(res == 0);
+ val = ethr_atomic_read(&at_done);
ASSERT(val >= 0);
ASSERT(val <= AT_THREADS);
} while (val != AT_THREADS);
print_line("Checking result");
- res = ethr_atomic_read(&at_data, &val);
+ val = ethr_atomic_read(&at_data);
ASSERT(res == 0);
ASSERT(val == data_final);
print_line("Result ok");
@@ -2143,190 +1507,6 @@ atomic_test(void)
}
-/*
- * The gate test case.
- *
- * Tests gates.
- */
-
-#define GT_THREADS 10
-
-static ethr_atomic_t gt_wait1;
-static ethr_atomic_t gt_wait2;
-static ethr_atomic_t gt_done;
-
-static ethr_gate gt_gate1;
-static ethr_gate gt_gate2;
-
-void *
-gt_thread(void *thr_no)
-{
- int no = (int)(long) thr_no;
- int swait = no % 2 == 0;
- int res;
- long done;
-
-
- do {
-
- res = ethr_atomic_inc(&gt_wait1);
- ASSERT(res == 0);
-
- if (swait)
- res = ethr_gate_swait(&gt_gate1, INT_MAX);
- else
- res = ethr_gate_wait(&gt_gate1);
- ASSERT(res == 0);
-
- res = ethr_atomic_dec(&gt_wait1);
- ASSERT(res == 0);
-
- res = ethr_atomic_inc(&gt_wait2);
- ASSERT(res == 0);
-
- if (swait)
- res = ethr_gate_swait(&gt_gate2, INT_MAX);
- else
- res = ethr_gate_wait(&gt_gate2);
- ASSERT(res == 0);
-
- res = ethr_atomic_dec(&gt_wait2);
- ASSERT(res == 0);
-
- res = ethr_atomic_read(&gt_done, &done);
- ASSERT(res == 0);
- } while (!done);
- return NULL;
-}
-
-
-static void
-gate_test(void)
-{
- long val;
- int res, i;
- ethr_tid tid[GT_THREADS];
-
- print_line("Initializing");
- res = ethr_atomic_init(&gt_wait1, 0);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_atomic_init(&gt_wait2, 0);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_atomic_init(&gt_done, 0);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_gate_init(&gt_gate1);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_gate_init(&gt_gate2);
- ASSERT_EQ(res, 0, "%d");
-
- print_line("Creating threads");
- for (i = 0; i < GT_THREADS; i++) {
- res = ethr_thr_create(&tid[i], gt_thread, (void *) i, NULL);
- ASSERT_EQ(res, 0, "%d");
- }
-
- print_line("Waiting for threads to ready up");
- do {
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT(0 <= val && val <= GT_THREADS);
- } while (val != GT_THREADS);
-
- print_line("Testing");
-
- res = ethr_gate_let_through(&gt_gate1, 8);
- ASSERT_EQ(res, 0, "%d");
-
- WAIT_UNTIL_LIM((res = ethr_atomic_read(&gt_wait2, &val),
- (res != 0 || val == 8)),
- 60);
-
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, GT_THREADS - 8, "%ld");
-
- res = ethr_atomic_read(&gt_wait2, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 8, "%ld");
-
- res = ethr_gate_let_through(&gt_gate2, 4);
- ASSERT_EQ(res, 0, "%d");
-
- WAIT_UNTIL_LIM((res = ethr_atomic_read(&gt_wait2, &val),
- (res != 0 || val == 4)),
- 60);
-
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, GT_THREADS - 4, "%ld");
-
- res = ethr_atomic_read(&gt_wait2, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 4, "%ld");
-
- res = ethr_gate_let_through(&gt_gate1, GT_THREADS);
- ASSERT_EQ(res, 0, "%d");
-
- WAIT_UNTIL_LIM((res = ethr_atomic_read(&gt_wait2, &val),
- (res != 0 || val == GT_THREADS)),
- 60);
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 0, "%ld");
-
- res = ethr_atomic_read(&gt_wait2, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, GT_THREADS, "%ld");
-
- res = ethr_gate_let_through(&gt_gate2, GT_THREADS);
- ASSERT_EQ(res, 0, "%d");
-
- WAIT_UNTIL_LIM((res = ethr_atomic_read(&gt_wait2, &val),
- (res != 0 || val == 4)),
- 60);
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, GT_THREADS - 4, "%ld");
-
- res = ethr_atomic_read(&gt_wait2, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 4, "%ld");
-
- res = ethr_atomic_set(&gt_done, 1);
- ASSERT_EQ(res, 0, "%d");
-
- res = ethr_gate_let_through(&gt_gate2, GT_THREADS);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_gate_let_through(&gt_gate1, GT_THREADS - 4);
- ASSERT_EQ(res, 0, "%d");
-
- WAIT_UNTIL_LIM(((res = ethr_atomic_read(&gt_wait1, &val)) != 0
- || (val == 0
- && ((res = ethr_atomic_read(&gt_wait2, &val)) != 0
- || val == 0))),
- 60);
-
- res = ethr_atomic_read(&gt_wait1, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 0, "%ld");
-
- res = ethr_atomic_read(&gt_wait2, &val);
- ASSERT_EQ(res, 0, "%d");
- ASSERT_EQ(val, 0, "%ld");
-
- print_line("Joining threads");
- for (i = 0; i < GT_THREADS; i++) {
- res = ethr_thr_join(tid[i], NULL);
- ASSERT_EQ(res, 0, "%d");
- }
-
- res = ethr_gate_destroy(&gt_gate1);
- ASSERT_EQ(res, 0, "%d");
- res = ethr_gate_destroy(&gt_gate2);
- ASSERT_EQ(res, 0, "%d");
-
-}
-
#endif /* #ifndef ETHR_NO_THREAD_LIB */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -2342,14 +1522,12 @@ main(int argc, char *argv[])
#ifndef ETHR_NO_THREAD_LIB
{
char *testcase;
- int res;
send_my_pid();
testcase = argv[1];
- res = ethr_init(NULL);
- if (res != 0)
+ if (ethr_init(NULL) != 0 || ethr_late_init(NULL) != 0)
fail("Failed to initialize the ethread library");
if (strcmp(testcase, "create_join_thread") == 0)
@@ -2360,24 +1538,16 @@ main(int argc, char *argv[])
mutex_test();
else if (strcmp(testcase, "try_lock_mutex") == 0)
try_lock_mutex_test();
- else if (strcmp(testcase, "recursive_mutex") == 0)
- recursive_mutex_test();
else if (strcmp(testcase, "time_now") == 0)
time_now_test();
else if (strcmp(testcase, "cond_wait") == 0)
- cond_wait_test(0);
- else if (strcmp(testcase, "cond_timedwait") == 0)
- cond_timedwait_test();
+ cond_wait_test();
else if (strcmp(testcase, "broadcast") == 0)
broadcast_test();
else if (strcmp(testcase, "detached_thread") == 0)
detached_thread_test();
else if (strcmp(testcase, "max_threads") == 0)
max_threads_test();
- else if (strcmp(testcase, "forksafety") == 0)
- forksafety_test();
- else if (strcmp(testcase, "vfork") == 0)
- vfork_test(argc, argv);
else if (strcmp(testcase, "tsd") == 0)
tsd_test();
else if (strcmp(testcase, "spinlock") == 0)
@@ -2388,8 +1558,6 @@ main(int argc, char *argv[])
rwmutex_test();
else if (strcmp(testcase, "atomic") == 0)
atomic_test();
- else if (strcmp(testcase, "gate") == 0)
- gate_test();
else
skip("Test case \"%s\" not implemented yet", testcase);
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 6e1338cff5..ce6330e6dd 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -17,8 +17,8 @@
# %CopyrightEnd%
#
-VSN = 5.8
-SYSTEM_VSN = R14A
+VSN = 5.8.1
+SYSTEM_VSN = R14B
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/.gitignore b/lib/.gitignore
index a33916b3bf..340baf5269 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -128,6 +128,7 @@
/megaco/src/text/megaco_text_parser_v1.erl
/megaco/src/text/megaco_text_parser_v2.erl
/megaco/src/text/megaco_text_parser_v3.erl
+/megaco/doc/html/mstone1.jpg
# mnesia
diff --git a/lib/appmon/src/appmon_web.erl b/lib/appmon/src/appmon_web.erl
index e8a8422a80..fb7144246c 100644
--- a/lib/appmon/src/appmon_web.erl
+++ b/lib/appmon/src/appmon_web.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2010. 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
@@ -38,12 +38,6 @@
%% webtool
-export([configData/0]).
-
-%% The following directive caters for (significantly) faster native
-%% code compilation of one function in this file by the HiPE compiler
-%% on register-poor architectures like the x86.
--compile([{hipe,[{regalloc,graph_color}]}]).
-
-behaviour(gen_server).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index b7e91e42a0..c0393f84fe 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1,323 +1,2 @@
#next version number to use is 1.6.15 | 1.7 | 2.0
ASN1_VSN = 1.6.14
-
-TICKETS = OTP-8565 \
- OTP-8516
-
-TICKETS_1.6.14 = \
- OTP-8565 \
- OTP-8516
-
-TICKETS_1.6.13 = \
- OTP-8463
-
-TICKETS_1.6.12 = \
- OTP-8256
-
-TICKETS_1.6.11 = \
- OTP-8136 \
- OTP-8047 \
- OTP-8046 \
- OTP-8043 \
- OTP-7972
-
-TICKETS_1.6.10 = \
- OTP-7954 \
- OTP-7953
-
-TICKETS_1.6.10 = \
- OTP-7954 \
- OTP-7953
-
-TICKETS_1.6.9 = \
- OTP-7909 \
- OTP-7904
-
-TICKETS_1.6.8.1 = \
- OTP-7900 \
- OTP-7910
-
-TICKETS_1.6.8 = \
- OTP-7876
-
-TICKETS_1.6.7 = \
- OTP-7801 \
- OTP-7806
-
-TICKETS_1.6.6 = \
- OTP-7759 \
- OTP-7763
-
-TICKETS_1.6.5 = \
- OTP-7734
-
-TICKETS_1.6.4 = \
- OTP-7708
-
-TICKETS_1.6.3 = \
- OTP-7681 \
- OTP-7678
-
-TICKETS_1.6.2 = \
- OTP-7608
-
-TICKETS_1.6.1 = \
- OTP-7602 \
- OTP-7533 \
- OTP-7476 \
- OTP-7334 \
- OTP-7332 \
- OTP-7322 \
- OTP-7306 \
- OTP-7299 \
- OTP-7295 \
- OTP-7204 \
- OTP-7174 \
- OTP-7166
-
-TICKETS_1.6 = \
- OTP-7407 \
- OTP-7403 \
- OTP-7400 \
- OTP-7375 \
- OTP-7374 \
- OTP-7335
-
-TICKETS_1.5.2 = \
- OTP-7263 \
- OTP-7264 \
- OTP-7268 \
- OTP-7269 \
- OTP-7273
-
-TICKETS_1.5.1 = \
- OTP-7149 \
- OTP-7151 \
- OTP-7154 \
- OTP-7155 \
- OTP-7169 \
- OTP-7171 \
- OTP-7193 \
- OTP-7199
-
-TICKETS_1.5 = \
- OTP-6835 \
- OTP-6882
-
-TICKETS_1.4.7 = \
- OTP-6828
-
-TICKETS_1.4.6 = \
- OTP-5067 \
- OTP-6763 \
- OTP-6769 \
- OTP-6770 \
- OTP-6786
-
-TICKETS_1.4.5 = \
- OTP-6493 \
- OTP-6601 \
- OTP-6695 \
- OTP-6698 \
- OTP-6702 \
- OTP-6707 \
- OTP-6717
-
-TICKETS_1.4.4.14 = \
- OTP-6462 \
- OTP-6506
-
-TICKETS_1.4.4.13 = \
- OTP-6405
-
-TICKETS_1.4.4.12 = \
- OTP-6314
-
-TICKETS_1.4.4.11 = \
- OTP-6143
-
-TICKETS_1.4.4.10 = \
- OTP-6111 \
- OTP-5932
-
-TICKETS_1.4.4.9 = \
- OTP-5783 \
- OTP-5788 \
- OTP-5812 \
- OTP-5831 \
- OPT-5832
-
-TICKETS_1.4.4.8 = \
- OTP-5687 \
- OTP-5688 \
- OTP-5689 \
- OTP-5701 \
- OTP-5710
-
-TICKETS_1.4.4.7 = \
- OTP-5477 \
- OTP-5509 \
- OTP-5511 \
- OTP-5602 \
- OTP-5616
-
-TICKETS_1.4.4.6 = \
- OTP-5457 \
- OTP-5466
-
-TICKETS_1.4.4.5 = \
- OTP-5302 \
- OTP-5378
-
-TICKETS_1.4.4.4 = \
- OTP-5240 \
- OTP-5243
-
-TICKETS_1.4.4.3 = \
- OTP-5103 \
- OTP-5104
-
-TICKETS_1.4.4.2 = \
- OTP-5022
-
-TICKETS_1.4.4.1 = \
- OTP-4970
-
-TICKETS_1.4.4 = \
- OTP-4893 \
- OTP-4894 \
- OTP-4895 \
- OTP-4917 \
- OTP-4918 \
- OTP-4919 \
- OTP-4944 \
- OTP-4953 \
- OTP-4955 \
- OTP-4957 \
- OTP-4965
-
-TICKETS_1.4.3.1 = \
- OTP-4866 \
- OTP-4869 \
- OTP-4872
-
-TICKETS_1.4.3 = \
- OTP-4832 \
- OTP-4833 \
- OTP-4835 \
- OTP-4856
-
-TICKETS_1.4.2.1 = \
- OTP-4773 \
- OTP-4791 \
- OTP-4792 \
- OTP-4797 \
- OTP-4798 \
- OTP-4799 \
- OTP-4809
-
-# OTP R9C
-TICKETS_1.4.2 = \
- OTP-4693 \
- OTP-4744
-
-TICKETS_1.4.1.1 = \
- OTP-4663 \
- OTP-4665 \
- OTP-4666
-
-TICKETS_1.4.1 = \
- OTP-4559 \
- OTP-4560 \
- OTP-4590 \
- OTP-4591 \
- OTP-4592 \
- OTP-4631 \
- OTP-4633
-
-TICKETS_1.4 = \
- OTP-3304
-
-TICKETS_1.3.3.1 = \
- OTP-4353 \
- OTP-4354 \
- OTP-4390 \
- OTP-4395
-
-TICKETS_1.3.3 = \
- OTP-4381 \
- OTP-4358 \
- OTP-4355 \
- OTP-4275 \
- OTP-4248 \
- OTP-4247 \
- OTP-4242 \
- OTP-4235 \
- OTP-4234 \
- OTP-4232 \
- OTP-4200 \
- OTP-4161 \
- OTP-4129
-
-TICKETS_1.3.2 = \
- OTP-4094 \
- OTP-4103 \
- OTP-3980 \
- OTP-4073
-
-TICKETS_1.3.1.1 = \
- OTP-4037 \
- OTP-4057 \
- OTP-4058
-
-TICKETS_1.3.1 = \
- OTP-4025 \
- OTP-4026
-
-TICKETS_1.3 = \
- OTP-3463 \
- OTP-3659 \
- OTP-3978 \
- OTP-3979 \
- OTP-3981 \
- OTP-3982 \
- OTP-3983 \
- OTP-3985 \
- OTP-3988 \
- OTP-3984 \
- OTP-3994
-
-TICKETS_1.2.9.6 = \
- OTP-3830
-
-TICKETS_1.2.9.5 = \
- OTP-3713 \
- OTP-3796 \
- OTP-3811
-
-TICKETS_1.2.9.3 = \
- OTP-3700 \
- OTP-3701
-
-TICKETS_1.2.9.2 = \
- OTP-xxxx
-
-TICKETS_1.2.9.1 = \
- OTP-xxxx
-
-TICKETS_1.2.9 = \
- OTP-3569 \
- OTP-3573
-
-TICKETS_1.2.8 = \
- OTP-3496
-
-TICKETS_1.2.7 = \
- OTP-3395
-
-TICKETS_1.2.6 = \
- OTP-3352
-
-TICKETS_1.2.5 = \
- OTP-3341
-
diff --git a/lib/common_test/Makefile b/lib/common_test/Makefile
index e16efd0c9d..aecec1a50d 100644
--- a/lib/common_test/Makefile
+++ b/lib/common_test/Makefile
@@ -25,12 +25,12 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
ifeq ($(findstring linux,$(TARGET)),linux)
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
else
ifeq ($(findstring solaris,$(TARGET)),solaris)
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
else
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
endif
endif
diff --git a/lib/common_test/doc/src/run_test.xml b/lib/common_test/doc/src/run_test.xml
index d609c4287f..2f0a94afba 100644
--- a/lib/common_test/doc/src/run_test.xml
+++ b/lib/common_test/doc/src/run_test.xml
@@ -45,6 +45,11 @@
flags start an Erlang node prepared for running Common Test in a
particular mode.</p>
+ <p>There is an interface function that corresponds to this program,
+ called <c>ct:run_test/1</c>, for starting Common Test from the Erlang
+ shell (or an Erlang program). Please see the <c>ct</c> man page for
+ details.</p>
+
<p><c>run_test</c> also accepts Erlang emulator flags. These are used
when <c>run_test</c> calls <c>erl</c> to start the Erlang node
(making it possible to e.g. add directories to the code server path,
@@ -72,6 +77,8 @@
<p>it prints all valid start flags to stdout.</p>
</description>
+ <marker id="run_test"></marker>
+
<section>
<title>Run tests from command line</title>
<pre>
@@ -83,6 +90,7 @@
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
+ [-label Label]
[-logdir LogDir]
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
[-stylesheet CSSFile]
@@ -107,6 +115,7 @@
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
+ [-label Label]
[-logdir LogDir]
[-allow_user_terms]
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
@@ -128,12 +137,12 @@
<title>Run tests in web based GUI</title>
<pre>
run_test -vts [-browser Browser]
+ [-dir TestDir1 TestDir2 .. TestDirN] |
+ [-suite Suite [[-group Group] [-case Case]]]
[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
- [-dir TestDir1 TestDir2 .. TestDirN] |
- [-suite Suite [[-group Group] [-case Case]]]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
[-muliply_timetraps Multiplier]
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 207df7f5b5..1efff25f5b 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -21,7 +21,7 @@
</legalnotice>
- <title>Running Test Suites</title>
+ <title>Running Tests</title>
<prepared>Peter Andersson, Kenneth Lundin</prepared>
<docno></docno>
<date></date>
@@ -130,6 +130,8 @@
<p>Other flags that may be used with <c>run_test</c>:</p>
<list>
<item><c><![CDATA[-logdir <dir>]]></c>, specifies where the HTML log files are to be written.</item>
+ <item><c><![CDATA[-label <name_of_test_run>]]></c>, associates the test run with a name that gets printed
+ in the overview HTML log files.</item>
<item><c>-refresh_logs</c>, refreshes the top level HTML index files.</item>
<item><c>-vts</c>, start web based GUI (see below).</item>
<item><c>-shell</c>, start interactive shell mode (see below).</item>
@@ -335,43 +337,72 @@
<marker id="test_specifications"></marker>
<title>Using test specifications</title>
- <p>The most expressive way to specify what to test is to use a so
- called test specification. A test specification is a sequence of
- Erlang terms. The terms may be declared in a text file or passed
- to the test server at runtime as a list (see <c>run_testspec/1</c>
- in the manual page for <c>ct</c>). There are two general types
- of terms: configuration terms and test specification terms.</p>
- <p>With configuration terms it is possible to import configuration
- data (similar to <c>run_test -config</c>), specify HTML log
- directories (similar to <c>run_test -logdir</c>), give aliases
- to test nodes and test directories (to make a specification
- easier to read and maintain), enable code coverage analysis
- (see the <seealso marker="cover_chapter#cover">Code Coverage
- Analysis</seealso> chapter) and specify event_handler plugins
+ <p>The most flexible way to specify what to test, is to use a so
+ called test specification. A test specification is a sequence of
+ Erlang terms. The terms may be declared in a text file or passed
+ to the test server at runtime as a list
+ (see <c>run_testspec/1</c> in the manual page
+ for <c>ct</c>). There are two general types of terms:
+ configuration terms and test specification terms.</p>
+ <p>With configuration terms it is possible to e.g. label the test
+ run (similar to <c>run_test -label</c>), evaluate arbitrary expressions
+ before starting a test, import configuration
+ data (similar to
+ <c>run_test -config/-userconfig</c>), specify HTML log directories (similar
+ to
+ <c>run_test -logdir</c>), give aliases to test nodes and test
+ directories (to make a specification easier to read and
+ maintain), enable code coverage analysis (see
+ the <seealso marker="cover_chapter#cover">Code Coverage
+ Analysis</seealso> chapter) and specify event_handler plugins
(see the <seealso marker="event_handler_chapter#event_handling">
- Event Handling</seealso> chapter). There is also a term
- for specifying include directories that should be passed on
- to the compiler when automatic compilation is performed
- (similar to <c>run_test -include</c>, see above).</p>
- <p>With test specification terms it is possible to state exactly which
- tests should run and in which order. A test term specifies either
- one or more suites or one or more test cases. An arbitrary number of test
- terms may be declared in sequence. A test term can also specify one or
- more test suites or test cases to be skipped. Skipped suites and cases
- are not executed and show up in the HTML test log as SKIPPED.</p>
-
- <note><p>It is not yet possible to specify test case groups in
- test specifications. This will be supported in a soon upcoming
- release.</p></note>
+ Event Handling</seealso> chapter). There is also a term for
+ specifying include directories that should be passed on to the
+ compiler when automatic compilation is performed (similar
+ to <c>run_test -include</c>, see above).</p>
+ <p>With test specification terms it is possible to state exactly
+ which tests should run and in which order. A test term specifies
+ either one or more suites, one or more test case groups, or one
+ or more test cases in a group or suite.</p>
+ <p>An arbitrary number of test terms may be declared in sequence.
+ Common Test will compile the terms into one or more tests to be
+ performed in one resulting test run. Note that a term that
+ specifies a set of test cases will "swallow" one that only
+ specifies a subset of these cases. E.g. the result of merging
+ one term that specifies that all cases in suite S should be
+ executed, with another term specifying only test case X and Y in
+ S, is a test of all cases in S. However, if a term specifying
+ test case X and Y in S is merged with a term specifying case Z
+ in S, the result is a test of X, Y and Z in S.</p>
+ <p>A test term can also specify one or more test suites, groups,
+ or test cases to be skipped. Skipped suites, groups and cases
+ are not executed and show up in the HTML test log files as
+ SKIPPED.</p>
+ <p>When a test case group is specified, the resulting test
+ executes the
+ <c>init_per_group</c> function, followed by all test cases and
+ sub groups (including their configuration functions), and
+ finally the <c>end_per_group</c> function. Also if particular
+ test cases in a group are specified, <c>init_per_group</c>
+ and <c>end_per_group</c> for the group in question are
+ called. If a group which is defined (in <c>Suite:group/0</c>) to
+ be a sub group of another group, is specified (or particular test
+ cases of a sub group are), Common Test will call the configuration
+ functions for the top level groups as well as for the sub group
+ in question (making it possible to pass configuration data all
+ the way from <c>init_per_suite</c> down to the test cases in the
+ sub group).</p>
<p>Below is the test specification syntax. Test specifications can
- be used to run tests both in a single test host environment and in
- a distributed Common Test environment (Large Scale Testing). The init term,
- as well as node parameters, are only relevant in the latter (see the
- <seealso marker="ct_master_chapter#test_specifications">Large Scale Testing</seealso>
- chapter for information). For details on the event_handler term, see the
- <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso>
- chapter.</p>
+ be used to run tests both in a single test host environment and
+ in a distributed Common Test environment (Large Scale
+ Testing). The node parameters in the init term are only
+ relevant in the latter (see the
+ <seealso marker="ct_master_chapter#test_specifications">Large
+ Scale Testing</seealso> chapter for information). For details on
+ the event_handler term, see the
+ <seealso marker="event_handler_chapter#event_handling">Event
+ Handling</seealso> chapter.</p>
<p>Config terms:</p>
<pre>
{node, NodeAlias, Node}.
@@ -379,11 +410,17 @@
{init, InitOptions}.
{init, [NodeAlias], InitOptions}.
+ {label, Label}.
+ {label, NodeRefs, Label}.
+
{multiply_timetraps, N}.
+ {multiply_timetraps, NodeRefs, N}.
+
{scale_timetraps, Bool}.
+ {scale_timetraps, NodeRefs, Bool}.
{cover, CoverSpecFile}.
- {cover, NodeRef, CoverSpecFile}.
+ {cover, NodeRefs, CoverSpecFile}.
{include, IncludeDirs}.
{include, NodeRefs, IncludeDirs}.
@@ -409,6 +446,12 @@
{suites, DirRef, Suites}.
{suites, NodeRefs, DirRef, Suites}.
+ {groups, DirRef, Suite, Groups}.
+ {groups, NodeRefsDirRef, Suite, Groups}.
+
+ {groups, DirRef, Suite, Group, {cases,Cases}}.
+ {groups, NodeRefsDirRef, Suite, Group, {cases,Cases}}.
+
{cases, DirRef, Suite, Cases}.
{cases, NodeRefs, DirRef, Suite, Cases}.
@@ -437,6 +480,9 @@
InitArgs = [term()]
DirRef = DirAlias | Dir
Suites = atom() | [atom()] | all
+ Suite = atom()
+ Groups = atom() | [atom()] | all
+ Group = atom()
Cases = atom() | [atom()] | all
Comment = string() | ""
</pre>
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index f144847a29..6372bbc8d5 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -56,8 +56,9 @@ ifneq ($(findstring win32,$(TARGET)),win32)
#
# Files
#
-FILES = vts.tool run_test.in
-SCRIPTS = install.sh
+FILES =
+SCRIPTS =
+IMAGES = tile1.jpg
#
# Rules
@@ -83,14 +84,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
ifeq ($(XNIX),true)
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(SCRIPTS) $(RELSYSDIR)
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
else
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(SCRIPTS) $(RELSYSDIR)
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
endif
release_docs_spec:
@@ -105,6 +104,7 @@ else
# Files
#
FILES = vts.tool
+IMAGES = tile1.jpg
#
# Rules
@@ -123,8 +123,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
release_docs_spec:
diff --git a/lib/common_test/priv/tile1.jpg b/lib/common_test/priv/tile1.jpg
new file mode 100644
index 0000000000..8749383716
--- /dev/null
+++ b/lib/common_test/priv/tile1.jpg
Binary files differ
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 0d82a86e7d..8ae175f10d 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -138,10 +138,10 @@ run(TestDirs) ->
%%%-----------------------------------------------------------------
%%% @spec run_test(Opts) -> Result
%%% Opts = [OptTuples]
-%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%%% {userconfig, UserConfig} |
-%%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} |
-%%% {allow_user_terms,Bool} | {logdir,LogDir} |
+%%% OptTuples = {dir,TestDirs} | {suite,Suites} | {group,Groups} |
+%%% {testcase,Cases} | {spec,TestSpecs} | {label,Label} |
+%%% {config,CfgFiles} | {userconfig, UserConfig} |
+%%% {allow_user_terms,Bool} | {logdir,LogDir} |
%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
%%% {cover,CoverSpecFile} | {step,StepOpts} |
%%% {event_handler,EventHandlers} | {include,InclDirs} |
@@ -149,15 +149,16 @@ run(TestDirs) ->
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {basic_html,Bool}
-%%% CfgFiles = [string()] | string()
-%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
-%%% CallbackMod = atom()
-%%% CfgStrings = [string()] | string()
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | string()
%%% Cases = [atom()] | atom()
%%% Groups = [atom()] | atom()
%%% 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()
@@ -177,7 +178,8 @@ run(TestDirs) ->
%%% DecryptFile = string()
%%% Result = [TestResult] | {error,Reason}
%%% @doc Run tests as specified by the combination of options in <code>Opts</code>.
-%%% The options are the same as those used with the <code>run_test</code> program.
+%%% The options are the same as those used with the
+%%% <seealso marker="run_test#run_test"><code>run_test</code></seealso> program.
%%% Note that here a <code>TestDir</code> can be used to point out the path to
%%% a <code>Suite</code>. Note also that the option <code>testcase</code>
%%% corresponds to the <code>-case</code> option in the <code>run_test</code>
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 3dd1026f13..f2ca023cff 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -27,8 +27,12 @@
-export([init_tc/3, end_tc/3, get_suite/2, report/2, warn/1]).
-export([error_notification/4]).
+-export([overview_html_header/1]).
+
-export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]).
+-export([make_all_conf/3, make_conf/5]).
+
-include("ct_event.hrl").
-include("ct_util.hrl").
@@ -101,7 +105,8 @@ init_tc1(Mod,Func,[Config0],DoInit) when is_list(Config0) ->
[{saved_config,{LastFunc,SavedConfig}} |
lists:keydelete(saved_config,1,Config0)];
{{LastSuite,InitOrEnd},SavedConfig} when InitOrEnd == init_per_suite ;
- InitOrEnd == end_per_suite -> % last suite
+ InitOrEnd == end_per_suite ->
+ %% last suite
[{saved_config,{LastSuite,SavedConfig}} |
lists:keydelete(saved_config,1,Config0)];
undefined ->
@@ -649,7 +654,7 @@ get_suite(Mod, all) ->
{'EXIT',_} ->
get_all(Mod, []);
GroupDefs when is_list(GroupDefs) ->
- case catch check_groups(Mod, GroupDefs) of
+ case catch find_groups(Mod, all, all, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
@@ -664,102 +669,193 @@ get_suite(Mod, all) ->
%%!============================================================
%%! Note: The handling of sequences in get_suite/2 and get_all/2
-%%! is deprecated and should be removed after OTP R13!
+%%! is deprecated and should be removed at some point...
%%!============================================================
-get_suite(Mod, Name) ->
- %% Name may be name of a group or a test case. If it's a group,
- %% it should be expanded to list of cases (in a conf term)
+%% group
+get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
+ Name = proplists:get_value(name, Props),
case catch apply(Mod, groups, []) of
{'EXIT',_} ->
- get_seq(Mod, Name);
+ [Group];
GroupDefs when is_list(GroupDefs) ->
- case catch check_groups(Mod, GroupDefs) of
+ case catch find_groups(Mod, Name, TCs, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
[{?MODULE,error_in_suite,[[Error]]}];
+ [] ->
+ {error,{invalid_group_spec,Name}};
ConfTests ->
-
- %%! --- Thu Jun 3 19:13:22 2010 --- peppe was here!
- %%! HEERE!
- %%! Must be able to search recursively for group Name,
- %%! this only handles top level groups!
-
- FindConf = fun({conf,Props,_,_,_}) ->
- case proplists:get_value(name, Props) of
- Name -> true;
- _ -> false
- end
- end,
- case lists:filter(FindConf, ConfTests) of
- [] -> % must be a test case
- get_seq(Mod, Name);
- [ConfTest|_] ->
- ConfTest
+ case lists:member(skipped, Props) of
+ true ->
+ %% a *subgroup* specified *only* as skipped (and not
+ %% as an explicit test) should not be returned, or
+ %% init/end functions for top groups will be executed
+ case catch proplists:get_value(name, element(2, hd(ConfTests))) of
+ Name -> % top group
+ ConfTests;
+ _ ->
+ []
+ end;
+ false ->
+ ConfTests
end
end;
_ ->
E = "Bad return value from "++atom_to_list(Mod)++":groups/0",
[{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}]
- end.
+ end;
-check_groups(_Mod, []) ->
- [];
-check_groups(Mod, Defs) ->
- check_groups(Mod, Defs, Defs, []).
+%% testcase
+get_suite(Mod, Name) ->
+ get_seq(Mod, Name).
-check_groups(Mod, [TC | Gs], Defs, Levels) when is_atom(TC), length(Levels)>0 ->
- [TC | check_groups(Mod, Gs, Defs, Levels)];
+%%%-----------------------------------------------------------------
-check_groups(Mod, [{group,SubName} | Gs], Defs, Levels) when is_atom(SubName) ->
- case lists:member(SubName, Levels) of
- true ->
- E = "Cyclic reference to group "++atom_to_list(SubName)++
- " in "++atom_to_list(Mod)++":groups/0",
- throw({error,list_to_atom(E)});
- false ->
- case find_group(Mod, SubName, Defs) of
- {error,_} = Error ->
- throw(Error);
- G ->
- [check_groups(Mod, [G], Defs, Levels) |
- check_groups(Mod, Gs, Defs, Levels)]
- end
+find_groups(Mod, Name, TCs, GroupDefs) ->
+ Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false),
+ Trimmed = trim(Found),
+ delete_subs(Trimmed, Trimmed).
+
+find(Mod, all, _TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) ->
+ cyclic_test(Mod, Name, Known),
+ [make_conf(Mod, Name, Props,
+ find(Mod, all, all, Tests, [Name | Known], Defs, true)) |
+ find(Mod, all, all, Gs, [], Defs, true)];
+
+find(Mod, Name, TCs, [{Name,Props,Tests} | _Gs], Known, Defs, false)
+ when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ case TCs of
+ all ->
+ [make_conf(Mod, Name, Props,
+ find(Mod, Name, TCs, Tests, [Name | Known], Defs, true))];
+ _ ->
+ Tests1 = [TC || TC <- TCs,
+ lists:member(TC, Tests) == true],
+ [make_conf(Mod, Name, Props, Tests1)]
end;
-check_groups(Mod, [{Name,Tests} | Gs], Defs, Levels) when is_atom(Name),
- is_list(Tests) ->
- check_groups(Mod, [{Name,[],Tests} | Gs], Defs, Levels);
-
-check_groups(Mod, [{Name,Props,Tests} | Gs], Defs, Levels) when is_atom(Name),
- is_list(Props),
- is_list(Tests) ->
- {TestSpec,Levels1} =
- case Levels of
- [] ->
- {check_groups(Mod, Tests, Defs, [Name]),[]};
- _ ->
- {check_groups(Mod, Tests, Defs, [Name|Levels]),Levels}
- end,
- [make_conf(Mod, Name, Props, TestSpec) |
- check_groups(Mod, Gs, Defs, Levels1)];
+find(Mod, Name, TCs, [{Name1,Props,Tests} | Gs], Known, Defs, false)
+ when is_atom(Name1), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name1, Known),
+ [make_conf(Mod, Name1, Props,
+ find(Mod, Name, TCs, Tests, [Name1 | Known], Defs, false)) |
+ find(Mod, Name, TCs, Gs, [], Defs, false)];
+
+find(Mod, Name, _TCs, [{Name,_Props,_Tests} | _Gs], _Known, _Defs, true)
+ when is_atom(Name) ->
+ E = "Duplicate groups named "++atom_to_list(Name)++" in "++
+ atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)});
+
+find(Mod, Name, all, [{Name1,Props,Tests} | Gs], Known, Defs, true)
+ when is_atom(Name1), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name1, Known),
+ [make_conf(Mod, Name1, Props,
+ find(Mod, Name, all, Tests, [Name1 | Known], Defs, true)) |
+ find(Mod, Name, all, Gs, [], Defs, true)];
+
+find(Mod, Name, TCs, [{group,Name1} | Gs], Known, Defs, Found) when is_atom(Name1) ->
+ find(Mod, Name, TCs, [expand(Mod, Name1, Defs) | Gs], Known, Defs, Found);
+
+find(Mod, Name, TCs, [{Name1,Tests} | Gs], Known, Defs, Found)
+ when is_atom(Name1), is_list(Tests) ->
+ find(Mod, Name, TCs, [{Name1,[],Tests} | Gs], Known, Defs, Found);
+
+find(Mod, Name, TCs, [TC | Gs], Known, Defs, false) when is_atom(TC) ->
+ find(Mod, Name, TCs, Gs, Known, Defs, false);
-check_groups(Mod, [BadTerm | _Gs], _Defs, Levels) ->
- Where = if length(Levels) == 0 ->
+find(Mod, Name, TCs, [TC | Gs], Known, Defs, true) when is_atom(TC) ->
+ [TC | find(Mod, Name, TCs, Gs, Known, Defs, true)];
+
+find(Mod, _Name, _TCs, [BadTerm | _Gs], Known, _Defs, _Found) ->
+ Where = if length(Known) == 0 ->
atom_to_list(Mod)++":groups/0";
true ->
- "group "++atom_to_list(lists:last(Levels))++
+ "group "++atom_to_list(lists:last(Known))++
" in "++atom_to_list(Mod)++":groups/0"
end,
Term = io_lib:format("~p", [BadTerm]),
E = "Bad term "++lists:flatten(Term)++" in "++Where,
throw({error,list_to_atom(E)});
-check_groups(_Mod, [], _Defs, _) ->
+find(_Mod, _Name, _TCs, [], _Known, _Defs, false) ->
+ ['$NOMATCH'];
+
+find(_Mod, _Name, _TCs, [], _Known, _Defs, _Found) ->
+ [].
+
+delete_subs([Conf | Confs], All) ->
+ All1 = delete_conf(Conf, All),
+ case is_sub(Conf, All1) of
+ true ->
+ delete_subs(Confs, All1);
+ false ->
+ delete_subs(Confs, All)
+ end;
+
+delete_subs([], All) ->
+ All.
+
+delete_conf({conf,Props,_,_,_}, Confs) ->
+ Name = proplists:get_value(name, Props),
+ [Conf || Conf = {conf,Props0,_,_,_} <- Confs,
+ Name =/= proplists:get_value(name, Props0)].
+
+is_sub({conf,Props,_,_,_}=Conf, [{conf,_,_,Tests,_} | Confs]) ->
+ Name = proplists:get_value(name, Props),
+ case lists:any(fun({conf,Props0,_,_,_}) ->
+ case proplists:get_value(name, Props0) of
+ N when N == Name ->
+ true;
+ _ ->
+ false
+ end;
+ (_) ->
+ false
+ end, Tests) of
+ true ->
+ true;
+ false ->
+ is_sub(Conf, Tests) or is_sub(Conf, Confs)
+ end;
+
+is_sub(Conf, [_TC | Tests]) ->
+ is_sub(Conf, Tests);
+
+is_sub(_Conf, []) ->
+ false.
+
+trim(['$NOMATCH' | Tests]) ->
+ trim(Tests);
+
+trim([{conf,Props,Init,Tests,End} | Confs]) ->
+ case trim(Tests) of
+ [] ->
+ trim(Confs);
+ Trimmed ->
+ [{conf,Props,Init,Trimmed,End} | trim(Confs)]
+ end;
+
+trim([TC | Tests]) ->
+ [TC | trim(Tests)];
+
+trim([]) ->
[].
-find_group(Mod, Name, Defs) ->
+cyclic_test(Mod, Name, Names) ->
+ case lists:member(Name, Names) of
+ true ->
+ E = "Cyclic reference to group "++atom_to_list(Name)++
+ " in "++atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)});
+ false ->
+ ok
+ end.
+
+expand(Mod, Name, Defs) ->
case lists:keysearch(Name, 1, Defs) of
{value,Def} ->
Def;
@@ -769,7 +865,48 @@ find_group(Mod, Name, Defs) ->
throw({error,list_to_atom(E)})
end.
+make_all_conf(Dir, Mod, _Props) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_all_conf(Mod).
+
+make_all_conf(Mod) ->
+ case catch apply(Mod, groups, []) of
+ {'EXIT',_} ->
+ {error,{invalid_group_definition,Mod}};
+ GroupDefs when is_list(GroupDefs) ->
+ case catch find_groups(Mod, all, all, GroupDefs) of
+ {error,_} = Error ->
+ %% this makes test_server call error_in_suite as first
+ %% (and only) test case so we can report Error properly
+ [{?MODULE,error_in_suite,[[Error]]}];
+ [] ->
+ {error,{invalid_group_spec,Mod}};
+ ConfTests ->
+ [{conf,Props,Init,all,End} || {conf,Props,Init,_,End} <- ConfTests]
+ end
+ end.
+
+make_conf(Dir, Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_conf(Mod, Name, Props, TestSpec).
+
make_conf(Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_file(Mod);
+ _ ->
+ ok
+ end,
{InitConf,EndConf} =
case erlang:function_exported(Mod,init_per_group,2) of
true ->
@@ -780,6 +917,7 @@ make_conf(Mod, Name, Props, TestSpec) ->
end,
{conf,[{name,Name}|Props],InitConf,TestSpec,EndConf}.
+%%%-----------------------------------------------------------------
get_all(Mod, ConfTests) ->
case catch apply(Mod, all, []) of
@@ -1095,4 +1233,31 @@ add_data_dir(File,Config) when is_list(File) ->
File
end.
+%%%-----------------------------------------------------------------
+%%% @spec overview_html_header(TestName) -> Header
+overview_html_header(TestName) ->
+ TestName1 = lists:flatten(io_lib:format("~p", [TestName])),
+ Label = case application:get_env(common_test, test_label) of
+ {ok,Lbl} when Lbl =/= undefined ->
+ "<H1><FONT color=\"green\">" ++ Lbl ++ "</FONT></H1>\n";
+ _ ->
+ ""
+ end,
+ Bgr = case ct_logs:basic_html() of
+ true ->
+ "";
+ false ->
+ CTPath = code:lib_dir(common_test),
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ " background=\"" ++ TileFile ++ "\""
+ end,
+
+ ["<html>\n",
+ "<head><title>Test ", TestName1, " results</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body", Bgr, " bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n",
+ Label,
+ "<H2>Results from test ", TestName1, "</H2>\n"].
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 5683d06aa7..f8ae7202e6 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -36,7 +36,8 @@
-export([make_all_suites_index/1,make_all_runs_index/1]).
%% Logging stuff directly from testcase
--export([tc_log/3,tc_print/3,tc_pal/3]).
+-export([tc_log/3,tc_print/3,tc_pal/3,
+ basic_html/0]).
%% Simulate logger process for use without ct environment running
-export([simulate/0]).
@@ -57,7 +58,7 @@
-define(table_color2,"#E4F0FE").
-define(table_color3,"#F0F8FF").
--define(testname_width, 70).
+-define(testname_width, 60).
-define(abs(Name), filename:absname(Name)).
@@ -716,7 +717,7 @@ make_last_run_index1(StartTime,IndexName) ->
[Log];
Logs ->
case read_totals_file(?totals_name) of
- {_Node,Logs0,_Totals} ->
+ {_Node,_Lbl,Logs0,_Totals} ->
insert_dirs(Logs,Logs0);
_ ->
%% someone deleted the totals file!?
@@ -728,10 +729,15 @@ make_last_run_index1(StartTime,IndexName) ->
{ok,Bin} -> binary_to_term(Bin);
_ -> []
end,
- {ok,Index0,Totals} = make_last_run_index(Logs1, index_header(StartTime),
+ Label = case application:get_env(common_test, test_label) of
+ {ok,Lbl} -> Lbl;
+ _ -> undefined
+ end,
+ {ok,Index0,Totals} = make_last_run_index(Logs1,
+ index_header(Label,StartTime),
0, 0, 0, 0, 0, Missing),
%% write current Totals to file, later to be used in all_runs log
- write_totals_file(?totals_name,Logs1,Totals),
+ write_totals_file(?totals_name,Label,Logs1,Totals),
Index = [Index0|index_footer()],
case force_write_file(IndexName, Index) of
ok ->
@@ -761,7 +767,7 @@ make_last_run_index([Name|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip,
TotNotBuilt, Missing);
LastLogDir ->
SuiteName = filename:rootname(filename:basename(Name)),
- case make_one_index_entry(SuiteName, LastLogDir, false, Missing) of
+ case make_one_index_entry(SuiteName, LastLogDir, "-", false, Missing) of
{Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
@@ -780,18 +786,18 @@ make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuil
{ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, false)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
-make_one_index_entry(SuiteName, LogDir, All, Missing) ->
+make_one_index_entry(SuiteName, LogDir, Label, All, Missing) ->
case count_cases(LogDir) of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(SuiteName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(SuiteName, LogDir, Succ, Fail,
+ NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail,
UserSkip, AutoSkip, NotBuilt, All),
{NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
error ->
error
end.
-make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
+make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
NotBuilt, All) ->
LogFile = filename:join(Link, ?suitelog_name ++ ".html"),
CrashDumpName = SuiteName ++ "_erl_crash.dump",
@@ -803,7 +809,7 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
false ->
""
end,
- {Timestamp,Node,AllInfo} =
+ {Lbl,Timestamp,Node,AllInfo} =
case All of
{true,OldRuns} ->
[_Prefix,NodeOrDate|_] = string:tokens(Link,"."),
@@ -811,20 +817,21 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
0 -> "-";
_ -> NodeOrDate
end,
- N = ["<TD ALIGN=right>",Node1,"</TD>\n"],
+ N = ["<TD ALIGN=right><FONT SIZE=-1>",Node1,"</FONT></TD>\n"],
CtRunDir = filename:dirname(filename:dirname(Link)),
- T = ["<TD>",timestamp(CtRunDir),"</TD>\n"],
+ L = ["<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</FONT></B></TD>\n"],
+ T = ["<TD><FONT SIZE=-1>",timestamp(CtRunDir),"</FONT></TD>\n"],
CtLogFile = filename:join(CtRunDir,?ct_log_name),
OldRunsLink =
case OldRuns of
[] -> "none";
_ -> "<A HREF=\""++?all_runs_name++"\">Old Runs</A>"
end,
- A=["<TD><A HREF=\"",CtLogFile,"\">CT Log</A></TD>\n",
- "<TD>",OldRunsLink,"</TD>\n"],
- {T,N,A};
+ A=["<TD><FONT SIZE=-1><A HREF=\"",CtLogFile,"\">CT Log</A></FONT></TD>\n",
+ "<TD><FONT SIZE=-1>",OldRunsLink,"</FONT></TD>\n"],
+ {L,T,N,A};
false ->
- {"","",""}
+ {"","","",""}
end,
NotBuiltStr =
if NotBuilt == 0 ->
@@ -851,7 +858,8 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
end,
["<TR valign=top>\n",
- "<TD><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</TD>\n",
+ "<TD><FONT SIZE=-1><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</FONT></TD>\n",
+ Lbl,
Timestamp,
"<TD ALIGN=right>",integer_to_list(Success),"</TD>\n",
"<TD ALIGN=right>",FailStr,"</TD>\n",
@@ -862,12 +870,14 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
AllInfo,
"</TR>\n"].
total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
- {TimestampCell,AllInfo} =
+ {Label,TimestampCell,AllInfo} =
case All of
- true ->
- {"<TD>&nbsp;</TD>\n","<TD>&nbsp;</TD>\n<TD>&nbsp;</TD>\n"};
+ true ->
+ {"<TD>&nbsp;</TD>\n",
+ "<TD>&nbsp;</TD>\n",
+ "<TD>&nbsp;</TD>\n<TD>&nbsp;</TD>\n"};
false ->
- {"",""}
+ {"","",""}
end,
{AllSkip,UserSkipStr,AutoSkipStr} =
@@ -877,6 +887,7 @@ total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
end,
["<TR valign=top>\n",
"<TD><B>Total</B></TD>",
+ Label,
TimestampCell,
"<TD ALIGN=right><B>",integer_to_list(Success),"<B></TD>\n",
"<TD ALIGN=right><B>",integer_to_list(Fail),"<B></TD>\n",
@@ -937,13 +948,21 @@ term_to_text(Term) ->
%%% Headers and footers.
-index_header(StartTime) ->
- [header("Test Results " ++ format_time(StartTime)) |
+index_header(Label, StartTime) ->
+ Head =
+ case Label of
+ undefined ->
+ header("Test Results", format_time(StartTime));
+ _ ->
+ header("Test Results for \"" ++ Label ++ "\"",
+ format_time(StartTime))
+ end,
+ [Head |
["<CENTER>\n",
"<P><A HREF=\"",?ct_log_name,"\">Common Test Framework Log</A></P>",
"<TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color3,"\">\n"
- "<th><B>Name</B></th>\n",
+ "<th><B>Test Name</B></th>\n",
"<th><font color=\"",?table_color3,"\">_</font>Ok"
"<font color=\"",?table_color3,"\">_</font></th>\n"
"<th>Failed</th>\n",
@@ -952,13 +971,17 @@ index_header(StartTime) ->
"\n"]].
all_suites_index_header() ->
+ {ok,Cwd} = file:get_cwd(),
+ LogDir = filename:basename(Cwd),
+ AllRuns = "All test runs in \"" ++ LogDir ++ "\"",
[header("Test Results") |
["<CENTER>\n",
- "<A HREF=\"",?all_runs_name,"\">All Test Runs in this directory</A>\n",
+ "<A HREF=\"",?all_runs_name,"\">",AllRuns,"</A>\n",
"<br><br>\n",
"<TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color2,"\">\n"
- "<th>Name</th>\n",
+ "<th>Test Name</th>\n",
+ "<th>Label</th>\n",
"<th>Test Run Started</th>\n",
"<th><font color=\"",?table_color2,"\">_</font>Ok"
"<font color=\"",?table_color2,"\">_</font></th>\n"
@@ -971,13 +994,17 @@ all_suites_index_header() ->
"\n"]].
all_runs_header() ->
- [header("All test runs in current directory") |
+ {ok,Cwd} = file:get_cwd(),
+ LogDir = filename:basename(Cwd),
+ Title = "All test runs in \"" ++ LogDir ++ "\"",
+ [header(Title) |
["<CENTER><TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color1,"\">\n"
"<th><B>History</B></th>\n"
"<th><B>Node</B></th>\n"
+ "<th><B>Label</B></th>\n"
"<th>Tests</th>\n"
- "<th><B>Names</B></th>\n"
+ "<th><B>Test Names</B></th>\n"
"<th>Total</th>\n"
"<th><font color=\"",?table_color1,"\">_</font>Ok"
"<font color=\"",?table_color1,"\">_</font></th>\n"
@@ -987,12 +1014,23 @@ all_runs_header() ->
"\n"]].
header(Title) ->
+ header1(Title, "").
+header(Title, SubTitle) ->
+ header1(Title, SubTitle).
+
+header1(Title, SubTitle) ->
+ SubTitleHTML = if SubTitle =/= "" ->
+ ["<CENTER>\n",
+ "<H2>" ++ SubTitle ++ "</H2>\n",
+ "</CENTER>\n<BR>\n"];
+ true -> "<BR>\n"
+ end,
["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
"<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
"<HTML>\n",
"<HEAD>\n",
- "<TITLE>" ++ Title ++ "</TITLE>\n",
+ "<TITLE>" ++ Title ++ " " ++ SubTitle ++ "</TITLE>\n",
"<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE\">\n",
"</HEAD>\n",
@@ -1004,6 +1042,7 @@ header(Title) ->
"<CENTER>\n",
"<H1>" ++ Title ++ "</H1>\n",
"</CENTER>\n",
+ SubTitleHTML,
"<!-- ---- CONTENT ---- -->\n"].
@@ -1013,19 +1052,28 @@ index_footer() ->
footer() ->
["<P><CENTER>\n"
- "<HR>\n"
- "<P><FONT SIZE=-1>\n"
- "Copyright &copy; ", year(),
- " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n"
- "Updated: <!date>", current_time(), "<!/date><BR>\n"
- "</FONT>\n"
- "</CENTER>\n"
- "</body>\n"].
+ "<BR><BR>\n"
+ "<HR>\n"
+ "<P><FONT SIZE=-1>\n"
+ "Copyright &copy; ", year(),
+ " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n"
+ "Updated: <!date>", current_time(), "<!/date><BR>\n"
+ "</FONT>\n"
+ "</CENTER>\n"
+ "</body>\n"].
body_tag() ->
- "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\""
- "vlink=\"#800080\" alink=\"#FF0000\">\n".
+ case basic_html() of
+ true ->
+ "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
+ "vlink=\"#800080\" alink=\"#FF0000\">\n";
+ false ->
+ CTPath = code:lib_dir(common_test),
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ "<body background=\"" ++ TileFile ++ "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
+ "vlink=\"#800080\" alink=\"#FF0000\">\n"
+ end.
current_time() ->
format_time(calendar:local_time()).
@@ -1217,7 +1265,7 @@ runentry(Dir, BasicHtml) ->
TotalsFile = filename:join(Dir,?totals_name),
TotalsStr =
case read_totals_file(TotalsFile) of
- {Node,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
+ {Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
TotFailStr =
if TotFail > 0 ->
["<FONT color=\"red\">",
@@ -1263,6 +1311,7 @@ runentry(Dir, BasicHtml) ->
end,
Total = TotSucc+TotFail+AllSkip,
A = ["<TD ALIGN=center><FONT SIZE=-1>",Node,"</FONT></TD>\n",
+ "<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</B></FONT></TD>\n",
"<TD ALIGN=right>",NoOfTests,"</TD>\n"],
B = if BasicHtml ->
["<TD ALIGN=center><FONT SIZE=-1>",TestNamesTrunc,"</FONT></TD>\n"];
@@ -1283,17 +1332,19 @@ runentry(Dir, BasicHtml) ->
end,
Index = filename:join(Dir,?index_name),
["<TR>\n"
- "<TD><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</TD>\n"
+ "<TD><FONT SIZE=-1><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</FONT></TD>\n"
"</TR>\n"].
-write_totals_file(Name,Logs,Totals) ->
+write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
notify_and_lock_file(AbsName),
force_write_file(AbsName,
term_to_binary({atom_to_list(node()),
- Logs,Totals})),
+ Label,Logs,Totals})),
notify_and_unlock_file(AbsName).
+%% this function needs to convert from old formats to new so that old
+%% test results (prev ct versions) can be listed together with new
read_totals_file(Name) ->
AbsName = ?abs(Name),
notify_and_lock_file(AbsName),
@@ -1303,12 +1354,23 @@ read_totals_file(Name) ->
case catch binary_to_term(Bin) of
{'EXIT',_Reason} -> % corrupt file
{"-",[],undefined};
- R = {Node,Ls,Tot} ->
+ {Node,Label,Ls,Tot} -> % all info available
+ Label1 = case Label of
+ undefined -> "-";
+ _ -> Label
+ end,
+ case Tot of
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {Node,Label1,Ls,Tot};
+ {TotSucc,TotFail,AllSkip,NotBuilt} ->
+ {Node,Label1,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ end;
+ {Node,Ls,Tot} -> % no label found
case Tot of
- {_,_,_,_,_} -> % latest format
- R;
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {Node,"-",Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,"-",Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
%% for backwards compatibility
{Ls,Tot} -> {"-",Ls,Tot};
@@ -1411,7 +1473,7 @@ make_all_suites_index1(When,AllSuitesLogDirs) ->
make_all_suites_index2(IndexName,AllSuitesLogDirs) ->
{ok,Index0,_Totals} = make_all_suites_index3(AllSuitesLogDirs,
all_suites_index_header(),
- 0, 0, 0, 0, 0),
+ 0, 0, 0, 0, 0, []),
Index = [Index0|index_footer()],
case force_write_file(IndexName, Index) of
ok ->
@@ -1421,14 +1483,25 @@ make_all_suites_index2(IndexName,AllSuitesLogDirs) ->
end.
make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest],
- Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt) ->
+ Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
+ Labels) ->
[EntryDir|_] = filename:split(LastLogDir),
Missing =
case file:read_file(filename:join(EntryDir,?missing_suites_info)) of
{ok,Bin} -> binary_to_term(Bin);
_ -> []
end,
- case make_one_index_entry(SuiteName, LastLogDir, {true,OldDirs}, Missing) of
+ {Label,Labels1} =
+ case proplists:get_value(EntryDir, Labels) of
+ undefined ->
+ case read_totals_file(filename:join(EntryDir,?totals_name)) of
+ {_,Lbl,_,_} -> {Lbl,[{EntryDir,Lbl}|Labels]};
+ _ -> {"-",[{EntryDir,"-"}|Labels]}
+ end;
+ Lbl ->
+ {Lbl,Labels}
+ end,
+ case make_one_index_entry(SuiteName, LastLogDir, Label, {true,OldDirs}, Missing) of
{Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
@@ -1437,13 +1510,13 @@ make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest],
end,
make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt);
+ TotNotBuilt+NotBuilt,Labels1);
error ->
make_all_suites_index3(Rest, Result, TotSucc, TotFail,
- UserSkip, AutoSkip, TotNotBuilt)
+ UserSkip, AutoSkip, TotNotBuilt,Labels1)
end;
make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
+ TotNotBuilt,_) ->
{ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 6a9c42d1b9..c5bfd01642 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -45,7 +45,8 @@
-define(abs(Name), filename:absname(Name)).
-define(testdir(Name, Suite), ct_util:get_testdir(Name, Suite)).
--record(opts, {vts,
+-record(opts, {label,
+ vts,
shell,
cover,
coverspec,
@@ -153,14 +154,16 @@ script_start(Args) ->
Result
end,
stop_trace(Tracing),
+ timer:sleep(1000),
Res.
script_start1(Parent, Args) ->
%% read general start flags
+ Label = get_start_opt(label, fun([Lbl]) -> Lbl end, Args),
Vts = get_start_opt(vts, true, Args),
Shell = get_start_opt(shell, true, Args),
Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args),
- LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, ".", Args),
+ LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
MultTT = get_start_opt(multiply_timetraps,
fun([MT]) -> list_to_integer(MT) end, 1, Args),
ScaleTT = get_start_opt(scale_timetraps,
@@ -229,7 +232,7 @@ script_start1(Parent, Args) ->
application:set_env(common_test, basic_html, true)
end,
- StartOpts = #opts{vts = Vts, shell = Shell, cover = Cover,
+ StartOpts = #opts{label = Label, vts = Vts, shell = Shell, cover = Cover,
logdir = LogDir, event_handlers = EvHandlers,
include = IncludeDirs,
silent_connections = SilentConns,
@@ -288,6 +291,9 @@ script_start2(StartOpts = #opts{vts = undefined,
TS ->
SpecStartOpts = get_data_for_node(TS, node()),
+ Label = choose_val(StartOpts#opts.label,
+ SpecStartOpts#opts.label),
+
LogDir = choose_val(StartOpts#opts.logdir,
SpecStartOpts#opts.logdir),
@@ -303,7 +309,8 @@ script_start2(StartOpts = #opts{vts = undefined,
SpecStartOpts#opts.include]),
application:set_env(common_test, include, AllInclude),
- {TS,StartOpts#opts{testspecs = Specs,
+ {TS,StartOpts#opts{label = Label,
+ testspecs = Specs,
cover = Cover,
logdir = LogDir,
config = SpecStartOpts#opts.config,
@@ -317,29 +324,30 @@ script_start2(StartOpts = #opts{vts = undefined,
end,
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
+ TheLogDir = which(logdir, Opts#opts.logdir),
case {TestSpec,Terms} of
{_,{error,_}=Error} ->
Error;
{[],_} ->
{error,no_testspec_specified};
{undefined,_} -> % no testspec used
- case check_and_install_configfiles(InitConfig,
- which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(InitConfig, TheLogDir,
Opts#opts.event_handlers) of
ok -> % go on read tests from start flags
- script_start3(Opts#opts{config=InitConfig}, Args);
+ script_start3(Opts#opts{config=InitConfig,
+ logdir=TheLogDir}, Args);
Error ->
Error
end;
{_,_} -> % testspec used
%% merge config from start flags with config from testspec
AllConfig = merge_vals([InitConfig, Opts#opts.config]),
- case check_and_install_configfiles(AllConfig,
- which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(AllConfig, TheLogDir,
Opts#opts.event_handlers) of
ok -> % read tests from spec
{Run,Skip} = ct_testspec:prepare_tests(Terms, node()),
- do_run(Run, Skip, Opts#opts{config=AllConfig}, Args);
+ do_run(Run, Skip, Opts#opts{config=AllConfig,
+ logdir=TheLogDir}, Args);
Error ->
Error
end
@@ -348,11 +356,12 @@ script_start2(StartOpts = #opts{vts = undefined,
script_start2(StartOpts, Args) ->
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
- case check_and_install_configfiles(InitConfig,
- which(logdir,StartOpts#opts.logdir),
+ LogDir = which(logdir, StartOpts#opts.logdir),
+ case check_and_install_configfiles(InitConfig, LogDir,
StartOpts#opts.event_handlers) of
ok -> % go on read tests from start flags
- script_start3(StartOpts#opts{config=InitConfig}, Args);
+ script_start3(StartOpts#opts{config=InitConfig,
+ logdir=LogDir}, Args);
Error ->
Error
end.
@@ -427,8 +436,12 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers,
end, [], Config),
vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests);
-script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
+script_start4(#opts{label = Label, shell = true, config = Config,
+ event_handlers = EvHandlers,
logdir = LogDir, testspecs = Specs}, _Args) ->
+ %% label - used by ct_logs
+ application:set_env(common_test, test_label, Label),
+
InstallOpts = [{config,Config},{event_handler,EvHandlers}],
if Config == [] ->
ok;
@@ -613,9 +626,13 @@ run_test(StartOpts) when is_list(StartOpts) ->
end.
run_test1(StartOpts) ->
+ %% label
+ Label = get_start_opt(label, fun(Lbl) when is_list(Lbl) -> Lbl;
+ (Lbl) when is_atom(Lbl) -> atom_to_list(Lbl)
+ end, StartOpts),
%% logdir
LogDir = get_start_opt(logdir, fun(LD) when is_list(LD) -> LD end,
- ".", StartOpts),
+ StartOpts),
%% config & userconfig
CfgFiles = ct_config:get_config_file_list(StartOpts),
@@ -711,7 +728,8 @@ run_test1(StartOpts) ->
%% stepped execution
Step = get_start_opt(step, value, StartOpts),
- Opts = #opts{cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
+ Opts = #opts{label = Label,
+ cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
event_handlers = EvHandlers, include = Include,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -747,6 +765,8 @@ run_spec_file(Relaxed,
exit(CTReason);
TS ->
SpecOpts = get_data_for_node(TS, node()),
+ Label = choose_val(Opts#opts.label,
+ SpecOpts#opts.label),
LogDir = choose_val(Opts#opts.logdir,
SpecOpts#opts.logdir),
AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]),
@@ -766,8 +786,9 @@ run_spec_file(Relaxed,
which(logdir,LogDir),
AllEvHs) of
ok ->
- Opts1 = Opts#opts{cover = Cover,
- logdir = LogDir,
+ Opts1 = Opts#opts{label = Label,
+ cover = Cover,
+ logdir = which(logdir, LogDir),
config = AllConfig,
event_handlers = AllEvHs,
include = AllInclude,
@@ -775,7 +796,7 @@ run_spec_file(Relaxed,
multiply_timetraps = MultTT,
scale_timetraps = ScaleTT},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, Opts1, StartOpts);
+ reformat_result(catch do_run(Run, Skip, Opts1, StartOpts));
{error,GCFReason} ->
exit(GCFReason)
end
@@ -785,9 +806,11 @@ run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers},
StartOpts) ->
- case check_and_install_configfiles(CfgFiles, LogDir, EvHandlers) of
+ LogDir1 = which(logdir, LogDir),
+ case check_and_install_configfiles(CfgFiles, LogDir1, EvHandlers) of
ok ->
- do_run(Run, Skip, Opts, StartOpts);
+ reformat_result(catch do_run(Run, Skip, Opts#opts{logdir = LogDir1},
+ StartOpts));
{error,Reason} ->
exit(Reason)
end.
@@ -816,6 +839,8 @@ check_config_file(Callback, File)->
run_dir(Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers}, StartOpts) ->
+ LogDir1 = which(logdir, LogDir),
+ Opts1 = Opts#opts{logdir = LogDir1},
AbsCfgFiles =
lists:map(fun({Callback,FileList})->
case code:is_loaded(Callback) of
@@ -834,7 +859,7 @@ run_dir(Opts = #opts{logdir = LogDir,
check_config_file(Callback, File)
end, FileList)}
end, CfgFiles),
- case install([{config,AbsCfgFiles},{event_handler,EvHandlers}], LogDir) of
+ case install([{config,AbsCfgFiles},{event_handler,EvHandlers}], LogDir1) of
ok -> ok;
{error,IReason} -> exit(IReason)
end,
@@ -842,7 +867,7 @@ run_dir(Opts = #opts{logdir = LogDir,
{value,{_,Dirs=[Dir|_]}} when not is_integer(Dir),
length(Dirs)>1 ->
%% multiple dirs (no suite)
- do_run(tests(Dirs), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dirs), [], Opts1, StartOpts));
false -> % no dir
%% fun for converting suite name to {Dir,Mod} tuple
S2M = fun(S) when is_list(S) ->
@@ -857,12 +882,15 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, StartOpts, [])) ++
listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dir, listify(Mod)),
+ [], Opts1, StartOpts));
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(Dir, Mod, GsAndCs),
+ [], Opts1, StartOpts))
end;
{value,{_,Suites}} ->
- do_run(tests(lists:map(S2M, Suites)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(lists:map(S2M, Suites)),
+ [], Opts1, StartOpts));
_ ->
exit(no_tests_specified)
end;
@@ -875,17 +903,22 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, StartOpts, [])) ++
listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dir, listify(Mod)),
+ [], Opts1, StartOpts));
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(Dir, Mod, GsAndCs),
+ [], Opts1, StartOpts))
end;
{value,{_,Suites=[Suite|_]}} when is_list(Suite) ->
Mods = lists:map(fun(Str) -> list_to_atom(Str) end, Suites),
- do_run(tests(delistify(Dir), Mods), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(delistify(Dir), Mods),
+ [], Opts1, StartOpts));
{value,{_,Suites}} ->
- do_run(tests(delistify(Dir), Suites), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(delistify(Dir), Suites),
+ [], Opts1, StartOpts));
false -> % no suite, only dir
- do_run(tests(listify(Dir)), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(listify(Dir)),
+ [], Opts1, StartOpts))
end
end.
@@ -925,28 +958,30 @@ run_testspec1(TestSpec) ->
EnvInclude++Opts#opts.include
end,
application:set_env(common_test, include, AllInclude),
-
- case check_and_install_configfiles(Opts#opts.config,
- which(logdir,Opts#opts.logdir),
+ LogDir1 = which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(Opts#opts.config, LogDir1,
Opts#opts.event_handlers) of
ok ->
- Opts1 = Opts#opts{testspecs = [TestSpec],
+ Opts1 = Opts#opts{testspecs = [],
+ logdir = LogDir1,
include = AllInclude},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, Opts1, []);
+ reformat_result(catch do_run(Run, Skip, Opts1, []));
{error,GCFReason} ->
exit(GCFReason)
end
end.
-get_data_for_node(#testspec{logdir=LogDirs,
- cover=CoverFs,
- config=Cfgs,
- userconfig=UsrCfgs,
- event_handler=EvHs,
- include=Incl,
- multiply_timetraps=MTs,
- scale_timetraps=STs}, Node) ->
+get_data_for_node(#testspec{label = Labels,
+ logdir = LogDirs,
+ cover = CoverFs,
+ config = Cfgs,
+ userconfig = UsrCfgs,
+ event_handler = EvHs,
+ include = Incl,
+ multiply_timetraps = MTs,
+ scale_timetraps = STs}, Node) ->
+ Label = proplists:get_value(Node, Labels),
LogDir = case proplists:get_value(Node, LogDirs) of
undefined -> ".";
Dir -> Dir
@@ -958,7 +993,8 @@ get_data_for_node(#testspec{logdir=LogDirs,
[CBF || {N,CBF} <- UsrCfgs, N==Node],
EvHandlers = [{H,A} || {N,H,A} <- EvHs, N==Node],
Include = [I || {N,I} <- Incl, N==Node],
- #opts{logdir = LogDir,
+ #opts{label = Label,
+ logdir = LogDir,
cover = Cover,
config = ConfigFiles,
event_handlers = EvHandlers,
@@ -1023,21 +1059,26 @@ delistify(E) -> E.
%%% @equiv ct:run/3
run(TestDir, Suite, Cases) ->
install([]),
- do_run(tests(TestDir, Suite, Cases), []).
+ reformat_result(catch do_run(tests(TestDir, Suite, Cases), [])).
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/2
run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
install([]),
- do_run(tests(TestDir, Suite), []).
+ reformat_result(catch do_run(tests(TestDir, Suite), [])).
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/1
run(TestDirs) ->
install([]),
- do_run(tests(TestDirs), []).
+ reformat_result(catch do_run(tests(TestDirs), [])).
+
+reformat_result({user_error,Reason}) ->
+ {error,Reason};
+reformat_result(Result) ->
+ Result.
suite_to_test(Suite) ->
{filename:dirname(Suite),list_to_atom(filename:rootname(filename:basename(Suite)))}.
@@ -1092,7 +1133,17 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) ->
do_run(Tests, [], Opts1#opts{logdir = LogDir}, []).
do_run(Tests, Skip, Opts, Args) ->
- #opts{cover = Cover} = Opts,
+ #opts{label = Label, cover = Cover} = Opts,
+
+ %% label - used by ct_logs
+ TestLabel =
+ if Label == undefined -> undefined;
+ is_atom(Label) -> atom_to_list(Label);
+ is_list(Label) -> Label;
+ true -> undefined
+ end,
+ application:set_env(common_test, test_label, TestLabel),
+
case code:which(test_server) of
non_existing ->
exit({error,no_path_to_test_server});
@@ -1156,10 +1207,19 @@ do_run(Tests, Skip, Opts, Args) ->
true ->
SavedErrors = save_make_errors(SuiteMakeErrors),
ct_repeat:log_loop_info(Args),
- {Tests1,Skip1} = final_tests(Tests,[],Skip,SavedErrors),
- R = do_run_test(Tests1, Skip1, Opts1),
- ct_util:stop(normal),
- R;
+
+ {Tests1,Skip1} = final_tests(Tests,Skip,SavedErrors),
+
+ R = (catch do_run_test(Tests1, Skip1, Opts1)),
+ case R of
+ {EType,_} = Error when EType == user_error ;
+ EType == error ->
+ ct_util:stop(clean),
+ exit(Error);
+ _ ->
+ ct_util:stop(normal),
+ R
+ end;
false ->
io:nl(),
ct_util:stop(clean),
@@ -1316,8 +1376,22 @@ suite_tuples([{TestDir,Suite,_} | Tests]) when is_atom(Suite) ->
suite_tuples([]) ->
[].
-final_tests([{TestDir,Suites,_}|Tests],
- Final, Skip, Bad) when is_list(Suites), is_atom(hd(Suites)) ->
+final_tests(Tests, Skip, Bad) ->
+
+ %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here!
+ %%! io:format(user, "FINAL0 = ~p~nSKIP0 = ~p~n", [Tests, Skip]),
+
+ {Tests1,Skip1} = final_tests1(Tests, [], Skip, Bad),
+ Skip2 = final_skip(Skip1, []),
+
+
+ %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here!
+ %%! io:format(user, "FINAL1 = ~p~nSKIP1 = ~p~n", [Tests1, Skip2]),
+
+ {Tests1,Skip2}.
+
+final_tests1([{TestDir,Suites,_}|Tests], Final, Skip, Bad) when
+ is_list(Suites), is_atom(hd(Suites)) ->
% Separate =
% fun(S,{DoSuite,Dont}) ->
% case lists:keymember({TestDir,S},1,Bad) of
@@ -1336,9 +1410,9 @@ final_tests([{TestDir,Suites,_}|Tests],
Skip1 = [{TD,S,"Make failed"} || {{TD,S},_} <- Bad, S1 <- Suites,
S == S1, TD == TestDir],
Final1 = [{TestDir,S,all} || S <- Suites],
- final_tests(Tests, lists:reverse(Final1)++Final, Skip++Skip1, Bad);
+ final_tests1(Tests, lists:reverse(Final1)++Final, Skip++Skip1, Bad);
-final_tests([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
+final_tests1([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
MissingSuites =
case lists:keysearch({TestDir,all}, 1, Bad) of
{value,{_,Failed}} ->
@@ -1348,26 +1422,58 @@ final_tests([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
end,
Missing = [{TestDir,S,"Make failed"} || S <- MissingSuites],
Final1 = [{TestDir,all,all}|Final],
- final_tests(Tests, Final1, Skip++Missing, Bad);
+ final_tests1(Tests, Final1, Skip++Missing, Bad);
-final_tests([{TestDir,Suite,Cases}|Tests],
- Final, Skip, Bad) when Cases==[]; Cases==all ->
- final_tests([{TestDir,[Suite],all}|Tests], Final, Skip, Bad);
+final_tests1([{TestDir,Suite,Cases}|Tests], Final, Skip, Bad) when
+ Cases==[]; Cases==all ->
+ final_tests1([{TestDir,[Suite],all}|Tests], Final, Skip, Bad);
-final_tests([{TestDir,Suite,Cases}|Tests], Final, Skip, Bad) ->
+final_tests1([{TestDir,Suite,GrsOrCs}|Tests], Final, Skip, Bad) when
+ is_list(GrsOrCs) ->
case lists:keymember({TestDir,Suite}, 1, Bad) of
- false ->
- Do = {TestDir,Suite,Cases},
- final_tests(Tests, [Do|Final], Skip, Bad);
true ->
- Do = {TestDir,Suite,Cases},
- Skip1 = Skip ++ [{TestDir,Suite,Cases,"Make failed"}],
- final_tests(Tests, [Do|Final], Skip1, Bad)
+ Skip1 = Skip ++ [{TestDir,Suite,all,"Make failed"}],
+ final_tests1(Tests, [{TestDir,Suite,all}|Final], Skip1, Bad);
+ false ->
+ GrsOrCs1 =
+ lists:flatmap(
+ %% for now, only flat group defs are allowed as
+ %% start options and test spec terms
+ fun({all,all}) ->
+ ct_framework:make_all_conf(TestDir,
+ Suite, []);
+ ({skipped,Group,TCs}) ->
+ [ct_framework:make_conf(TestDir, Suite,
+ Group, [skipped], TCs)];
+ ({Group,TCs}) ->
+ [ct_framework:make_conf(TestDir, Suite,
+ Group, [], TCs)];
+ (TC) ->
+ [TC]
+ end, GrsOrCs),
+ Do = {TestDir,Suite,GrsOrCs1},
+ final_tests1(Tests, [Do|Final], Skip, Bad)
end;
-final_tests([], Final, Skip, _Bad) ->
+final_tests1([], Final, Skip, _Bad) ->
{lists:reverse(Final),Skip}.
+final_skip([{TestDir,Suite,{all,all},Reason}|Skips], Final) ->
+ SkipConf = ct_framework:make_conf(TestDir, Suite, all, [], all),
+ Skip = {TestDir,Suite,SkipConf,Reason},
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([{TestDir,Suite,{Group,TCs},Reason}|Skips], Final) ->
+ Conf = ct_framework:make_conf(TestDir, Suite, Group, [], TCs),
+ Skip = {TestDir,Suite,Conf,Reason},
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([Skip|Skips], Final) ->
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([], Final) ->
+ lists:reverse(Final).
+
continue([]) ->
true;
continue(_MakeErrors) ->
@@ -1489,6 +1595,7 @@ do_run_test(Tests, Skip, Opts) ->
_ ->
false
end,
+
%% let test_server expand the test tuples and count no of cases
{Suites,NoOfCases} = count_test_cases(Tests, Skip),
Suites1 = delete_dups(Suites),
@@ -1544,19 +1651,30 @@ count_test_cases(Tests, Skip) ->
TSPid = test_server_ctrl:start_get_totals(SendResult),
Ref = erlang:monitor(process, TSPid),
add_jobs(Tests, Skip, #opts{}, []),
- {Suites,NoOfCases} = count_test_cases1(length(Tests), 0, [], Ref),
+ Counted = (catch count_test_cases1(length(Tests), 0, [], Ref)),
erlang:demonitor(Ref, [flush]),
- test_server_ctrl:stop_get_totals(),
- {Suites,NoOfCases}.
+ case Counted of
+ {error,{test_server_died}} = Error ->
+ throw(Error);
+ {error,Reason} ->
+ unlink(whereis(test_server_ctrl)),
+ test_server_ctrl:stop(),
+ throw({user_error,Reason});
+ Result ->
+ test_server_ctrl:stop_get_totals(),
+ Result
+ end.
count_test_cases1(0, N, Suites, _) ->
{lists:flatten(Suites), N};
count_test_cases1(Jobs, N, Suites, Ref) ->
receive
+ {_,{error,_Reason} = Error} ->
+ throw(Error);
{no_of_cases,{Ss,N1}} ->
count_test_cases1(Jobs-1, add_known(N,N1), [Ss|Suites], Ref);
- {'DOWN', Ref, _, _, _} ->
- {[],0}
+ {'DOWN', Ref, _, _, Info} ->
+ throw({error,{test_server_died,Info}})
end.
add_known(unknown, _) ->
@@ -1604,13 +1722,36 @@ add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp) ->
Error
end;
-%% group
-add_jobs([{TestDir,Suite,[{GroupName,_Cases}]}|Tests], Skip, Opts, CleanUp) when
- is_atom(GroupName) ->
- add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
-add_jobs([{TestDir,Suite,{GroupName,_Cases}}|Tests], Skip, Opts, CleanUp) when
- is_atom(GroupName) ->
- add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
+%% group (= conf case in test_server)
+add_jobs([{TestDir,Suite,Confs}|Tests], Skip, Opts, CleanUp) when
+ element(1, hd(Confs)) == conf ->
+ Group = fun(Conf) -> proplists:get_value(name, element(2, Conf)) end,
+ TestCases = fun(Conf) -> element(4, Conf) end,
+ TCTestName = fun(all) -> "";
+ ([C]) when is_atom(C) -> "." ++ atom_to_list(C);
+ (Cs) when is_list(Cs) -> ".cases"
+ end,
+ GrTestName =
+ case Confs of
+ [Conf] ->
+ "." ++ atom_to_list(Group(Conf)) ++ TCTestName(TestCases(Conf));
+ _ ->
+ ".groups"
+ end,
+ TestName = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ GrTestName,
+ case maybe_interpret(Suite, init_per_group, Opts) of
+ ok ->
+ case catch test_server_ctrl:add_conf_with_skip(TestName, Suite, Confs,
+ skiplist(TestDir,Skip)) of
+ {'EXIT',_} ->
+ CleanUp;
+ _ ->
+ wait_for_idle(),
+ add_jobs(Tests, Skip, Opts, [Suite|CleanUp])
+ end;
+ Error ->
+ Error
+ end;
%% test case
add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 0f68b062f6..f5069427a2 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -185,7 +185,15 @@ prepare_cases(Node,Dir,Suite,Cases) ->
{[{{Node,Dir},{Suite,all}}],SkipAll};
Skipped ->
%% note: this adds a test even if only skip is specified
- PrepC = lists:foldr(fun({C,{skip,_Cmt}},Acc) ->
+ PrepC = lists:foldr(fun({{G,Cs},{skip,_Cmt}}, Acc) when
+ is_atom(G) ->
+ case lists:keymember(G, 1, Cases) of
+ true ->
+ Acc;
+ false ->
+ [{skipped,G,Cs}|Acc]
+ end;
+ ({C,{skip,_Cmt}},Acc) ->
case lists:member(C,Cases) of
true ->
Acc;
@@ -194,7 +202,7 @@ prepare_cases(Node,Dir,Suite,Cases) ->
end;
(C,Acc) -> [C|Acc]
end, [], Cases),
- {{{Node,Dir},{Suite,PrepC}},Skipped}
+ {{{Node,Dir},{Suite,PrepC}},Skipped}
end.
get_skipped_suites(Node,Dir,Suites) ->
@@ -210,7 +218,7 @@ get_skipped_cases(Node,Dir,Suite,Cases) ->
case lists:keysearch(all,1,Cases) of
{value,{all,{skip,Cmt}}} ->
[{{Node,Dir},{Suite,Cmt}}];
- false ->
+ _ ->
get_skipped_cases1(Node,Dir,Suite,Cases)
end.
@@ -432,6 +440,15 @@ save_nodes(Nodes,Spec=#testspec{nodes=NodeRefs}) ->
list_nodes(#testspec{nodes=NodeRefs}) ->
lists:map(fun({_Ref,Node}) -> Node end, NodeRefs).
+
+
+%% ---------------------------------------------------------
+%% / \
+%% | When adding tests, remember to update valid_terms/0 also! |
+%% \ /
+%% ---------------------------------------------------------
+
+
%% Associate a "global" logdir with all nodes
%% except those with specific logdir, e.g:
%% ["/tmp/logdir",{ct1@finwe,"/tmp/logdir2"}]
@@ -457,6 +474,24 @@ add_tests([{logdir,Node,Dir}|Ts],Spec) ->
add_tests([{logdir,Dir}|Ts],Spec) ->
add_tests([{logdir,all_nodes,Dir}|Ts],Spec);
+%% --- label ---
+add_tests([{label,all_nodes,Lbl}|Ts],Spec) ->
+ Labels = Spec#testspec.label,
+ Tests = [{label,N,Lbl} || N <- list_nodes(Spec),
+ lists:keymember(ref2node(N,Spec#testspec.nodes),
+ 1,Labels) == false],
+ add_tests(Tests++Ts,Spec);
+add_tests([{label,Nodes,Lbl}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,label,[Lbl],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{label,Node,Lbl}|Ts],Spec) ->
+ Labels = Spec#testspec.label,
+ Labels1 = [{ref2node(Node,Spec#testspec.nodes),Lbl} |
+ lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,Labels)],
+ add_tests(Ts,Spec#testspec{label=Labels1});
+add_tests([{label,Lbl}|Ts],Spec) ->
+ add_tests([{label,all_nodes,Lbl}|Ts],Spec);
+
%% --- cover ---
add_tests([{cover,all_nodes,File}|Ts],Spec) ->
Tests = lists:map(fun(N) -> {cover,N,File} end, list_nodes(Spec)),
@@ -878,8 +913,13 @@ skip_suites(_Node,_Dir,[],_Cmt,Tests) ->
skip_suites(Node,Dir,S,Cmt,Tests) ->
skip_suites(Node,Dir,[S],Cmt,Tests).
-skip_groups(Node,Dir,Suite,Group,Case,Cmt,Tests) when is_atom(Group) ->
- skip_groups(Node,Dir,Suite,[Group],[Case],Cmt,Tests);
+skip_groups(Node,Dir,Suite,Group,all,Cmt,Tests) when is_atom(Group) ->
+ skip_groups(Node,Dir,Suite,[Group],all,Cmt,Tests);
+skip_groups(Node,Dir,Suite,Group,Cases,Cmt,Tests) when is_atom(Group) ->
+ skip_groups(Node,Dir,Suite,[Group],Cases,Cmt,Tests);
+skip_groups(Node,Dir,Suite,Groups,Case,Cmt,Tests) when is_atom(Case),
+ Case =/= all ->
+ skip_groups(Node,Dir,Suite,Groups,[Case],Cmt,Tests);
skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests) when
((Cases == all) or is_list(Cases)) and is_list(Groups) ->
Suites =
@@ -1001,22 +1041,34 @@ valid_terms() ->
{cover,3},
{config,2},
{config,3},
- {userconfig, 2},
- {userconfig, 3},
+ {userconfig,2},
+ {userconfig,3},
{alias,3},
{logdir,2},
{logdir,3},
+ {label,2},
+ {label,3},
{event_handler,2},
{event_handler,3},
{event_handler,4},
+ {multiply_timetraps,2},
+ {multiply_timetraps,3},
+ {scale_timetraps,2},
+ {scale_timetraps,3},
{include,2},
{include,3},
{suites,3},
{suites,4},
+ {groups,4},
+ {groups,5},
+ {groups,6},
{cases,4},
{cases,5},
{skip_suites,4},
{skip_suites,5},
+ {skip_groups,5},
+ {skip_groups,6},
+ {skip_groups,7},
{skip_cases,5},
{skip_cases,6}
].
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index eddaf4c8b9..0a434666fa 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -619,7 +619,6 @@ get_testdir(Dir, Suite) when is_list(Suite) ->
get_testdir(Dir, _) ->
get_testdir(Dir, all).
-
%%%-----------------------------------------------------------------
%%% @spec
%%%
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 54eed29415..ee973f6220 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -30,6 +30,7 @@
-record(testspec, {spec_dir,
nodes=[],
init=[],
+ label=[],
logdir=["."],
cover=[],
config=[],
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 97ded5eb9a..3fb0d627a0 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -32,6 +32,7 @@ MODULES= \
ct_event_handler_SUITE \
ct_groups_test_1_SUITE \
ct_groups_test_2_SUITE \
+ ct_testspec_1_SUITE \
ct_skip_SUITE \
ct_error_SUITE \
ct_test_server_if_1_SUITE \
diff --git a/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl b/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
index c6d50443d0..c69400e938 100644
--- a/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
+++ b/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
@@ -99,6 +99,7 @@ init_per_group(Group, Config) ->
{Grs,_} = grs_and_tcs(),
case lists:member(Group, Grs) of
true ->
+ ct:comment(Group),
init = ?config(suite,Config),
[{Group,Group} | Config];
false ->
@@ -109,6 +110,7 @@ end_per_group(Group, Config) ->
{Grs,_} = grs_and_tcs(),
case lists:member(Group, Grs) of
true ->
+ ct:comment(Group),
init = ?config(suite,Config),
Group = ?config(Group,Config),
ok;
diff --git a/lib/common_test/test/ct_groups_test_2_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE.erl
index 56e0ac30c7..c4371501b3 100644
--- a/lib/common_test/test/ct_groups_test_2_SUITE.erl
+++ b/lib/common_test/test/ct_groups_test_2_SUITE.erl
@@ -60,7 +60,7 @@ all(doc) ->
["Run smoke tests of Common Test."];
all(suite) ->
- [missing_conf, testspec_1, repeat_1].
+ [missing_conf, repeat_1].
%%--------------------------------------------------------------------
%% TEST CASES
@@ -88,25 +88,6 @@ missing_conf(Config) when is_list(Config) ->
%%%-----------------------------------------------------------------
%%%
-testspec_1(Config) when is_list(Config) ->
- DataDir = ?config(data_dir, Config),
-
- TestSpec = filename:join(DataDir, "specs/groups_2.1.spec"),
-
- {Opts,ERPid} = setup({spec,TestSpec}, Config),
- ok = ct_test_support:run(Opts, Config),
- Events = ct_test_support:get_events(ERPid, Config),
-
- ct_test_support:log_events(testspec_1,
- reformat(Events, ?eh),
- ?config(priv_dir, Config)),
-
- TestEvents = events_to_check(testspec_1),
- ok = ct_test_support:verify_events(TestEvents, Events, Config).
-
-%%%-----------------------------------------------------------------
-%%%
-
repeat_1(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -173,9 +154,6 @@ test_events(missing_conf) ->
{?eh,stop_logging,[]}
];
-test_events(testspec_1) ->
- [];
-
test_events(repeat_1) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
diff --git a/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec b/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec
deleted file mode 100644
index 24d778ac44..0000000000
--- a/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec
+++ /dev/null
@@ -1,26 +0,0 @@
-
-{config, "../cfgs/groups_2.1.cfg"}.
-{alias, groups_2, "../groups_2"}.
-
-{suites, groups_2, groups_21_SUITE}.
-%{skip_groups, groups_2, groups_21_SUITE,
-% [test_group_1b, test_group_7], "Skip tg_1b & tg_7"}.
-{skip_cases, groups_2, groups_21_SUITE,
- [testcase_1b, testcase_3a], "Skip tc_1b & tc_3a"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_1a}.
-{skip_cases, groups_2, groups_22_SUITE,
- testcase_1a, "Skip tc_1a"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_1b}.
-{skip_cases, groups_2, groups_22_SUITE,
- testcase_1b, "Skip tc_1b"}.
-%{skip_groups, groups_2, groups_21_SUITE,
-% [test_group_3], "Skip tg_3"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_5}.
-{skip_cases, groups_2, groups_22_SUITE,
- [testcase_7a, testcase_7b], "Skip tc_7a & tc_7b"}.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 6a75c8f789..7bfb9ffb49 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -23,7 +23,7 @@
%%%
-module(ct_test_support).
--include("test_server.hrl").
+-include_lib("test_server/include/test_server.hrl").
-include_lib("common_test/include/ct_event.hrl").
-export([init_per_suite/1, init_per_suite/2, end_per_suite/1,
@@ -111,8 +111,9 @@ init_per_testcase(_TestCase, Config) ->
case lists:keysearch(master, 1, Config) of
false->
test_server:format("See Common Test logs here:\n\n"
- "<a href=\"file://~s/all_runs.html\">~s/all_runs.html</a>",
- [LogDir,LogDir]);
+ "<a href=\"file://~s/all_runs.html\">~s/all_runs.html</a>\n"
+ "<a href=\"file://~s/index.html\">~s/index.html</a>",
+ [LogDir,LogDir,LogDir,LogDir]);
{value, _}->
test_server:format("See CT Master Test logs here:\n\n"
"<a href=\"file://~s/master_runs.html\">~s/master_runs.html</a>",
diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl
new file mode 100644
index 0000000000..dc399bfb4c
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE.erl
@@ -0,0 +1,433 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_testspec_1_SUITE
+%%%
+%%% Description:
+%%% Test test specifications
+%%%
+%%% The suites used for the test are located in the data directory.
+%%%-------------------------------------------------------------------
+-module(ct_testspec_1_SUITE).
+
+-compile(export_all).
+
+-include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+all(doc) ->
+ ["Run smoke tests of Common Test."];
+
+all(suite) ->
+ [all_suites, skip_all_suites,
+ suite, skip_suite,
+ all_testcases, skip_all_testcases,
+ testcase, skip_testcase,
+ all_groups, skip_all_groups,
+ group, skip_group,
+ group_all_testcases, skip_group_all_testcases,
+ group_testcase, skip_group_testcase,
+ topgroup,
+ subgroup, skip_subgroup,
+ subgroup_all_testcases, skip_subgroup_all_testcases,
+ subgroup_testcase, skip_subgroup_testcase,
+ sub_skipped_by_top,
+ testcase_in_multiple_groups].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_suites(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,"all_suites"},
+ {suites,TestDir,all}],
+
+ setup_and_execute(all_suites, TestSpec, Config).
+
+skip_all_suites(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,skip_all_suites},
+ {suites,TestDir,all},
+ {skip_suites,TestDir,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_suites, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+suite(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,undefined},
+ {suites,TestDir,simple_1_SUITE}],
+
+ setup_and_execute(suite, TestSpec, Config).
+
+skip_suite(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{suites,TestDir,[simple_1_SUITE,simple_2_SUITE]},
+ {skip_suites,TestDir,simple_1_SUITE,"SKIPPED!"}],
+
+ setup_and_execute(skip_suite, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,all}],
+
+ setup_and_execute(all_testcases, TestSpec, Config).
+
+skip_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{suites,TestDir,[simple_1_SUITE]},
+ {skip_cases,TestDir,simple_1_SUITE,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,tc1}],
+
+ setup_and_execute(testcase, TestSpec, Config).
+
+skip_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,[tc1,tc2]},
+ {cases,TestDir,simple_2_SUITE,[tc2,tc1]},
+ {skip_cases,TestDir,simple_1_SUITE,[tc1],"SKIPPED!"},
+ {skip_cases,TestDir,simple_2_SUITE,tc2,"SKIPPED!"}],
+
+ setup_and_execute(skip_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,all}],
+
+ setup_and_execute(all_groups, TestSpec, Config).
+
+skip_all_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,all},
+ {skip_groups,TestDir,groups_11_SUITE,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_groups, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a}],
+
+ setup_and_execute(group, TestSpec, Config).
+
+skip_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[test_group_1a,
+ test_group_1b]},
+ {skip_groups,TestDir,groups_11_SUITE,
+ [test_group_1b,test_group_2,test_group_7],"SKIPPED!"}],
+
+ setup_and_execute(skip_group, TestSpec, Config).
+
+
+%%%-----------------------------------------------------------------
+%%%
+
+group_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,{cases,all}}],
+
+ setup_and_execute(group_all_testcases, TestSpec, Config).
+
+skip_group_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[test_group_1a,
+ test_group_1b]},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1b,{cases,all},"SKIPPED!"},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1a,{cases,all},"SKIPPED!"}],
+
+ setup_and_execute(skip_group_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+group_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,{cases,testcase_1a}}],
+
+ setup_and_execute(group_testcase, TestSpec, Config).
+
+skip_group_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,
+ {cases,[testcase_1a,testcase_1b]}},
+ {groups,TestDir,groups_11_SUITE,test_group_1b,
+ {cases,[testcase_1b,testcase_1a]}},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1a,{cases,testcase_1b},"SKIPPED!"},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1b,{cases,[testcase_1a]},"SKIPPED!"}],
+
+ setup_and_execute(skip_group_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+topgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_2},
+ {groups,TestDir,groups_12_SUITE,test_group_4}],
+
+ setup_and_execute(topgroup, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_3}],
+
+ setup_and_execute(subgroup, TestSpec, Config).
+
+skip_subgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,[test_group_4]},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_8,"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,
+ test_group_5,{cases,all}},
+ {groups,TestDir,groups_12_SUITE,
+ test_group_3,{cases,all}}],
+
+ setup_and_execute(subgroup_all_testcases, TestSpec, Config).
+
+skip_subgroup_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_4},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_5,{cases,all},"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,
+ test_group_7,{cases,testcase_7a}},
+ {groups,TestDir,groups_12_SUITE,
+ test_group_3,{cases,testcase_3b}}],
+
+ setup_and_execute(subgroup_testcase, TestSpec, Config).
+
+skip_subgroup_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_5},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_7,{cases,[testcase_7a,testcase_7b]},"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+%%!
+%%! Somewhat weird result from this one:
+%%!
+sub_skipped_by_top(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_5},
+ {skip_groups,TestDir,groups_12_SUITE,test_group_4,"SKIPPED!"}],
+
+ setup_and_execute(sub_skipped_by_top, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+testcase_in_multiple_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{cases,TestDir,groups_12_SUITE,[testcase_1a,testcase_1b]},
+ {skip_cases,TestDir,groups_12_SUITE,[testcase_1b],"SKIPPED!"}],
+
+ setup_and_execute(testcase_in_multiple_groups, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup_and_execute(TCName, TestSpec, Config) ->
+ SpecFile = create_spec_file(?config(priv_dir, Config),
+ TCName, TestSpec),
+ TestTerms =
+ case lists:keymember(label, 1, TestSpec) of
+ true -> [{spec,SpecFile}];
+ false -> [{spec,SpecFile},{label,TCName}]
+ end,
+ {Opts,ERPid} = setup(TestTerms, Config),
+ ok = ct_test_support:run(Opts, Config),
+ TestSpec1 = [{logdir,proplists:get_value(logdir,Opts)},
+ {label,proplists:get_value(label,TestTerms)} | TestSpec],
+ ok = ct_test_support:run(ct, run_testspec, [TestSpec1], Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(TCName,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config)),
+
+ TestEvents = events_to_check(TCName),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config).
+
+create_spec_file(SpecDir, TCName, TestSpec) ->
+ FileName = filename:join(SpecDir,
+ atom_to_list(TCName)++".spec"),
+ {ok,Dev} = file:open(FileName, [write]),
+ [io:format(Dev, "~p.~n", [Term]) || Term <- TestSpec],
+ file:close(Dev),
+ io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n",
+ [FileName,FileName]),
+ FileName.
+
+setup(Test, Config) when is_tuple(Test) ->
+ setup([Test], Config);
+setup(Tests, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ Tests ++ [{event_handler,{?eh,EvHArgs}}],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+%reformat(Events, _EH) ->
+% Events.
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(_) ->
+ [
+ ].
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
new file mode 100644
index 0000000000..4f11d8a0e8
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
@@ -0,0 +1,281 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_11_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [testcase_1a,testcase_1b]},
+
+ {test_group_1b, [], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [], [testcase_2a,
+
+ {test_group_3, [], [testcase_3a,
+ testcase_3b]},
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+ {test_group_6, [{group, test_group_7}]},
+
+ {test_group_7, [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [testcase_1,
+ {group, test_group_1a},
+ {group, test_group_1b},
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1,
+ testcase_1a, testcase_1b,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ [{name,Group}] = ?config(tc_group_properties,Config),
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(Group),
+ init = ?config(suite,Config),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(Group),
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl
new file mode 100644
index 0000000000..69c06f9b83
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl
@@ -0,0 +1,344 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_12_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]},
+
+ {test_group_1b, [parallel], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [parallel], [testcase_2a,
+
+ {test_group_3, [{repeat,2}],
+ [testcase_3a, testcase_3b]},
+
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [parallel], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [parallel], [{group, test_group_7},
+ {group, test_group_8}]},
+
+ {test_group_7, [sequence], [testcase_7a,testcase_7b]},
+
+ {test_group_8, [shuffle,sequence], [testcase_8a,testcase_8b]}
+ ].
+
+all() ->
+ [{group, test_group_1a},
+ {group, test_group_1b},
+ testcase_1,
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7,
+ test_group_8
+ ],
+ [
+ testcase_1a, testcase_1b, testcase_1c,
+ testcase_1,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b,
+ testcase_8a, testcase_8b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ Cmt =
+ case {Group,?config(tc_group_properties,Config)} of
+ {test_group_1a,[{shuffle,S},{name,test_group_1a}]} ->
+ io_lib:format("shuffled, ~w", [S]);
+ {test_group_1b,[{name,test_group_1b},parallel]} -> "parallel";
+ {test_group_2,[{name,test_group_2},parallel]} -> "parallel";
+ {test_group_3,[{name,test_group_3},{repeat,2}]} -> "repeat 2";
+ {test_group_3,[{name,test_group_3}]} -> "repeat 1";
+ {test_group_4,[{name,test_group_4}]} -> ok;
+ {test_group_5,[{name,test_group_5},parallel]} -> "parallel";
+ {test_group_6,[{name,test_group_6},parallel]} -> "parallel";
+ {test_group_7,[{name,test_group_7},sequence]} -> "sequence";
+ {test_group_8,[{shuffle,_},{name,test_group_8},sequence]} ->
+ "shuffle & sequence"
+ end,
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ ct:comment(io_lib:format("~w, ~s", [Group,Cmt])),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_1c() ->
+ [].
+testcase_1c(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1b,Config),
+ testcase_1c = ?config(testcase_1c,Config),
+ ok.
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ %% increase chance the done event will come
+ %% during execution of subgroup (could be
+ %% tricky to handle)
+ timer:sleep(3),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
+
+testcase_8a() ->
+ [].
+testcase_8a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_8 = ?config(test_group_8,Config),
+ testcase_8a = ?config(testcase_8a,Config),
+ ok.
+testcase_8b() ->
+ [].
+testcase_8b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_8 = ?config(test_group_8,Config),
+ undefined = ?config(testcase_8a,Config),
+ testcase_8b = ?config(testcase_8b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl
new file mode 100644
index 0000000000..2533ac8e84
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl
@@ -0,0 +1,281 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_21_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [testcase_1a,testcase_1b]},
+
+ {test_group_1b, [], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [], [testcase_2a,
+
+ {test_group_3, [], [testcase_3a,
+ testcase_3b]},
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [{group, test_group_7}]},
+
+ {test_group_7, [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [testcase_1,
+ {group, test_group_1a},
+ {group, test_group_1b},
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1,
+ testcase_1a, testcase_1b,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ [{name,Group}] = ?config(tc_group_properties,Config),
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(io_lib:format("~w", [Group])),
+ init = ?config(suite,Config),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl
new file mode 100644
index 0000000000..cd517876df
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl
@@ -0,0 +1,314 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_22_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]},
+
+ {test_group_1b, [parallel], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [parallel], [testcase_2a,
+
+ {test_group_3, [{repeat,1}],
+ [testcase_3a, testcase_3b]},
+
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [parallel], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [parallel], [{group, test_group_7}]},
+
+ {test_group_7, [sequence], [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [{group, test_group_1a},
+ {group, test_group_1b},
+ testcase_1,
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1a, testcase_1b, testcase_1c,
+ testcase_1,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ Cmt =
+ case {Group,?config(tc_group_properties,Config)} of
+ {test_group_1a,[{shuffle,S},{name,test_group_1a}]} ->
+ io_lib:format("shuffled, ~w", [S]);
+ {test_group_1b,[{name,test_group_1b},parallel]} -> "parallel";
+ {test_group_2,[{name,test_group_2},parallel]} -> "parallel";
+ {test_group_3,[{name,test_group_3},{repeat,1}]} -> "repeat 1";
+ {test_group_3,[{name,test_group_3}]} -> "repeat 0";
+ {test_group_4,[{name,test_group_4}]} -> ok;
+ {test_group_5,[{name,test_group_5},parallel]} -> "parallel";
+ {test_group_6,[{name,test_group_6},parallel]} -> "parallel";
+ {test_group_7,[{name,test_group_7},sequence]} -> "sequence"
+ end,
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ ct:comment(io_lib:format("~w, ~s", [Group,Cmt])),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_1c() ->
+ [].
+testcase_1c(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1b,Config),
+ testcase_1c = ?config(testcase_1c,Config),
+ ok.
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ %% increase chance the done event will come
+ %% during execution of subgroup (could be
+ %% tricky to handle)
+ timer:sleep(3),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl
new file mode 100644
index 0000000000..b789851134
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl
@@ -0,0 +1,146 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(simple_1_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Function: suite() -> Info
+%%
+%% Info = [tuple()]
+%% List of key/value pairs.
+%%
+%% Description: Returns list of tuples to set default properties
+%% for the suite.
+%%
+%% Note: The suite/0 function is only meant to be used to return
+%% default data values, not perform any other operations.
+%%--------------------------------------------------------------------
+suite() ->
+ [
+ {timetrap,{seconds,10}}
+ ].
+
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the suite.
+%%
+%% Description: Initialization before the suite.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ [{ips,ips_data} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after the suite.
+%%--------------------------------------------------------------------
+end_per_suite(Config) ->
+ ips_data = ?config(ips, Config).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is about to run.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the test case.
+%%
+%% Description: Initialization before each test case.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_testcase(TestCase, Config) ->
+ [{TestCase,{TestCase,data}} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is finished.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after each test case.
+%%--------------------------------------------------------------------
+end_per_testcase(TestCase, Config) ->
+ {TestCase,data} = ?config(TestCase, Config).
+
+%%--------------------------------------------------------------------
+%% Function: all() -> TestCases | {skip,Reason}
+%%
+%% TestCases = [TestCase | {sequence,SeqName}]
+%% TestCase = atom()
+%% Name of a test case.
+%% SeqName = atom()
+%% Name of a test case sequence.
+%% Reason = term()
+%% The reason for skipping all test cases.
+%%
+%% Description: Returns the list of test cases that are to be executed.
+%%--------------------------------------------------------------------
+all() ->
+ [tc1,
+ tc2].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+tc1() ->
+ [{userdata,{info, "This is a testcase"}}].
+
+tc1(Config) ->
+ ips_data = ?config(ips, Config),
+ {tc1,data} = ?config(tc1, Config),
+ ok.
+
+tc2() ->
+ [{timetrap,5000}].
+
+tc2(Config) ->
+ ips_data = ?config(ips, Config),
+ undefined = ?config(tc1, Config),
+ {tc2,data} = ?config(tc2, Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl
new file mode 100644
index 0000000000..eb7e9cdf7b
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl
@@ -0,0 +1,146 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(simple_2_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Function: suite() -> Info
+%%
+%% Info = [tuple()]
+%% List of key/value pairs.
+%%
+%% Description: Returns list of tuples to set default properties
+%% for the suite.
+%%
+%% Note: The suite/0 function is only meant to be used to return
+%% default data values, not perform any other operations.
+%%--------------------------------------------------------------------
+suite() ->
+ [
+ {timetrap,{seconds,10}}
+ ].
+
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the suite.
+%%
+%% Description: Initialization before the suite.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ [{ips,ips_data} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after the suite.
+%%--------------------------------------------------------------------
+end_per_suite(Config) ->
+ ips_data = ?config(ips, Config).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is about to run.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the test case.
+%%
+%% Description: Initialization before each test case.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_testcase(TestCase, Config) ->
+ [{TestCase,{TestCase,data}} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is finished.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after each test case.
+%%--------------------------------------------------------------------
+end_per_testcase(TestCase, Config) ->
+ {TestCase,data} = ?config(TestCase, Config).
+
+%%--------------------------------------------------------------------
+%% Function: all() -> TestCases | {skip,Reason}
+%%
+%% TestCases = [TestCase | {sequence,SeqName}]
+%% TestCase = atom()
+%% Name of a test case.
+%% SeqName = atom()
+%% Name of a test case sequence.
+%% Reason = term()
+%% The reason for skipping all test cases.
+%%
+%% Description: Returns the list of test cases that are to be executed.
+%%--------------------------------------------------------------------
+all() ->
+ [tc1,
+ tc2].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+tc1() ->
+ [{userdata,{info, "This is a testcase"}}].
+
+tc1(Config) ->
+ ips_data = ?config(ips, Config),
+ {tc1,data} = ?config(tc1, Config),
+ ok.
+
+tc2() ->
+ [{timetrap,5000}].
+
+tc2(Config) ->
+ ips_data = ?config(ips, Config),
+ undefined = ?config(tc1, Config),
+ {tc2,data} = ?config(tc2, Config),
+ ok.
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 2947c6a152..413ef21df3 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1,3 +1,3 @@
-COMMON_TEST_VSN = 1.5
+COMMON_TEST_VSN = 1.5.1
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 4ffe8bc606..a1f994dfbd 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -33,7 +33,7 @@
exports = [] :: [{label(), arity(), label()}],
locals = [] :: [{label(), arity(), label()}],
imports = gb_trees:empty() :: gb_tree(), %{{M,F,A},Index}
- strings = [] :: [string()], %String pool
+ strings = <<>> :: binary(), %String pool
lambdas = [], %[{...}]
literals = dict:new() :: dict(), %Format: {Literal,Number}
next_atom = 1 :: pos_integer(),
@@ -119,10 +119,11 @@ import(Mod0, Name0, Arity, #asm{imports=Imp0,next_import=NextIndex}=D0)
string(Str, Dict) when is_list(Str) ->
#asm{strings=Strings,string_offset=NextOffset} = Dict,
- case old_string(Str, Strings) of
+ StrBin = list_to_binary(Str),
+ case old_string(StrBin, Strings) of
none ->
- NewDict = Dict#asm{strings=Strings++Str,
- string_offset=NextOffset+length(Str)},
+ NewDict = Dict#asm{strings = <<Strings/binary,StrBin/binary>>,
+ string_offset=NextOffset+byte_size(StrBin)},
{NextOffset,NewDict};
Offset when is_integer(Offset) ->
{NextOffset-Offset,Dict}
@@ -187,7 +188,7 @@ import_table(#asm{imports=Imp,next_import=NumImports}) ->
ImpTab = [MFA || {MFA,_} <- Sorted],
{NumImports,ImpTab}.
--spec string_table(bdict()) -> {non_neg_integer(), [string()]}.
+-spec string_table(bdict()) -> {non_neg_integer(), binary()}.
string_table(#asm{strings=Strings,string_offset=Size}) ->
{Size,Strings}.
@@ -217,15 +218,12 @@ literal_table(#asm{literals=Tab,next_literal=NumLiterals}) ->
my_term_to_binary(Term) ->
term_to_binary(Term, [{minor_version,1}]).
-%% Search for string Str in the string pool Pool.
+%% Search for binary string Str in the binary string pool Pool.
%% old_string(Str, Pool) -> none | Index
--spec old_string(string(), [string()]) -> 'none' | pos_integer().
-
-old_string([C|Str]=Str0, [C|Pool]) ->
- case lists:prefix(Str, Pool) of
- true -> length(Pool)+1;
- false -> old_string(Str0, Pool)
- end;
-old_string([_|_]=Str, [_|Pool]) ->
- old_string(Str, Pool);
-old_string([_|_], []) -> none.
+-spec old_string(binary(), binary()) -> 'none' | pos_integer().
+
+old_string(Str, Pool) ->
+ case binary:match(Pool, Str) of
+ nomatch -> none;
+ {Start,_Length} -> byte_size(Pool) - Start
+ end.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 4642fb68b3..26da3ecad2 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -41,8 +41,7 @@
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
--type line() :: integer().
--type err_info() :: {line(), module(), term()}. %% ErrorDescriptor
+-type err_info() :: {erl_scan:line(), module(), term()}. %% ErrorDescriptor
-type errors() :: [{file:filename(), [err_info()]}].
-type warnings() :: [{file:filename(), [err_info()]}].
-type mod_ret() :: {'ok', module()}
@@ -70,7 +69,7 @@
file(File) -> file(File, ?DEFAULT_OPTIONS).
--spec file(module() | file:filename(), [option()]) -> comp_ret().
+-spec file(module() | file:filename(), [option()] | option()) -> comp_ret().
file(File, Opts) when is_list(Opts) ->
do_compile({file,File}, Opts++env_default_opts());
@@ -88,6 +87,8 @@ forms(Forms, Opt) when is_atom(Opt) ->
%% would have generated a Beam file, false otherwise (if only a binary or a
%% listing file would have been generated).
+-spec output_generated([option()]) -> boolean().
+
output_generated(Opts) ->
noenv_output_generated(Opts++env_default_opts()).
@@ -96,6 +97,8 @@ output_generated(Opts) ->
%% for default options.
%%
+-spec noenv_file(module() | file:filename(), [option()] | option()) -> comp_ret().
+
noenv_file(File, Opts) when is_list(Opts) ->
do_compile({file,File}, Opts);
noenv_file(File, Opt) ->
@@ -106,6 +109,8 @@ noenv_forms(Forms, Opts) when is_list(Opts) ->
noenv_forms(Forms, Opt) when is_atom(Opt) ->
noenv_forms(Forms, [Opt|?DEFAULT_OPTIONS]).
+-spec noenv_output_generated([option()]) -> boolean().
+
noenv_output_generated(Opts) ->
any(fun ({save_binary,_F}) -> true;
(_Other) -> false
@@ -216,16 +221,16 @@ format_error({module_name,Mod,Filename}) ->
[Mod,Filename]).
%% The compile state record.
--record(compile, {filename="",
- dir="",
- base="",
- ifile="",
- ofile="",
+-record(compile, {filename="" :: file:filename(),
+ dir="" :: file:filename(),
+ base="" :: file:filename(),
+ ifile="" :: file:filename(),
+ ofile="" :: file:filename(),
module=[],
code=[],
core_code=[],
abstract_code=[], %Abstract code for debugger.
- options=[],
+ options=[] :: [option()],
errors=[],
warnings=[]}).
@@ -362,7 +367,7 @@ mpf(Ms) ->
[{File,[M || {F,M} <- Ms, F =:= File]} ||
File <- lists:usort([F || {F,_} <- Ms])].
-%% passes(form|file, [Option]) -> [{Name,PassFun}]
+%% passes(forms|file, [Option]) -> [{Name,PassFun}]
%% Figure out which passes that need to be run.
passes(forms, Opts) ->
@@ -819,6 +824,10 @@ foldl_transform(St, [T|Ts]) ->
{'EXIT',R} ->
Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}};
+ {warning, Forms, Ws} ->
+ foldl_transform(
+ St#compile{code=Forms,
+ warnings=St#compile.warnings ++ Ws}, Ts);
Forms ->
foldl_transform(St#compile{code=Forms}, Ts)
end;
@@ -828,7 +837,6 @@ get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
core_transforms(St) ->
%% The options field holds the complete list of options at this
-
Ts = get_core_transforms(St#compile.options),
foldl_core_transforms(St, Ts).
@@ -1172,12 +1180,12 @@ write_binary(Name, Bin, St) ->
%% report_errors(State) -> ok
%% report_warnings(State) -> ok
-report_errors(St) ->
- case member(report_errors, St#compile.options) of
+report_errors(#compile{options=Opts,errors=Errors}) ->
+ case member(report_errors, Opts) of
true ->
foreach(fun ({{F,_L},Eds}) -> list_errors(F, Eds);
({F,Eds}) -> list_errors(F, Eds) end,
- St#compile.errors);
+ Errors);
false -> ok
end.
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index d4843c9eba..9c06740816 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -46,7 +46,7 @@ all(suite) ->
trycatch_4, opt_crash,
otp_5404,otp_5436,otp_5481,otp_5553,otp_5632,
otp_5714,otp_5872,otp_6121,otp_6121a,otp_6121b,
- otp_7202,otp_7345,on_load
+ otp_7202,otp_7345,on_load,string_table
].
-define(comp(N),
@@ -596,4 +596,15 @@ otp_7345(ObjRef, _RdEnv, Args) ->
10},
id(LlUnitdataReq).
+%% Check the generation of the string table.
+
+string_table(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line File = filename:join(DataDir, "string_table.erl"),
+ ?line {ok,string_table,Beam,[]} = compile:file(File, [return, binary]),
+ ?line {ok,{string_table,[StringTableChunk]}} = beam_lib:chunks(Beam, ["StrT"]),
+ ?line {"StrT", <<"stringabletringtable">>} = StringTableChunk,
+ ok.
+
+
id(I) -> I.
diff --git a/lib/compiler/test/compilation_SUITE_data/string_table.erl b/lib/compiler/test/compilation_SUITE_data/string_table.erl
new file mode 100644
index 0000000000..1da1d015dd
--- /dev/null
+++ b/lib/compiler/test/compilation_SUITE_data/string_table.erl
@@ -0,0 +1,8 @@
+-module(string_table).
+-export([f/1, g/1]).
+
+f(<<"string">>) -> string;
+f(<<"stringtable">>) -> stringtable.
+
+g(<<"stringtable">>) -> stringtable;
+g(<<"table">>) -> table.
diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk
index 9f326b39b6..9c00a17100 100644
--- a/lib/cosEvent/vsn.mk
+++ b/lib/cosEvent/vsn.mk
@@ -1,15 +1 @@
-
COSEVENT_VSN = 2.1.9
-
-TICKETS = OTP-8543
-
-TICKETS_2.1.8 = OTP-8355 \
- OTP-8409
-
-TICKETS_2.1.7 = OTP-8201
-
-TICKETS_2.1.6 = OTP-7987
-
-TICKETS_2.1.5 = OTP-7837
-
-TICKETS_2.1.4 = OTP-7595
diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk
index dceee34181..bd21133fe5 100644
--- a/lib/cosEventDomain/vsn.mk
+++ b/lib/cosEventDomain/vsn.mk
@@ -1,15 +1 @@
-
COSEVENTDOMAIN_VSN = 1.1.9
-
-TICKETS = OTP-8543
-
-TICKETS_1.1.8 = OTP-8353 \
- OTP-8355
-
-TICKETS_1.1.7 = OTP-8201
-
-TICKETS_1.1.6 = OTP-7987
-
-TICKETS_1.1.5 = OTP-7837
-
-TICKETS_1.1.4 = OTP-7595
diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk
index 2700ecb3e3..ef8ee53c5e 100644
--- a/lib/cosFileTransfer/vsn.mk
+++ b/lib/cosFileTransfer/vsn.mk
@@ -1,16 +1 @@
COSFILETRANSFER_VSN = 1.1.10
-
-TICKETS = \
- OTP-8355 \
- OTP-8374
-
-
-TICKETS_1.1.9 = OTP-8201
-
-TICKETS_1.1.8 = OTP-7987
-
-TICKETS_1.1.7 = OTP-7837
-
-TICKETS_1.1.6 = \
- OTP-7595 \
- OTP-7599 \ No newline at end of file
diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk
index a19facffd5..c03f0ef161 100644
--- a/lib/cosNotification/vsn.mk
+++ b/lib/cosNotification/vsn.mk
@@ -1,18 +1 @@
COSNOTIFICATION_VSN = 1.1.14
-
-TICKETS = OTP-8489 \
- OTP-8543
-
-TICKETS_1.1.13 = OTP-8353 \
- OTP-8354 \
- OTP-8355
-
-TICKETS_1.1.12 = OTP-8201
-
-TICKETS_1.1.11 = OTP-7987
-
-TICKETS_1.1.10 = OTP-7837
-
-TICKETS_1.1.9 = OTP-7595
-
-TICKETS_1.1.8 = OTP-7553
diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk
index 3d594a8329..ca9a7ca77e 100644
--- a/lib/cosProperty/vsn.mk
+++ b/lib/cosProperty/vsn.mk
@@ -1,13 +1 @@
COSPROPERTY_VSN = 1.1.12
-
-TICKETS = OTP-8543
-
-TICKETS_1.1.11 = OTP-8355
-
-TICKETS_1.1.10 = OTP-8201
-
-TICKETS_1.1.9 = OTP-7987
-
-TICKETS_1.1.8 = OTP-7837
-
-TICKETS_1.1.7 = OTP-7595
diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk
index 9d8057e8db..429613fb61 100644
--- a/lib/cosTime/vsn.mk
+++ b/lib/cosTime/vsn.mk
@@ -1,13 +1 @@
COSTIME_VSN = 1.1.9
-
-TICKETS = OTP-8543
-
-TICKETS_1.1.8 = OTP-8355
-
-TICKETS_1.1.7 = OTP-8201
-
-TICKETS_1.1.6 = OTP-7987
-
-TICKETS_1.1.5 = OTP-7837
-
-TICKETS_1.1.4 = OTP-7595
diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk
index 34775be7e4..82e46f51dd 100644
--- a/lib/cosTransactions/vsn.mk
+++ b/lib/cosTransactions/vsn.mk
@@ -1,14 +1 @@
COSTRANSACTIONS_VSN = 1.2.10
-
-TICKETS = OTP-8489 \
- OTP-8543
-
-TICKETS_1.2.9 = OTP-8355
-
-TICKETS_1.2.8 = OTP-8201
-
-TICKETS_1.2.7 = OTP-7987
-
-TICKETS_1.2.6 = OTP-7837
-
-TICKETS_1.2.5 = OTP-7595
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 68079f06c7..8823bba3b6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -950,7 +950,7 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
RC4(rc4_key, data.size, data.data,
enif_make_new_binary(env, data.size, &new_data));
- return enif_make_tuple2(env,argv[0],new_data);
+ return enif_make_tuple2(env,new_state,new_data);
}
static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 39512d27e1..19fa495b7d 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -195,8 +195,8 @@ sha_final(_Context) -> ?nif_stub.
%%
%% MD5_MAC
%%
--spec md5_mac(iodata(), iodata()) -> binary.
--spec md5_mac_96(iodata(), iodata()) -> binary.
+-spec md5_mac(iodata(), iodata()) -> binary().
+-spec md5_mac_96(iodata(), iodata()) -> binary().
md5_mac(Key, Data) ->
md5_mac_n(Key,Data,16).
@@ -209,8 +209,8 @@ md5_mac_n(_Key,_Data,_MacSz) -> ?nif_stub.
%%
%% SHA_MAC
%%
--spec sha_mac(iodata(), iodata()) -> binary.
--spec sha_mac_96(iodata(), iodata()) -> binary.
+-spec sha_mac(iodata(), iodata()) -> binary().
+-spec sha_mac_96(iodata(), iodata()) -> binary().
sha_mac(Key, Data) ->
sha_mac_n(Key,Data,20).
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 576949d38d..06b284d50d 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -54,6 +54,7 @@
dh/1,
exor_test/1,
rc4_test/1,
+ rc4_stream_test/1,
blowfish_cfb64/1,
smp/1,
cleanup/1]).
@@ -89,6 +90,7 @@ all(suite) ->
dh,
exor_test,
rc4_test,
+ rc4_stream_test,
mod_exp_test,
blowfish_cfb64,
smp],
@@ -979,6 +981,21 @@ rc4_test(Config) when is_list(Config) ->
CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)),
ok.
+rc4_stream_test(doc) ->
+ ["Test rc4 stream encryption ."];
+rc4_stream_test(suite) ->
+ [];
+rc4_stream_test(Config) when is_list(Config) ->
+ CT1 = <<"hej">>,
+ CT2 = <<" p� dig">>,
+ K = "apaapa",
+ State0 = crypto:rc4_set_key(K),
+ {State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
+ {_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
+ R = list_to_binary([R1, R2]),
+ <<71,112,14,44,140,33,212,144,155,47>> = R,
+ ok.
+
blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
blowfish_cfb64(suite) -> [];
blowfish_cfb64(Config) when is_list(Config) ->
@@ -1029,7 +1046,7 @@ worker_loop(0, _) ->
worker_loop(N, Config) ->
Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc,
aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test,
- rsa_verify_test, exor_test, rc4_test, mod_exp_test },
+ rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test },
F = element(random:uniform(size(Funcs)),Funcs),
%%io:format("worker ~p calling ~p\n",[self(),F]),
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 7ccb9793a3..a26b16c82d 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -94,7 +94,7 @@ break_p(Mod, Line, Le, Bs) ->
Bool = case Cond of
null -> true;
{CM, CN} ->
- try apply(CM, CN, [Bs]) of
+ try CM:CN(Bs) of
true -> true;
false -> false;
_Term -> false
@@ -245,7 +245,7 @@ handle_int_msg({attached, AttPid}, Status, _Bs,
%% Tell attached process in which module evalution is located
if
- Le==1 ->
+ Le =:= 1 ->
tell_attached({attached, undefined, -1, get(trace)});
true ->
tell_attached({attached, M, Line, get(trace)}),
@@ -269,7 +269,7 @@ handle_int_msg(detached, _Status, _Bs, _Ieval) ->
handle_int_msg({old_code,Mod}, Status, Bs,
#ieval{level=Le,module=M}=Ieval) ->
if
- Status==idle, Le==1 ->
+ Status =:= idle, Le =:= 1 ->
erase([Mod|db]),
put(cache, []);
true ->
@@ -352,9 +352,9 @@ set_stack_trace(true) ->
set_stack_trace(all);
set_stack_trace(Flag) ->
if
- Flag==false ->
+ Flag =:= false ->
put(stack, []);
- Flag==no_tail; Flag==all ->
+ Flag =:= no_tail; Flag =:= all ->
ignore
end,
put(trace_stack, Flag),
@@ -367,7 +367,7 @@ bindings(Bs, nostack) ->
Bs;
bindings(Bs, SP) ->
case dbg_ieval:stack_level() of
- Le when SP>Le ->
+ Le when SP > Le ->
Bs;
_ ->
dbg_ieval:bindings(SP)
@@ -377,7 +377,6 @@ messages() ->
{messages, Msgs} = erlang:process_info(get(self), messages),
Msgs.
-
%%====================================================================
%% Evaluating expressions within process context
%%====================================================================
@@ -398,7 +397,7 @@ eval_restricted({From,_Mod,Cmd,SP}, Bs) ->
From ! {self(), {eval_rsp, Rsp}}
end.
-eval_nonrestricted({From,Mod,Cmd,SP}, Bs, #ieval{level=Le}) when SP<Le->
+eval_nonrestricted({From,Mod,Cmd,SP}, Bs, #ieval{level=Le}) when SP < Le->
%% Evaluate in stack
eval_restricted({From, Mod, Cmd, SP}, Bs),
Bs;
@@ -424,15 +423,15 @@ eval_nonrestricted({From, _Mod, Cmd, _SP}, Bs,
eval_nonrestricted_1({match,_,{var,_,Var},Expr}, Bs, Ieval) ->
{value,Res,Bs2} =
dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{last_call=false}),
- Bs3 = case lists:keysearch(Var, 1, Bs) of
- {value, {Var,_Value}} ->
+ Bs3 = case lists:keyfind(Var, 1, Bs) of
+ {Var,_Value} ->
lists:keyreplace(Var, 1, Bs2, {Var,Res});
false -> [{Var,Res} | Bs2]
end,
{Res,Bs3};
eval_nonrestricted_1({var,_,Var}, Bs, _Ieval) ->
- Res = case lists:keysearch(Var, 1, Bs) of
- {value, {Var, Value}} -> Value;
+ Res = case lists:keyfind(Var, 1, Bs) of
+ {Var, Value} -> Value;
false -> unbound
end,
{Res,Bs};
@@ -458,7 +457,6 @@ parse_cmd(Cmd, LineNo) ->
{ok,Forms} = erl_parse:parse_exprs(Tokens),
Forms.
-
%%====================================================================
%% Library functions for attached process handling
%%====================================================================
@@ -470,13 +468,12 @@ tell_attached(Msg) ->
AttPid ! {self(), Msg}
end.
-
%%====================================================================
%% get_binding/2
%%====================================================================
get_binding(Var, Bs) ->
- case lists:keysearch(Var, 1, Bs) of
- {value, {Var, Value}} -> {value, Value};
+ case lists:keyfind(Var, 1, Bs) of
+ {Var, Value} -> {value, Value};
false -> unbound
end.
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index c13fda7ac1..476dfd8796 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -120,9 +120,9 @@ check_exit_msg({'EXIT', Int, Reason}, _Bs, #ieval{level=Le}) ->
%% This *must* be interpreter which has terminated,
%% we are not linked to anyone else
if
- Le==1 ->
+ Le =:= 1 ->
exit(Reason);
- Le>1 ->
+ Le > 1 ->
exit({Int, Reason})
end;
check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
@@ -139,9 +139,9 @@ check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
%% importance in this case
%% If we don't save them, however, post-mortem analysis
%% of the process isn't possible
- undefined when Le==1 -> % died outside interpreted code
+ undefined when Le =:= 1 -> % died outside interpreted code
{};
- undefined when Le>1 ->
+ undefined when Le > 1 ->
StackBin = term_to_binary(get(stack)),
{{Mod, Li}, Bs, StackBin};
@@ -152,9 +152,9 @@ check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
dbg_iserver:cast(get(int), {set_exit_info,self(),ExitInfo}),
if
- Le==1 ->
+ Le =:= 1 ->
exit(Reason);
- Le>1 ->
+ Le > 1 ->
exit({get(self), Reason})
end;
check_exit_msg(_Msg, _Bs, _Ieval) ->
@@ -271,7 +271,7 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
end;
%% Re-entry to Meta from non-interpreted code
- {re_entry, Debugged, {eval,{M,F,As}}} when Le==1 ->
+ {re_entry, Debugged, {eval,{M,F,As}}} when Le =:= 1 ->
%% Reset process dictionary
%% This is really only necessary if the process left
%% interpreted code at a call level > 1
@@ -346,7 +346,7 @@ push(MFA, Bs, #ieval{level=Le,module=Cm,line=Li,last_call=Lc}) ->
[] -> put(stack, [Entry]);
[_Entry|Entries] -> put(stack, [Entry|Entries])
end;
- _ -> % all | no_tail when Lc==false
+ _ -> % all | no_tail when Lc =:= false
put(stack, [Entry|get(stack)])
end.
@@ -413,10 +413,10 @@ sublist(L, Start, Length) ->
lists:sublist(L, Start, Length).
fix_stacktrace2([{_,{{M,F,As1},_,_}}, {_,{{M,F,As2},_,_}}|_])
- when length(As1)==length(As2) ->
+ when length(As1) =:= length(As2) ->
[{M,F,As1}];
fix_stacktrace2([{_,{{Fun,As1},_,_}}, {_,{{Fun,As2},_,_}}|_])
- when length(As1)==length(As2) ->
+ when length(As1) =:= length(As2) ->
[{Fun,As1}];
fix_stacktrace2([{_,{MFA,_,_}}|Entries]) ->
[MFA|fix_stacktrace2(Entries)];
@@ -465,9 +465,9 @@ stack_frame(SP, Dir, [{SP, _}|Stack]) ->
case Stack of
[{Le, {_MFA,Where,Bs}}|_] ->
{Le, Where, Bs};
- [] when Dir==up ->
+ [] when Dir =:= up ->
top;
- [] when Dir==down ->
+ [] when Dir =:= down ->
bottom
end;
stack_frame(SP, Dir, [_Entry|Stack]) ->
@@ -509,7 +509,7 @@ trace(What, Args, true) ->
end,
io_lib:format(" (~w) receive " ++ Tail, [Le]);
- received when Args==null ->
+ received when Args =:= null ->
io_lib:format("~n", []);
received -> % Args=Msg
io_lib:format("~n<== ~p~n", [Args]);
@@ -586,8 +586,8 @@ eval_mfa(Debugged, M, F, As, Ieval) ->
end.
eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
- Mod==?MODULE,
- Fun==eval_fun ->
+ Mod =:= ?MODULE,
+ Fun =:= eval_fun ->
#ieval{level=Le, line=Li, last_call=Lc} = Ieval,
case lambda(Fun, As0) of
{Cs,Module,Name,As,Bs} ->
@@ -657,7 +657,7 @@ eval_function(Mod, Name, As0, Bs0, Called, Ieval) ->
lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) ->
%% Fun defined in interpreted code, called from outside
if
- length(element(3,hd(Cs))) == length(As) ->
+ length(element(3,hd(Cs))) =:= length(As) ->
db_ref(Mod), %% Adds ref between module and process
{Cs,Mod,Name,As,Bs};
true ->
@@ -672,7 +672,7 @@ lambda(Fun, As) when is_function(Fun) ->
{env, [{Mod,Name},Bs,Cs]} = erlang:fun_info(Fun, env),
{arity, Arity} = erlang:fun_info(Fun, arity),
if
- length(As) == Arity ->
+ length(As) =:= Arity ->
db_ref(Mod), %% Adds ref between module and process
{Cs,Mod,Name,As,Bs};
true ->
@@ -731,7 +731,7 @@ db_ref(Mod) ->
ModDb ->
Node = node(get(int)),
DbRef = if
- Node/=node() -> {Node,ModDb};
+ Node =/= node() -> {Node,ModDb};
true -> ModDb
end,
put([Mod|db], DbRef),
@@ -741,13 +741,12 @@ db_ref(Mod) ->
DbRef
end.
-
cache(Key, Data) ->
put(cache, lists:sublist([{Key,Data}|get(cache)], 5)).
cached(Key) ->
- case lists:keysearch(Key, 1, get(cache)) of
- {value,{Key,Data}} -> Data;
+ case lists:keyfind(Key, 1, get(cache)) of
+ {Key,Data} -> Data;
false -> false
end.
@@ -844,7 +843,7 @@ expr({'try',Line,Es,CaseCs,CatchCs,[]}, Bs0, Ieval0) ->
case_clauses(Val, CaseCs, Bs, try_clause, Ieval)
end
catch
- Class:Reason when CatchCs=/=[] ->
+ Class:Reason when CatchCs =/= [] ->
catch_clauses({Class,Reason,[]}, CatchCs, Bs0, Ieval)
end;
expr({'try',Line,Es,CaseCs,CatchCs,As}, Bs0, Ieval0) ->
@@ -1498,10 +1497,7 @@ guard(Gs, Bs) -> or_guard(Gs, Bs).
or_guard([G|Gs], Bs) ->
%% Short-circuit OR.
- case and_guard(G, Bs) of
- true -> true;
- false -> or_guard(Gs, Bs)
- end;
+ and_guard(G, Bs) orelse or_guard(Gs, Bs);
or_guard([], _) -> false.
and_guard([G|Gs], Bs) ->
@@ -1598,8 +1594,7 @@ match1({bin,_,Fs}, B, Bs0, BBs0) when is_bitstring(B) ->
try eval_bits:match_bits(Fs, B, Bs1, BBs,
fun(L, R, Bs) -> match1(L, R, Bs, BBs) end,
fun(E, Bs) -> expr(E, Bs, #ieval{}) end,
- false) of
- Match -> Match
+ false)
catch
_:_ -> throw(nomatch)
end;
@@ -1687,7 +1682,7 @@ merge_bindings([{Name,V}|B1s], B2s, Ieval) ->
case binding(Name, B2s) of
{value,V} -> % Already there, and the same
merge_bindings(B1s, B2s, Ieval);
- {value,_} when Name=='_' -> % Already there, but anonymous
+ {value,_} when Name =:= '_' -> % Already there, but anonymous
B2s1 = lists:keydelete('_', 1, B2s),
[{Name,V}|merge_bindings(B1s, B2s1, Ieval)];
{value,_} -> % Already there, but different => badmatch
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index ec54c646c8..2ae0c333da 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -26,7 +26,7 @@
%%--------------------------------------------------------------------
%% load_mod(Mod, File, Binary, Db) -> {ok, Mod}
-%% Mod = atom()
+%% Mod = module()
%% File = string() Source file (including path)
%% Binary = binary()
%% Db = ETS identifier
@@ -408,8 +408,7 @@ expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,fault}},[_]=As}) ->
{dbg,Line,fault,expr_list(As)};
expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}) ->
{dbg,Line,exit,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},As0})
- when length(As0) == 3 ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}) ->
As = expr_list(As0),
{apply,Line,As};
expr({call,Line,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}) ->
@@ -517,15 +516,9 @@ expr(Other) ->
%% here as sys_pre_expand has transformed source.
is_guard_test({op,_,Op,L,R}) ->
- case erl_internal:comp_op(Op, 2) of
- true -> is_gexpr_list([L,R]);
- false -> false
- end;
+ erl_internal:comp_op(Op, 2) andalso is_gexpr_list([L,R]);
is_guard_test({call,_,{remote,_,{atom,_,erlang},{atom,_,Test}},As}) ->
- case erl_internal:type_test(Test, length(As)) of
- true -> is_gexpr_list(As);
- false -> false
- end;
+ erl_internal:type_test(Test, length(As)) andalso is_gexpr_list(As);
is_guard_test({atom,_,true}) -> true;
is_guard_test(_) -> false.
@@ -542,22 +535,12 @@ is_gexpr({call,_,{remote,_,{atom,_,erlang},{atom,_,F}},As}) ->
Ar = length(As),
case erl_internal:guard_bif(F, Ar) of
true -> is_gexpr_list(As);
- false ->
- case erl_internal:arith_op(F, Ar) of
- true -> is_gexpr_list(As);
- false -> false
- end
+ false -> erl_internal:arith_op(F, Ar) andalso is_gexpr_list(As)
end;
is_gexpr({op,_,Op,A}) ->
- case erl_internal:arith_op(Op, 1) of
- true -> is_gexpr(A);
- false -> false
- end;
+ erl_internal:arith_op(Op, 1) andalso is_gexpr(A);
is_gexpr({op,_,Op,A1,A2}) ->
- case erl_internal:arith_op(Op, 2) of
- true -> is_gexpr_list([A1,A2]);
- false -> false
- end;
+ erl_internal:arith_op(Op, 2) andalso is_gexpr_list([A1,A2]);
is_gexpr(_) -> false.
is_gexpr_list(Es) -> lists:all(fun (E) -> is_gexpr(E) end, Es).
diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl
index 4c1e9ccb7b..59188d83a2 100644
--- a/lib/debugger/src/dbg_iserver.erl
+++ b/lib/debugger/src/dbg_iserver.erl
@@ -155,11 +155,8 @@ handle_call(get_stack_trace, _From, State) ->
%% Retrieving information
handle_call(snapshot, _From, State) ->
- Reply = lists:map(fun(Proc) ->
- {Proc#proc.pid, Proc#proc.function,
- Proc#proc.status, Proc#proc.info}
- end,
- State#state.procs),
+ Reply = [{Proc#proc.pid, Proc#proc.function,
+ Proc#proc.status, Proc#proc.info} || Proc <- State#state.procs],
{reply, Reply, State};
handle_call({get_meta, Pid}, _From, State) ->
Reply = case get_proc({pid, Pid}, State#state.procs) of
@@ -181,21 +178,21 @@ handle_call({get_attpid, Pid}, _From, State) ->
%% Breakpoint handling
handle_call({new_break, Point, Options}, _From, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
+ case lists:keymember(Point, 1, State#state.breaks) of
false ->
Break = {Point, Options},
send_all([subscriber, meta, attached],
{new_break, Break}, State),
Breaks = keyinsert(Break, 1, State#state.breaks),
{reply, ok, State#state{breaks=Breaks}};
- {value, _Break} ->
+ true ->
{reply, {error, break_exists}, State}
end;
handle_call(all_breaks, _From, State) ->
{reply, State#state.breaks, State};
handle_call({all_breaks, Mod}, _From, State) ->
Reply = lists:filter(fun({{M,_L}, _Options}) ->
- if M==Mod -> true; true -> false end
+ M =/= Mod
end,
State#state.breaks),
{reply, Reply, State};
@@ -276,7 +273,7 @@ handle_call({contents, Mod, Pid}, _From, State) ->
Db = State#state.db,
[{{Mod, refs}, ModDbs}] = ets:lookup(Db, {Mod, refs}),
ModDb = if
- Pid==any -> hd(ModDbs);
+ Pid =:= any -> hd(ModDbs);
true ->
lists:foldl(fun(T, not_found) ->
[{T, Pids}] = ets:lookup(Db, T),
@@ -295,7 +292,7 @@ handle_call({raw_contents, Mod, Pid}, _From, State) ->
Db = State#state.db,
[{{Mod, refs}, ModDbs}] = ets:lookup(Db, {Mod, refs}),
ModDb = if
- Pid==any -> hd(ModDbs);
+ Pid =:= any -> hd(ModDbs);
true ->
lists:foldl(fun(T, not_found) ->
[{T, Pids}] = ets:lookup(Db, T),
@@ -360,15 +357,15 @@ handle_cast({set_stack_trace, Flag}, State) ->
%% Retrieving information
handle_cast(clear, State) ->
Procs = lists:filter(fun(#proc{status=Status}) ->
- if Status==exit -> false; true -> true end
+ Status =/= exit
end,
State#state.procs),
{noreply, State#state{procs=Procs}};
%% Breakpoint handling
handle_cast({delete_break, Point}, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
- {value, _Break} ->
+ case lists:keymember(Point, 1, State#state.breaks) of
+ true ->
send_all([subscriber, meta, attached],
{delete_break, Point}, State),
Breaks = lists:keydelete(Point, 1, State#state.breaks),
@@ -377,8 +374,8 @@ handle_cast({delete_break, Point}, State) ->
{noreply, State}
end;
handle_cast({break_option, Point, Option, Value}, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
- {value, {Point, Options}} ->
+ case lists:keyfind(Point, 1, State#state.breaks) of
+ {Point, Options} ->
N = case Option of
status -> 1;
action -> 2;
@@ -399,7 +396,7 @@ handle_cast(no_break, State) ->
handle_cast({no_break, Mod}, State) ->
send_all([subscriber, meta, attached], {no_break, Mod}, State),
Breaks = lists:filter(fun({{M, _L}, _O}) ->
- if M==Mod -> false; true -> true end
+ M =/= Mod
end,
State#state.breaks),
{noreply, State#state{breaks=Breaks}};
@@ -409,7 +406,7 @@ handle_cast({set_status, Meta, Status, Info}, State) ->
{true, Proc} = get_proc({meta, Meta}, State#state.procs),
send_all(subscriber, {new_status, Proc#proc.pid, Status, Info}, State),
if
- Status==break ->
+ Status =:= break ->
auto_attach(break, State#state.auto, Proc);
true -> ignore
end,
@@ -526,11 +523,10 @@ code_change(_OldVsn, State, _Extra) ->
%% Internal functions
%%====================================================================
-auto_attach(Why, Auto, Proc) when is_record(Proc, proc) ->
- case Proc#proc.attpid of
- AttPid when is_pid(AttPid) -> ignore;
- undefined ->
- auto_attach(Why, Auto, Proc#proc.pid)
+auto_attach(Why, Auto, #proc{attpid = Attpid, pid = Pid}) ->
+ case Attpid of
+ undefined -> auto_attach(Why, Auto, Pid);
+ _ when is_pid(Attpid) -> ignore
end;
auto_attach(Why, Auto, Pid) when is_pid(Pid) ->
case Auto of
@@ -545,7 +541,7 @@ auto_attach(Why, Auto, Pid) when is_pid(Pid) ->
keyinsert(Tuple1, N, [Tuple2|Tuples]) ->
if
- element(N, Tuple1)<element(N, Tuple2) ->
+ element(N, Tuple1) < element(N, Tuple2) ->
[Tuple1, Tuple2|Tuples];
true ->
[Tuple2 | keyinsert(Tuple1, N, Tuples)]
@@ -576,7 +572,7 @@ send_all([], _Msg, _State) -> ok;
send_all(subscriber, Msg, State) ->
send_all(State#state.subs, Msg);
send_all(meta, Msg, State) ->
- Metas = lists:map(fun(Proc) -> Proc#proc.meta end, State#state.procs),
+ Metas = [Proc#proc.meta || Proc <- State#state.procs],
send_all(Metas, Msg);
send_all(attached, Msg, State) ->
AttPids= mapfilter(fun(Proc) ->
@@ -600,7 +596,7 @@ get_proc({Type, Pid}, Procs) ->
meta -> #proc.meta;
attpid -> #proc.attpid
end,
- case lists:keysearch(Pid, Index, Procs) of
- {value, Proc} -> {true, Proc};
- false -> false
+ case lists:keyfind(Pid, Index, Procs) of
+ false -> false;
+ Proc -> {true, Proc}
end.
diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl
index a56fe36828..0c1e25e703 100644
--- a/lib/debugger/src/dbg_ui_break_win.erl
+++ b/lib/debugger/src/dbg_ui_break_win.erl
@@ -268,12 +268,7 @@ handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) ->
IndexL ->
Funcs = WinInfo#winInfo.funcs,
Breaks =
- lists:map(fun(Index) ->
- Func = lists:nth(Index+1,
- Funcs),
- [Mod | Func]
- end,
- IndexL),
+ [[Mod|lists:nth(Index+1, Funcs)] || Index <- IndexL],
{break, Breaks, enable}
end
end;
diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl
index f7d76076a5..79ccf20946 100644
--- a/lib/debugger/src/dbg_ui_filedialog_win.erl
+++ b/lib/debugger/src/dbg_ui_filedialog_win.erl
@@ -202,8 +202,7 @@ handle_event({gs, 'Files', doubleclick, _Data, _Arg}, WinInfo) ->
handle_event({gs, _Id, click, select, _Arg}, _WinInfo) ->
{select, gs:read('Selection', text)};
handle_event({gs, _Id, click, multiselect, _Arg}, WinInfo) ->
- Files = lists:map(fun(File) -> untag(File) end,
- gs:read('Files', items)),
+ Files = [untag(File) || File <- gs:read('Files', items)],
{multiselect, WinInfo#winInfo.cwd, Files};
handle_event({gs, _Id, click, filter, _Arg}, WinInfo) ->
{Cwd, Pattern} = update_win(gs:read('Filter', text),
@@ -286,7 +285,7 @@ max_existing([Name | Names]) ->
max_existing(Dir, [Name | Names]) ->
Dir2 = filename:join(Dir, Name),
case filelib:is_file(Dir2, erl_prim_loader) of
- true when Names==[] -> {Dir2, []};
+ true when Names =:= [] -> {Dir2, []};
true -> max_existing(Dir2, Names);
false -> {Dir, [Name | Names]}
end.
@@ -309,11 +308,8 @@ extra_filter([], _Dir, _Fun) -> [].
get_subdirs(Dir) ->
case erl_prim_loader:list_dir(Dir) of
{ok, FileNames} ->
- X = lists:filter(fun(FileName) ->
- File = filename:join(Dir, FileName),
- filelib:is_dir(File, erl_prim_loader)
- end,
- FileNames),
+ X = [FN || FN <- FileNames,
+ filelib:is_dir(filename:join(Dir, FN), erl_prim_loader)],
lists:sort(X);
_Error ->
[]
@@ -335,4 +331,3 @@ compare([], [$/|File]) ->
File;
compare(_, _) ->
error.
-
diff --git a/lib/debugger/src/dbg_ui_mon.erl b/lib/debugger/src/dbg_ui_mon.erl
index 8888075124..82fe210968 100644
--- a/lib/debugger/src/dbg_ui_mon.erl
+++ b/lib/debugger/src/dbg_ui_mon.erl
@@ -162,7 +162,7 @@ init2(CallingPid, Mode, SFile, GS) ->
CallingPid ! {initialization_complete, self()},
if
- SFile==default ->
+ SFile =:= default ->
loop(State3);
true ->
loop(load_settings(SFile, State3))
@@ -226,7 +226,7 @@ loop(State) ->
gui_cmd(stopped, State);
%% From the GUI
- GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent)==gs ->
+ GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent) =:= gs ->
Cmd = dbg_ui_mon_win:handle_event(GuiEvent,State#state.win),
State2 = gui_cmd(Cmd, State),
loop(State2);
@@ -269,7 +269,7 @@ gui_cmd(ignore, State) ->
State;
gui_cmd(stopped, State) ->
if
- State#state.starter==true -> int:stop();
+ State#state.starter =:= true -> int:stop();
true -> int:auto_attach(false)
end,
exit(stop);
@@ -413,9 +413,9 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
State2;
gui_cmd({'Auto Attach', When}, State) ->
if
- When==[] -> int:auto_attach(false);
+ When =:= [] -> int:auto_attach(false);
true ->
- Flags = lists:map(fun(Name) -> map(Name) end, When),
+ Flags = [map(Name) || Name <- When],
int:auto_attach(Flags, trace_function(State))
end,
State;
@@ -676,7 +676,7 @@ load_settings2(Settings, State) ->
Break,
int:break(Mod, Line),
if
- Status==inactive ->
+ Status =:= inactive ->
int:disable_break(Mod, Line);
true -> ignore
end,
@@ -700,12 +700,8 @@ save_settings(SFile, State) ->
int:auto_attach(),
int:stack_trace(),
State#state.backtrace,
- lists:map(fun(Mod) ->
- int:file(Mod)
- end,
- int:interpreted()),
+ [int:file(Mod) || Mod <- int:interpreted()],
int:all_breaks()},
-
Binary = term_to_binary({debugger_settings, Settings}),
case file:write_file(SFile, Binary) of
ok ->
@@ -720,13 +716,12 @@ save_settings(SFile, State) ->
%%====================================================================
registered_name(Pid) ->
-
%% Yield in order to give Pid more time to register its name
timer:sleep(200),
Node = node(Pid),
if
- Node==node() ->
+ Node =:= node() ->
case erlang:process_info(Pid, registered_name) of
{registered_name, Name} -> Name;
_ -> undefined
diff --git a/lib/debugger/src/dbg_ui_mon_win.erl b/lib/debugger/src/dbg_ui_mon_win.erl
index ba2f94c550..66e59a822a 100644
--- a/lib/debugger/src/dbg_ui_mon_win.erl
+++ b/lib/debugger/src/dbg_ui_mon_win.erl
@@ -224,8 +224,7 @@ select(MenuItem, Bool) ->
%%--------------------------------------------------------------------
add_module(WinInfo, Menu, Mod) ->
Modules = WinInfo#winInfo.modules,
- case lists:keysearch(Mod, #moduleInfo.module, Modules) of
- {value, _ModInfo} -> WinInfo;
+ case lists:keymember(Mod, #moduleInfo.module, Modules) of
false ->
%% Create a menu for the module
Font = dbg_ui_win:font(normal),
@@ -244,7 +243,8 @@ add_module(WinInfo, Menu, Mod) ->
gs:config(WinInfo#winInfo.listbox, {add, Mod}),
ModInfo = #moduleInfo{module=Mod, menubtn=MenuBtn},
- WinInfo#winInfo{modules=[ModInfo | Modules]}
+ WinInfo#winInfo{modules=[ModInfo | Modules]};
+ true -> WinInfo
end.
%%--------------------------------------------------------------------
@@ -491,14 +491,13 @@ handle_event({gs, _Id, click, autoattach, _Arg}, WinInfo) ->
%% Process grid
handle_event({gs, _Id, keypress, _Data, [Key|_]}, WinInfo) when
- Key=='Up'; Key=='Down' ->
- Dir = if Key=='Up' -> up; Key=='Down' -> down end,
+ Key =:= 'Up'; Key =:= 'Down' ->
+ Dir = if Key =:= 'Up' -> up; Key =:= 'Down' -> down end,
Row = move(WinInfo, Dir),
-
if Row>1 ->
WinInfo2 = highlight(WinInfo, Row),
- {value, #procInfo{pid=Pid}} =
- lists:keysearch(Row, #procInfo.row, WinInfo#winInfo.processes),
+ #procInfo{pid=Pid} =
+ lists:keyfind(Row, #procInfo.row, WinInfo#winInfo.processes),
{focus, Pid, WinInfo2};
true ->
ignore
@@ -515,10 +514,9 @@ handle_event(_GSEvent, _WinInfo) ->
move(WinInfo, Dir) ->
Row = WinInfo#winInfo.focus,
Last = WinInfo#winInfo.row,
-
if
- Dir==up, Row>1 -> Row-1;
- Dir==down, Row<Last -> Row+1;
+ Dir =:= up, Row > 1 -> Row-1;
+ Dir =:= down, Row < Last -> Row+1;
true -> Row
end.
@@ -533,7 +531,6 @@ highlight(WinInfo, Row) ->
GridLine2 = gs:read(Grid, {obj_at_row, Row}),
gs:config(GridLine2, {fg, white}),
WinInfo#winInfo{focus=Row}.
-
%%====================================================================
%% Internal functions
@@ -545,7 +542,7 @@ configure(WinInfo, {W, H}) ->
Dx = NewW - gs:read(Grid, width),
Dy = H-42 - gs:read(Grid, height),
if
- (Dx+Dy)=/=0 ->
+ (Dx+Dy) =/= 0 ->
gs:config(Grid, [{width, NewW}, {height, H-30}]),
Cols = calc_columnwidths(NewW),
gs:config(Grid, Cols);
@@ -555,10 +552,9 @@ configure(WinInfo, {W, H}) ->
calc_columnwidths(Width) ->
W = if
- Width=<?Wg -> ?Wg;
+ Width =< ?Wg -> ?Wg;
true -> Width
end,
- First = lists:map(fun (X) -> round(X) end,
- [0.13*W, 0.27*W, 0.18*W, 0.18*W]),
+ First = [round(X) || X <- [0.13*W, 0.27*W, 0.18*W, 0.18*W]],
Last = W - lists:sum(First) - 30,
{columnwidths, First++[Last]}.
diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl
index c6f041a63d..82d4199630 100644
--- a/lib/debugger/src/dbg_ui_trace_win.erl
+++ b/lib/debugger/src/dbg_ui_trace_win.erl
@@ -147,17 +147,17 @@ configure(WinInfo, TraceWin) ->
H = gs:read(Win, height),
H2 = if
- Bu1==close, Bu2==open ->
+ Bu1 =:= close, Bu2 =:= open ->
resize_button_area(open, width, W-4),
gs:config('ButtonArea', {height, 30}),
H+30;
- Bu1==open, Bu2==close ->
+ Bu1 =:= open, Bu2 =:= close ->
gs:config('ButtonArea', [{width, 0}, {height, 0}]),
H-30;
true -> H
end,
H3 = if
- Ev1==close, Ev2==open, Bi1==open ->
+ Ev1 =:= close, Ev2 =:= open, Bi1 =:= open ->
Wnew1 = round((W-10-4)/2), % W = window/2 - rb - pads
Hbi1 = gs:read('BindArea', height), % H = bind area h
resize_eval_area(open, width, Wnew1),
@@ -167,25 +167,25 @@ configure(WinInfo, TraceWin) ->
resize_bind_area(open, width,
Wnew1-gs:read('BindArea', width)),
H2;
- Ev1==close, Ev2==open, Bi1==close ->
+ Ev1 =:= close, Ev2 =:= open, Bi1 =:= close ->
resize_eval_area(open, width, W-4),
resize_eval_area(open, height, 200),
H2+200;
- Ev1==open, Ev2==close, Bi1==open ->
+ Ev1 =:= open, Ev2 =:= close, Bi1 =:= open ->
gs:config('EvalArea', [{width,0}, {height,0}]),
gs:config('RB3', [{width, 0}, {height, 0}]),
Wnew2 = W-4,
resize_bind_area(open, width,
Wnew2-gs:read('BindArea', width)),
H2;
- Ev1==open, Ev2==close, Bi1==close ->
+ Ev1 =:= open, Ev2 =:= close, Bi1 =:= close ->
Hs1 = gs:read('EvalArea', height),
gs:config('EvalArea', [{width, 0}, {height, 0}]),
H2-Hs1;
true -> H2
end,
H4 = if
- Bi1==close, Bi2==open, Ev2==open ->
+ Bi1 =:= close, Bi2 =:= open, Ev2 =:= open ->
Wnew3 = round((W-10-4)/2), % W = window/2 - rb - pads
Hs2 = gs:read('EvalArea', height), % H = eval area h
resize_bind_area(open, width, Wnew3),
@@ -194,29 +194,29 @@ configure(WinInfo, TraceWin) ->
resize_eval_area(open, width,
Wnew3-gs:read('EvalArea', width)),
H3;
- Bi1==close, Bi2==open, Ev2==close ->
+ Bi1 =:= close, Bi2 =:= open, Ev2 =:= close ->
resize_bind_area(open, width, W-4),
resize_bind_area(open, height, 200),
H3+200;
- Bi1==open, Bi2==close, Ev2==open ->
+ Bi1 =:= open, Bi2 =:= close, Ev2 =:= open ->
gs:config('BindArea', [{width, 0}, {height, 0}]),
gs:config('RB3', [{width, 0}, {height, 0}]),
Wnew4 = W-4,
resize_eval_area(open, width,
Wnew4-gs:read('EvalArea', width)),
H3;
- Bi1==open, Bi2==close, Ev2==close ->
+ Bi1 =:= open, Bi2 =:= close, Ev2 =:= close ->
Hbi2 = gs:read('BindArea', height),
gs:config('BindArea', [{width, 0}, {height, 0}]),
H3-Hbi2;
true -> H3
end,
H5 = if
- Tr1==close, Tr2==open ->
+ Tr1 =:= close, Tr2 =:= open ->
resize_trace_area(open, width, W-4),
resize_trace_area(open, height, 200),
H4+200;
- Tr1==open, Tr2==close ->
+ Tr1 =:= open, Tr2 =:= close ->
Hf = gs:read('TraceArea', height),
gs:config('TraceArea', [{width, 0}, {height, 0}]),
H4-Hf;
@@ -226,10 +226,10 @@ configure(WinInfo, TraceWin) ->
RB1old = rb1(OldFlags), RB1new = rb1(NewFlags),
if
- RB1old==close, RB1new==open ->
+ RB1old =:= close, RB1new =:= open ->
gs:config('RB1', [{width, W-4}, {height, 10}]),
gs:config(Win, {height, gs:read(Win, height)+10});
- RB1old==open, RB1new==close ->
+ RB1old =:= open, RB1new =:= close ->
gs:config('RB1', [{width, 0}, {height, 0}, lower]),
gs:config(Win, {height, gs:read(Win, height)-10});
true -> ignore
@@ -237,10 +237,10 @@ configure(WinInfo, TraceWin) ->
RB2old = rb2(OldFlags), RB2new = rb2(NewFlags),
if
- RB2old==close, RB2new==open ->
+ RB2old =:= close, RB2new =:= open ->
gs:config('RB2', [{width, W-4}, {height, 10}]),
gs:config(Win, {height,gs:read(Win, height)+10});
- RB2old==open, RB2new==close ->
+ RB2old =:= open, RB2new =:= close ->
gs:config('RB2', [{width, 0}, {height, 0}, lower]),
gs:config(Win, {height, gs:read(Win, height)-10});
true -> ignore
@@ -301,15 +301,15 @@ select(MenuItem, Bool) ->
%% Cond = null | {Mod, Func}
%%--------------------------------------------------------------------
add_break(WinInfo, Menu, {{Mod,Line},[Status|_Options]}=Break) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
add_break_to_code(Editor, Line, Status);
false -> ignore
end,
add_break_to_menu(WinInfo, Menu, Break).
add_break_to_code(Editor, Line, Status) ->
- Color = if Status==active -> red; Status==inactive -> blue end,
+ Color = if Status =:= active -> red; Status =:= inactive -> blue end,
config_editor(Editor, [{overwrite,{{Line,0},"-@- "}},
{fg,{{{Line,0},{Line,lineend}}, Color}}]).
@@ -330,8 +330,8 @@ add_break_to_menu(WinInfo, Menu, {Point, [Status|_Options]=Options}) ->
%% Cond = null | {Mod, Func}
%%--------------------------------------------------------------------
update_break(WinInfo, {{Mod,Line},[Status|_Options]}=Break) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
add_break_to_code(Editor, Line, Status);
false -> ignore
end,
@@ -352,8 +352,8 @@ update_break_in_menu(WinInfo, {Point, [Status|_Options]=Options}) ->
%% Point = {Mod, Line}
%%--------------------------------------------------------------------
delete_break(WinInfo, {Mod,Line}=Point) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} -> delete_break_from_code(Editor, Line);
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} -> delete_break_from_code(Editor, Line);
false -> ignore
end,
delete_break_from_menu(WinInfo, Point).
@@ -379,11 +379,11 @@ clear_breaks(WinInfo) ->
clear_breaks(WinInfo, all).
clear_breaks(WinInfo, Mod) ->
Remove = if
- Mod==all -> WinInfo#winInfo.breaks;
+ Mod =:= all -> WinInfo#winInfo.breaks;
true ->
lists:filter(fun(#breakInfo{point={Mod2,_L}}) ->
if
- Mod2==Mod -> true;
+ Mod2 =:= Mod -> true;
true -> false
end
end,
@@ -450,8 +450,8 @@ display(Arg) ->
%% Note: remove_code/2 should not be used for currently shown module.
%%--------------------------------------------------------------------
is_shown(WinInfo, Mod) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
gs:config(Editor, raise),
{true, WinInfo#winInfo{editor={Mod, Editor}}};
false -> false
@@ -459,24 +459,22 @@ is_shown(WinInfo, Mod) ->
show_code(WinInfo, Mod, Contents) ->
Editors = WinInfo#winInfo.editors,
- {Flag, Editor} = case lists:keysearch(Mod, 1, Editors) of
- {value, {Mod, Ed}} -> {existing, Ed};
+ {Flag, Editor} = case lists:keyfind(Mod, 1, Editors) of
+ {Mod, Ed} -> {existing, Ed};
false -> {new, code_editor()}
end,
-
%% Insert code and update breakpoints, if any
config_editor(Editor, [raise, clear]),
show_code(Editor, Contents),
lists:foreach(fun(BreakInfo) ->
case BreakInfo#breakInfo.point of
- {Mod2, Line} when Mod2==Mod ->
+ {Mod2, Line} when Mod2 =:= Mod ->
Status = BreakInfo#breakInfo.status,
add_break_to_code(Editor, Line,Status);
_Point -> ignore
end
end,
WinInfo#winInfo.breaks),
-
case Flag of
existing ->
WinInfo#winInfo{editor={Mod, Editor}};
@@ -485,7 +483,7 @@ show_code(WinInfo, Mod, Contents) ->
editors=[{Mod, Editor} | Editors]}
end.
-show_code(Editor, Text) when length(Text)>1500 ->
+show_code(Editor, Text) when length(Text) > 1500 ->
%% Add some text at a time so that other processes may get scheduled
Str = string:sub_string(Text, 1, 1500),
config_editor(Editor, {insert,{'end', Str}}),
@@ -494,21 +492,19 @@ show_code(Editor, Text) ->
config_editor(Editor, {insert,{'end',Text}}).
show_no_code(WinInfo) ->
- {value, {'$top', Editor}} =
- lists:keysearch('$top', 1, WinInfo#winInfo.editors),
+ {'$top', Editor} = lists:keyfind('$top', 1, WinInfo#winInfo.editors),
gs:config(Editor, raise),
WinInfo#winInfo{editor={'$top', Editor}}.
remove_code(WinInfo, Mod) ->
Editors = WinInfo#winInfo.editors,
- case lists:keysearch(Mod, 1, Editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, Editors) of
+ {Mod, Editor} ->
gs:destroy(Editor),
WinInfo#winInfo{editors=lists:keydelete(Mod, 1, Editors)};
false ->
WinInfo
end.
-
%%--------------------------------------------------------------------
%% mark_line(WinInfo, Line, How) -> WinInfo
@@ -522,7 +518,7 @@ mark_line(WinInfo, Line, How) ->
mark_line2(Editor, WinInfo#winInfo.marked_line, false),
mark_line2(Editor, Line, How),
if
- Line/=0 -> config_editor(Editor, {vscrollpos, Line-5});
+ Line =/= 0 -> config_editor(Editor, {vscrollpos, Line-5});
true -> ignore
end,
WinInfo#winInfo{marked_line=Line}.
@@ -537,7 +533,7 @@ mark_line2(Editor, Line, How) ->
false -> " "
end,
Font = if
- How==false -> dbg_ui_win:font(normal);
+ How =:= false -> dbg_ui_win:font(normal);
true -> dbg_ui_win:font(bold)
end,
config_editor(Editor, [{overwrite, {{Line,5}, Prefix}},
@@ -558,10 +554,10 @@ select_line(WinInfo, Line) ->
%% help window, it must be checked that it is correct
Size = gs:read(Editor, size),
if
- Line==0 ->
+ Line =:= 0 ->
select_line(Editor, WinInfo#winInfo.selected_line, false),
WinInfo#winInfo{selected_line=0};
- Line<Size ->
+ Line < Size ->
select_line(Editor, Line, true),
config_editor(Editor, {vscrollpos, Line-5}),
WinInfo#winInfo{selected_line=Line};
@@ -712,10 +708,10 @@ handle_event({gs, Editor, buttonpress, code_editor, _Arg}, WinInfo) ->
{Row, _} ->
{Mod, _Editor} = WinInfo#winInfo.editor,
Point = {Mod, Row},
- case lists:keysearch(Point, #breakInfo.point,
+ case lists:keymember(Point, #breakInfo.point,
WinInfo#winInfo.breaks) of
- {value, _BreakInfo} -> {break, Point, delete};
- false -> {break, Point, add}
+ false -> {break, Point, add};
+ true -> {break, Point, delete}
end;
{Row2, _} ->
select_line(Editor, Row2, true),
@@ -776,7 +772,7 @@ code_editor() ->
code_editor(Name, W, H) ->
Editor = if
- Name==null -> gs:editor('CodeArea', []);
+ Name =:= null -> gs:editor('CodeArea', []);
true -> gs:editor(Name, 'CodeArea', [])
end,
gs:config(Editor, [{x,5}, {y,30}, {width,W}, {height,H},
@@ -814,8 +810,8 @@ buttons() ->
{'Where','WhereButton'}, {'Up','UpButton'}, {'Down','DownButton'}].
is_button(Name) ->
- case lists:keysearch(Name, 1, buttons()) of
- {value, {Name, Button}} -> {true, Button};
+ case lists:keyfind(Name, 1, buttons()) of
+ {Name, Button} -> {true, Button};
false -> false
end.
@@ -847,7 +843,7 @@ resize_button_area(open, width, Diff) ->
eval_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{W,H} = if
- Ev==open -> {289,200};
+ Ev =:= open -> {289,200};
true -> {0,0}
end,
Font = dbg_ui_win:font(normal),
@@ -870,7 +866,7 @@ eval_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{font_style,{{{1,0},'end'},Font}}]),
gs:config('EvalEditor', {enable, false}),
if
- Ev==open, Bi==close -> resize_eval_area(Ev, width, 257);
+ Ev =:= open, Bi =:= close -> resize_eval_area(Ev, width, 257);
true -> ignore
end.
@@ -891,7 +887,7 @@ resize_eval_area(open, Key, Diff) ->
bind_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{W,H} = if
- Bi==open -> {249,200};
+ Bi =:= open -> {249,200};
true -> {0,0}
end,
gs:frame('BindArea', Win,
@@ -908,7 +904,7 @@ bind_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{text,{1,"Name"}}, {text,{2,"Value"}}, {font,Font}]),
gs:config('BindGrid', {rows,{1,1}}),
if
- Bi==open, Ev==close -> resize_bind_area(Bi, width, 297);
+ Bi =:= open, Ev =:= close -> resize_bind_area(Bi, width, 297);
true -> ignore
end.
@@ -993,15 +989,15 @@ resizebar(Flag, Name, X, Y, W, H, Obj) ->
rb1({_Bu,Ev,Bi,Tr}) ->
if
- Ev==close, Bi==close, Tr==close -> close;
+ Ev =:= close, Bi =:= close, Tr =:= close -> close;
true -> open
end.
rb2({_Bu,Ev,Bi,Tr}) ->
if
- Tr==open ->
+ Tr =:= open ->
if
- Ev==close, Bi==close -> close;
+ Ev =:= close, Bi =:= close -> close;
true -> open
end;
true -> close
@@ -1009,7 +1005,7 @@ rb2({_Bu,Ev,Bi,Tr}) ->
rb3({_Bu,Ev,Bi,_Tr}) ->
if
- Ev==open, Bi==open -> open;
+ Ev =:= open, Bi =:= open -> open;
true -> close
end.
@@ -1067,7 +1063,7 @@ configure(WinInfo, NewW, NewH) ->
%% Adjust width unless it is unchanged or less than minimum width
if
- OldW/=NewW ->
+ OldW =/= NewW ->
{Dcode,Deval,Dbind} = configure_widths(OldW,NewW,Flags),
resize_code_area(WinInfo, width, Dcode),
case rb1(Flags) of
@@ -1090,7 +1086,7 @@ configure(WinInfo, NewW, NewH) ->
%% Adjust height unless it is unchanged or less than minimum height
if
- OldH/=NewH ->
+ OldH =/= NewH ->
{Dcode2,Deval2,Dtrace} = configure_heights(OldH,NewH,Flags),
resize_code_area(WinInfo, height, Dcode2),
resize_eval_area(Ev, height, Deval2),
@@ -1117,11 +1113,11 @@ configure_widths(OldW, NewW, Flags) ->
%% Check how much the frames can be resized in reality
Limits = if
%% Window larger
- NewW>OldW ->
+ NewW > OldW ->
if
- Ev==open,Bi==open -> {0,Diff,Diff};
- Ev==open -> {0,Diff,0};
- Bi==open -> {0,0,Diff};
+ Ev =:= open, Bi =:= open -> {0,Diff,Diff};
+ Ev =:= open -> {0,Diff,0};
+ Bi =:= open -> {0,0,Diff};
true -> {Diff,0,0}
end;
@@ -1129,12 +1125,12 @@ configure_widths(OldW, NewW, Flags) ->
%% and current size
OldW>NewW ->
if
- Ev==open,Bi==open ->
+ Ev =:= open, Bi =:= open ->
{0,
gs:read('EvalArea',width)-204,
gs:read('BindArea',width)-112};
- Ev==open -> {0,Diff,0};
- Bi==open -> {0,0,Diff};
+ Ev =:= open -> {0,Diff,0};
+ Bi =:= open -> {0,0,Diff};
true -> {Diff,0,0}
end
end,
@@ -1142,13 +1138,13 @@ configure_widths(OldW, NewW, Flags) ->
case Limits of
%% No Shell or Bind frame, larger window
- {T,0,0} when NewW>OldW -> {T,0,0};
+ {T,0,0} when NewW > OldW -> {T,0,0};
%% No Shell or Bind frame, smaller window
- {T,0,0} when OldW>NewW -> {-T,0,0};
+ {T,0,0} when OldW > NewW -> {-T,0,0};
%% Window larger; divide Diff among the frames and return result
- {_,Sf,B} when NewW>OldW ->
+ {_,Sf,B} when NewW > OldW ->
{_,Sf2,B2} = divide([{0,0},{0,Sf},{0,B}],Diff),
{Sf2+B2,Sf2,B2};
@@ -1171,33 +1167,33 @@ configure_heights(OldH, NewH, Flags) ->
%% Check how much the frames can be resized in reality
{T,Sf,Ff} = if
%% Window larger
- NewH>OldH ->
+ NewH > OldH ->
{Diff,
if
- Ev==close, Bi==close -> 0;
+ Ev =:= close, Bi =:= close -> 0;
true -> Diff
end,
if
- Tr==open -> Diff;
+ Tr =:= open -> Diff;
true -> 0
end};
%% Window smaller; get difference between min size
%% and current size
- OldH>NewH ->
+ OldH > NewH ->
{gs:read('CodeArea',height)-100,
if
- Ev==close, Bi==close -> 0;
+ Ev =:= close, Bi =:= close -> 0;
true ->
if
- Ev==open ->
+ Ev =:= open ->
gs:read('EvalArea',height)-100;
- Bi==open ->
+ Bi =:= open ->
gs:read('BindArea',height)-100
end
end,
if
- Tr==open -> gs:read('TraceArea',height)-100;
+ Tr =:= open -> gs:read('TraceArea',height)-100;
true -> 0
end}
end,
@@ -1251,10 +1247,8 @@ divide(L, Diff) ->
if
%% All of Diff has been distributed
- D==0 -> {T,S,F};
-
+ D =:= 0 -> {T,S,F};
true ->
-
%% For each element, try to add as much as possible of D
{NewT,Dt} = divide2(D,T,Tmax),
{NewS,Ds} = divide2(D,S,Smax),
@@ -1296,25 +1290,25 @@ resize(WinInfo, ResizeBar) ->
rblimits('RB2',W,H),
rblimits('RB3',W,H)).
-resizeloop(WI, RB, Prev, {Min1,Max1},{Min2,Max2},{Min3,Max3}) ->
+resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}) ->
receive
- {gs,_,motion,_,[_,Y]} when RB=='RB1', Y>Min1,Y<Max1 ->
+ {gs,_,motion,_,[_,Y]} when RB =:= 'RB1', Y > Min1, Y < Max1 ->
gs:config('RB1', {y,Y}),
- resizeloop(WI, RB, Y, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB1' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB1' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
- {gs,_,motion,_,[_,Y]} when RB=='RB2', Y>Min2,Y<Max2 ->
+ {gs,_,motion,_,[_,Y]} when RB =:= 'RB2', Y > Min2, Y < Max2 ->
gs:config('RB2', {y,Y}),
- resizeloop(WI, RB, Y, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB2' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB2' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
- {gs,_,motion,_,[X,_]} when RB=='RB3', X>Min3,X<Max3 ->
+ {gs,_,motion,_,[X,_]} when RB =:= 'RB3', X > Min3, X < Max3 ->
gs:config('RB3', {x,X}),
- resizeloop(WI, RB, X, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB3' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, X, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB3' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
{gs,_,buttonrelease,_,_} ->
resize_win(WI, RB, Prev)
@@ -1329,7 +1323,7 @@ resize_win(WinInfo, 'RB1', Y) ->
%% Resize Code, Evaluator and Binding areas
resize_code_area(WinInfo, height, -Diff),
if
- S==close, Bi==close, F==open ->
+ S =:= close, Bi =:= close, F =:= open ->
resize_trace_area(open, height, Diff);
true ->
resize_eval_area(S, height, Diff),
@@ -1388,7 +1382,7 @@ rblimits('RB1',_W,H) ->
RB2 = gs:read('RB2',height),
FF = gs:read('TraceArea',height),
Max = case RB2 of
- 0 when FF/=0 ->
+ 0 when FF =/= 0 ->
H-112;
_ ->
Y = gs:read('RB2',y),
@@ -1397,18 +1391,14 @@ rblimits('RB1',_W,H) ->
{Min,Max};
rblimits('RB2',_W,H) ->
-
- %% TraceFrame should not have height <100
+ %% TraceFrame should not have height < 100
Max = H-112,
-
%% Min is decided by a minimum distance to 'RB1'
Y = gs:read('RB1',y),
Min = erlang:min(Max,Y+140),
-
{Min,Max};
rblimits('RB3',W,_H) ->
-
%% Neither CodeArea nor BindArea should occupy
%% less than 1/3 of the total window width and EvalFrame should
%% be at least 289 pixels wide
@@ -1484,7 +1474,7 @@ helpwin_action(gotoline, default, AttPid, _Editor, Data, Win) ->
end,
Data;
helpwin_action(search, case_sensitive, _AttPid, _Ed, {Pos, CS}, _Win) ->
- Bool = if CS==true -> false; CS==false -> true end,
+ Bool = if CS =:= true -> false; CS =:= false -> true end,
{Pos, Bool};
helpwin_action(search, default, _AttPid, Editor, {Pos, CS}, Win) ->
gs:config(lbl(Win), {label, {text, ""}}),
@@ -1517,13 +1507,9 @@ search(Str, Editor, Max, {Row, Col}, CS) ->
lowercase(true, Str) -> Str;
lowercase(false, Str) ->
- lists:map(fun(Char) ->
- if
- Char>=$A, Char=<$Z -> Char+32;
- true -> Char
- end
- end,
- Str).
+ [if Char >= $A, Char =< $Z -> Char+32;
+ true -> Char
+ end || Char <- Str].
mark_string(Editor, {Row, Col}, Str) ->
Between = {{Row,Col}, {Row,Col+length(Str)}},
@@ -1540,10 +1526,9 @@ unmark_string(Editor, {Row, Col}) ->
{fg, {Between, black}}]).
helpwin(Type, GS, {X, Y}) ->
- W = 200, Pad=10, Wbtn = 50,
+ W = 200, Pad = 10, Wbtn = 50,
- Title =
- case Type of search -> "Search"; gotoline -> "Go To Line" end,
+ Title = case Type of search -> "Search"; gotoline -> "Go To Line" end,
Win = gs:window(GS, [{title, Title}, {x, X}, {y, Y}, {width, W},
{destroy, true}]),
diff --git a/lib/debugger/src/dbg_ui_view.erl b/lib/debugger/src/dbg_ui_view.erl
index 075275f196..7350a830a8 100644
--- a/lib/debugger/src/dbg_ui_view.erl
+++ b/lib/debugger/src/dbg_ui_view.erl
@@ -21,9 +21,6 @@
%% External exports
-export([start/2]).
-%% Internal exports
--export([init/3]).
-
-record(state, {gs, % term() Graphics system id
win, % term() Attach process window data
coords, % {X,Y} Mouse point position
@@ -42,7 +39,7 @@ start(GS, Mod) ->
Title = "View Module " ++ atom_to_list(Mod),
case dbg_ui_winman:is_started(Title) of
true -> ignore;
- false -> spawn(?MODULE, init, [GS, Mod, Title])
+ false -> spawn(fun () -> init(GS, Mod, Title) end)
end.
@@ -51,7 +48,6 @@ start(GS, Mod) ->
%%====================================================================
init(GS, Mod, Title) ->
-
%% Subscribe to messages from the interpreter
int:subscribe(),
diff --git a/lib/debugger/src/dbg_ui_win.erl b/lib/debugger/src/dbg_ui_win.erl
index 74ff2503ab..9bed6a1ec5 100644
--- a/lib/debugger/src/dbg_ui_win.erl
+++ b/lib/debugger/src/dbg_ui_win.erl
@@ -24,7 +24,6 @@
create_menus/2, select/2, selected/1,
add_break/2, update_break/2, delete_break/1,
motion/2
-
]).
-record(break, {mb, smi, emi, dimi, demi}).
@@ -49,11 +48,11 @@ init() ->
font(Style) ->
GS = init(),
Style2 = if
- Style==normal -> [];
+ Style =:= normal -> [];
true -> [Style]
end,
case gs:read(GS, {choose_font, {screen,Style2,12}}) of
- Font when element(1, Font)==screen ->
+ Font when element(1, Font) =:= screen ->
Font;
_ ->
gs:read(GS, {choose_font, {courier,Style2,12}})
@@ -168,8 +167,7 @@ select(MenuItem, Bool) ->
%%--------------------------------------------------------------------
selected(Menu) ->
Children = gs:read(Menu, children),
- Selected = lists:filter(fun(Child) -> gs:read(Child, select) end,
- Children),
+ Selected = [gs:read(Child, select) || Child <- Children],
lists:map(fun(Child) ->
{text, Name} = gs:read(Child, label),
list_to_atom(Name)
diff --git a/lib/debugger/src/dbg_ui_winman.erl b/lib/debugger/src/dbg_ui_winman.erl
index 71023cd0d6..398735a7ca 100644
--- a/lib/debugger/src/dbg_ui_winman.erl
+++ b/lib/debugger/src/dbg_ui_winman.erl
@@ -120,9 +120,9 @@ init(_Arg) ->
{ok, #state{}}.
handle_call({is_started, Title}, _From, State) ->
- Reply = case lists:keysearch(Title, #win.title, State#state.wins) of
- {value, Win} -> {true, Win#win.win};
- false -> false
+ Reply = case lists:keyfind(Title, #win.title, State#state.wins) of
+ false -> false;
+ Win -> {true, Win#win.win}
end,
{reply, Reply, State}.
@@ -134,8 +134,8 @@ handle_cast({insert, Pid, Title, Win}, State) ->
handle_cast({clear_process, Title}, State) ->
OldWins = State#state.wins,
- Wins = case lists:keysearch(Title, #win.title, OldWins) of
- {value, #win{owner=Pid}} ->
+ Wins = case lists:keyfind(Title, #win.title, OldWins) of
+ #win{owner=Pid} ->
Msg = {dbg_ui_winman, destroy},
Pid ! Msg,
lists:keydelete(Title, #win.title, OldWins);
@@ -147,7 +147,7 @@ handle_cast({clear_process, Title}, State) ->
handle_info({'EXIT', Pid, _Reason}, State) ->
[Mon | _Wins] = State#state.wins,
if
- Pid==Mon#win.owner -> {stop, normal, State};
+ Pid =:= Mon#win.owner -> {stop, normal, State};
true ->
Wins2 = lists:keydelete(Pid, #win.owner, State#state.wins),
inform_all(Wins2),
diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl
index 5dafb0fbe6..78733c98c8 100644
--- a/lib/debugger/src/dbg_wx_break_win.erl
+++ b/lib/debugger/src/dbg_wx_break_win.erl
@@ -206,11 +206,7 @@ handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OkorDoubleClick}},
OkorDoubleClick =:= command_listbox_doubleclicked ->
Mod = wxComboBox:getValue(Text),
{_, IndexL} = wxListBox:getSelections(LB),
- Breaks = lists:map(fun(Index) ->
- Func = lists:nth(Index+1, Funcs),
- [list_to_atom(Mod) | Func]
- end,
- IndexL),
+ Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL],
wxDialog:destroy(Win),
{break, Breaks, enable};
handle_event(#wx{id=?wxID_OK},#winInfo{win=Win,text=Text, entries=Es, trigger=Trigger}) ->
diff --git a/lib/debugger/src/dbg_wx_interpret.erl b/lib/debugger/src/dbg_wx_interpret.erl
index f711ba679d..ffcfbcf36b 100644
--- a/lib/debugger/src/dbg_wx_interpret.erl
+++ b/lib/debugger/src/dbg_wx_interpret.erl
@@ -115,11 +115,11 @@ interpret_all(Dir, [File0|Files], Mode, Window, Errors) ->
interpret_all(_Dir, [], _Mode, _Window, []) ->
true;
interpret_all(Dir, [], _Mode, Window, Errors) ->
- Msg = lists:map(fun(Name) ->
- File = filename:join(Dir, Name),
- Error = format_error(int:interpretable(File)),
- ["\n ",Name,": ",Error]
- end, Errors),
+ Msg = [begin
+ File = filename:join(Dir, Name),
+ Error = format_error(int:interpretable(File)),
+ ["\n ",Name,": ",Error]
+ end || Name <- Errors],
All = ["Error when interpreting: ", Msg],
dbg_wx_win:confirm(Window, lists:flatten(All)),
true.
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index 3f55c38d35..6bdec994b1 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -170,7 +170,7 @@ init2(CallingPid, Mode, SFile, GS) ->
CallingPid ! {initialization_complete, self()},
if
- SFile==default ->
+ SFile =:= default ->
loop(State3);
true ->
loop(load_settings(SFile, State3))
@@ -268,7 +268,7 @@ gui_cmd(ignore, State) ->
State;
gui_cmd(stopped, State) ->
if
- State#state.starter==true -> int:stop();
+ State#state.starter =:= true -> int:stop();
true -> int:auto_attach(false)
end,
exit(stop);
@@ -420,9 +420,9 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
State2;
gui_cmd({'Auto Attach', When}, State) ->
if
- When==[] -> int:auto_attach(false);
+ When =:= [] -> int:auto_attach(false);
true ->
- Flags = lists:map(fun(Name) -> map(Name) end, When),
+ Flags = [map(Name) || Name <- When],
int:auto_attach(Flags, trace_function(State))
end,
State;
@@ -691,12 +691,12 @@ load_settings2(Settings, State) ->
Break,
int:break(Mod, Line),
if
- Status==inactive ->
+ Status =:= inactive ->
int:disable_break(Mod, Line);
true -> ignore
end,
if
- Action/=enable ->
+ Action =/= enable ->
int:action_at_break(Mod,Line,Action);
true -> ignore
end,
@@ -715,10 +715,7 @@ save_settings(SFile, State) ->
int:auto_attach(),
int:stack_trace(),
State#state.backtrace,
- lists:map(fun(Mod) ->
- int:file(Mod)
- end,
- int:interpreted()),
+ [int:file(Mod) || Mod <- int:interpreted()],
int:all_breaks()},
Binary = term_to_binary({debugger_settings, Settings}),
@@ -741,7 +738,7 @@ registered_name(Pid) ->
Node = node(Pid),
if
- Node==node() ->
+ Node =:= node() ->
case erlang:process_info(Pid, registered_name) of
{registered_name, Name} -> Name;
_ -> undefined
diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl
index 8ad4f4213f..04c3501b8c 100644
--- a/lib/debugger/src/dbg_wx_mon_win.erl
+++ b/lib/debugger/src/dbg_wx_mon_win.erl
@@ -266,8 +266,7 @@ select(MenuItem, Bool) ->
add_module(WinInfo, MenuName, Mod) ->
Win = WinInfo#winInfo.window,
Modules = WinInfo#winInfo.modules,
- case lists:keysearch(Mod, #moduleInfo.module, Modules) of
- {value, _ModInfo} -> WinInfo;
+ case lists:keymember(Mod, #moduleInfo.module, Modules) of
false ->
%% Create a menu for the module
Menu = get(MenuName),
@@ -284,8 +283,9 @@ add_module(WinInfo, MenuName, Mod) ->
wxListBox:append(WinInfo#winInfo.listbox, atom_to_list(Mod)),
ModInfo = #moduleInfo{module=Mod, menubtn={Menu,MenuBtn}},
- WinInfo#winInfo{modules=[ModInfo | Modules]}
- end.
+ WinInfo#winInfo{modules=[ModInfo | Modules]};
+ true -> WinInfo
+ end.
%%--------------------------------------------------------------------
%% delete_module(WinInfo, Mod) -> WinInfo
@@ -559,8 +559,7 @@ handle_event(#wx{event=#wxCommand{type=command_checkbox_clicked}},
handle_event(#wx{event=#wxList{type=command_list_item_selected,
itemIndex=Row}}, WinInfo) ->
#winInfo{processes=Pids} = WinInfo,
- {value, #procInfo{pid=Pid}} =
- lists:keysearch(Row, #procInfo.row, Pids),
+ #procInfo{pid=Pid} = lists:keyfind(Row, #procInfo.row, Pids),
{focus, Pid, WinInfo#winInfo{focus=Row}};
handle_event(#wx{event=#wxList{type=command_list_item_activated}},
_WinInfo) ->
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index f9fdf593c4..6675ea33e7 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -180,12 +180,12 @@ init_contents(Breaks, State) ->
State#state{win=Win}.
-loop(#state{meta=Meta} = State) ->
+loop(#state{meta=Meta, win=Win} = State) ->
receive
%% From the GUI main window
- GuiEvent when element(1, GuiEvent)==wx ->
+ GuiEvent when element(1, GuiEvent) =:= wx ->
Cmd = wx:batch(fun() ->
- dbg_wx_trace_win:handle_event(GuiEvent,State#state.win)
+ dbg_wx_trace_win:handle_event(GuiEvent,Win)
end),
State2 = gui_cmd(Cmd, State),
loop(State2);
@@ -211,11 +211,11 @@ loop(#state{meta=Meta} = State) ->
%% From the dbg_wx_winman process (Debugger window manager)
{dbg_ui_winman, update_windows_menu, Data} ->
- Window = dbg_wx_trace_win:get_window(State#state.win),
+ Window = dbg_wx_trace_win:get_window(Win),
dbg_wx_winman:update_windows_menu(Window,Data),
loop(State);
{dbg_ui_winman, destroy} ->
- dbg_wx_trace_win:stop(State#state.win),
+ dbg_wx_trace_win:stop(Win),
exit(stop)
end.
@@ -269,7 +269,7 @@ gui_cmd('Continue', State) ->
int:meta(State#state.meta, continue),
{Status, Mod, Line} = State#state.status,
if
- Status==wait_break ->
+ Status =:= wait_break ->
Win = dbg_wx_trace_win:unmark_line(State#state.win),
gui_enable_functions(wait_running),
State#state{win=Win, status={wait_running,Mod,Line}};
@@ -291,7 +291,7 @@ gui_cmd('Stop', State) ->
int:meta(State#state.meta, stop),
{Status, Mod, Line} = State#state.status,
if
- Status==wait_running ->
+ Status =:= wait_running ->
Win = dbg_wx_trace_win:mark_line(State#state.win, Line,
break),
gui_enable_functions(wait_break),
@@ -421,7 +421,7 @@ gui_cmd('Function Break...', State) ->
gui_cmd('Enable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.cm,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:enable_break(Mod, Line);
(_Break) ->
ignore
@@ -431,7 +431,7 @@ gui_cmd('Enable All', State) ->
gui_cmd('Disable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.cm,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:disable_break(Mod, Line);
(_Break) ->
ignore
@@ -458,7 +458,7 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
Win = dbg_wx_trace_win:configure(State#state.win, TraceWin),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(Trace, State#state.stack_trace);
true -> ignore
end,
@@ -467,7 +467,7 @@ gui_cmd({'Stack Trace', [Name]}, State) ->
int:meta(State#state.meta, stack_trace, map(Name)),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(State#state.trace, map(Name));
true -> ignore
end,
@@ -490,9 +490,9 @@ gui_cmd('Debugger', State) ->
gui_cmd({user_command, Cmd}, State) ->
{Status, _Mod, _Line} = State#state.status,
if
- Status==break;
- Status==wait_break;
- Status==wait_running ->
+ Status =:= break;
+ Status =:= wait_break;
+ Status =:= wait_running ->
Cm = State#state.cm,
Arg = case State#state.stack of
{Cur, Max} when Cur<Max -> {Cm, Cmd, Cur};
@@ -531,14 +531,14 @@ add_break(WI, Coords, Type, Mod, Line) ->
int_cmd({interpret, Mod}, State) ->
if
- Mod==State#state.cm ->
+ Mod =:= State#state.cm ->
State#state{cm_obsolete=true};
true ->
State
end;
int_cmd({no_interpret, Mod}, State) ->
if
- Mod==State#state.cm ->
+ Mod =:= State#state.cm ->
State#state{cm_obsolete=true};
true ->
Win = dbg_wx_trace_win:remove_code(State#state.win, Mod),
@@ -584,7 +584,7 @@ meta_cmd({re_entry, dbg_ieval, eval_fun}, State) ->
meta_cmd({re_entry, Mod, _Func}, State) ->
Obs = State#state.cm_obsolete,
case State#state.cm of
- Mod when Obs==true ->
+ Mod when Obs =:= true ->
Win = gui_load_module(State#state.win, Mod,State#state.pid),
State#state{win=Win, cm_obsolete=false};
Mod -> State;
@@ -630,11 +630,11 @@ meta_cmd({func_at, Mod, Line, Cur}, State) ->
gui_enable_functions(idle),
dbg_wx_trace_win:display(State#state.win, idle),
State#state{win=Win, cm=Mod, status={idle,Mod,Line}, stack=Stack};
-meta_cmd({wait_at, Mod, Line, Cur}, #state{status={Status,_,_}}=State)
- when Status/=init, Status/=break ->
+meta_cmd({wait_at, Mod, Line, Cur}, #state{status={Status,_,_}, win=Win}=State)
+ when Status =/= init, Status =/= break ->
Stack = {Cur,Cur},
gui_enable_functions(wait_running),
- dbg_wx_trace_win:display(State#state.win, {wait,Mod,Line}),
+ dbg_wx_trace_win:display(Win, {wait,Mod,Line}),
State#state{status={wait_running,Mod,Line}, stack=Stack};
meta_cmd({wait_at, Mod, Line, Cur}, State) ->
Stack = {Cur,Cur},
@@ -675,7 +675,7 @@ meta_cmd({stack_trace, Flag}, State) ->
gui_enable_updown(Flag, State#state.stack),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(State#state.trace, Flag);
true -> ignore
end,
@@ -813,7 +813,7 @@ gui_enable_functions(Status) ->
gui_enable_updown(Flag, Stack) ->
{Enable, Disable} =
if
- Flag==false -> {[], ['Up', 'Down']};
+ Flag =:= false -> {[], ['Up', 'Down']};
true ->
case Stack of
{1,1} -> {[], ['Up', 'Down']};
@@ -826,14 +826,14 @@ gui_enable_updown(Flag, Stack) ->
dbg_wx_trace_win:enable(Enable, true),
dbg_wx_trace_win:enable(Disable, false),
if
- Enable==[] -> dbg_wx_trace_win:enable(['Where'], false);
+ Enable =:= [] -> dbg_wx_trace_win:enable(['Where'], false);
true -> dbg_wx_trace_win:enable(['Where'], true)
end.
gui_enable_btrace(Trace, StackTrace) ->
Bool = if
- Trace==false -> false;
- StackTrace==false -> false;
+ Trace =:= false -> false;
+ StackTrace =:= false -> false;
true -> true
end,
dbg_wx_trace_win:enable(['Back Trace'], Bool).
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 2b4a1164ad..720b913024 100755
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
@@ -410,11 +410,11 @@ clear_breaks(WinInfo) ->
clear_breaks(WinInfo, all).
clear_breaks(WinInfo, Mod) ->
Remove = if
- Mod==all -> WinInfo#winInfo.breaks;
+ Mod =:= all -> WinInfo#winInfo.breaks;
true ->
lists:filter(fun(#breakInfo{point={Mod2,_L}}) ->
if
- Mod2==Mod -> true;
+ Mod2 =:= Mod -> true;
true -> false
end
end,
@@ -481,8 +481,8 @@ display(#winInfo{window=Win, sb=Sb},Arg) ->
%% Note: remove_code/2 should not be used for currently shown module.
%%--------------------------------------------------------------------
is_shown(WinInfo, Mod) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
gs:config(Editor, raise), %% BUGBUG
{true, WinInfo#winInfo{editor={Mod, Editor}}};
false -> false
@@ -494,7 +494,7 @@ show_code(WinInfo = #winInfo{editor={_, Ed}}, Mod, Contents) ->
lists:foreach(fun(BreakInfo) ->
case BreakInfo#breakInfo.point of
- {Mod2, Line} when Mod2==Mod ->
+ {Mod2, Line} when Mod2 =:= Mod ->
Status = BreakInfo#breakInfo.status,
dbg_wx_code:add_break_to_code(Ed, Line,Status);
_Point -> ignore
@@ -540,10 +540,10 @@ select_line(WinInfo, Line) ->
%% help window, it must be checked that it is correct
Size = dbg_wx_code:get_no_lines(Ed),
if
- Line==0 ->
+ Line =:= 0 ->
dbg_wx_code:goto_line(Ed,1),
WinInfo#winInfo{selected_line=0};
- Line<Size ->
+ Line < Size ->
dbg_wx_code:goto_line(Ed,Line),
WinInfo#winInfo{selected_line=Line};
true ->
@@ -764,8 +764,8 @@ handle_event(#wx{event=#wxStyledText{type=stc_doubleclick}},
WinInfo = #winInfo{editor={Mod,Ed}}) ->
Line = wxStyledTextCtrl:getCurrentLine(Ed),
Point = {Mod, Line+1},
- case lists:keysearch(Point, #breakInfo.point,WinInfo#winInfo.breaks) of
- {value, _BreakInfo} -> {break, Point, delete};
+ case lists:keymember(Point, #breakInfo.point, WinInfo#winInfo.breaks) of
+ true -> {break, Point, delete};
false -> {break, Point, add}
end;
@@ -837,7 +837,7 @@ handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=Str}},
%% Button area
handle_event(#wx{id=ID, event=#wxCommand{type=command_button_clicked}},_Wi) ->
- {value, {Button, _}} = lists:keysearch(ID, 2, buttons()),
+ {Button, _} = lists:keyfind(ID, 2, buttons()),
Button;
%% Evaluator area
@@ -908,8 +908,8 @@ buttons() ->
{'Where',?WhereButton}, {'Up',?UpButton}, {'Down',?DownButton}].
is_button(Name) ->
- case lists:keysearch(Name, 1, buttons()) of
- {value, {Name, Button}} -> {true, Button};
+ case lists:keyfind(Name, 1, buttons()) of
+ {Name, Button} -> {true, Button};
false -> false
end.
diff --git a/lib/debugger/src/dbg_wx_view.erl b/lib/debugger/src/dbg_wx_view.erl
index 6d34e5650c..8ff89a4847 100644
--- a/lib/debugger/src/dbg_wx_view.erl
+++ b/lib/debugger/src/dbg_wx_view.erl
@@ -23,9 +23,6 @@
%% External exports
-export([start/2]).
-%% Internal exports
--export([init/4]).
-
-record(state, {gs, % term() Graphics system id
win, % term() Attach process window data
coords, % {X,Y} Mouse point position
@@ -46,7 +43,7 @@ start(GS, Mod) ->
true -> ignore;
false ->
Env = wx:get_env(),
- spawn_link(?MODULE, init, [GS, Env, Mod, Title])
+ spawn_link(fun () -> init(GS, Env, Mod, Title) end)
end.
@@ -84,7 +81,7 @@ loop(State) ->
receive
%% From the GUI main window
- GuiEvent when element(1, GuiEvent)==wx ->
+ GuiEvent when element(1, GuiEvent) =:= wx ->
Cmd = wx:batch(fun() ->
dbg_wx_trace_win:handle_event(GuiEvent, State#state.win)
end),
@@ -167,7 +164,7 @@ gui_cmd('Function Break...', State) ->
gui_cmd('Enable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.mod,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:enable_break(Mod, Line);
(_Break) ->
ignore
@@ -177,7 +174,7 @@ gui_cmd('Enable All', State) ->
gui_cmd('Disable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.mod,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:disable_break(Mod, Line);
(_Break) ->
ignore
@@ -214,21 +211,19 @@ add_break(GS, Coords, Type, Mod, Line) ->
%%--Commands from the interpreter-------------------------------------
-int_cmd({new_break, {{Mod,_Line},_Options}=Break}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:add_break(State#state.win, 'Break', Break),
- State#state{win=Win};
-int_cmd({delete_break, {Mod,_Line}=Point}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:delete_break(State#state.win, Point),
- State#state{win=Win};
-int_cmd({break_options, {{Mod,_Line},_Options}=Break}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:update_break(State#state.win, Break),
- State#state{win=Win};
-int_cmd(no_break, State) ->
- Win = dbg_wx_trace_win:clear_breaks(State#state.win),
- State#state{win=Win};
-int_cmd({no_break, _Mod}, State) ->
- Win = dbg_wx_trace_win:clear_breaks(State#state.win),
- State#state{win=Win};
+int_cmd({new_break, {{Mod,_Line},_Options}=Break},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:add_break(Win, 'Break', Break)};
+int_cmd({delete_break, {Mod,_Line}=Point},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:delete_break(Win, Point)};
+int_cmd({break_options, {{Mod,_Line},_Options}=Break},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:update_break(Win, Break)};
+int_cmd(no_break, #state{win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:clear_breaks(Win)};
+int_cmd({no_break, _Mod}, #state{win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:clear_breaks(Win)};
int_cmd(_, State) ->
State.
diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl
index 1daabe3435..d0ddfeb51a 100755
--- a/lib/debugger/src/dbg_wx_winman.erl
+++ b/lib/debugger/src/dbg_wx_winman.erl
@@ -118,9 +118,9 @@ init([]) ->
{ok, #state{}}.
handle_call({is_started, Title}, _From, State) ->
- Reply = case lists:keysearch(Title, #win.title, State#state.wins) of
- {value, Win} -> {true, Win#win.win};
- false -> false
+ Reply = case lists:keyfind(Title, #win.title, State#state.wins) of
+ false -> false;
+ Win -> {true, Win#win.win}
end,
{reply, Reply, State}.
@@ -132,8 +132,8 @@ handle_cast({insert, Pid, Title, Win}, State) ->
handle_cast({clear_process, Title}, State) ->
OldWins = State#state.wins,
- Wins = case lists:keysearch(Title, #win.title, OldWins) of
- {value, #win{owner=Pid}} ->
+ Wins = case lists:keyfind(Title, #win.title, OldWins) of
+ #win{owner=Pid} ->
Msg = {dbg_ui_winman, destroy},
Pid ! Msg,
lists:keydelete(Title, #win.title, OldWins);
@@ -145,7 +145,7 @@ handle_cast({clear_process, Title}, State) ->
handle_info({'EXIT', Pid, _Reason}, State) ->
[Mon | _Wins] = State#state.wins,
if
- Pid==Mon#win.owner -> {stop, normal, State};
+ Pid =:= Mon#win.owner -> {stop, normal, State};
true ->
Wins2 = lists:keydelete(Pid, #win.owner, State#state.wins),
inform_all(Wins2),
diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl
index 7c2fb22946..476a53482e 100644
--- a/lib/debugger/src/i.erl
+++ b/lib/debugger/src/i.erl
@@ -31,7 +31,6 @@
iv() ->
Vsn = string:substr(filename:basename(code:lib_dir(debugger)), 10),
list_to_atom(Vsn).
-
%% -------------------------------------------
%% Start a new graphical monitor.
@@ -288,10 +287,9 @@ ia(X,Y,Z) ->
%% -------------------------------------------
ia(Pid,Fnk) ->
- case lists:keysearch(Pid, 1, int:snapshot()) of
- {value, _PidTuple} ->
- int:attach(Pid,Fnk);
- false -> no_proc
+ case lists:keymember(Pid, 1, int:snapshot()) of
+ false -> no_proc;
+ true -> int:attach(Pid,Fnk)
end.
ia(X,Y,Z,Fnk) ->
diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl
index eeb4df4a8e..9ee2102a19 100644
--- a/lib/debugger/src/int.erl
+++ b/lib/debugger/src/int.erl
@@ -261,7 +261,7 @@ del_break_in(Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arit
end.
first_lines(Clauses) ->
- lists:map(fun(Clause) -> first_line(Clause) end, Clauses).
+ [first_line(Clause) || Clause <- Clauses].
first_line({clause,_L,_Vars,_,Exprs}) ->
first_line(Exprs);
@@ -469,10 +469,10 @@ contents(Mod, Pid) ->
%% Arity = integer()
%%--------------------------------------------------------------------
functions(Mod) ->
- lists:filter(fun([module_info, _Arity]) -> false;
- (_Func) -> true
- end,
- dbg_iserver:call({functions, Mod})).
+ [F || F <- dbg_iserver:call({functions, Mod}), functions_1(F)].
+
+functions_1([module_info, _Arity]) -> false;
+functions_1(_Func) -> true.
%%====================================================================
diff --git a/lib/docbuilder/src/docb_edoc_xml_cb.erl b/lib/docbuilder/src/docb_edoc_xml_cb.erl
index 4dba843341..f5cfc0fe18 100644
--- a/lib/docbuilder/src/docb_edoc_xml_cb.erl
+++ b/lib/docbuilder/src/docb_edoc_xml_cb.erl
@@ -478,31 +478,29 @@ otp_xmlify_a_href("#"++_ = Marker, Es0) -> % <seealso marker="#what">
otp_xmlify_a_href("http:"++_ = URL, Es0) -> % external URL
{URL, Es0};
otp_xmlify_a_href("OTPROOT"++AppRef, Es0) -> % <.. marker="App:FileRef
- case split(AppRef, "/") of
- [AppS, "doc", FileRef1] ->
- FileRef = AppS++":"++otp_xmlify_a_fileref(FileRef1, AppS),
- [#xmlText{value=Str0} = T] = Es0,
- Str = case split(Str0, "/") of
- %% //Application
- [AppS2] ->
- %% AppS2 can differ from AppS
- %% Example: xmerl/XMerL
- AppS2;
- [_AppS,ModRef] ->
- case split(ModRef, ":") of
- %% //Application/Module
- [Module] ->
- Module++"(3)";
- %% //Application/Module:Type()
- [_Module,_Type] ->
- ModRef
- end;
- %% //Application/Module:Function/Arity
- [_AppS,ModFunc,Arity] ->
- ModFunc++"/"++Arity
- end,
- {FileRef, [T#xmlText{value=Str}]}
- end;
+ [AppS, "doc", FileRef1] = split(AppRef, "/"),
+ FileRef = AppS++":"++otp_xmlify_a_fileref(FileRef1, AppS),
+ [#xmlText{value=Str0} = T] = Es0,
+ Str = case split(Str0, "/") of
+ %% //Application
+ [AppS2] ->
+ %% AppS2 can differ from AppS
+ %% Example: xmerl/XMerL
+ AppS2;
+ [_AppS,ModRef] ->
+ case split(ModRef, ":") of
+ %% //Application/Module
+ [Module] ->
+ Module++"(3)";
+ %% //Application/Module:Type()
+ [_Module,_Type] ->
+ ModRef
+ end;
+ %% //Application/Module:Function/Arity
+ [_AppS,ModFunc,Arity] ->
+ ModFunc++"/"++Arity
+ end,
+ {FileRef, [T#xmlText{value=Str}]};
otp_xmlify_a_href("../"++File, Es0) ->
%% Special case: This kind of relative path is used on some
%% places within i.e. EDoc and refers to a file within the same
@@ -639,13 +637,13 @@ otp_xmlify_table([#xmlText{} = E|Es]) ->
[E | otp_xmlify_table(Es)];
otp_xmlify_table([#xmlElement{name=tbody} = E|Es]) ->
otp_xmlify_table(E#xmlElement.content)++otp_xmlify_table(Es);
-otp_xmlify_table([#xmlElement{name=tr} = E|Es]) ->
+otp_xmlify_table([#xmlElement{name=tr, content=Content}|Es]) ->
%% Insert newlines between table rows
- otp_xmlify_table(E#xmlElement.content)++[{br,[]}]++otp_xmlify_table(Es);
-otp_xmlify_table([#xmlElement{name=th} = E|Es]) ->
- [{em, E#xmlElement.content} | otp_xmlify_table(Es)];
-otp_xmlify_table([#xmlElement{name=td} = E|Es]) ->
- otp_xmlify_e(E#xmlElement.content) ++ otp_xmlify_table(Es);
+ otp_xmlify_table(Content)++[{br,[]}]++otp_xmlify_table(Es);
+otp_xmlify_table([#xmlElement{name=th, content=Content}|Es]) ->
+ [{em, Content} | otp_xmlify_table(Es)];
+otp_xmlify_table([#xmlElement{name=td, content=Content}|Es]) ->
+ otp_xmlify_e(Content) ++ otp_xmlify_table(Es);
otp_xmlify_table([]) ->
[].
@@ -1155,8 +1153,8 @@ get_text(#xmlElement{content=[E]}) ->
%% text_only(Es) -> Ts
%% Takes a list of xmlElement and xmlText and return a lists of xmlText.
-text_only([#xmlElement{} = E |Es]) ->
- text_only(E#xmlElement.content) ++ text_only(Es);
+text_only([#xmlElement{content = Content}|Es]) ->
+ text_only(Content) ++ text_only(Es);
text_only([#xmlText{} = E |Es]) ->
[E | text_only(Es)];
text_only([]) ->
diff --git a/lib/docbuilder/src/docb_html.erl b/lib/docbuilder/src/docb_html.erl
index 9aea4c8a66..bdfc5ea876 100644
--- a/lib/docbuilder/src/docb_html.erl
+++ b/lib/docbuilder/src/docb_html.erl
@@ -283,16 +283,16 @@ rule([term|_], {_, [ID], _}, Opts) ->
ID,
"</strong></em> "]}, Opts};
TermList ->
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop, ["<em><strong>", ID,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, [ "<em><strong>", Name,
"</strong></em> "]},
Opts}
@@ -306,16 +306,16 @@ rule([term|_], {_, [ID], _}, Opts) ->
TermList ->
PartApplication =
docb_util:lookup_option(part_application, Opts),
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", ID,
"</a> "]}, Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", Name,
"</a> "]}, Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", Name,
"</a> "]}, Opts}
@@ -331,17 +331,16 @@ rule([cite|_], {_, [ID], _}, Opts) ->
{{drop, ["<em><strong>", ID, "</strong></em> "]},
Opts};
CiteList ->
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop,
["<em><strong>", ID, "</strong></em> "]},
Opts};
-
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts}
@@ -355,18 +354,18 @@ rule([cite|_], {_, [ID], _}, Opts) ->
CiteList ->
PartApp =
docb_util:lookup_option(part_application, Opts),
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", ID,
"</a> "]},
Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", Name,
"</a> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", Name,
"</a> "]},
@@ -376,7 +375,7 @@ rule([cite|_], {_, [ID], _}, Opts) ->
end;
rule([code|_], {_, [Type], [{pcdata, _, Code}]}, Opts) ->
- case lists:member(Type,["ERL","C","NONE"]) of
+ case lists:member(Type, ["ERL","C","NONE"]) of
true ->
{{drop, ["\n<div class=\"example\"><pre>\n", docb_html_util:element_cdata_to_html(Code),
"\n</pre></div>\n"]}, Opts};
diff --git a/lib/docbuilder/src/docb_html_util.erl b/lib/docbuilder/src/docb_html_util.erl
index b2951706ea..02ce8b52a7 100644
--- a/lib/docbuilder/src/docb_html_util.erl
+++ b/lib/docbuilder/src/docb_html_util.erl
@@ -136,7 +136,6 @@ copy_pics(Src, Dest, Opts) ->
Dir = code:lib_dir(docbuilder),
InFile = filename:join([Dir, "etc", Src]),
OutFile = docb_util:outfile(Dest, "", Opts),
-
case filelib:last_modified(OutFile) of
0 -> % File doesn't exist
file:copy(InFile, OutFile);
@@ -156,10 +155,10 @@ copy_pics(Src, Dest, Opts) ->
%%--Resolve header data-------------------------------------------------
extract_header_data(Key, {header, [], List}) ->
- case lists:keysearch(Key, 1, List) of
- {value, {Key, [], []}} ->
+ case lists:keyfind(Key, 1, List) of
+ {Key, [], []} ->
"";
- {value, {Key, [], [{pcdata, [], Value}]}} ->
+ {Key, [], [{pcdata, [], Value}]} ->
pcdata_to_html(Value);
false ->
""
@@ -253,7 +252,7 @@ make_anchor_href(HRef) ->
{ok, [HRef]} ->
%% No `#' in HRef, i.e. only path
make_anchor_href(HRef, "");
- {ok, [Path, Fragment]}->
+ {ok, [Path, Fragment]} ->
make_anchor_href(Path, Fragment)
end.
@@ -398,10 +397,10 @@ count_sections([]) ->
%%--Make a ToC----------------------------------------------------------
format_toc(Toc) ->
- lists:map(fun({Number, Title}) ->
- [Number, " <a href = \"#", Number,
- "\">", Title, "</a><br/>\n"]
- end, Toc).
+ [format_toc1(T) || T <- Toc].
+
+format_toc1({Number, Title}) ->
+ [Number, " <a href = \"#", Number, "\">", Title, "</a><br/>\n"].
%%--Convert HTML ISO Latin 1 characters to ordinary characters----------
diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl
index ef21f65557..87a1401a02 100644
--- a/lib/docbuilder/src/docb_main.erl
+++ b/lib/docbuilder/src/docb_main.erl
@@ -55,7 +55,7 @@ process(File, Opts) ->
%% If no target format is specified, assume HTML:
Tos = if
- Tos0==[] -> [html];
+ Tos0 =:= [] -> [html];
true -> Tos0
end,
@@ -327,12 +327,8 @@ verify(Tree) -> verify(Tree, [], 1).
verify({pcdata, Optional, _}, Path, Level) ->
verify_optional(Optional, Path, Level);
verify({Tag, Optional, Args}, Path, Level) when is_list(Args) ->
- case verify_optional(Optional, Path, Level) of
- true ->
- verify_list(Args, [Tag|Path], Level);
- false ->
- false
- end;
+ verify_optional(Optional, Path, Level)
+ andalso verify_list(Args, [Tag|Path], Level);
verify(Other, Path, Level) ->
verify_error(Other, Path, Level).
@@ -342,12 +338,7 @@ verify_error(X, Path, Level) ->
false.
verify_list([H|T], Path, Level) ->
- case verify(H, Path, Level) of
- true ->
- verify_list(T, Path, Level +1);
- false ->
- false
- end;
+ verify(H, Path, Level) andalso verify_list(T, Path, Level + 1);
verify_list([], _, _) ->
true.
@@ -419,7 +410,7 @@ edit1_list(_Tag, [], _Op) ->
%% Actual transformation of tree structure to desired format.
transform(From, To, Opts, File, Tree) ->
Filter = if
- To==html; To==kwic ->
+ To =:= html; To =:= kwic ->
list_to_atom("docb_tr_" ++ atom_to_list(From) ++
[$2|atom_to_list(To)]);
true ->
@@ -427,7 +418,7 @@ transform(From, To, Opts, File, Tree) ->
[$2|atom_to_list(To)])
end,
- case catch apply(Filter, transform, [File, Tree, Opts]) of
+ case catch Filter:transform(File, Tree, Opts) of
%% R5C
{'EXIT', {undef, [{Filter, transform, [File, Tree, Opts]}|_]}}->
@@ -459,9 +450,9 @@ transform(From, To, Opts, File, Tree) ->
finish_transform(Tree, File, Opts, Filter) ->
{Str, NewOpts} = pp(Tree, [], 1, Filter, Opts),
Extension =
- case catch apply(Filter, extension, [NewOpts]) of
+ case catch Filter:extension(NewOpts) of
{'EXIT', _} ->
- apply(Filter, extension, []);
+ Filter:extension();
Others ->
Others
end,
@@ -606,7 +597,7 @@ include_all(Fd) ->
eof ->
[];
ListOfChars ->
- lists:append(ListOfChars, include_all(Fd))
+ ListOfChars ++ include_all(Fd)
end.
extract(File, Fd, StartTag, StopTag, State) ->
diff --git a/lib/docbuilder/src/docb_pretty_format.erl b/lib/docbuilder/src/docb_pretty_format.erl
index 0c4fb0507b..25dcd8987b 100644
--- a/lib/docbuilder/src/docb_pretty_format.erl
+++ b/lib/docbuilder/src/docb_pretty_format.erl
@@ -47,7 +47,7 @@ term(Term) ->
%% the next line to need an "extra" indent!).
term([], Indent) ->
{Indent, [$[,$]]};
-term(L, Indent) when list(L) ->
+term(L, Indent) when is_list(L) ->
case is_string(L) of
true ->
{Indent, io_lib:write_string(L)};
@@ -59,7 +59,7 @@ term(L, Indent) when list(L) ->
write_simple_list(L, Indent)
end
end;
-term(T, Indent) when tuple(T) ->
+term(T, Indent) when is_tuple(T) ->
case complex_tuple(T) of
true ->
write_complex_tuple(T, Indent);
diff --git a/lib/docbuilder/src/docb_tr_application2html.erl b/lib/docbuilder/src/docb_tr_application2html.erl
index 4084cfe6ba..d8cb214d0a 100644
--- a/lib/docbuilder/src/docb_tr_application2html.erl
+++ b/lib/docbuilder/src/docb_tr_application2html.erl
@@ -119,8 +119,8 @@ transform(File, {application, _Attrs, [Header|Rest]}, Opts0) ->
case docb_main:parse1("fascicules", Opts0) of
{ok, Parse} ->
FascData = get_fasc_data(Parse),
- case lists:keysearch(File, 1, FascData) of
- {value, {_, _, "YES", _}} ->
+ case lists:keyfind(File, 1, FascData) of
+ {_, _, "YES", _} ->
OrigFile =
docb_util:outfile(File++"_frame",
".html", Opts0),
@@ -167,7 +167,7 @@ concat_files([File|Rest], Body, Opts) ->
%% Remove the reference manual header
[{Ref, [], [_Hdr| NewBody]}] = NewParse,
RefParse = [{Ref, [], NewBody}],
- lists:append(Body, concat_files(Rest, RefParse, Opts));
+ Body ++ concat_files(Rest, RefParse, Opts);
errors ->
errors
end;
@@ -216,7 +216,7 @@ make_toc([{lib, Attrs, More}|Rest]) ->
make_toc([{com, Attrs, More}|Rest]) ->
[{com, Attrs, More}|make_toc(Rest)];
make_toc([{_Tag, _Attrs, More}|Rest]) ->
- lists:append(make_toc(More), make_toc(Rest)).
+ make_toc(More) ++ make_toc(Rest).
rule([module|_], {_, [File], _}) ->
{"<small><a target=\"document\" href=\"" ++
@@ -280,9 +280,7 @@ get_fasc_data({fascicules, _, Fascs}) ->
Fascs).
get_avals(Atts) ->
- lists:map(fun(Tuple) ->
- element(3, Tuple) end,
- Atts).
+ [element(3, Tuple) || Tuple <- Atts].
get_pc_text([{pcdata, _, Text}]) ->
Text.
diff --git a/lib/docbuilder/src/docb_tr_cite2html.erl b/lib/docbuilder/src/docb_tr_cite2html.erl
index 4ecbfa4e91..77f1c4e636 100644
--- a/lib/docbuilder/src/docb_tr_cite2html.erl
+++ b/lib/docbuilder/src/docb_tr_cite2html.erl
@@ -39,24 +39,22 @@ purge_body([], _) ->
purge_body([{pcdata,_Attrs,_More}|Rest], CiteList) ->
purge_body(Rest, CiteList);
purge_body([{cite,[{"ID","CDATA",ID}],More}|Rest], CiteList) ->
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
[{cite, [{"NAME","CDATA",ID}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)];
- {value, {ID, Name, _Description, _Responsible}} ->
+ {ID, Name, _Description, _Responsible} ->
[{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)];
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
[{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)]
end;
purge_body([{_Tag,_Attrs,More}|Rest], CiteList) ->
- lists:append(purge_body(More, CiteList),
- purge_body(Rest, CiteList)).
+ purge_body(More, CiteList) ++ purge_body(Rest, CiteList).
rule([header|_], _) ->
{drop, ""};
-
rule(_, _) ->
{drop, ""}.
@@ -91,19 +89,19 @@ rule([cite|_], {_,[Name,ID], [{citedef,[],[{pcdata,[],Def}]}]}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
docb_util:message(warning,
"Global cite ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
docb_util:message(warning,
"Global cite ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
@@ -117,19 +115,19 @@ rule([cite|_], {_,[Name,ID],_}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
docb_util:message(error,
"The cite ~s has no definition", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
"??" ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
diff --git a/lib/docbuilder/src/docb_tr_index2html.erl b/lib/docbuilder/src/docb_tr_index2html.erl
index bbf419f3ef..312342add2 100644
--- a/lib/docbuilder/src/docb_tr_index2html.erl
+++ b/lib/docbuilder/src/docb_tr_index2html.erl
@@ -73,9 +73,7 @@ prune_flat([], _) ->
[].
keep_pcdata(Trees) ->
- lists:filter(fun({pcdata, _, _}) -> true;
- (_) -> false
- end, Trees).
+ [T || T = {pcdata, _, _} <- Trees].
new_trees(FileFuncs) ->
Files0 = [{File, RefType} || {File, RefType, _} <- FileFuncs],
diff --git a/lib/docbuilder/src/docb_tr_part2html.erl b/lib/docbuilder/src/docb_tr_part2html.erl
index dd44c4a8df..30befe8432 100644
--- a/lib/docbuilder/src/docb_tr_part2html.erl
+++ b/lib/docbuilder/src/docb_tr_part2html.erl
@@ -93,8 +93,8 @@ transform(File, {part, _Attrs, [Header| Rest]}, Opts0) ->
case docb_main:parse1("fascicules", Opts0) of
{ok, Parse} ->
FascData = get_fasc_data(Parse),
- case lists:keysearch(File, 1, FascData) of
- {value, {_, _, "YES", _}} ->
+ case lists:keyfind(File, 1, FascData) of
+ {_, _, "YES", _} ->
OrigFile =
docb_util:outfile(File++"_frame",
".html", Opts0),
@@ -137,7 +137,7 @@ concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
case docb_main:parse1(File, Opts) of
{ok, Parse} ->
{TopTag, Attrs, [Header = {header, _, HeaderContents} | More]} = Parse,
- {value,{title,_,Title}} = lists:keysearch(title,1,HeaderContents),
+ {title,_,Title} = lists:keyfind(title,1,HeaderContents),
NewMore = [{section, [], [{title, [], Title}| More]}],
NewParse = {TopTag, Attrs, [Header| NewMore]},
if
@@ -156,9 +156,8 @@ concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
docb_html_util:number(NewParse,
integer_to_list(ChLevel), File),
{_, [], [_| NewBody]} = NumberTree,
- lists:append(Body,
- concat_files(Rest, NewBody, ChLevel+1, Opts,
- TP, TOpts, Ext));
+ Body ++ concat_files(Rest, NewBody, ChLevel+1, Opts,
+ TP, TOpts, Ext);
errors ->
throw({error,"Parse error when building chapter "++File})
end;
@@ -232,9 +231,7 @@ get_fasc_data({fascicules, _, Fascs}) ->
Fascs).
get_avals(Atts) ->
- lists:map(fun(Tuple) ->
- element(3, Tuple) end,
- Atts).
+ [element(3, Tuple) || Tuple <- Atts].
get_pc_text([{pcdata, _, Text}]) ->
Text.
diff --git a/lib/docbuilder/src/docb_tr_term2html.erl b/lib/docbuilder/src/docb_tr_term2html.erl
index 0a993cebb1..a3c4a5312a 100644
--- a/lib/docbuilder/src/docb_tr_term2html.erl
+++ b/lib/docbuilder/src/docb_tr_term2html.erl
@@ -39,24 +39,22 @@ purge_body([], _) ->
purge_body([{pcdata,_Attrs,_More}|Rest], TermList) ->
purge_body(Rest, TermList);
purge_body([{term,[{"ID","CDATA",ID}],More}|Rest], TermList) ->
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
[{term,[{"NAME","CDATA",ID},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)];
- {value, {ID, Name, _Description, _Responsible}} ->
+ {ID, Name, _Description, _Responsible} ->
[{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)];
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
[{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)]
end;
purge_body([{_Tag,_Attrs,More}|Rest], TermList) ->
- lists:append(purge_body(More, TermList),
- purge_body(Rest, TermList)).
+ purge_body(More, TermList) ++ purge_body(Rest, TermList).
rule([header|_], _) ->
{drop, ""};
-
rule(_, _) ->
{drop, ""}.
@@ -82,19 +80,19 @@ rule([term|_], {_,[Name,ID],[{termdef,[],[{pcdata,[],Def}]}]}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a>\n</dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
docb_util:message(warning,
"Global term ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
docb_util:message(warning,
"Global term ~s overriding local", [ID]),
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
@@ -107,19 +105,19 @@ rule([term|_], {_,[Name,ID],_}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
docb_util:message(error,
"The term ~s has no definition", [ID]),
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
"??" ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
diff --git a/lib/docbuilder/src/docb_transform.erl b/lib/docbuilder/src/docb_transform.erl
index a432038adf..9c7561b07b 100644
--- a/lib/docbuilder/src/docb_transform.erl
+++ b/lib/docbuilder/src/docb_transform.erl
@@ -135,8 +135,8 @@ parse([Opt | _RawOpts], _Opts) ->
get_defs(Type, File, Opts) ->
Key = {defs,Type},
{PrevDefs, Opts2} =
- case lists:keysearch(Key, 1, Opts) of
- {value, {_, Defs0}} ->
+ case lists:keyfind(Key, 1, Opts) of
+ {_, Defs0} ->
{Defs0, lists:keydelete(Key, 1, Opts)};
false ->
{[], Opts}
diff --git a/lib/docbuilder/src/docb_util.erl b/lib/docbuilder/src/docb_util.erl
index 59673ef3a4..9b2eec7733 100644
--- a/lib/docbuilder/src/docb_util.erl
+++ b/lib/docbuilder/src/docb_util.erl
@@ -61,7 +61,7 @@ html_snippet(What, Opts) ->
case lookup_option(html_mod, Opts) of
false -> "";
Module ->
- case catch apply(Module, What, []) of
+ case catch Module:What() of
HTML when is_list(HTML) ->
HTML;
{'EXIT', {undef, _}} ->
@@ -82,7 +82,7 @@ html_snippet(What, Arg, Opts) ->
case lookup_option(html_mod, Opts) of
false -> "";
Module ->
- case catch apply(Module, What, [Arg]) of
+ case catch Module:What(Arg) of
HTML when is_list(HTML) ->
HTML;
{'EXIT', {undef, _}} ->
@@ -106,8 +106,8 @@ html_snippet(What, Arg, Opts) ->
%% lookup_option(Opt, Opts) -> Value | false
lookup_option(Opt, Opts) ->
- case lists:keysearch(Opt, 1, Opts) of
- {value, {Opt,Value}} -> Value;
+ case lists:keyfind(Opt, 1, Opts) of
+ {Opt,Value} -> Value;
false -> false
end.
diff --git a/lib/docbuilder/src/docb_xmerl_tree_cb.erl b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
index d57f55bff8..bc62069230 100644
--- a/lib/docbuilder/src/docb_xmerl_tree_cb.erl
+++ b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
@@ -188,8 +188,8 @@ attrs(DTD, Tag, GivenAttrs) ->
merge_attrs(Tag, default_attrs(DTD, Tag), GivenAttrs).
merge_attrs(Tag, [{NameA, Type, DefVal}|Default], GivenAttrs) ->
- Val = case lists:keysearch(NameA, #xmlAttribute.name, GivenAttrs) of
- {value, #xmlAttribute{value=Val0}} -> Val0;
+ Val = case lists:keyfind(NameA, #xmlAttribute.name, GivenAttrs) of
+ #xmlAttribute{value=Val0} -> Val0;
false -> DefVal
end,
Attr = {attr_name(NameA), Type, attr_val(Type, Val)},
diff --git a/lib/docbuilder/vsn.mk b/lib/docbuilder/vsn.mk
index 2852ebcc8b..5bb92fd209 100644
--- a/lib/docbuilder/vsn.mk
+++ b/lib/docbuilder/vsn.mk
@@ -1,14 +1 @@
DOCB_VSN = 0.9.8.7
-
-TICKETS = OTP-8343
-
-TICKETS_0.9.8.6 = OTP-8201
-
-TICKETS_0.9.8.5 = OTP-7851
-
-TICKETS_0.9.8.4 = OTP-7236
-
-TICKETS_0.9.8.1 = OTP-7236
-
-
-
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index 47e61f7932..5b7fb1e0d2 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -472,7 +472,7 @@ uri_get_file(File0) ->
uri_get_http(URI) ->
%% Try using option full_result=false
- case catch {ok, http:request(get, {URI,[]}, [],
+ case catch {ok, httpc:request(get, {URI,[]}, [],
[{full_result, false}])} of
{'EXIT', _} ->
uri_get_http_r10(URI);
@@ -482,7 +482,7 @@ uri_get_http(URI) ->
uri_get_http_r10(URI) ->
%% Try most general form of request
- Result = (catch {ok, http:request(get, {URI,[]}, [], [])}),
+ Result = (catch {ok, httpc:request(get, {URI,[]}, [], [])}),
uri_get_http_1(Result, URI).
uri_get_http_1(Result, URI) ->
diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml
index abf705f9e2..927395d1bf 100644
--- a/lib/erl_interface/doc/src/ei_connect.xml
+++ b/lib/erl_interface/doc/src/ei_connect.xml
@@ -54,7 +54,7 @@
the operation, if the primitive does not complete within the time
specified, the function will return an error and
<c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[ETIMEDOUT]]></c>. With
- communication primitive is ment an operation on the socket, like
+ communication primitive is meant an operation on the socket, like
<c><![CDATA[connect]]></c>, <c><![CDATA[accept]]></c>, <c><![CDATA[recv]]></c> or <c><![CDATA[send]]></c>.</p>
<p>Obviously the timeouts are for implementing fault tolerance,
not to keep hard realtime promises. The <c><![CDATA[_tmo]]></c> functions
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index c57c552b90..18315bfbd3 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
+#include <limits.h>
#include "erl_interface.h"
#include "erl_marshal.h"
@@ -178,26 +179,14 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
return 0;
case ERL_INTEGER:
- i = ep->uval.ival.i;
- /* ERL_SMALL_BIG */
- if ((i > ERL_MAX) || (i < ERL_MIN)) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte */
- i = -i;
- *(*ext)++ = i & 0xff; /* LSB first */
- *(*ext)++ = (i >> 8) & 0xff;
- *(*ext)++ = (i >> 16) & 0xff;
- *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */
- return 0;
- }
+ i = ep->uval.ival.i;
/* SMALL_INTEGER */
if ((i < 256) && (i >= 0)) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = i & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (i >> 24) & 0xff;
*(*ext)++ = (i >> 16) & 0xff;
@@ -208,23 +197,23 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_INTEGER:
u = ep->uval.uival.u;
/* ERL_U_SMALL_BIG */
- if (u > ERL_MAX) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- *(*ext)++ = 0; /* sign byte */
- *(*ext)++ = u & 0xff; /* LSB first */
- *(*ext)++ = (u >> 8) & 0xff;
- *(*ext)++ = (u >> 16) & 0xff;
- *(*ext)++ = (u >> 24) & 0xff;
- return 0;
+ if ((int)u < 0) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 4; /* four bytes */
+ *(*ext)++ = 0; /* sign byte */
+ *(*ext)++ = u & 0xff; /* LSB first */
+ *(*ext)++ = (u >> 8) & 0xff;
+ *(*ext)++ = (u >> 16) & 0xff;
+ *(*ext)++ = (u >> 24) & 0xff;
+ return 0;
}
/* SMALL_INTEGER */
- if ((u < 256) && (u >= 0)) {
+ if (u < 256) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = u & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (u >> 24) & 0xff;
*(*ext)++ = (u >> 16) & 0xff;
@@ -234,29 +223,28 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_LONGLONG:
l = ep->uval.llval.i;
/* ERL_SMALL_BIG */
- if ((l > ((long long) ERL_MAX)) ||
- (l < ((long long) ERL_MIN))) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 8; /* eight bytes */
- if ((*(*ext)++ = ((l>>63) & 0x01))) /* sign byte */
+ if (l > ((long long) INT_MAX) || l < ((long long) INT_MIN)) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 8;
+ if ((*(*ext)++ = (l<0))) /* sign byte */
l = -l;
- *(*ext)++ = l & 0xff; /* LSB first */
+ *(*ext)++ = l & 0xff; /* LSB first */
*(*ext)++ = (l >> 8) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
- *(*ext)++ = (l >> 24) & 0xff;
- *(*ext)++ = (l >> 32) & 0xff;
- *(*ext)++ = (l >> 40) & 0xff;
- *(*ext)++ = (l >> 48) & 0xff;
- *(*ext)++ = (l >> 56) & 0x7f; /* Don't include the sign bit */
+ *(*ext)++ = (l >> 24) & 0xff;
+ *(*ext)++ = (l >> 32) & 0xff;
+ *(*ext)++ = (l >> 40) & 0xff;
+ *(*ext)++ = (l >> 48) & 0xff;
+ *(*ext)++ = (l >> 56) & 0xff;
return 0;
}
/* SMALL_INTEGER */
if ((l < 256) && (l >= 0)) {
- *(*ext)++ = ERL_SMALL_INTEGER_EXT;
- *(*ext)++ = l & 0xff;
- return 0;
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = l & 0xff;
+ return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (l >> 24) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
@@ -267,7 +255,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_LONGLONG:
ul = ep->uval.ullval.u;
/* ERL_U_SMALL_BIG */
- if (ul > ((unsigned long long) ERL_MAX)) {
+ if (ul > ((unsigned long long) INT_MAX)) {
*(*ext)++ = ERL_SMALL_BIG_EXT;
*(*ext)++ = 8; /* eight bytes */
*(*ext)++ = 0; /* sign byte */
@@ -287,7 +275,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
*(*ext)++ = ul & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (ul >> 24) & 0xff;
*(*ext)++ = (ul >> 16) & 0xff;
@@ -732,11 +720,6 @@ static ETERM *erl_decode_it(unsigned char **ext)
if (arity > 8)
goto big_truncate;
- if (arity == 8 && ((*ext)[7] & 0x80) && sign) {
- /* MSB already occupied ! */
- goto big_truncate;
- }
-
if (arity == 4 && ((*ext)[3] & 0x80) && !sign) {
/* It will fit into an unsigned int !! */
u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext));
@@ -747,14 +730,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
return ep;
} else if (arity == 4 && !((*ext)[3] & 0x80)) {
/* It will fit into an int !!
- * Note: It comes in "one's-complement notation"
*/
- if (sign)
- i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign);
- else
- i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext));
+ i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
+ ((*ext)[1]) << 8 | (**ext));
+ if (sign) i = -i;
ERL_TYPE(ep) = ERL_INTEGER;
ep->uval.ival.i = i;
*ext += arity;
@@ -780,8 +759,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
for(x = 0 ; x < arity ; x++) {
l |= ((long long)(*ext)[x]) << ((long long)(8*x));
}
-
- if (sign) l = (long long) (~l | (unsigned long long) sign);
+ if (sign) {
+ l = -l;
+ if (l > 0) goto big_truncate;
+ }
ERL_TYPE(ep) = ERL_LONGLONG;
ep->uval.llval.i = l;
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
index ddcbfa5a9a..75c5dc9460 100644
--- a/lib/erl_interface/src/misc/ei_decode_term.c
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -34,7 +34,6 @@ int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
const char* s = buf + *index, * s0 = s;
int len, i, n, sign;
char c;
- double f;
if (term == NULL) return -1;
c = term->ei_type = get8(s);
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index f0d638324d..93b84cbb36 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -812,7 +812,8 @@ static int get_module(char **mbuf, char **mname)
*mname = (char *) calloc(i+1, sizeof(char));
memcpy(*mname, start, i);
}
- free(mbuf); /* Allocated in read_stdin() */
+ if (*mbuf)
+ free(*mbuf); /* Allocated in read_stdin() */
return len;
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index c6858b45ad..09a37409f2 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -222,14 +222,16 @@ send_integers(P) ->
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
-
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
-
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
+
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest (32 bis)
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
+
case erlang:system_info(wordsize) of
4 ->
?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
@@ -266,15 +268,17 @@ send_integers2(P) ->
?line send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
+
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
- ?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32
?line send_term_as_binary(P, 16#7fffffffffff), % largest i48
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 5447e2deb3..b349138ae9 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
@@ -246,13 +246,23 @@ TESTCASE(test_ei_decode_long)
EI_DECODE_2 (decode_long, 5, long, 256);
EI_DECODE_2 (decode_long, 5, long, -1);
+ /* Old 28 bit limits for INTEGER_EXT */
EI_DECODE_2 (decode_long, 5, long, 0x07ffffff);
EI_DECODE_2 (decode_long, 5, long, -0x08000000);
- EI_DECODE_2 (decode_long, 7, long, 0x08000000);
- EI_DECODE_2 (decode_long, 7, long, -0x08000001);
+ EI_DECODE_2 (decode_long, 5, long, 0x08000000);
+ EI_DECODE_2 (decode_long, 5, long, -0x08000001);
- EI_DECODE_2 (decode_long, 7, long, 0x7fffffff);
- EI_DECODE_2 (decode_long, 7, long, -ll(0x80000000)); /* Strange :-( */
+ /* New 32 bit limits for INTEGER_EXT */
+ EI_DECODE_2 (decode_long, 5, long, 0x7fffffff);
+ EI_DECODE_2 (decode_long, 5, long, -ll(0x80000000)); /* Strange :-( */
+ if (sizeof(long) > 4) {
+ EI_DECODE_2(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2(decode_long, 7, long, -ll(0x80000001));
+ }
+ else {
+ EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_long, 7, long, -ll(0x80000001));
+ }
EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
EI_DECODE_2_FAIL(decode_long, 7, long, 0xffffffff);
@@ -280,11 +290,13 @@ TESTCASE(test_ei_decode_ulong)
EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000000);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -0x08000001);
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000001);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000001));
if (sizeof(long) > 4) {
EI_DECODE_2 (decode_ulong, 11, unsigned long, ll(0x8000000000000000));
@@ -319,13 +331,14 @@ TESTCASE(test_ei_decode_longlong)
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x07ffffff);
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x7fffffff);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x08000000);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x7fffffff);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x80000000);
+ EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000001));
+
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0xffffffff);
EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, ll(0x7fffffffffff));
@@ -352,13 +365,14 @@ TESTCASE(test_ei_decode_ulonglong)
EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000000);
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x80000001);
+
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0xffffffff);
EI_DECODE_2 (decode_ulonglong, 9, EI_ULONGLONG, ll(0x7fffffffffff));
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
index 6b2ec8f766..f273efd532 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
@@ -63,32 +63,108 @@ TESTCASE(build_terms)
report(1);
}
+static int abs_and_sign(ETERM* v, unsigned long long* av, int* sign)
+{
+ long long sv;
+ switch (ERL_TYPE(v)) {
+ case ERL_INTEGER: sv = ERL_INT_VALUE(v); break;
+ case ERL_U_INTEGER: *av = ERL_INT_UVALUE(v); *sign = 0; return 1;
+ case ERL_LONGLONG: sv = ERL_LL_VALUE(v); break;
+ case ERL_U_LONGLONG: *av = ERL_LL_UVALUE(v); *sign = 0; return 1;
+ default: return 0;
+ }
+ if (sv < 0) {
+ *av = -sv;
+ *sign = 1;
+ }
+ else {
+ *av = sv;
+ *sign = 0;
+ }
+ return 1;
+}
+
+/* Shouldn't erl_match() cope with this?
+*/
+static int eq_ints(ETERM* a, ETERM* b)
+{
+ unsigned long long a_abs, b_abs;
+ int a_sign, b_sign;
+ return abs_and_sign(a, &a_abs, &a_sign) && abs_and_sign(b, &b_abs, &b_sign)
+ && (a_abs == b_abs) && (a_sign == b_sign);
+}
+
+static void encode_decode(ETERM* original, const char* text)
+{
+ static unsigned char encoded[16*1024];
+ ETERM* new_terms;
+ int bytes = erl_encode(original, encoded);
+
+ if (bytes == 0) {
+ fail("failed to encode terms");
+ }
+ else if (bytes > sizeof(encoded)) {
+ fail("encoded terms buffer overflow");
+ }
+ else if ((new_terms = erl_decode(encoded)) == NULL) {
+ fail("failed to decode terms");
+ }
+ else if (!erl_match(original, new_terms) && !eq_ints(original, new_terms)) {
+ erl_print_term(stderr, original);
+ fprintf(stderr, "(%i) != (%i)", ERL_TYPE(original), ERL_TYPE(new_terms));
+ erl_print_term(stderr, new_terms);
+ fprintf(stderr, " [%s]\r\n", text);
+ fail("decoded terms didn't match original");
+ }
+ erl_free_term(original);
+ erl_free_term(new_terms);
+}
/*
* Converts an Erlang term to the external term format and back again.
*/
TESTCASE(round_trip_conversion)
{
- ETERM* original;
- ETERM* new_terms;
- char encoded[16*1024];
- int n;
+ int n, i;
erl_init(NULL, 0);
- original = all_types();
- if (erl_encode(original, encoded) == 0)
+ encode_decode(all_types(), "ALL");
+
{
- fail("failed to encode terms");
- } else if ((new_terms = erl_decode(encoded)) == NULL)
+ int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_int(v+i), "INT");
+ encode_decode(erl_mk_int(-(v+i)), "NEG INT");
+ }
+ }
+ }
{
- fail("failed to decode terms");
- } else if (!erl_match(original, new_terms))
+ unsigned int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_uint(v+i), "UINT");
+ }
+ }
+ }
{
- fail("decoded terms didn't match original");
+ long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_longlong(v+i), "LONGLONG");
+ encode_decode(erl_mk_longlong(-(v+i)), "NEG LONGLONG");
+ }
+ }
+ }
+ {
+ unsigned long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_ulonglong(v+i), "ULONGLONG");
+ }
+ }
}
- erl_free_term(original);
- erl_free_term(new_terms);
report(1);
}
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index b7d65b12a2..c3a42af156 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -17,8 +17,3 @@
# %CopyrightEnd%
ET_VSN = 1.4
-TICKETS = OTP-8058
-
-TICKETS_1_3_3 = OTP-8201
-TICKETS_1_3_2 = OTP-8078
-TICKETS_1_3_1 = OTP-7830
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index 2583f0be25..be05a13fba 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -913,7 +913,7 @@ To make the descriptions simpler, we first list some definitions:
<td>`CleanupX'</td><td>`(X::any(), R::any()) -> any()'</td>
</tr>
<tr>
-<td>`Instantiator'</td><td>`((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}'</td>
+<td>`Instantiator'</td><td>`((R::any()) -> Tests | {with, [AbstractTestFun::((any()) -> any())]}'</td>
</tr>
<tr>
<td>`Where'</td><td>`local | spawn | {spawn, Node::atom()}'</td>
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 9df3dedb45..6eeeab3610 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -1638,7 +1638,6 @@ type(erlang, system_info, 1, Xs) ->
t_non_neg_integer()])]));
['allocator'] ->
t_tuple([t_sup([t_atom('undefined'),
- t_atom('elib_malloc'),
t_atom('glibc')]),
t_list(t_integer()),
t_list(t_atom()),
@@ -1659,9 +1658,8 @@ type(erlang, system_info, 1, Xs) ->
t_binary();
['dist_ctrl'] ->
t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])]));
- ['elib_malloc'] ->
- t_sup([t_atom('false'),
- t_list(t_tuple([t_atom(), t_any()]))]);
+ %% elib_malloc is intentionally not included,
+ %% because it scheduled for removal in R15.
['endian'] ->
t_endian();
['fullsweep_after'] ->
@@ -2337,8 +2335,7 @@ type(lists, flatten, 1, Xs) ->
t_list();
false ->
X2 = type(lists, flatten, 1, [t_inf(X1, t_list())]),
- t_sup(t_list(t_subtract(X1, t_list())),
- X2)
+ t_sup(t_list(t_subtract(X1, t_list())), X2)
end
end
end);
@@ -2349,10 +2346,20 @@ type(lists, flatmap, 2, Xs) ->
true -> t_nil();
false ->
case check_fun_application(F, [t_list_elements(List)]) of
- ok ->
- case t_is_cons(List) of
- true -> t_nonempty_list(t_list_elements(t_fun_range(F)));
- false -> t_list(t_list_elements(t_fun_range(F)))
+ ok ->
+ R = t_fun_range(F),
+ case t_is_nil(R) of
+ true -> t_nil();
+ false ->
+ Elems = t_list_elements(R),
+ case t_is_cons(List) of
+ true ->
+ case t_is_subtype(t_nil(), R) of
+ true -> t_list(Elems);
+ false -> t_nonempty_list(Elems)
+ end;
+ false -> t_list(Elems)
+ end
end;
error ->
case t_is_cons(List) of
diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl
index 560e0259f8..0361053676 100644
--- a/lib/hipe/rtl/hipe_rtl_primops.erl
+++ b/lib/hipe/rtl/hipe_rtl_primops.erl
@@ -701,9 +701,9 @@ gen_cons(Dst, [Arg1, Arg2]) ->
%% Increase refcount
%% fe->refc++;
%%
-%% Link to the process off_heap.funs list
-%% funp->next = p->off_heap.funs;
-%% p->off_heap.funs = funp;
+%% Link to the process off_heap list
+%% funp->next = p->off_heap.first;
+%% p->off_heap.first = funp;
%%
%% Tag the thing
%% return make_fun(funp);
@@ -729,9 +729,9 @@ gen_mkfun([Dst], {_Mod, _FunId, _Arity} = MFidA, MagicNr, Index, FreeVars) ->
%% fe->refc++;
SkeletonCode = gen_fun_thing_skeleton(HP, MFidA, NumFree, MagicNr, Index),
- %% Link to the process off_heap.funs list
- %% funp->next = p->off_heap.funs;
- %% p->off_heap.funs = funp;
+ %% Link to the process off_heap list
+ %% funp->next = p->off_heap.first;
+ %% p->off_heap.first = funp;
LinkCode = gen_link_closure(HP),
%% Tag the thing and increase the heap_pointer.
@@ -797,14 +797,14 @@ gen_link_closure(FUNP) ->
end.
gen_link_closure_private(FUNP) ->
- %% Link to the process off_heap.funs list
- %% funp->next = p->off_heap.funs;
- %% p->off_heap.funs = funp;
+ %% Link fun to the process off_heap list
+ %% funp->next = p->off_heap.first;
+ %% p->off_heap.first = funp;
FunsVar = hipe_rtl:mk_new_reg(),
- [load_p_field(FunsVar,?P_OFF_HEAP_FUNS),
+ [load_p_field(FunsVar,?P_OFF_HEAP_FIRST),
hipe_rtl:mk_store(FUNP, hipe_rtl:mk_imm(?EFT_NEXT), FunsVar),
- store_p_field(FUNP,?P_OFF_HEAP_FUNS)].
+ store_p_field(FUNP,?P_OFF_HEAP_FIRST)].
gen_link_closure_non_private(_FUNP) -> [].
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index dc44b803a1..c0b6dfad8a 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -849,9 +849,9 @@ create_refc_binary(Base, Size, Flags, Dst) ->
heap_arch_spec(HP) ->
Tmp1 = hipe_rtl:mk_new_reg(), % MSO state
- [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_MSO),
+ [hipe_rtl_arch:pcb_load(Tmp1, ?P_OFF_HEAP_FIRST),
set_field_from_pointer({proc_bin, next}, HP, Tmp1),
- hipe_rtl_arch:pcb_store(?P_OFF_HEAP_MSO, HP)].
+ hipe_rtl_arch:pcb_store(?P_OFF_HEAP_FIRST, HP)].
test_heap_binary(Binary, TrueLblName, FalseLblName) ->
Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
index 4aa2a04b60..074d0b3d39 100644
--- a/lib/ic/vsn.mk
+++ b/lib/ic/vsn.mk
@@ -1,20 +1 @@
IC_VSN = 4.2.25
-
-TICKETS = OTP-8639
-
-TICKETS_4.2.24 = OTP-8307 \
- OTP-8353 \
- OTP-8354 \
- OTP-8355
-
-TICKETS_4.2.23 = OTP-8201
-
-TICKETS_4.2.22 = OTP-8088
-
-TICKETS_4.2.21 = OTP-7982
-
-TICKETS_4.2.20 = OTP-7837
-
-TICKETS_4.2.19 = OTP-7595
-
-TICKETS_4.2.18 = OTP-7313
diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml
index 510c30eb35..ea8053cafa 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>2009</year>
+ <year>2004</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -56,8 +56,8 @@
<pre>
[{inets, [{services, [{httpc, PropertyList}]}]}]
</pre>
- <p>For valid properties see <seealso
- marker="http">http(3)</seealso></p>
+ <p>For valid properties see
+ <seealso marker="http">httpc(3)</seealso>. </p>
</section>
<section>
@@ -71,67 +71,66 @@
but not for requests to localhost. This will apply to all subsequent
requests</p>
<code type="erl">
- 2 > http:set_options([{proxy, {{"www-proxy.mycompany.com", 8000},
+ 2 > httpc:set_options([{proxy, {{"www-proxy.mycompany.com", 8000},
["localhost"]}}]).
ok
</code>
<p>An ordinary synchronous request. </p>
<code type="erl">
3 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
- http:request(get, {"http://www.erlang.org", []}, [], []).
+ httpc:request(get, {"http://www.erlang.org", []}, [], []).
</code>
<p>With all default values, as above, a get request can also be written
like this.</p>
<code type="erl">
4 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
- http:request("http://www.erlang.org").
+ httpc:request("http://www.erlang.org").
</code>
<p>An ordinary asynchronous request. The result will be sent
to the calling process on the form {http, {ReqestId, Result}}</p>
<code type="erl">
5 > {ok, RequestId} =
- http:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]).
+ httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]).
</code>
<p>In this case the calling process is the shell, so we receive the
result.</p>
<code type="erl">
- 6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end.
+ 6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end.
ok
</code>
<p>Send a request with a specified connection header. </p>
<code type="erl">
7 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} =
- http:request(get, {"http://www.erlang.org", [{"connection", "close"}]},
+ httpc:request(get, {"http://www.erlang.org", [{"connection", "close"}]},
[], []).
</code>
<p>Start a HTTP client profile. </p>
<code><![CDATA[
- 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]).
+ 8 > {ok, Pid} = inets:start(httpc, [{profile, foo}]).
{ok, <0.45.0>}
]]></code>
<p>The new profile has no proxy settings so the connection will
be refused</p>
<code type="erl">
- 9 > http:request("http://www.erlang.org", foo).
- {error,econnrefused}
+ 9 > httpc:request("http://www.erlang.org", foo).
+ {error, econnrefused}
</code>
<p>Stop a HTTP client profile. </p>
<code type="erl">
- 10 > inets:stop(httpc, foo).
+ 10 > inets:stop(httpc, foo).
ok
</code>
<p>Alternatively:</p>
<code type="erl">
- 10 > inets:stop(httpc, Pid).
+ 10 > inets:stop(httpc, Pid).
ok
</code>
-
</section>
</chapter>
diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml
index 81dfe7e944..c367d7fa77 100644
--- a/lib/inets/doc/src/inets.xml
+++ b/lib/inets/doc/src/inets.xml
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>inets</title>
@@ -40,13 +40,13 @@
<title>COMMON DATA TYPES </title>
<p>Type definitions that are used more than once in
this module: </p>
- <p><c> service() = ftpc | tfptd | httpc | httpd</c></p>
+ <p><c> service() = ftpc | tftp | httpc | httpd</c></p>
<p><c> property() = atom() </c></p>
</section>
<funcs>
<func>
<name>services() -> [{Service, Pid}]</name>
- <fsummary>Returns a list of currently running services. </fsummary>
+ <fsummary>Returns a list of currently running services. </fsummary>
<type>
<v>Service = service()</v>
<v>Pid = pid()</v>
@@ -97,7 +97,7 @@
<name>start(Type) -> ok | {error, Reason}</name>
<fsummary>Starts the Inets application. </fsummary>
<type>
- <v>Type = permanent | transient | temporary</v>
+ <v>Type = permanent | transient | temporary</v>
</type>
<desc>
<p>Starts the Inets application. Default type
@@ -115,11 +115,9 @@
</func>
<func>
<name>start(Service, ServiceConfig) -> {ok, Pid} | {error, Reason}</name>
- <name>start(Service, ServiceConfig, How) -> {ok, Pid} |
- {error, Reason}</name>
+ <name>start(Service, ServiceConfig, How) -> {ok, Pid} | {error, Reason}</name>
<fsummary>Dynamically starts an inets
- service after the inets application has been
- started. </fsummary>
+ service after the inets application has been started. </fsummary>
<type>
<v>Service = service()</v>
<v>ServiceConfig = [{Option, Value}]</v>
@@ -153,9 +151,9 @@
<fsummary>Stops a started service of the inets application or takes
down a "stand_alone-service" gracefully.</fsummary>
<type>
- <v>Service = service() | stand_alone</v>
+ <v>Service = service() | stand_alone</v>
<v>Reference = pid() | term() - service specified reference</v>
- <v>Reason = term()</v>
+ <v>Reason = term()</v>
</type>
<desc>
<p>Stops a started service of the inets application or takes
@@ -169,7 +167,7 @@
<section>
<title>SEE ALSO</title>
<p><seealso marker="ftp">ftp(3)</seealso>,
- <seealso marker="http">http(3)</seealso>,
+ <seealso marker="httpc">httpc(3)</seealso>,
<seealso marker="httpd">httpd(3)</seealso>,
<seealso marker="tftp">tftp(3)</seealso></p>
</section>
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index c34b641b7b..8af6613fa2 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -605,24 +605,29 @@ handle_info({ssl_error, _, _} = Reason, State) ->
%% Internally, to a request handling process, a request timeout is
%% seen as a canceled request.
handle_info({timeout, RequestId},
- #state{request = #request{id = RequestId} = Request,
- canceled = Canceled} = State) ->
+ #state{request = #request{id = RequestId} = Request,
+ canceled = Canceled,
+ profile_name = ProfileName} = State) ->
?hcri("timeout of current request", [{id, RequestId}]),
httpc_response:send(Request#request.from,
httpc_response:error(Request, timeout)),
+ httpc_manager:request_done(RequestId, ProfileName),
?hcrv("response (timeout) sent - now terminate", []),
{stop, normal,
State#state{request = Request#request{from = answer_sent},
canceled = [RequestId | Canceled]}};
-handle_info({timeout, RequestId}, #state{canceled = Canceled} = State) ->
+handle_info({timeout, RequestId},
+ #state{canceled = Canceled,
+ profile_name = ProfileName} = State) ->
?hcri("timeout", [{id, RequestId}]),
Filter =
fun(#request{id = Id, from = From} = Request) when Id =:= RequestId ->
?hcrv("found request", [{id, Id}, {from, From}]),
%% Notify the owner
- Response = httpc_response:error(Request, timeout),
- httpc_response:send(From, Response),
+ httpc_response:send(From,
+ httpc_response:error(Request, timeout)),
+ httpc_manager:request_done(RequestId, ProfileName),
?hcrv("response (timeout) sent", []),
[Request#request{from = answer_sent}];
(_) ->
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index d5d6376369..1e1bde220b 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -66,15 +66,6 @@
state % State of the handler: initiating | started | operational | canceled
}).
-%% Entries in the handler / request cross-ref table
-%% -record(request_info,
-%% {
-%% id, % Id of the request
-%% handler, % Pid of the handler process
-%% from, % The From value for the caller
-%% mref % Monitor ref for the caller
-%% }).
-
%%====================================================================
%% Internal Application API
@@ -577,7 +568,9 @@ handle_info({'EXIT', Pid, Reason}, #state{handler_db = HandlerDb} = State) ->
handle_info({'DOWN', _, _, Pid, _}, State) ->
%%
- %% Check what happens to waiting requests! Chall we not send a reply?
+ %% Normally this should have been cleaned up already
+ %% (when receiving {request_done, PequestId}), but
+ %% just in case there is a glitch, cleanup anyway.
%%
Pattern = #handler_info{handler = Pid, _ = '_'},
@@ -649,7 +642,16 @@ get_handler_info(Tab) ->
Acc
end,
Handlers2 = lists:foldl(F, [], Handlers1),
- Handlers3 = [{Pid, State, httpc_handler:info(Pid)} ||
+ Handlers3 = [{Pid, State,
+ case (catch httpc_handler:info(Pid)) of
+ {'EXIT', _} ->
+ %% Why would this crash?
+ %% Only if the process has died, but we don't
+ %% know about it?
+ [];
+ Else ->
+ Else
+ end} ||
{Pid, State} <- Handlers2],
Handlers3.
@@ -666,6 +668,10 @@ handle_started(StarterPid, ReqId, HandlerPid,
case ets:lookup(HandlerDb, ReqId) of
[#handler_info{state = initiating} = HandlerInfo] ->
?hcri("received started ack for initiating handler", []),
+ %% As a last resort, make sure we know when it exits,
+ %% in case it forgets to notify us.
+ %% We dont need to know the ref id?
+ erlang:monitor(process, HandlerPid),
HandlerInfo2 = HandlerInfo#handler_info{handler = HandlerPid,
state = started},
ets:insert(HandlerDb, HandlerInfo2),
diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl
index f1fa5fd997..054468e445 100644
--- a/lib/inets/src/inets_app/inets.erl
+++ b/lib/inets/src/inets_app/inets.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -57,7 +57,7 @@ start(Type) ->
%% Function: start(Service, ServiceConfig [, How]) -> {ok, Pid} |
%% {error, Reason}
%%
-%% Service = - ftpc | tftpd | httpc | httpd
+%% Service = - ftpc | tftpd | tftpc | tftp | httpc | httpd
%% ServiceConfig = ConfPropList | ConfFile
%% ConfPropList = [{Property, Value}] according to service
%% ConfFile = Path - when service is httpd
@@ -100,7 +100,7 @@ stop() ->
%%--------------------------------------------------------------------
%% Function: stop(Service, Pid) -> ok
%%
-%% Service - ftp | tftpd | http | httpd | stand_alone
+%% Service - ftpc | ftp | tftpd | tftpc | tftp | httpc | httpd | stand_alone
%%
%% Description: Stops a started service of the inets application or takes
%% down a stand alone "service" gracefully.
@@ -382,7 +382,7 @@ key1search(Key, Vals, Def) ->
%% Description: Returns a list of supported services
%%-------------------------------------------------------------------
service_names() ->
- [ftpc, tftpd, httpc, httpd].
+ [ftpc, tftp, httpc, httpd].
%%-----------------------------------------------------------------
@@ -725,8 +725,8 @@ call_service(Service, Call, Args) ->
service_module(tftpd) ->
tftp;
-service_module(httpc) ->
- httpc;
+service_module(tftpc) ->
+ tftp;
service_module(ftpc) ->
ftp;
service_module(Service) ->
diff --git a/lib/inets/test/ftp_macosx_x86_test.erl b/lib/inets/test/ftp_macosx_x86_test.erl
index c59a992421..5566d4feaa 100644
--- a/lib/inets/test/ftp_macosx_x86_test.erl
+++ b/lib/inets/test/ftp_macosx_x86_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2010. 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
@@ -108,7 +108,7 @@ passive_pwd(X) -> ?LIB_MOD:passive_pwd(X).
passive_cd(X) -> ?LIB_MOD:passive_cd(X).
passive_lcd(X) -> ?LIB_MOD:passive_lcd(X).
passive_ls(X) -> ?LIB_MOD:passive_ls(X).
-passive_nlist(X) -> ?LIB_MOD:passive_nlist(X).
+passive_nlist(X) -> ?LIB_MOD:passive_nlist([{wildcard_support, false} | X]).
passive_rename(X) -> ?LIB_MOD:passive_rename(X).
passive_delete(X) -> ?LIB_MOD:passive_delete(X).
passive_mkdir(X) -> ?LIB_MOD:passive_mkdir(X).
@@ -129,7 +129,7 @@ active_pwd(X) -> ?LIB_MOD:active_pwd(X).
active_cd(X) -> ?LIB_MOD:active_cd(X).
active_lcd(X) -> ?LIB_MOD:active_lcd(X).
active_ls(X) -> ?LIB_MOD:active_ls(X).
-active_nlist(X) -> ?LIB_MOD:active_nlist(X).
+active_nlist(X) -> ?LIB_MOD:active_nlist([{wildcard_support, false} | X]).
active_rename(X) -> ?LIB_MOD:active_rename(X).
active_delete(X) -> ?LIB_MOD:active_delete(X).
active_mkdir(X) -> ?LIB_MOD:active_mkdir(X).
diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
index 5e27bc3a86..c539b7c17c 100644
--- a/lib/inets/test/ftp_suite_lib.erl
+++ b/lib/inets/test/ftp_suite_lib.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -508,7 +508,8 @@ passive_nlist(suite) ->
[];
passive_nlist(Config) when is_list(Config) ->
Pid = ?config(ftp, Config),
- do_nlist(Pid).
+ WildcardSupport = ?config(wildcard_support, Config),
+ do_nlist(Pid, WildcardSupport).
%%-------------------------------------------------------------------------
@@ -768,7 +769,8 @@ active_nlist(suite) ->
[];
active_nlist(Config) when is_list(Config) ->
Pid = ?config(ftp, Config),
- do_nlist(Pid).
+ WildcardSupport = ?config(wildcard_support, Config),
+ do_nlist(Pid, WildcardSupport).
%%-------------------------------------------------------------------------
@@ -1242,16 +1244,20 @@ do_ls(Pid) ->
{ok, _} = ftp:ls(Pid, "incom*"),
ok.
-do_nlist(Pid) ->
+do_nlist(Pid, WildcardSupport) ->
{ok, _} = ftp:nlist(Pid),
{ok, _} = ftp:nlist(Pid, "incoming"),
%% neither nlist nor ls operates on a directory
%% they operate on a pathname, which *can* be a
%% directory, but can also be a filename or a group
%% of files (including wildcards).
- {ok, _} = ftp:nlist(Pid, "incom*"),
-%% {error, epath} = ftp:nlist(Pid, ?BAD_DIR),
- ok.
+ case WildcardSupport of
+ true ->
+ {ok, _} = ftp:nlist(Pid, "incom*"),
+ ok;
+ _ ->
+ ok
+ end.
do_rename(Pid, Config) ->
PrivDir = ?config(priv_dir, Config),
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index b5fd896001..902e440c80 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -306,7 +306,8 @@ tickets(suite) ->
otp_8106,
otp_8056,
otp_8352,
- otp_8371
+ otp_8371,
+ otp_8739
].
@@ -2561,7 +2562,78 @@ otp_8371(Config) when is_list(Config) ->
ok.
+%%-------------------------------------------------------------------------
+otp_8739(doc) ->
+ ["OTP-8739"];
+otp_8739(suite) ->
+ [];
+otp_8739(Config) when is_list(Config) ->
+ {_DummyServerPid, Port} = otp_8739_dummy_server(),
+ URL = ?URL_START ++ integer_to_list(Port) ++ "/dummy.html",
+ Method = get,
+ Request = {URL, []},
+ HttpOptions = [{connect_timeout, 500}, {timeout, 1}],
+ Options = [{sync, true}],
+ case http:request(Method, Request, HttpOptions, Options) of
+ {error, timeout} ->
+ %% And now we check the size of the handler db
+ Info = httpc:info(),
+ tsp("Info: ~p", [Info]),
+ {value, {handlers, Handlers}} =
+ lists:keysearch(handlers, 1, Info),
+ case Handlers of
+ [] ->
+ ok;
+ _ ->
+ tsf({unexpected_handlers, Handlers})
+ end;
+ Unexpected ->
+ tsf({unexpected, Unexpected})
+ end.
+
+
+otp_8739_dummy_server() ->
+ Parent = self(),
+ Pid = spawn_link(fun() -> otp_8739_dummy_server_init(Parent) end),
+ receive
+ {port, Port} ->
+ {Pid, Port}
+ end.
+
+otp_8739_dummy_server_init(Parent) ->
+ {ok, ListenSocket} =
+ gen_tcp:listen(0, [binary, inet, {packet, 0},
+ {reuseaddr,true},
+ {active, false}]),
+ {ok, Port} = inet:port(ListenSocket),
+ Parent ! {port, Port},
+ otp_8739_dummy_server_main(Parent, ListenSocket).
+
+otp_8739_dummy_server_main(Parent, ListenSocket) ->
+ case gen_tcp:accept(ListenSocket) of
+ {ok, Sock} ->
+ %% Ignore the request, and simply wait for the socket to close
+ receive
+ {tcp_closed, Sock} ->
+ (catch gen_tcp:close(ListenSocket)),
+ exit(normal);
+ {tcp_error, Sock, Reason} ->
+ tsp("socket error: ~p", [Reason]),
+ (catch gen_tcp:close(ListenSocket)),
+ exit(normal)
+ after 10000 ->
+ %% Just in case
+ (catch gen_tcp:close(Sock)),
+ (catch gen_tcp:close(ListenSocket)),
+ exit(timeout)
+ end;
+ Error ->
+ exit(Error)
+ end.
+
+
+
%%--------------------------------------------------------------------
%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 57c87e7036..ea6f4c9903 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -21,98 +21,3 @@ APPLICATION = inets
INETS_VSN = 5.4
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
-
-TICKETS = OTP-7907 OTP-8564 OTP-8573
-
-TICKETS_5_3_3 = \
- OTP-8609 \
- OTP-8610 \
- OTP-8624
-
-TICKETS_5_3_2 = \
- OTP-8542 \
- OTP-8607
-
-TICKETS_5_3_1 = \
- OTP-8508 \
- OTP-8509
-
-TICKETS_5_3 = \
- OTP-8016 \
- OTP-8056 \
- OTP-8103 \
- OTP-8106 \
- OTP-8312 \
- OTP-8315 \
- OTP-8327 \
- OTP-8349 \
- OTP-8351 \
- OTP-8352 \
- OTP-8359 \
- OTP-8371
-
-TICKETS_5_2 = \
- OTP-8204 \
- OTP-8206 \
- OTP-8247 \
- OTP-8248 \
- OTP-8249 \
- OTP-8258 \
- OTP-8280
-
-TICKETS_5_1_3 = OTP-8154
-
-TICKETS_5_1_2 = OTP-7298 OTP-8101 OTP-8118
-
-TICKETS_5_1_1 = OTP-8052 OTP-8069
-
-TICKETS_5_1 = OTP-7994 OTP-7998 OTP-8001 OTP-8004 OTP-8005
-
-TICKETS_5_0_14 = OTP-7882 OTP-7883 OTP-7888 OTP-7950 OTP-7976
-
-TICKETS_5.0.13 = \
- OTP-7723 \
- OTP-7724 \
- OTP-7726 \
- OTP-7463 \
- OTP-7815 \
- OTP-7857
-
-# TICKETS_5.0.12 = \
-# OTP-7636
-#
-# TICKETS_5.0.11 = \
-# OTP-7574 \
-# OTP-7597 \
-# OTP-7598 \
-# OTP-7605
-#
-# TICKETS_5.0.10 = \
-# OTP-7450 \
-# OTP-7454 \
-# OTP-7490 \
-# OTP-7512
-#
-# TICKETS_5.0.9 = \
-# OTP-7257 \
-# OTP-7323 \
-# OTP-7341
-#
-# TICKETS_5.0.8 = \
-# OTP-7315 \
-# OTP-7321
-#
-# TICKETS_5.0.7 = \
-# OTP-7304
-#
-# TICKETS_5.0.6 = \
-# OTP-7266
-#
-# TICKETS_5.0.5 = \
-# OTP-7220 \
-# OTP-7221
-#
-# TICKETS_5.0.4 = \
-# OTP-7173
-#
-
diff --git a/lib/inviso/src/inviso.erl b/lib/inviso/src/inviso.erl
index de42926ffe..0eda06a5c2 100644
--- a/lib/inviso/src/inviso.erl
+++ b/lib/inviso/src/inviso.erl
@@ -129,7 +129,7 @@ start(Options) ->
add_node(Reference) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,any_ref},?CALL_TIMEOUT).
-add_node(Reference,Options) when list(Options) ->
+add_node(Reference,Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,any_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -142,7 +142,7 @@ add_node(Reference,Options) when list(Options) ->
add_node_if_ref(Reference) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,if_ref},?CALL_TIMEOUT).
-add_node_if_ref(Reference,Options) when list(Options) ->
+add_node_if_ref(Reference,Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,if_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -156,10 +156,10 @@ add_node_if_ref(Reference,Options) when list(Options) ->
%% system. By speicifying node() as the node where the runtime component shall
%% be started. The return value will then follow the rules of non distributed
%% returnvalues and not have a node indicator.
-add_nodes(Nodes,Reference) when list(Nodes) ->
+add_nodes(Nodes,Reference) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,any_ref},?CALL_TIMEOUT).
-add_nodes(Nodes,Reference,Options) when list(Nodes),list(Options) ->
+add_nodes(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,any_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -168,10 +168,10 @@ add_nodes(Nodes,Reference,Options) when list(Nodes),list(Options) ->
%%
%% As add_nodes/2,/3 but will only connect to an already existing runtime component
%% if its reference is the same as the one given as argument.
-add_nodes_if_ref(Nodes,Reference) when list(Nodes) ->
+add_nodes_if_ref(Nodes,Reference) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,if_ref},?CALL_TIMEOUT).
-add_nodes_if_ref(Nodes,Reference,Options) when list(Nodes),list(Options) ->
+add_nodes_if_ref(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,if_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -182,9 +182,9 @@ add_nodes_if_ref(Nodes,Reference,Options) when list(Nodes),list(Options) ->
%%
%% Change options on all or specified Nodes. This may result in for instance
%% reinitialization of overloadcheck.
-change_options(Options) when list(Options) ->
+change_options(Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{change_options,all,Options},?CALL_TIMEOUT).
-change_options(Nodes,Options) when list(Nodes),list(Options) ->
+change_options(Nodes,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{change_options,Nodes,Options},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -234,7 +234,7 @@ change_options(Nodes,Options) when list(Nodes),list(Options) ->
init_tracing(TracerDataList) ->
gen_server:call(?CONTROLLER,{init_tracing,TracerDataList},?CALL_TIMEOUT).
-init_tracing(Nodes,TracerData) when list(Nodes) ->
+init_tracing(Nodes,TracerData) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{init_tracing,Nodes,TracerData},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -270,10 +270,10 @@ stop_tracing(Nodes) when is_list(Nodes) ->
clear() ->
gen_server:call(?CONTROLLER,{clear,all,[]},?CALL_TIMEOUT).
-clear(Nodes) when list(Nodes) ->
+clear(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{clear,Nodes,[]},?CALL_TIMEOUT).
-clear(Nodes,Options) when list(Nodes),list(Options) ->
+clear(Nodes,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{clear,Nodes,Options},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -355,9 +355,9 @@ stop_all() ->
tp(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
-tp(Nodes,Module,Function,Arity,MatchSpec) when list(Nodes) ->
+tp(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[global]);
-tp(Module,Function,Arity,MatchSpec,Opts) when atom(Module) ->
+tp(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
tp(Module,Function,Arity,MatchSpec) ->
@@ -384,9 +384,9 @@ tp(PatternList) ->
tpl(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
-tpl(Nodes,Module,Function,Arity,MatchSpec) when list(Nodes) ->
+tpl(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[local]);
-tpl(Module,Function,Arity,MatchSpec,Opts) when atom(Module) ->
+tpl(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
tpl(Module,Function,Arity,MatchSpec) ->
@@ -417,12 +417,12 @@ ctp(Nodes,Module,Function,Arity) ->
ctp(Module,Function,Arity) ->
trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[global]).
-ctp(Nodes,PatternList) when list(PatternList) ->
+ctp(Nodes,PatternList) when is_list(PatternList) ->
trace_pattern(Nodes,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[global]).
-ctp(PatternList) when list(PatternList) ->
+ctp(PatternList) when is_list(PatternList) ->
trace_pattern(all,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[global]).
@@ -445,12 +445,12 @@ ctpl(Nodes,Module,Function,Arity) ->
ctpl(Module,Function,Arity) ->
trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[local]).
-ctpl(Nodes,PatternList) when list(PatternList) ->
+ctpl(Nodes,PatternList) when is_list(PatternList) ->
trace_pattern(Nodes,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[local]).
-ctpl(PatternList) when list(PatternList) ->
+ctpl(PatternList) when is_list(PatternList) ->
trace_pattern(all,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[local]).
@@ -485,19 +485,19 @@ trace_pattern(Nodes,Patterns,FlagList) ->
%% specifying a certain pid at all nodes. Or an empty TraceConfList for all
%% nodes.
%% When calling several nodes, the nodes are called in parallel.
-tf(Nodes,PidSpec,FlagList) when list(Nodes),list(FlagList) ->
+tf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) ->
trace_flags(Nodes,[{PidSpec, FlagList}],true).
-tf(Nodes,TraceConfList) when list(Nodes),list(TraceConfList) ->
+tf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) ->
trace_flags(Nodes,TraceConfList,true);
-tf(PidSpec,FlagList) when list(FlagList) ->
+tf(PidSpec,FlagList) when is_list(FlagList) ->
trace_flags(all,[{PidSpec,FlagList}],true).
-tf(ArgList) when list(ArgList) -> % This one has triple functionality!
+tf(ArgList) when is_list(ArgList) -> % This one has triple functionality!
case ArgList of
- [{_Process,Flags}|_] when list(Flags),atom(hd(Flags))-> % A call to all nodes.
+ [{_Process,Flags}|_] when is_list(Flags),is_atom(hd(Flags))-> % A call to all nodes.
trace_flags(all,ArgList,true);
- [{_Node,TraceConfList}|_] when list(TraceConfList),tuple(hd(TraceConfList)) ->
+ [{_Node,TraceConfList}|_] when is_list(TraceConfList),is_tuple(hd(TraceConfList)) ->
trace_flags(ArgList,true);
[{_Node,_TraceConfList,_How}|_] ->
trace_flags(ArgList);
@@ -517,15 +517,15 @@ tf(ArgList) when list(ArgList) -> % This one has triple functionality
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
-ctf(Nodes,PidSpec,FlagList) when list(Nodes),list(FlagList) ->
+ctf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) ->
trace_flags(Nodes,[{PidSpec,FlagList}],false).
-ctf(Nodes,TraceConfList) when list(Nodes),list(TraceConfList) ->
+ctf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) ->
trace_flags(Nodes,TraceConfList,false);
-ctf(PidSpec,FlagList) when list(FlagList) ->
+ctf(PidSpec,FlagList) when is_list(FlagList) ->
trace_flags(all,[{PidSpec,FlagList}],false).
-ctf(TraceConfList) when list(TraceConfList) ->
+ctf(TraceConfList) when is_list(TraceConfList) ->
trace_flags(all,TraceConfList,false).
%% -----------------------------------------------------------------------------
@@ -668,10 +668,10 @@ init_tpm(Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
tpm(Mod,Func,Arity,MS) ->
tpm(all,Mod,Func,Arity,MS).
-tpm(Nodes,Mod,Func,Arity,MS) when integer(Arity) ->
+tpm(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm,[Mod,Func,Arity,MS]}});
-tpm(Mod,Func,Arity,MS,CallFunc) when integer(Arity) ->
+tpm(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) ->
tpm(all,Mod,Func,Arity,MS,CallFunc).
tpm(Nodes,Mod,Func,Arity,MS,CallFunc) ->
@@ -695,11 +695,11 @@ tpm(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
tpm_tracer(Mod,Func,Arity,MS) ->
tpm_tracer(all,Mod,Func,Arity,MS).
-tpm_tracer(Nodes,Mod,Func,Arity,MS) when integer(Arity) ->
+tpm_tracer(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm_tracer,[Mod,Func,Arity,MS]}},
?CALL_TIMEOUT);
-tpm_tracer(Mod,Func,Arity,MS,CallFunc) when integer(Arity) ->
+tpm_tracer(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) ->
tpm_tracer(all,Mod,Func,Arity,MS,CallFunc).
tpm_tracer(Nodes,Mod,Func,Arity,MS,CallFunc) ->
@@ -878,7 +878,7 @@ cancel_suspension() ->
%% Status=running|{suspended,SReason}
%%
%% Get Status form all or specified runtime components.
-get_status(Nodes) when list(Nodes) ->
+get_status(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{get_status,Nodes},?CALL_TIMEOUT).
get_status() ->
@@ -918,7 +918,7 @@ get_tracerdata(Nodes) when is_list(Nodes) ->
list_logs() ->
gen_server:call(?CONTROLLER,list_logs,?CALL_TIMEOUT).
-list_logs(TracerDataOrNodesList) when list(TracerDataOrNodesList) ->
+list_logs(TracerDataOrNodesList) when is_list(TracerDataOrNodesList) ->
gen_server:call(?CONTROLLER,{list_logs,TracerDataOrNodesList},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
@@ -960,17 +960,17 @@ list_logs(TracerDataOrNodesList) when list(TracerDataOrNodesList) ->
%% Note that the client process using this function will wait until all files
%% are moved. The job can be cancelled, causing any already copied files to be
%% removed, by simply terminating the waiting client process.
-fetch_log(DestDir,Prefix) when list(DestDir),list(Prefix) ->
+fetch_log(DestDir,Prefix) when is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,node(),all,DestDir,Prefix},infinity).
-fetch_log(ToNode,DestDir,Prefix) when atom(ToNode),list(DestDir),list(Prefix) ->
+fetch_log(ToNode,DestDir,Prefix) when is_atom(ToNode),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,ToNode,all,DestDir,Prefix},infinity);
-fetch_log(LogSpecList,DestDir,Prefix) when list(LogSpecList),list(DestDir),list(Prefix) ->
+fetch_log(LogSpecList,DestDir,Prefix) when is_list(LogSpecList),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,node(),LogSpecList,DestDir,Prefix},infinity).
fetch_log(ToNode,LogSpecList,DestDir,Prefix)
- when atom(ToNode),list(LogSpecList),list(DestDir),list(Prefix) ->
+ when is_atom(ToNode),is_list(LogSpecList),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,ToNode,LogSpecList,DestDir,Prefix},infinity).
%% ------------------------------------------------------------------------------
diff --git a/lib/inviso/src/inviso_c.erl b/lib/inviso/src/inviso_c.erl
index ecbd5b0778..b1597a7f35 100644
--- a/lib/inviso/src/inviso_c.erl
+++ b/lib/inviso/src/inviso_c.erl
@@ -100,7 +100,7 @@ init({_Parent,Options}) ->
end.
%% ------------------------------------------------------------------------------
-handle_call({subscribe,Pid},_From,LD) when pid(Pid) ->
+handle_call({subscribe,Pid},_From,LD) when is_pid(Pid) ->
MRef=erlang:monitor(process,Pid),
{reply,ok,LD#state{subscribers=[{Pid,MRef}|LD#state.subscribers]}};
handle_call({subscribe,Faulty},_From,LD) ->
@@ -131,7 +131,7 @@ handle_call({change_options,Nodes,Opts},_From,LD) ->
end;
handle_call({init_tracing,TracerDataList},_From,LD) ->
{reply,adapt_reply(LD,do_init_tracing(TracerDataList,LD)),LD};
-handle_call({init_tracing,Nodes,TracerData},_From,LD) when list(Nodes) ->
+handle_call({init_tracing,Nodes,TracerData},_From,LD) when is_list(Nodes) ->
TracerDataList=
lists:map(fun(N)->{N,TracerData} end,started_trace_nodes(Nodes,LD)),
{reply,adapt_reply(LD,do_init_tracing(TracerDataList,LD)),LD};
@@ -173,7 +173,7 @@ handle_call({fetch_log,ToNode,Spec,Dest,Prefix},From,LD) ->
end;
handle_call({delete_log,NodesOrNodeSpecs},_From,LD) ->
{reply,adapt_reply(LD,do_delete_log(NodesOrNodeSpecs,LD)),LD};
-handle_call({delete_log,Nodes,Specs},_From,LD) when list(Nodes) ->
+handle_call({delete_log,Nodes,Specs},_From,LD) when is_list(Nodes) ->
Reply=do_delete_log(lists:map(fun(N)->{N,Specs} end,Nodes),LD),
{reply,adapt_reply(LD,Reply),LD};
handle_call({delete_log,FaultyNodes,_Specs},_From,LD) ->
@@ -283,7 +283,7 @@ do_change_option(Nodes,Options,LD) ->
do_change_option_2([Node|Tail],Options,LD,Replies) ->
case get_node_rec(Node,LD) of
- Rec when record(Rec,node) ->
+ Rec when is_record(Rec,node) ->
Answer=?RUNTIME:change_options(Rec#node.pid,Options),
do_change_option_2(Tail,Options,LD,[{Node,Answer}|Replies]);
Error ->
@@ -333,7 +333,7 @@ do_init_tracing_2(What,_LD,_) ->
%% Returns {ok,Reply} or {error,Reason}.
distribute_tp(all,Patterns,FlagList,LD) ->
distribute_tp(started_trace_nodes(all,LD),Patterns,FlagList,LD);
-distribute_tp(Nodes,Patterns,FlagList,LD) when list(Nodes) ->
+distribute_tp(Nodes,Patterns,FlagList,LD) when is_list(Nodes) ->
RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of
#node{pid=Pid} ->
{Pid,N};
@@ -354,7 +354,7 @@ distribute_tp(Faulty,_,_,_) ->
%% Returns {ok,Reply} or {error,Reason}.
distribute_tf(all,Args,How,LD) ->
distribute_tf(started_trace_nodes(all,LD),Args,How,LD);
-distribute_tf(Nodes,Args,How,LD) when list(Nodes) ->
+distribute_tf(Nodes,Args,How,LD) when is_list(Nodes) ->
RTpids=lists:map(fun(Node)->
case get_node_rec(Node,LD) of
#node{pid=Pid} ->
@@ -369,7 +369,7 @@ distribute_tf(Faulty,_,_,_) ->
{error,{badarg,Faulty}}.
%% As above but specific args for each node.
-distribute_tf(NodeArgs,How,LD) when list(NodeArgs) ->
+distribute_tf(NodeArgs,How,LD) when is_list(NodeArgs) ->
RTpidArgs=lists:map(fun({Node,Args})->
case get_node_rec(Node,LD) of
#node{pid=Pid} ->
@@ -384,7 +384,7 @@ distribute_tf(Faulty,_,_) ->
{error,{badarg,Faulty}}.
%% As above but both specific args for each node and How (set or remove flag).
-distribute_tf(NodeArgHows,LD) when list(NodeArgHows) ->
+distribute_tf(NodeArgHows,LD) when is_list(NodeArgHows) ->
RTpidArgHows=
lists:map(fun({Node,Args,How}) ->
case get_node_rec(Node,LD) of
@@ -405,7 +405,7 @@ distribute_tf(Faulty,_) ->
%% Returns {ok,Reply} or {error,Reason}.
distribute_metapattern(all,Args,LD) ->
distribute_metapattern(started_trace_nodes(all,LD),Args,LD);
-distribute_metapattern(Nodes,Args,LD) when list(Nodes) ->
+distribute_metapattern(Nodes,Args,LD) when is_list(Nodes) ->
RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of
#node{pid=Pid} ->
{Pid,N};
@@ -480,7 +480,7 @@ do_cancel_suspension_2(Faulty,_,_) ->
%% Return {ok,Reply} or {error,Reason}.
do_stop_tracing(all,LD) ->
do_stop_tracing(started_trace_nodes(all,LD),LD);
-do_stop_tracing(Nodes,LD) when list(Nodes) ->
+do_stop_tracing(Nodes,LD) when is_list(Nodes) ->
RTpids=lists:map(fun(N)->case get_node_rec(N,LD) of
#node{pid=Pid} ->
{Pid,N};
@@ -580,7 +580,7 @@ do_list_logs_2(Other,_LD,_Replies) ->
%% proper strings.
do_fetch_log(ToNode,all,Dest,Prefix,From,LD) ->
do_fetch_log(ToNode,started_trace_nodes(all,LD),Dest,Prefix,From,LD);
-do_fetch_log(ToNode,Specs,Dest,Prefix,From,LD) when list(Dest),list(Prefix) ->
+do_fetch_log(ToNode,Specs,Dest,Prefix,From,LD) when is_list(Dest),is_list(Prefix) ->
CollectPid=spawn_link(ToNode,?MODULE,log_rec_init,[self(),Dest,Prefix,From]),
do_fetch_log_2(Specs,LD,CollectPid,[],[]);
do_fetch_log(_ToNode,_Specs,Dest,Prefix,From,_LD) ->
@@ -639,7 +639,7 @@ do_delete_log(NodeSpecs,LD) ->
LD,[]);
false ->
if
- list(NodeSpecs),list(hd(NodeSpecs)) -> % A list of files.
+ is_list(NodeSpecs),is_list(hd(NodeSpecs)) -> % A list of files.
do_delete_log_2(lists:map(fun(N)->{N,NodeSpecs} end,
started_trace_nodes(all,LD)),
LD,[]);
@@ -785,9 +785,9 @@ check_options(Options, Context) ->
check_options_2([],_Context,Result) ->
{ok,Result};
-check_options_2([{subscribe,Pid}|OptionsTail],start,Result) when pid(Pid) ->
+check_options_2([{subscribe,Pid}|OptionsTail],start,Result) when is_pid(Pid) ->
check_options_2(OptionsTail,start,[{subscribe,Pid}|Result]);
-check_options_2([{unsubscribe,Pid}|OptionsTail],start,Result) when pid(Pid) ->
+check_options_2([{unsubscribe,Pid}|OptionsTail],start,Result) when is_pid(Pid) ->
check_options_2(OptionsTail,start,[{unsubscribe,Pid}|Result]);
check_options_2([{dependency,How}|OptionsTail],Context,Result) ->
check_options_2(OptionsTail,Context,[{dependency,How}|Result]);
@@ -819,12 +819,12 @@ initiate_state(Options) ->
LD1#state{distributed=true}
end.
-initiate_state_2([{subscribe,Proc}|Tail],LD) when pid(Proc);atom(Proc)->
+initiate_state_2([{subscribe,Proc}|Tail],LD) when is_pid(Proc);is_atom(Proc)->
MRef=erlang:monitor(process,Proc),
initiate_state_2(Tail,LD#state{subscribers=[{Proc,MRef}|LD#state.subscribers]});
-initiate_state_2([Opt|Tail],LD) when tuple(Opt),size(Opt)>=1 ->
+initiate_state_2([Opt|Tail],LD) when is_tuple(Opt),size(Opt)>=1 ->
initiate_state_2(Tail,initiate_state_3(element(1,Opt),Opt,LD));
-initiate_state_2([Opt|Tail],LD) when atom(Opt) ->
+initiate_state_2([Opt|Tail],LD) when is_atom(Opt) ->
initiate_state_2(Tail,initiate_state_3(Opt,Opt,LD));
initiate_state_2([_|Tail],LD) ->
initiate_state_2(Tail,LD);
@@ -853,9 +853,9 @@ initiate_state_is_rt_option(_) -> false.
%% or more values associated with the Parameter, or just an atom.
merge_options([], Options) ->
Options;
-merge_options([T|DefaultTail],Options) when tuple(T),size(T)>=1 ->
+merge_options([T|DefaultTail],Options) when is_tuple(T),size(T)>=1 ->
merge_options(DefaultTail,merge_options_2(element(1,T),T,Options));
-merge_options([Param|DefaultTail],Options) when atom(Param) ->
+merge_options([Param|DefaultTail],Options) when is_atom(Param) ->
merge_options(DefaultTail,merge_options_2(Param,Param,Options));
merge_options([_|DefaultTail],Options) -> % Strange, bad default option!
merge_options(DefaultTail,Options).
@@ -868,7 +868,7 @@ merge_options_2(Param,Opt,Options) ->
[Opt|Options]
end.
-merge_options_find(Param,[T|_]) when tuple(T),element(1,T)==Param ->
+merge_options_find(Param,[T|_]) when is_tuple(T),element(1,T)==Param ->
true;
merge_options_find(Param,[Param|_]) ->
true;
@@ -883,7 +883,7 @@ merge_options_find(_,[]) ->
%% It also checks the formatting of the tracerdata since runtime components
%% does not accept too badly formatted tracerdata.
%% Returns {ok,NewTraceData} or {error,Reason}.
-check_modify_tracerdata(TracerData,LoopData) when list(TracerData) ->
+check_modify_tracerdata(TracerData,LoopData) when is_list(TracerData) ->
case lists:keysearch(trace,1,TracerData) of
{value,{_,TraceTD}} -> % Examine the trace part.
case check_modify_tracerdata(TraceTD,LoopData) of
@@ -908,7 +908,7 @@ check_modify_tracerdata({relayer,Collector},LoopData) when is_atom(Collector) ->
end;
check_modify_tracerdata({Type,Data},_LoopData) when Type==ip;Type==file ->
{ok,{Type,Data}};
-check_modify_tracerdata({Handler,Data},_LoopData) when function(Handler) ->
+check_modify_tracerdata({Handler,Data},_LoopData) when is_function(Handler) ->
{ok,{Handler,Data}};
check_modify_tracerdata(Data,_LoopData) ->
{error,{bad_tracerdata,Data}}.
@@ -999,7 +999,7 @@ set_node_rec_2(Rec,[NodeRec|Tail]) ->
%% Help function finding a node record for Node in a list of #node or in loopdata.
%% Returns the #node in question or {error,not_an_added_node}.
-get_node_rec(Node,NodeList) when list(NodeList) ->
+get_node_rec(Node,NodeList) when is_list(NodeList) ->
get_node_rec_2(Node,NodeList);
get_node_rec(Node,#state{nodes=NodeList}) ->
get_node_rec_2(Node,NodeList).
@@ -1016,7 +1016,7 @@ get_node_rec_2(Node,[_NodeRec|Tail]) ->
%% structure. Returns a new list of #node or a new loopdata structure.
delete_node_rec(Node,LD=#state{nodes=NodeList}) ->
LD#state{nodes=delete_node_rec_2(Node,NodeList)};
-delete_node_rec(Node,NodeList) when list(NodeList) ->
+delete_node_rec(Node,NodeList) when is_list(NodeList) ->
delete_node_rec_2(Node,NodeList).
delete_node_rec_2(_,[]) ->
@@ -1059,7 +1059,7 @@ log_rec_init(Parent,Dest,Prefix,From={ClientPid,_}) ->
Fetchers),
CMRef=erlang:monitor(process,ClientPid), % Monitor the client.
case log_rec_loop(Dest,Prefix,RTs,InitialReplies,CMRef) of
- Reply when list(Reply) -> % It is an ok value.
+ Reply when is_list(Reply) -> % It is an ok value.
gen_server:reply(From,{ok,Reply});
{error,Reason} ->
gen_server:reply(From,{error,Reason});
diff --git a/lib/inviso/src/inviso_lfm.erl b/lib/inviso/src/inviso_lfm.erl
index 362176c776..085048518c 100644
--- a/lib/inviso/src/inviso_lfm.erl
+++ b/lib/inviso/src/inviso_lfm.erl
@@ -87,13 +87,13 @@
%% close the outfile.
%%
%% Using merge/2 assumes you want to use default handlers writing to a file.
-merge(Files,OutputFile) when list(OutputFile) ->
+merge(Files,OutputFile) when is_list(OutputFile) ->
merge(Files,fun outfile_opener/1,fun outfile_writer/4,fun outfile_closer/1,OutputFile,off).
-merge(Files,WorkHandlerFun,HandlerData) when function(WorkHandlerFun) ->
+merge(Files,WorkHandlerFun,HandlerData) when is_function(WorkHandlerFun) ->
merge(Files,void,WorkHandlerFun,void,HandlerData,off);
-merge(Files,OutputFile,Dbg) when list(OutputFile) ->
+merge(Files,OutputFile,Dbg) when is_list(OutputFile) ->
merge(Files,fun outfile_opener/1,fun outfile_writer/4,fun outfile_closer/1,OutputFile,Dbg).
-merge(Files,WorkHandlerFun,HandlerData,Dbg) when function(WorkHandlerFun) ->
+merge(Files,WorkHandlerFun,HandlerData,Dbg) when is_function(WorkHandlerFun) ->
merge(Files,void,WorkHandlerFun,void,HandlerData,Dbg).
merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData) ->
merge(Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerData,off).
@@ -123,7 +123,7 @@ init_receiver(From,Files,BeginHandlerFun,WorkHandlerFun,EndHandlerFun,HandlerDat
{ok,Readers} ->
process_flag(trap_exit,true),
if
- function(BeginHandlerFun) ->
+ is_function(BeginHandlerFun) ->
case catch BeginHandlerFun(HandlerData) of
{ok,NewHandlerData} ->
init_receiver_2(From,WorkHandlerFun,EndHandlerFun,
@@ -145,7 +145,7 @@ init_receiver_2(From,WorkHandlerFun,EndHandlerFun,HandlerData,Dbg,Readers) ->
{Reply,NewHandlerData}=
loop(From,WorkHandlerFun,HandlerData,NewReaders,EntryStruct,Dbg,0),
if
- function(EndHandlerFun) ->
+ is_function(EndHandlerFun) ->
case EndHandlerFun(NewHandlerData) of
ok ->
From ! {reply,self(),Reply};
@@ -207,7 +207,7 @@ find_oldest_entry(EntryStruct) ->
case list_all_entries(EntryStruct) of
[] -> % The we are done!
done;
- EntryList when list(EntryList) -> % Find smallest timestamp in here then.
+ EntryList when is_list(EntryList) -> % Find smallest timestamp in here then.
{Pid,Node,PidMappings,_TS,Term}=
lists:foldl(fun({P,N,PMap,TS1,T},{_P,_N,_PMap,TS0,_T}) when TS1<TS0 ->
{P,N,PMap,TS1,T};
diff --git a/lib/inviso/src/inviso_lfm_tpfreader.erl b/lib/inviso/src/inviso_lfm_tpfreader.erl
index d0db4b6d02..6de4d11fe0 100644
--- a/lib/inviso/src/inviso_lfm_tpfreader.erl
+++ b/lib/inviso/src/inviso_lfm_tpfreader.erl
@@ -60,9 +60,9 @@
%% File=string()
%% Spawn on this function to start a reader process for trace-port generated
%% logfiles, possibly with inviso-generated ti-files.
-init(RecPid,LogFiles=[Tuple|_]) when tuple(Tuple) -> % Only one LogFiles.
+init(RecPid,LogFiles=[Tuple|_]) when is_tuple(Tuple) -> % Only one LogFiles.
init(RecPid,[LogFiles]);
-init(RecPid,FileStruct) when list(FileStruct) ->
+init(RecPid,FileStruct) when is_list(FileStruct) ->
logfiles_loop(RecPid,FileStruct).
%% -----------------------------------------------------------------------------
@@ -135,7 +135,7 @@ read_traceport_file(FileName,FD) ->
case file:read(FD,5) of % Trace-port file entries start with 5 bytes.
{ok,<<0,Size:32>>} -> % Each entry in a traceport file begins.
case file:read(FD,Size) of
- {ok,Bin} when binary(Bin),size(Bin)=:=Size ->
+ {ok,Bin} when is_binary(Bin),size(Bin)=:=Size ->
try binary_to_term(Bin) of
Term -> % Bin was a properly formatted term!
{ok,Term}
@@ -244,7 +244,7 @@ find_timestamp_in_term(_) -> % Don't know if there is a timestamp
%% (1) plain straight raw binary files.
handle_ti_file(FileStruct) ->
case lists:keysearch(ti_log,1,FileStruct) of
- {value,{_,[FileName]}} when list(FileName) -> % There is one ti-file in this set.
+ {value,{_,[FileName]}} when is_list(FileName) -> % There is one ti-file in this set.
case file:open(FileName,[read,raw,binary]) of
{ok,FD} ->
TIdAlias=ets:new(list_to_atom("inviso_ti_atab_"++pid_to_list(self())),
@@ -308,9 +308,9 @@ handle_ti_file_2(FD,TIdAlias,TIdUnalias) ->
handle_logfiles(FileStruct) ->
handle_logfiles_2(lists:keysearch(trace_log,1,FileStruct)).
-handle_logfiles_2({value,{_,[FileName]}}) when list(FileName)-> % One single plain file.
+handle_logfiles_2({value,{_,[FileName]}}) when is_list(FileName)-> % One single plain file.
[FileName];
-handle_logfiles_2({value,{_,Files}}) when list(Files) -> % A wrap-set.
+handle_logfiles_2({value,{_,Files}}) when is_list(Files) -> % A wrap-set.
handle_logfile_sort_wrapset(Files);
handle_logfiles_2(_) ->
[]. % Pretend there were no files otherwise.
diff --git a/lib/inviso/src/inviso_tool.erl b/lib/inviso/src/inviso_tool.erl
index 7126ba4387..05158f58fe 100644
--- a/lib/inviso/src/inviso_tool.erl
+++ b/lib/inviso/src/inviso_tool.erl
@@ -267,9 +267,9 @@ stop(UntouchedNodes) ->
%% tracing.
reconnect_nodes() ->
gen_server:call(?MODULE,{reconnect_nodes,local_runtime},?CALL_TIMEOUT).
-reconnect_nodes(Node) when atom(Node) ->
+reconnect_nodes(Node) when is_atom(Node) ->
reconnect_nodes([Node]);
-reconnect_nodes(Nodes) when list(Nodes) ->
+reconnect_nodes(Nodes) when is_list(Nodes) ->
gen_server:call(?MODULE,{reconnect_nodes,Nodes},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
@@ -572,7 +572,7 @@ reactivator_reply(TPid,Counter) ->
init(Config) ->
case fetch_configuration(Config) of % From conf-file and Config.
- {ok,LD} when record(LD,ld) ->
+ {ok,LD} when is_record(LD,ld) ->
case start_inviso_at_c_node(LD) of
{ok,CPid} ->
LD2=start_runtime_components(LD),
@@ -650,7 +650,7 @@ start_runtime_components_2([],_,LD) ->
start_runtime_components_mk_opts(Node,{M,F,Args}) ->
case catch apply(M,F,[Node|Args]) of
- {ok,Opts} when list(Opts) ->
+ {ok,Opts} when is_list(Opts) ->
start_runtime_component_mk_opts_add_dependency(Opts);
_ ->
[?DEFAULT_DEPENDENCY]
@@ -698,7 +698,7 @@ handle_call({reconnect_nodes,Nodes},_From,LD) ->
{reply,
build_reconnect_nodes_reply(Nodes,Nodes2,NodesErr,NewLD#ld.nodes),
NewLD};
- list(Nodes) ->
+ is_list(Nodes) ->
{reply,
{ok,build_reconnect_nodes_reply(Nodes,Nodes2,NodesErr,NewLD#ld.nodes)},
NewLD}
@@ -711,7 +711,7 @@ handle_call({start_session,MoreTDGargs},_From,LD=#ld{session_state=SState}) ->
case is_tracing(SState) of
false -> % No session running.
if
- list(MoreTDGargs) ->
+ is_list(MoreTDGargs) ->
DateTime=calendar:universal_time(),
{M,F,Args}=LD#ld.tdg,
TDGargs=inviso_tool_lib:mk_tdg_args(DateTime,MoreTDGargs++Args),
@@ -757,15 +757,15 @@ handle_call({reinitiate_session,Nodes},_From,LD=#ld{session_state=SState}) ->
end;
handle_call({restore_session,{FileName,MoreTDGargs}},_From,LD=#ld{chl=OldCHL})
- when list(MoreTDGargs) ->
+ when is_list(MoreTDGargs) ->
case is_tracing(LD#ld.session_state) of
false ->
case catch make_absolute_path(FileName,LD#ld.dir) of
- AbsFileName when list(AbsFileName) ->
+ AbsFileName when is_list(AbsFileName) ->
case file:read_file(AbsFileName) of
{ok,Bin} ->
if
- list(MoreTDGargs) ->
+ is_list(MoreTDGargs) ->
case catch replace_history_chl(OldCHL,
binary_to_term(Bin)) of
{ok,CHL} -> % The file was well formatted.
@@ -803,7 +803,7 @@ handle_call({restore_session,MoreTDGargs},_From,LD=#ld{chl=CHL}) ->
case history_exists_chl(CHL) of
true -> % There is a history to redo.
if
- list(MoreTDGargs) ->
+ is_list(MoreTDGargs) ->
case h_restore_session(MoreTDGargs,LD) of
{ok,{SessionNr,ReturnVal,NewLD}} ->
{reply,
@@ -879,7 +879,7 @@ handle_call({sync_atc,{TC,Id,Vars,TimeOut}},_From,LD=#ld{session_state=SState})
case is_tracing(SState) of
true ->
if
- integer(TimeOut);TimeOut==infinity ->
+ is_integer(TimeOut);TimeOut==infinity ->
case h_sync_atc(TC,Id,Vars,TimeOut,LD) of
{ok,NewLD,Result} ->
{reply,Result,NewLD};
@@ -897,7 +897,7 @@ handle_call({sync_rtc,{TC,Vars,TimeOut}},_From,LD=#ld{session_state=SState}) ->
case is_tracing(SState) of
true ->
if
- integer(TimeOut);TimeOut==infinity ->
+ is_integer(TimeOut);TimeOut==infinity ->
case h_sync_rtc(TC,Vars,TimeOut,LD) of
{ok,NewLD,Result} ->
{reply,Result,NewLD};
@@ -929,7 +929,7 @@ handle_call({sync_dtc,{TC,Id,TimeOut}},_From,LD=#ld{session_state=SState}) ->
case is_tracing(SState) of % Check that we are tracing now.
true ->
if
- integer(TimeOut);TimeOut==infinity ->
+ is_integer(TimeOut);TimeOut==infinity ->
case h_sync_dtc(TC,Id,TimeOut,LD) of
{ok,NewLD,Result} ->
{reply,Result,NewLD};
@@ -947,7 +947,7 @@ handle_call({inviso,{Cmd,Args}},_From,LD=#ld{session_state=SState}) ->
case is_tracing(SState) of
true ->
if
- list(Args) ->
+ is_list(Args) ->
case h_inviso(Cmd,Args,LD) of
{ok,{Reply,NewLD}} ->
{reply,Reply,NewLD};
@@ -1156,7 +1156,7 @@ h_reconnect_nodes(local_runtime,LD=#ld{nodes=NodesD}) -> % Non-distributed.
_ -> % Allready connected!
{ok,{[],{error,already_connected},LD}}
end;
-h_reconnect_nodes(Nodes,LD=#ld{nodes=NodesD}) when list(Nodes) ->
+h_reconnect_nodes(Nodes,LD=#ld{nodes=NodesD}) when is_list(Nodes) ->
{Nodes2,NodesErr}=
lists:foldl(fun(N,{Nodes2,NodesErr})->
case get_state_nodes(N,NodesD) of
@@ -1246,7 +1246,7 @@ h_start_session_ctp_all_2([],Errors,Nodes) ->
%% Help function doing the actual init_tracing.
h_start_session_2(undefined,TracerData,_Errors) -> % Non distributed case.
case inviso:init_tracing(TracerData) of
- {ok,LogResult} when list(LogResult) ->
+ {ok,LogResult} when is_list(LogResult) ->
{ok,{ok,LogResult}};
{error,already_initated} -> % Perhaps adopted!?
{ok,{error,already_initiated}}; % Not necessarily wrong.
@@ -1360,7 +1360,7 @@ h_reinitiate_session_2(local_runtime,NodesD,undefined) -> % Non distributed case
_ ->
{ok,{[],{error,already_in_session}}}
end;
-h_reinitiate_session_2(Nodes,NodesD,CNode) when list(Nodes) ->
+h_reinitiate_session_2(Nodes,NodesD,CNode) when is_list(Nodes) ->
{ok,lists:foldl(fun(N,{Nodes2,NodesErr})->
case get_state_nodes(N,NodesD) of
{inactive,running} -> % Only ok case.
@@ -1515,7 +1515,7 @@ h_atc(TC,Id,Vars,LD=#ld{c_node=CNode,tc_dict=TCdict,chl=CHL},Nodes) ->
case check_bindings(Vars,TraceCase) of
{ok,Bindings} -> % Necessary vars exists in Vars.
if
- list(Nodes) -> % Nodes predefined.
+ is_list(Nodes) -> % Nodes predefined.
h_atc_2(TC,Id,CNode,CHL,LD,TraceCase,Bindings,Nodes);
true -> % Use all tracing and running nodes.
Nodes1=get_nodenames_running_nodes(LD#ld.nodes),
@@ -1769,13 +1769,13 @@ h_reactivate(Node,CNode) ->
h_save_history(HDir,Dir,FileName,SortedLog) ->
Dir0=
if
- list(HDir) -> % There is a history dir specified.
+ is_list(HDir) -> % There is a history dir specified.
HDir; % Use it then.
true ->
Dir % Else use the tool dir.
end,
case catch make_absolute_path(FileName,Dir0) of
- AbsFileName when list(AbsFileName) ->
+ AbsFileName when is_list(AbsFileName) ->
Log2=build_saved_history_data(SortedLog), % Remove stopped tracecases.
case file:write_file(AbsFileName,term_to_binary(Log2)) of
ok ->
@@ -1801,7 +1801,7 @@ h_get_autostart_data(local_runtime,_,Dependency,ASD,M,F,TDGargs,OptsG) ->
Opts=[Dependency|lists:keydelete(dependency,1,Opts0)],
{ok,{ASD,{ok,{Opts,{tdg,{M,F,CompleteTDGargs}}}}}};
-h_get_autostart_data(Nodes,CNode,Dependency,ASD,M,F,TDGargs,OptsG) when list(Nodes) ->
+h_get_autostart_data(Nodes,CNode,Dependency,ASD,M,F,TDGargs,OptsG) when is_list(Nodes) ->
{ok,{ASD,h_get_autostart_data_2(Nodes,CNode,Dependency,M,F,TDGargs,OptsG)}};
h_get_autostart_data(Nodes,_CNode,_Dependency,_ASD,_M,_F,_TDGargs,_OptsG) ->
{error,{badarg,Nodes}}.
@@ -2144,14 +2144,14 @@ expand_module_regexps(Args,_RegExpNode,_Nodes,false) ->
{ok,Args};
expand_module_regexps([PatternList],RegExpNode,Nodes,{tp,1,1}) ->
case catch expand_module_regexps_tp(PatternList,RegExpNode,Nodes) of
- NewPatternList when list(NewPatternList) ->
+ NewPatternList when is_list(NewPatternList) ->
{ok,[NewPatternList]};
{error,Reason} ->
{error,Reason}
end;
expand_module_regexps([PatternList],RegExpNode,Nodes,{ctp,1,1}) ->
case catch expand_module_regexps_ctp(PatternList,RegExpNode,Nodes) of
- NewPatternList when list(NewPatternList) ->
+ NewPatternList when is_list(NewPatternList) ->
{ok,[NewPatternList]};
{error,Reason} ->
{error,Reason}
@@ -2164,9 +2164,9 @@ expand_module_regexps([M,F,Arity],RegExpNode,Nodes,{ctp,3,1}) ->
expand_module_regexps([[{M,F,Arity}]],RegExpNode,Nodes,{ctp,1,1}).
-expand_module_regexps_tp([E={M,_,_,_,_}|Rest],RegExpNode,Nodes) when atom(M) ->
+expand_module_regexps_tp([E={M,_,_,_,_}|Rest],RegExpNode,Nodes) when is_atom(M) ->
[E|expand_module_regexps_tp(Rest,RegExpNode,Nodes)];
-expand_module_regexps_tp([{M,F,Arity,MS,Opts}|Rest],RegExpNode,Nodes) when list(M);tuple(M) ->
+expand_module_regexps_tp([{M,F,Arity,MS,Opts}|Rest],RegExpNode,Nodes) when is_list(M);is_tuple(M) ->
case inviso_tool_lib:expand_module_names([RegExpNode],
M,
[{expand_only_at,RegExpNode}]) of
@@ -2193,9 +2193,9 @@ expand_module_regexps_tp_2([M|MRest],F,Arity,MS,Opts,Rest,RegExpNode,Nodes) ->
expand_module_regexps_tp_2([],_,_,_,_,Rest,RegExpNode,Nodes) ->
expand_module_regexps_tp(Rest,RegExpNode,Nodes).
-expand_module_regexps_ctp([E={M,_,_}|Rest],RegExpNode,Nodes) when atom(M) ->
+expand_module_regexps_ctp([E={M,_,_}|Rest],RegExpNode,Nodes) when is_atom(M) ->
[E|expand_module_regexps_ctp(Rest,RegExpNode,Nodes)];
-expand_module_regexps_ctp([{M,F,Arity}|Rest],RegExpNode,Nodes) when list(M);tuple(M) ->
+expand_module_regexps_ctp([{M,F,Arity}|Rest],RegExpNode,Nodes) when is_list(M);is_tuple(M) ->
case inviso_tool_lib:expand_module_names([RegExpNode],
M,
[{expand_only_at,RegExpNode}]) of
@@ -2450,7 +2450,7 @@ fetch_configuration(Config) ->
%% Returns {ok,FileName} or 'false'. The latter if no name could be determined.
fetch_config_filename(Config) ->
case catch lists:keysearch(config_file,1,Config) of
- {value,{_,FName}} when list(FName) ->
+ {value,{_,FName}} when is_list(FName) ->
{ok,FName};
_ -> % No filename in the start argument.
fetch_config_filename_2()
@@ -2458,7 +2458,7 @@ fetch_config_filename(Config) ->
fetch_config_filename_2() ->
case application:get_env(inviso_tool_config_file) of
- {ok,FName} when list(FName) ->
+ {ok,FName} when is_list(FName) ->
{ok,FName};
_ -> % Application parameter not specified.
false % Means no config file will be used.
@@ -2499,14 +2499,14 @@ read_config_list_2(LD,Terms,Tag) ->
%% Function updating a named field in a record. Returns a new record. Note that
%% this function must be maintained due the fact that field names are removed
%% at compile time.
-update_ld_record(LD,nodes,Value) when record(LD,ld) ->
+update_ld_record(LD,nodes,Value) when is_record(LD,ld) ->
case mk_nodes(Value) of
{ok,NodesD} ->
LD#ld{nodes=NodesD};
error ->
LD
end;
-update_ld_record(LD,Tag,Value) when record(LD,ld) ->
+update_ld_record(LD,Tag,Value) when is_record(LD,ld) ->
Index=
case Tag of
c_node -> % atom()
@@ -2546,7 +2546,7 @@ update_ld_record(LD,Tag,Value) when record(LD,ld) ->
%% ActivationFileName=DeactivationFileName=string()
read_trace_case_definitions(LD) ->
case LD#ld.tc_def_file of
- TCfileName when list(TCfileName) ->
+ TCfileName when is_list(TCfileName) ->
case catch file:consult(TCfileName) of
{ok,Terms} ->
Dir=LD#ld.dir, % The working directory of the tool.
@@ -2636,8 +2636,8 @@ get_status(CNode,Nodes) ->
%% We can end up here if a session is stopped with this node suspended.
%% Returns a nodes database structure filled with the nodes Nodes.
-mk_nodes(Nodes) when list(Nodes) ->
- {ok,lists:map(fun(N) when atom(N)->{N,down} end,Nodes)};
+mk_nodes(Nodes) when is_list(Nodes) ->
+ {ok,lists:map(fun(N) when is_atom(N)->{N,down} end,Nodes)};
mk_nodes(local_runtime) -> % The non-distributed case.
down;
mk_nodes(_Nodes) ->
@@ -2783,7 +2783,7 @@ set_suspended_nodes(_,{up,{State,_}}) ->
%% This function is called when reactivation is completed. Hence it moves the
%% node to no longer suspended. Note this can mean that the node is either
%% tracing or inactive. Reactivation is not allowed for a node have trace_failure.
-set_running_nodes(Node,NodesD) when list(NodesD) ->
+set_running_nodes(Node,NodesD) when is_list(NodesD) ->
case lists:keysearch(Node,1,NodesD) of
{value,{_,AvailableStatus}} ->
lists:keyreplace(Node,1,NodesD,{Node,set_running_nodes_2(AvailableStatus)});
@@ -2902,7 +2902,7 @@ get_available_nodes([]) ->
%% suspended or not.
%% Returns {State,Status} | reactivating | down
%% where
-get_state_nodes(Node,NodesD) when list(NodesD) ->
+get_state_nodes(Node,NodesD) when is_list(NodesD) ->
case lists:keysearch(Node,1,NodesD) of
{value,{_,AvailableStatus}} ->
get_state_nodes_2(AvailableStatus);
diff --git a/lib/inviso/src/inviso_tool_lib.erl b/lib/inviso/src/inviso_tool_lib.erl
index 20a8b509ae..7953acedd6 100644
--- a/lib/inviso/src/inviso_tool_lib.erl
+++ b/lib/inviso/src/inviso_tool_lib.erl
@@ -83,7 +83,7 @@ inviso_cmd(NodeName,Func,Args) ->
%% In the non-distributed case the singlenode_expansion will be returned.
expand_module_names(_Nodes,Mod={_,'_'},_) ->
{error,{faulty_regexp_combination,Mod}};
-expand_module_names(Nodes,{DirStr,ModStr},Opts) when list(DirStr), list(ModStr) ->
+expand_module_names(Nodes,{DirStr,ModStr},Opts) when is_list(DirStr), is_list(ModStr) ->
case expand_module_names_special_regexp(DirStr) of
{ok,NewDirStr} ->
case expand_module_names_special_regexp(ModStr) of
@@ -97,11 +97,11 @@ expand_module_names(Nodes,{DirStr,ModStr},Opts) when list(DirStr), list(ModStr)
end;
expand_module_names(_,'_',_Opts) -> % If we want to trace all modules
wildcard; % we shall not expand it.
-expand_module_names(_Nodes,Mod,_Opts) when atom(Mod) ->
+expand_module_names(_Nodes,Mod,_Opts) when is_atom(Mod) ->
module; % If it is an atom, no expansion.
expand_module_names(Nodes,"*",Opts) -> % Treat this as a reg.exp.
expand_module_names(Nodes,".*",Opts);
-expand_module_names(Nodes,ModStr,Opts) when list(ModStr) ->
+expand_module_names(Nodes,ModStr,Opts) when is_list(ModStr) ->
case expand_module_names_special_regexp(ModStr) of
{ok,NewModStr} ->
expand_module_names_2(Nodes,NewModStr,Opts);
@@ -115,7 +115,7 @@ expand_module_names_2(Nodes,ModStr,Opts) ->
case get_expand_regexp_at_opts(Opts) of
{ok,Node} -> % Expansion only at this node.
case inviso_rt_lib:expand_regexp([Node],ModStr,Opts) of
- [{Node,Modules}] when list(Modules) ->
+ [{Node,Modules}] when is_list(Modules) ->
{singlenode_expansion,Modules};
[{Node,_}] -> % Most likely badrpc.
{error,{faulty_node,Node}}
@@ -130,7 +130,7 @@ expand_module_names_2(Nodes,DirStr,ModStr,Opts) ->
case get_expand_regexp_at_opts(Opts) of
{ok,Node} -> % Expansion only at this node.
case inviso_rt_lib:expand_regexp([Node],DirStr,ModStr,Opts) of
- [{Node,Modules}] when list(Modules) ->
+ [{Node,Modules}] when is_list(Modules) ->
{singlenode_expansion,Modules};
[{Node,_}] -> % Most likely badrpc.
{error,{faulty_node,Node}}
@@ -186,12 +186,12 @@ make_patterns(Catches,Opts,Dbg,NodeModsOrMods,F,A,MS) ->
make_patterns_2(Catches,OwnArg,Dbg,NodeModsOrMods,F,A,MS)
end.
-make_patterns_2(Catches,OwnArg,Dbg,[{Node,Mods}|Rest],F,A,MS) when list(Mods) ->
+make_patterns_2(Catches,OwnArg,Dbg,[{Node,Mods}|Rest],F,A,MS) when is_list(Mods) ->
TPs=make_patterns_3(Catches,OwnArg,Dbg,Mods,F,A,MS,[]),
[{Node,join_patterns(TPs)}|make_patterns_2(Catches,OwnArg,Dbg,Rest,F,A,MS)];
make_patterns_2(Catches,OwnArg,Dbg,[{_Node,_}|Rest],F,A,MS) -> % badrpc!?
make_patterns_2(Catches,OwnArg,Dbg,Rest,F,A,MS);
-make_patterns_2(Catches,OwnArg,Dbg,Modules,F,A,MS) when list(Modules) ->
+make_patterns_2(Catches,OwnArg,Dbg,Modules,F,A,MS) when is_list(Modules) ->
TPs=make_patterns_3(Catches,OwnArg,Dbg,Modules,F,A,MS,[]),
join_patterns(TPs);
make_patterns_2(_,_,_,[],_,_,_) ->
@@ -330,7 +330,7 @@ get_datetime_from_tdg_args([DateTime|_]) ->
%% Returns a list.
get_ownarg_opts(Opts) ->
case lists:keysearch(arg,1,Opts) of
- {value,{_,OwnArg}} when list(OwnArg) ->
+ {value,{_,OwnArg}} when is_list(OwnArg) ->
OwnArg;
{value,{_,OwnArg}} ->
[OwnArg];
@@ -350,7 +350,7 @@ get_disable_safety_opts(Opts) ->
get_expand_regexp_at_opts(Opts) ->
case lists:keysearch(expand_only_at,1,Opts) of
- {value,{_,Node}} when atom(Node) ->
+ {value,{_,Node}} when is_atom(Node) ->
{ok,Node};
_ ->
false
diff --git a/lib/jinterface/java_src/Makefile b/lib/jinterface/java_src/Makefile
index 37a57352ad..22c55328b8 100644
--- a/lib/jinterface/java_src/Makefile
+++ b/lib/jinterface/java_src/Makefile
@@ -35,7 +35,21 @@ VSN=$(JINTERFACE_VSN)
SPECIAL_TARGETS =
+TARGET_FILES= $(POM_TARGET)
+SPECIAL_TARGETS =
+
+POM_FILE= pom.xml
+
+POM_TARGET= ../$(POM_FILE)
+POM_SRC= $(POM_FILE).src
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(POM_TARGET): $(POM_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Default Subdir Targets
@@ -43,7 +57,7 @@ SPECIAL_TARGETS =
.PHONY: debug opt instr release docs release_docs tests release_tests clean depend
-debug opt instr release docs release_docs tests release_tests clean depend:
+debug opt instr release docs release_docs tests release_tests clean depend: $(TARGET_FILES)
set -e; set -x; \
case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \
if test -f com/ericsson/otp/erlang/ignore_config_record.inf; then xflag=$$tflag; fi; \
diff --git a/lib/jinterface/java_src/pom.xml.src b/lib/jinterface/java_src/pom.xml.src
new file mode 100644
index 0000000000..cef49b735a
--- /dev/null
+++ b/lib/jinterface/java_src/pom.xml.src
@@ -0,0 +1,106 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.erlang.otp</groupId>
+ <artifactId>jinterface</artifactId>
+ <packaging>jar</packaging>
+ <version>%VSN%</version>
+ <name>jinterface</name>
+ <description>
+ Jinterface Java package contains java classes, which help you integrate programs written in Java with Erlang.
+ Erlang is a programming language designed at the Ericsson Computer Science Laboratory.
+ </description>
+ <url>http://erlang.org/</url>
+ <licenses>
+ <license>
+ <name>ERLANG PUBLIC LICENSE 1.1</name>
+ <url>http://www.erlang.org/EPLICENSE</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>git://github.com/erlang/otp.git</connection>
+ <developerConnection>git://github.com/erlang/otp.git</developerConnection>
+ <url>http://github.com/erlang/otp</url>
+ </scm>
+ <developers>
+ <developer>
+ <email>[email protected]</email>
+ </developer>
+ </developers>
+ <organization>
+ <name>Open Source Erlang</name>
+ <url>http://www.erlang.org/</url>
+ </organization>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>java_src</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <distributionManagement>
+ <repository>
+ <id>ossrh</id>
+ <url>http://oss.sonatype.org/service/local/staging/deploy/maven2</url>
+ </repository>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>http://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+ <profiles>
+ <profile>
+ <id>release-sign-artifacts</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.0-alpha-4</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/lib/jinterface/test/Makefile b/lib/jinterface/test/Makefile
new file mode 100644
index 0000000000..36955d1e91
--- /dev/null
+++ b/lib/jinterface/test/Makefile
@@ -0,0 +1,84 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-2010. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/jinterface_test
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+TEST_SPEC_FILE = jinterface.dynspec
+
+MODULES = nc_SUITE \
+ jinterface_SUITE
+
+GEN_MODULES = jitu
+
+ERL_FILES = $(MODULES:%=%.erl) $(GEN_MODULES:%=%.erl)
+
+GEN_TARGET_FILES = $(GEN_MODULES:%=%.$(EMULATOR))
+
+SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
+
+TARGET_FILES = \
+ $(GEN_TARGET_FILES) \
+ $(SUITE_TARGET_FILES)
+
+# ----------------------------------------------------
+# PROGRAMS
+# ----------------------------------------------------
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+tests debug opt:
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f errs core *~
+
+docs:
+
+# ----------------------------------------------------
+# Special Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec:
+
+release_docs_spec:
+
+release_tests_spec: tests
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(TEST_SPEC_FILE) $(ERL_FILES) $(RELSYSDIR)
+ @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
diff --git a/lib/jinterface/test/jinterface.dynspec b/lib/jinterface/test/jinterface.dynspec
new file mode 100644
index 0000000000..44712521df
--- /dev/null
+++ b/lib/jinterface/test/jinterface.dynspec
@@ -0,0 +1,32 @@
+%% -*- erlang -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% You can test this file using this command.
+%% file:script("jinterface.dynspec", [{'Os',"Unix"}]).
+
+case case code:priv_dir(jinterface) of
+ {error,bad_name} -> false;
+ P -> filelib:is_dir(P) end of
+ true ->
+ [];
+ false ->
+ NoApp = "No jinterface application",
+ [{skip,{nc_SUITE,NoApp}},
+ {skip,{jinterface_SUITE,NoApp}}]
+end.
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
new file mode 100644
index 0000000000..ea097680dd
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -0,0 +1,761 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(jinterface_SUITE).
+
+-export([all/1, init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
+
+-export([nodename/1, register_and_whereis/1, get_names/1, boolean_atom/1,
+ node_ping/1, mbox_ping/1,
+ java_erlang_send_receive/1,
+ java_internal_send_receive_same_node/1,
+ java_internal_send_receive_different_nodes/1,
+ java_internal_send_receive_self/1,
+ java_link_and_exit/1, erl_link_and_exit/1,
+ erl_link_java_exit/1, java_link_erl_exit/1,
+ internal_link_linking_exits/1, internal_link_linked_exits/1,
+ internal_unlink_linking_exits/1, internal_unlink_linked_exits/1,
+ normal_exit/1, kill_mbox/1, kill_erl_proc_from_java/1,
+ kill_mbox_from_erlang/1, erl_exit_with_reason_any_term/1,
+ java_exit_with_reason_any_term/1,
+ status_handler_localStatus/1, status_handler_remoteStatus/1,
+ status_handler_connAttempt/1]).
+
+-include("test_server.hrl").
+-include("test_server_line.hrl").
+
+-define(debug,true).
+-ifdef(debug).
+-define(dbg(Str,Args), io:format(Str,Args)).
+-else.
+-define(dbg(Str,Args), ok).
+-endif.
+
+-define(link_test_reason,link_test_reason).
+
+%% Test cases in MboxSendReceive.java
+-define(java_erlang_send_receive,1).
+-define(java_internal_send_receive_same_node,2).
+-define(java_internal_send_receive_different_nodes,3).
+-define(java_internal_send_receive_self,4).
+
+%% Test cases in MboxLinkUnlink.java
+-define(java_link_and_exit, 1).
+-define(erl_link_and_exit, 2).
+-define(erl_link_java_exit, 3).
+-define(java_link_erl_exit, 4).
+-define(internal_link_linking_exits, 5).
+-define(internal_link_linked_exits, 6).
+-define(internal_unlink_linking_exits,7).
+-define(internal_unlink_linked_exits,8).
+-define(normal_exit,9).
+-define(kill_mbox,10).
+-define(kill_erl_proc_from_java,11).
+-define(kill_mbox_from_erlang,12).
+-define(erl_exit_with_reason_any_term,13).
+-define(java_exit_with_reason_any_term,14).
+
+
+%% Test cases in NodeStatusHandler.java
+-define(status_handler_localStatus,1).
+-define(status_handler_remoteStatus,2).
+-define(status_handler_connAttempt,3).
+
+%%%-----------------------------------------------------------------
+%%% INIT/END
+%%%-----------------------------------------------------------------
+all(suite) ->
+ lists:append([
+ fundamental(),
+ ping(),
+ send_receive(),
+ link_unlink(),
+ status_handler()
+ ]).
+
+fundamental() ->
+ [
+ nodename, % Nodename.java
+ register_and_whereis, % RegisterAndWhereis.java
+ get_names, % GetNames.java
+ boolean_atom % BooleanAtom.java
+ ].
+
+ping() ->
+ [
+ %% Implemented in NodePing.java
+ node_ping,
+
+ %% Implemented in MboxPing.java
+ mbox_ping
+ ].
+
+
+send_receive() ->
+ [
+ %% Implemented in MboxSendReceive.java
+ java_erlang_send_receive,
+ java_internal_send_receive_same_node,
+ java_internal_send_receive_different_nodes,
+ java_internal_send_receive_self
+ ].
+
+%% Note:
+%%
+%% The test cases in MboxLinkUnlink.java and in
+%% NodePing.java, all uses default cookie, and if there
+%% is a problem with having the same default cookie in
+%% erlang vs jinterface, e.g because the home directory
+%% does not get the same in some cases on Windows
+%% - they will all fail.
+
+link_unlink() ->
+ [
+ %% Implemented in MboxLinkUnlink.java
+ java_link_and_exit,
+ erl_link_and_exit,
+ erl_link_java_exit,
+ java_link_erl_exit,
+ internal_link_linking_exits,
+ internal_link_linked_exits,
+ internal_unlink_linking_exits,
+ internal_unlink_linked_exits,
+ normal_exit,
+ kill_mbox,
+ kill_erl_proc_from_java,
+ kill_mbox_from_erlang,
+ erl_exit_with_reason_any_term,
+ java_exit_with_reason_any_term
+ ].
+
+status_handler() ->
+ [
+ %% Implemented in NodeStatusHandler.java
+ status_handler_localStatus,
+ status_handler_remoteStatus,
+ status_handler_connAttempt
+ ].
+
+
+init_per_suite(Config) when is_list(Config) ->
+ jitu:init_all(Config).
+
+end_per_suite(Config) when is_list(Config) ->
+ jitu:finish_all(Config).
+
+init_per_testcase(_Case,Config) ->
+ Dog = ?t:timetrap({seconds,10}),
+ [{watch_dog,Dog}|Config].
+
+end_per_testcase(_Case,Config) ->
+ ?t:timetrap_cancel(?config(watch_dog,Config)),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% TEST CASES
+%%%-----------------------------------------------------------------
+nodename(doc) ->
+ ["Nodename.java: "
+ "Test OtpNode.node(), OtpNode.alive() and OtpNode.host()"];
+nodename(suite) ->
+ [];
+nodename(Config) when is_list(Config) ->
+ [_,Host] = string:tokens(atom_to_list(node()),"@"),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "Nodename",
+ [list_to_atom(Host)]).
+
+%%%-----------------------------------------------------------------
+register_and_whereis(doc) ->
+ ["RegisterAndWhereis.java: "
+ "Test OtpNode.registerName(...), OtpMbox.registerName(...) and "
+ "OtpNode.whereis(...)"];
+register_and_whereis(suite) ->
+ [];
+register_and_whereis(Config) when is_list(Config) ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "RegisterAndWhereis",
+ []).
+
+%%%-----------------------------------------------------------------
+get_names(doc) ->
+ ["GetNames.java: "
+ "Test OtpNode.getNames()"];
+get_names(suite) ->
+ [];
+get_names(Config) when is_list(Config) ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "GetNames",
+ []).
+
+%%%-----------------------------------------------------------------
+boolean_atom(doc) ->
+ ["BooleanAtom.java: "
+ "Test OtpErlangAtom.booleanValue()"];
+boolean_atom(suite) ->
+ [];
+boolean_atom(Config) when is_list(Config) ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "BooleanAtom",
+ []).
+
+%%%-----------------------------------------------------------------
+node_ping(doc) ->
+ ["NodePing.java: "
+ "Test OtpNode.ping(java.lang.String node, long timeout)"];
+node_ping(suite) ->
+ [];
+node_ping(Config) when is_list(Config) ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "NodePing",
+ [erlang:get_cookie(),node()]).
+
+%%%-----------------------------------------------------------------
+mbox_ping(doc) ->
+ ["MboxPing.java: "
+ "Test OtpNode.createMbox(...) and OtpMbox.ping(...)"];
+mbox_ping(suite) ->
+ [];
+mbox_ping(Config) when is_list(Config) ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxPing",
+ [erlang:get_cookie(),node()]).
+
+%%%-----------------------------------------------------------------
+java_erlang_send_receive(doc) ->
+ ["Test sending/receiving of erlang messages between erlang and java"];
+java_erlang_send_receive(suite) ->
+ [];
+java_erlang_send_receive(Config) when is_list(Config) ->
+ send_receive(?java_erlang_send_receive, fun echo_loop/0, Config).
+
+echo_loop() ->
+ receive
+ {From,Msg} ->
+ ?dbg("erl_send_receive_server received ~p",[{From,Msg}]),
+ ?dbg("erl_send_receive_server sending ~p",[Msg]),
+ From ! Msg,
+ echo_loop();
+ done ->
+ ok
+ end.
+
+
+%%%-----------------------------------------------------------------
+java_internal_send_receive_same_node(doc) ->
+ ["MboxSendReceive.java: "
+ "Test sending/receiving of erlang messages between mboxes "
+ "on the same java node."];
+java_internal_send_receive_same_node(suite) ->
+ [];
+java_internal_send_receive_same_node(Config) when is_list(Config) ->
+ send_receive(?java_internal_send_receive_same_node,
+ fun() -> receive done -> ok end end,
+ Config).
+
+%%%-----------------------------------------------------------------
+java_internal_send_receive_different_nodes(doc) ->
+ ["MboxSendReceive.java: "
+ "Test sending/receiving of erlang messages between mboxes "
+ "on different java nodes."];
+java_internal_send_receive_different_nodes(suite) ->
+ [];
+java_internal_send_receive_different_nodes(Config) when is_list(Config) ->
+ send_receive(?java_internal_send_receive_different_nodes,
+ fun() -> receive done -> ok end end,
+ Config).
+
+%%%-----------------------------------------------------------------
+java_internal_send_receive_self(doc) ->
+ ["MboxSendReceive.java: "
+ "Test sending/receiving of erlang messages from an mbox to itself"];
+java_internal_send_receive_self(suite) ->
+ [];
+java_internal_send_receive_self(Config) when is_list(Config) ->
+ send_receive(?java_internal_send_receive_self,
+ fun() -> receive done -> ok end end,
+ Config).
+
+%%%-----------------------------------------------------------------
+java_link_and_exit(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between erlang process and java mailbox."
+ "Java mailbox links and exits"];
+java_link_and_exit(suite) ->
+ [];
+java_link_and_exit(Config) when is_list(Config) ->
+ LinkFun =
+ fun(Mbox) ->
+ Mbox ! {?java_link_and_exit,self(),?link_test_reason},
+ receive after infinity -> ok end
+ end,
+ erl_java_link(LinkFun,java_link_and_exit,Config).
+
+
+%%%-----------------------------------------------------------------
+erl_link_and_exit(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between erlang process and java mailbox."
+ "Erlang process links and exits"];
+erl_link_and_exit(suite) ->
+ [];
+erl_link_and_exit(Config) when is_list(Config) ->
+ LinkFun = fun(Mbox) ->
+ link(Mbox),
+ Mbox ! {?erl_link_and_exit,self(),?link_test_reason},
+ receive ok -> ok end,
+ exit(?link_test_reason)
+ end,
+ erl_java_link(LinkFun,erl_link_and_exit,Config).
+
+%%%-----------------------------------------------------------------
+erl_link_java_exit(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between erlang process and java mailbox."
+ "Erlang process links and java mailbox exits"];
+erl_link_java_exit(suite) ->
+ [];
+erl_link_java_exit(Config) when is_list(Config) ->
+ LinkFun = fun(Mbox) ->
+ link(Mbox),
+ Mbox ! {?erl_link_java_exit,self(),?link_test_reason},
+ receive after infinity -> ok end
+ end,
+ erl_java_link(LinkFun,erl_link_java_exit,Config).
+
+
+%%%-----------------------------------------------------------------
+java_link_erl_exit(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between erlang process and java mailbox."
+ "Java mailbox links and erlang process exits"];
+java_link_erl_exit(suite) ->
+ [];
+java_link_erl_exit(Config) when is_list(Config) ->
+ LinkFun =
+ fun(Mbox) ->
+ Mbox ! {?java_link_erl_exit,self(),?link_test_reason},
+ receive ok -> ok end,
+ exit(?link_test_reason)
+ end,
+ erl_java_link(LinkFun,java_link_erl_exit,Config).
+
+%%%-----------------------------------------------------------------
+internal_link_linking_exits(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between two java mailboxes."
+ "The mailbox which creates the link is the one exiting"];
+internal_link_linking_exits(suite) ->
+ [];
+internal_link_linking_exits(Config) when is_list(Config) ->
+ internal_link_unlink(?internal_link_linking_exits,
+ internal_link_linking_exits,
+ Config).
+
+%%%-----------------------------------------------------------------
+internal_link_linked_exits(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link between two java mailboxes."
+ "The mailbox which dies not create the link is the one exiting"];
+internal_link_linked_exits(suite) ->
+ [];
+internal_link_linked_exits(Config) when is_list(Config) ->
+ internal_link_unlink(?internal_link_linked_exits,
+ internal_link_linked_exits,
+ Config).
+
+%%%-----------------------------------------------------------------
+internal_unlink_linking_exits(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link and unlink between two java mailboxes. "
+ "Mailbox1 creates a link to mailbox2 and removes it. "
+ "Then it creates another link and mailbox2 removes is. "
+ "Finally mailbox1 exits - mailbox2 must survive"];
+internal_unlink_linking_exits(suite) ->
+ [];
+internal_unlink_linking_exits(Config) when is_list(Config) ->
+ internal_link_unlink(?internal_unlink_linking_exits,
+ internal_unlink_linking_exits,
+ Config).
+
+%%%-----------------------------------------------------------------
+internal_unlink_linked_exits(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test link and unlink between two java mailboxes. "
+ "Mailbox1 creates a link to mailbox2 and removes it. "
+ "Then it creates another link and mailbox2 removes is. "
+ "Finally mailbox2 exits - mailbox1 must survive"];
+internal_unlink_linked_exits(suite) ->
+ [];
+internal_unlink_linked_exits(Config) when is_list(Config) ->
+ internal_link_unlink(?internal_unlink_linked_exits,
+ internal_unlink_linked_exits,
+ Config).
+
+%%%-----------------------------------------------------------------
+normal_exit(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that mbox.close() uses exit reason 'normal', i.e. "
+ "that linked processes are not terminated."];
+normal_exit(suite) ->
+ [];
+normal_exit(Config) when is_list(Config) ->
+ Fun =
+ fun() ->
+ register(erl_link_server,self()),
+ process_flag(trap_exit,true),
+ receive
+ {Main,Mbox} when is_pid(Main), is_pid(Mbox) ->
+ ?dbg("Erlang sending \"~p\"",[normal_exit]),
+ link(Mbox),
+ Pid = spawn_link(fun() ->
+ link(Mbox),
+ Mbox ! {?normal_exit},
+ receive after infinity -> ok end
+ end),
+ receive
+ {'EXIT',Mbox,normal} ->
+ %% Make sure that we don't get the
+ %% exit signal from Pid, and Pid
+ %% should still be alive.
+ receive
+ {'EXIT',Pid,Reason} ->
+ ?dbg("Got unexpected exit signal: ~p",
+ [{'EXIT',Pid,Reason}]),
+ exit({unexpected,{'EXIT',Pid,Reason}})
+ after 500 ->
+ true = erlang:is_process_alive(Pid),
+ exit(Pid,kill)
+ end,
+ receive done -> Main ! done end
+ after 1000 ->
+ receive
+ Other ->
+ ?dbg("Got garbage when waiting for exit:"
+ " ~p", [Other]),
+ Main ! done,
+ exit({got_unexpected,Other})
+ after 0 ->
+ ok
+ end
+ end;
+ Other ->
+ ?dbg("Got garbage: ~p",[Other]),
+ exit(Other)
+ end
+ end,
+
+ spawn_link(Fun),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxLinkUnlink",
+ [erlang:get_cookie(),node()]).
+
+
+%%%-----------------------------------------------------------------
+kill_mbox(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that mbox.exit(new OtpErlangAtom(\"kill\") causes linked "
+ "processes to exit with reason 'killed', which can be trapped."];
+kill_mbox(suite) ->
+ {skip, "Not yet implemented"};
+kill_mbox(Config) when is_list(Config) ->
+ Fun =
+ fun() ->
+ register(erl_link_server,self()),
+ process_flag(trap_exit,true),
+ receive
+ {Main,Mbox} when is_pid(Main), is_pid(Mbox) ->
+ ?dbg("Erlang sending \"~p\"",[kill_mbox]),
+ Pid = spawn_link(fun() ->
+ process_flag(trap_exit,true),
+ link(Mbox),
+ Mbox ! {?kill_mbox},
+ receive
+ {'EXIT',Mbox,killed} ->
+ exit(correct_reason);
+ {'EXIT',Mbox,R} ->
+ exit({faulty_reason,R})
+ end
+ end),
+ receive
+ {'EXIT',Pid,{faulty_reason,Reason}} ->
+ receive done -> Main ! done end,
+ exit({faulty_reason,Reason});
+ {'EXIT',Pid,im_killed} ->
+ receive done -> Main ! done end
+ after 1000 ->
+ receive
+ Other ->
+ ?dbg("Got garbage when waiting for exit:"
+ " ~p", [Other]),
+ Main ! done,
+ exit({got_unexpected,Other})
+ after 0 ->
+ ok
+ end
+ end;
+ Other ->
+ ?dbg("Got garbage: ~p",[Other]),
+ exit(Other)
+ end
+ end,
+
+ spawn_link(Fun),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxLinkUnlink",
+ [erlang:get_cookie(),node()]).
+
+%%%-----------------------------------------------------------------
+kill_erl_proc_from_java(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that mbox.exit(pid, new OtpErlangAtom(\"kill\") causes erlang "
+ "processes <pid> to be killed, even if trapping exits"];
+kill_erl_proc_from_java(suite) ->
+ [];
+kill_erl_proc_from_java(Config) when is_list(Config) ->
+ LinkFun = fun(Mbox) ->
+ process_flag(trap_exit,true),
+ link(Mbox),
+ Mbox ! {?kill_erl_proc_from_java, self()},
+ receive after infinity -> ok end
+ end,
+ erl_java_link(LinkFun,kill_erl_proc_from_java,killed,Config).
+
+%%%-----------------------------------------------------------------
+kill_mbox_from_erlang(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that exit(Mbox,kill) causes linked the Mbox to be killed, and"
+ "linked processes to exit with reason 'killed', even if trapping exits"];
+kill_mbox_from_erlang(suite) ->
+ {skip, "Not yet implemented"};
+kill_mbox_from_erlang(Config) when is_list(Config) ->
+ LinkFun = fun(Mbox) ->
+ link(Mbox),
+ Mbox ! {?kill_mbox_from_erlang},
+ exit(Mbox,kill),
+ receive after infinity -> ok end
+ end,
+ erl_java_link(LinkFun,kill_mbox_from_erlang,killed,Config).
+
+%%%-----------------------------------------------------------------
+erl_exit_with_reason_any_term(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that any erlang term can be used as exit reason when erlang "
+ "process exits and is linked to an mbox."];
+erl_exit_with_reason_any_term(suite) ->
+ [];
+erl_exit_with_reason_any_term(Config) when is_list(Config) ->
+ Reason = [hei,self(),{this,is,"a",[different,"reason"]}],
+ LinkFun = fun(Mbox) ->
+ link(Mbox),
+ Mbox ! {?erl_exit_with_reason_any_term,self(),Reason},
+ receive ok -> ok end,
+ exit(Reason)
+ end,
+ erl_java_link(LinkFun,erl_exit_with_reason_any_term,Reason,Config).
+
+%%%-----------------------------------------------------------------
+java_exit_with_reason_any_term(doc) ->
+ ["MboxLinkUnlink.java: "
+ "Test that any erlang term can be used as exit reason when mbox "
+ "exits and is linked to an erlang process."];
+java_exit_with_reason_any_term(suite) ->
+ [];
+java_exit_with_reason_any_term(Config) when is_list(Config) ->
+ Reason = [hei,self(),{this,is,"a",[different,"reason"]}],
+ LinkFun =
+ fun(Mbox) ->
+ Mbox ! {?java_exit_with_reason_any_term,self(),Reason},
+ receive after infinity -> ok end
+ end,
+ erl_java_link(LinkFun,java_exit_with_reason_any_term,Reason,Config).
+
+
+%%%-----------------------------------------------------------------
+status_handler_localStatus(doc) ->
+ ["NodeStatusHandler.java: "
+ "Test OtpNode.registerStatusHandler(...) and the callback "
+ "OtpNodeStatus.localStatus(...)"];
+status_handler_localStatus(suite) ->
+ [];
+status_handler_localStatus(Config) when is_list(Config) ->
+ spawn_link(fun() ->
+ erl_status_server([{opt,{localStatus,"javanode1",true}},
+ {localStatus,"javanode1",false}])
+ end),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "NodeStatusHandler",
+ [erlang:get_cookie(),node(),?status_handler_localStatus]).
+
+%%%-----------------------------------------------------------------
+status_handler_remoteStatus(doc) ->
+ ["NodeStatusHandler.java: "
+ "Test OtpNode.registerStatusHandler(...) and the callback "
+ "OtpNodeStatus.remoteStatus(...)"];
+status_handler_remoteStatus(suite) ->
+ [];
+status_handler_remoteStatus(Config) when is_list(Config) ->
+ spawn_link(fun() ->
+ erl_status_server([{opt,{localStatus,"javanode1",true}},
+ {remoteStatus,"javanode2",true},
+ {remoteStatus,"javanode2",false}])
+ end),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "NodeStatusHandler",
+ [erlang:get_cookie(),node(),?status_handler_remoteStatus]).
+
+
+%%%-----------------------------------------------------------------
+status_handler_connAttempt(doc) ->
+ ["NodeStatusHandler.java: "
+ "Test OtpNode.registerStatusHandler(...) and the callback "
+ "OtpNodeStatus.connAttempt(...)"];
+status_handler_connAttempt(suite) ->
+ [];
+status_handler_connAttempt(Config) when is_list(Config) ->
+ spawn_link(fun() ->
+ erl_status_server([{opt,{localStatus,"javanode1",true}},
+ {connAttempt,"unknown",true},
+ {connAttempt,"javanode3",false}])
+ end),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "NodeStatusHandler",
+ [erlang:get_cookie(),node(),?status_handler_connAttempt]).
+
+
+%%%-----------------------------------------------------------------
+%%% INTERNAL FUNCTIONS
+%%%-----------------------------------------------------------------
+send_receive(TestCaseTag,Fun,Config) ->
+ spawn(fun() ->
+ register(erl_send_receive_server,self()),
+ receive
+ From when is_pid(From) ->
+ JavaNode = node(From),
+ [JavaNode] = nodes(hidden),
+ From ! {TestCaseTag,self()},
+ Fun(),
+ unregister(erl_send_receive_server)
+ end
+ end),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxSendReceive",
+ [erlang:get_cookie(),node()]).
+
+
+internal_link_unlink(Tag,Msg,Config) ->
+ Fun =
+ fun() ->
+ register(erl_link_server,self()),
+ process_flag(trap_exit,true),
+ receive
+ {Main,Mbox} when is_pid(Main), is_pid(Mbox) ->
+ ?dbg("Erlang sending \"~p\"",[Msg]),
+ Mbox ! {Tag,self(),?link_test_reason},
+ receive done -> Main ! done end;
+ Other ->
+ ?dbg("Got garbage: ~p",[Other]),
+ exit(Other)
+ end
+ end,
+
+ spawn_link(Fun),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxLinkUnlink",
+ [erlang:get_cookie(),node()]).
+
+
+erl_java_link(LinkFun,Msg,Config) ->
+ erl_java_link(LinkFun,Msg,?link_test_reason,Config).
+
+erl_java_link(LinkFun,Msg,Reason,Config) ->
+ Fun =
+ fun() ->
+ register(erl_link_server,self()),
+ process_flag(trap_exit,true),
+ receive
+ {Main,Mbox} when is_pid(Mbox), is_pid(Mbox) ->
+ ?dbg("Erlang sending \"~p\"",[Msg]),
+ Pid = spawn_link(fun() -> LinkFun(Mbox) end),
+ receive
+ {'EXIT',Pid,Reason} ->
+ receive done -> Main ! done end
+ after 1000 ->
+ receive
+ Other ->
+ ?dbg("Got garbage when waiting for exit:"
+ " ~p", [Other]),
+ Main ! done,
+ exit({got_unexpected,Other})
+ after 0 ->
+ ok
+ end
+ end;
+ Other ->
+ ?dbg("Got garbage: ~p",[Other]),
+ exit(Other)
+ end
+ end,
+
+ spawn_link(Fun),
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ "MboxLinkUnlink",
+ [erlang:get_cookie(),node()]).
+
+erl_status_server(List) ->
+ register(erl_status_server,self()),
+ erl_status_server(List,undefined).
+erl_status_server([{opt,{Tag,NodeName,Up}},{Tag2,NodeName2,Up2}|Rest],_) ->
+ receive
+ {Tag,Node,Up,From} = M ->
+ ?dbg("erl_status_server got: ~p",[M]),
+ true = lists:prefix(NodeName,Node),
+ erl_status_server([{Tag2,NodeName2,Up2}|Rest],From);
+ {Tag2,Node2,Up2,From2} = M2 ->
+ ?dbg("erl_status_server got: ~p",[M2]),
+ true = lists:prefix(NodeName2,Node2),
+ erl_status_server(Rest,From2)
+ end;
+erl_status_server([{Tag,NodeName,Up}|Rest],_) ->
+ receive
+ {Tag,Node,Up,From} = M ->
+ ?dbg("erl_status_server got: ~p",[M]),
+ true = lists:prefix(NodeName,Node),
+ erl_status_server(Rest,From);
+ Other ->
+ ?dbg("erl_status_server got garbage: ~p",[Other]),
+ exit(Other)
+ end;
+erl_status_server([],From) ->
+ From ! done.
diff --git a/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java b/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java
new file mode 100644
index 0000000000..9554d50c9f
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/BooleanAtom.java
@@ -0,0 +1,46 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class BooleanAtom {
+
+ /*
+ Implements test case jinterface_SUITE:boolean_atom/1
+
+ Test the function OtpErlangAtom.booleanValue()
+ */
+
+ public static void main(String argv[]) {
+
+ OtpErlangAtom atom = new OtpErlangAtom("true");
+ if (!atom.booleanValue()) fail(1);
+
+ atom = new OtpErlangAtom("false");
+ if (atom.booleanValue()) fail(2);
+
+ atom = new OtpErlangAtom("somethingelse");
+ if (atom.booleanValue()) fail(3);
+
+ }
+
+ private static void fail(int reason) {
+ System.exit(reason);
+ }
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/GetNames.java b/lib/jinterface/test/jinterface_SUITE_data/GetNames.java
new file mode 100644
index 0000000000..3d2bc4ac84
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/GetNames.java
@@ -0,0 +1,68 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import java.util.ArrayList;
+import com.ericsson.otp.erlang.*;
+
+class GetNames {
+
+ /*
+ Implements test case jinterface_SUITE:get_names/1
+
+ */
+
+ public static void main(String argv[]) {
+
+ try {
+ OtpNode node = new OtpNode("javanode");
+ OtpMbox mbox1 = node.createMbox();
+ mbox1.registerName("mbox1");
+ node.createMbox("mbox2");
+ OtpMbox mbox3 = node.createMbox();
+ node.registerName("mbox3",mbox3);
+
+ ArrayList existing_names = new ArrayList();
+ existing_names.add("mbox3");
+ existing_names.add("mbox2");
+ existing_names.add("mbox1");
+
+ String[] names = node.getNames();
+ if (names.length != existing_names.size()) fail(1);
+
+ for(int i=0; i<names.length; i++) {
+ System.out.println("" + names[i]);
+ existing_names.remove(names[i]);
+ }
+
+ if (!existing_names.isEmpty()) fail(2);
+ }
+ catch (Exception e) {
+ fail("" + e, 3);
+ }
+ }
+
+ private static void fail(int reason) {
+ System.exit(reason);
+ }
+
+ private static void fail(String str, int reason) {
+ System.out.println(str);
+ System.exit(reason);
+ }
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/Makefile.src b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..2a3dca463b
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/Makefile.src
@@ -0,0 +1,62 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-2010. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+# Note: This file *must* work for both Unix and Windows
+#
+# We use both `rm' (Unix) and `del' (Windows) for removing files, but
+# with a `-' in front so that the error in not finding `rm' (`del') on
+# Windows (Unix) is ignored.
+#
+# VxWorks? XXX
+#
+
+.SUFFIXES:
+.SUFFIXES: .java
+
+
+JAVAC = @JAVAC@
+ERLC = erlc
+
+JINTERFACE_CLASSPATH = @jinterface_classpath@
+
+CLASSPATH = .@PS@$(JINTERFACE_CLASSPATH)@PS@
+
+JAVA_FILES = \
+ Nodename.java \
+ RegisterAndWhereis.java \
+ GetNames.java \
+ BooleanAtom.java \
+ NodePing.java \
+ MboxPing.java \
+ MboxSendReceive.java \
+ MboxLinkUnlink.java \
+ NodeStatusHandler.java
+
+CLASS_FILES = $(JAVA_FILES:.java=.class)
+
+all: $(CLASS_FILES)
+
+clean:
+ -rm -f $(CLASS_FILES)
+ -del /F /Q $(CLASS_FILES)
+
+$(CLASS_FILES) : $(JAVA_FILES)
+ $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES)
+
+#
diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java b/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java
new file mode 100644
index 0000000000..5d1d097cc8
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/MboxLinkUnlink.java
@@ -0,0 +1,201 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class MboxLinkUnlink {
+
+ /*
+ Implements test case jinterface_SUITE:mbox_link_unlink/1
+
+
+
+ */
+
+ private static final int java_link_and_exit = 1;
+ private static final int erl_link_and_exit = 2;
+ private static final int erl_link_java_exit = 3;
+ private static final int java_link_erl_exit = 4;
+ private static final int internal_link_linking_exits = 5;
+ private static final int internal_link_linked_exits = 6;
+ private static final int internal_unlink_linking_exits = 7;
+ private static final int internal_unlink_linked_exits = 8;
+ private static final int normal_exit = 9;
+ private static final int kill_mbox = 10;
+ private static final int kill_erl_proc_from_java = 11;
+ private static final int kill_mbox_from_erlang = 12;
+ private static final int erl_exit_with_reason_any_term = 13;
+ private static final int java_exit_with_reason_any_term = 14;
+
+ private static boolean dbg = true;
+
+
+ public static void main(String argv[]) {
+
+
+ //String cookie = argv[0];
+ String erlNode = argv[1];
+ OtpErlangObject expected = null;
+ boolean waiting = false;
+
+ try { //
+ OtpNode node = new OtpNode("javanode");
+ OtpMbox mainMbox = node.createMbox();
+
+ try {
+ // Initiate and set up connection to erlang process
+ OtpMbox mbox = node.createMbox();
+ OtpMbox mbox2;
+
+ OtpErlangObject[] msg = {mainMbox.self(),mbox.self()};
+ mbox.send("erl_link_server", erlNode, new OtpErlangTuple(msg));
+ OtpErlangObject o = mbox.receive(1000);
+ if (o == null) System.exit(1);
+ OtpErlangTuple tuple = (OtpErlangTuple)o;
+ int tag = (int)((OtpErlangLong)tuple.elementAt(0)).longValue();
+
+ switch (tag) {
+
+ case java_exit_with_reason_any_term:
+ case java_link_and_exit:
+ dbg("Java got \"java_link_and_exit\" or " +
+ "\"java_exit_with_reason_any_term\"");
+ mbox.link((OtpErlangPid)tuple.elementAt(1));
+ mbox.send((OtpErlangPid)tuple.elementAt(1),
+ new OtpErlangAtom("ok"));
+ mbox.exit(tuple.elementAt(2));
+ break;
+ case erl_exit_with_reason_any_term:
+ case erl_link_and_exit:
+ dbg("Java got \"erl_link_and_exit\" or " +
+ "\"erl_exit_with_reason_any_term\"");
+ mbox.send((OtpErlangPid)tuple.elementAt(1),
+ new OtpErlangAtom("ok"));
+ waiting = true;
+ expected = tuple.elementAt(2);
+ mbox.receive(1000);
+ System.exit(2);
+ case erl_link_java_exit:
+ dbg("Java got \"erl_link_java_exit\"");
+ mbox.exit(tuple.elementAt(2));
+ break;
+ case java_link_erl_exit:
+ dbg("Java got \"java_link_erl_exit\"");
+ mbox.link((OtpErlangPid)tuple.elementAt(1));
+ mbox.send((OtpErlangPid)tuple.elementAt(1),
+ new OtpErlangAtom("ok"));
+ waiting = true;
+ expected = tuple.elementAt(2);
+ mbox.receive(1000);
+ System.exit(3);
+ case internal_link_linking_exits:
+ dbg("Java got \"internal_link_linking_exits\"");
+ mbox2 = node.createMbox();
+ mbox.link(mbox2.self());
+ mbox.exit(tuple.elementAt(2));
+ waiting = true;
+ expected = tuple.elementAt(2);
+ mbox2.receive(1000); // hanging waiting for exit
+ System.exit(4); // got someting other than exit
+ case internal_link_linked_exits:
+ dbg("Java got \"internal_link_linked_exits\"");
+ mbox2 = node.createMbox();
+ mbox.link(mbox2.self());
+ mbox2.exit(tuple.elementAt(2));
+ waiting = true;
+ expected = tuple.elementAt(2);
+ mbox.receive(1000); // hanging waiting for exit
+ System.exit(5); // got someting other than exit
+ case internal_unlink_linking_exits:
+ dbg("Java got \"internal_unlink_linking_exits\"");
+ mbox2 = node.createMbox();
+ mbox.link(mbox2.self());
+ mbox.unlink(mbox2.self());
+ mbox.link(mbox2.self());
+ mbox2.unlink(mbox.self());
+ mbox2.exit(tuple.elementAt(2));
+ if (mbox.receive(500)!=null) System.exit(6);
+ break;
+ case internal_unlink_linked_exits:
+ dbg("Java got \"internal_unlink_linked_exits\"");
+ mbox2 = node.createMbox();
+ mbox.link(mbox2.self());
+ mbox.unlink(mbox2.self());
+ mbox.link(mbox2.self());
+ mbox2.unlink(mbox.self());
+ mbox.exit(tuple.elementAt(2));
+ if (mbox2.receive(500)!=null) System.exit(7);
+ break;
+ case normal_exit:
+ dbg("Java got \"normal_exit\"");
+ mbox.close();
+ break;
+ case kill_mbox:
+ dbg("Java got \"kill_mbox\"");
+ mbox.exit("kill");
+ break;
+ case kill_erl_proc_from_java:
+ dbg("Java got \"kill_erl_proc_from_java\"");
+ mbox.exit((OtpErlangPid)tuple.elementAt(1),"kill");
+ break;
+ case kill_mbox_from_erlang:
+ dbg("Java got \"kill_mbox_from_erlang\"");
+ /* This will make the testcase successful, but it is
+ not the correct way to do it...
+ Mbox should probably just die when the kill signal is
+ received from erlang (or other mbox).
+
+ try {
+ mbox.receive(1000);
+ System.exit(8);
+ }
+ catch (OtpErlangExit exit) {
+ if(!(exit.reason().equals(new OtpErlangAtom("kill"))))
+ System.exit(9);
+ mbox.exit("killed");
+ }
+ */
+ break;
+ }
+ }
+ catch (OtpErlangExit exit) {
+ dbg("Java got exit: " + exit.reason());
+ if(!(waiting && exit.reason().equals(expected)))
+ System.exit(10);
+ }
+
+ OtpErlangAtom done = new OtpErlangAtom("done");
+ mainMbox.send("erl_link_server", erlNode, done);
+ OtpErlangObject o = mainMbox.receive(1000);
+ if (o == null) System.exit(11);
+ else if (!((OtpErlangAtom)o).equals(done))
+ System.exit(12);
+
+ }
+ catch (Exception e) {
+ System.out.println("EXCEPTION: " + e);
+ System.exit(13);
+ }
+ }
+
+ private static void dbg(String str) {
+ if (dbg) System.out.println(str);
+ }
+
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java b/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java
new file mode 100644
index 0000000000..3a8497028e
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/MboxPing.java
@@ -0,0 +1,50 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class MboxPing {
+
+ /*
+ Implements test case jinterface_SUITE:mbox_ping/1
+
+ Creates an OtpNode object with an OtpMbox object. The test_server
+ node is pinged from the OtpMbox.
+ */
+
+ public static void main(String argv[]) {
+
+ try {
+ OtpNode node = new OtpNode("javanode",argv[0]);
+ OtpMbox mbox = node.createMbox();
+ if (mbox.ping(argv[1],2000)) {
+ System.out.println("OtpMbox.ping(" + argv[1] + ") -> true");
+ }
+ else {
+ System.out.println("ERROR: OtpMbox.ping(" + argv[1] +
+ ") -> false");
+ System.exit(1);
+ }
+ }
+ catch (Exception e) {
+ System.out.println("" + e);
+ System.exit(2);
+ }
+ }
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java b/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java
new file mode 100644
index 0000000000..2db71bb5cd
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/MboxSendReceive.java
@@ -0,0 +1,229 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class MboxSendReceive {
+
+ /*
+ Implements test case jinterface_SUITE:mbox_send_receive/1
+
+ Test OtpMbox.send(...) and OtpMbox.receive(...)
+ */
+
+ private static final boolean dbg = true;
+ private static final int recTime = 2000;
+
+ private static final int java_erlang_send_receive = 1;
+ private static final int java_internal_send_receive_same_node = 2;
+ private static final int java_internal_send_receive_different_nodes = 3;
+ private static final int java_internal_send_receive_self = 4;
+
+ public static void main(String argv[]) {
+
+ String cookie = argv[0];
+ String erlNode = argv[1];
+
+ OtpErlangObject[] msgArray = new OtpErlangObject[2];
+ msgArray[1] = new OtpErlangAtom("hello world");
+ OtpErlangTuple msg = null;
+
+ try {
+ // Initiate: create javanode and mboxes
+ OtpNode node = new OtpNode("javanode",cookie);
+ OtpMbox mbox = node.createMbox();
+ OtpMbox mbox2 = node.createMbox("java_echo_server2");
+
+ // Send the pid of mbox to erlang and wait for test case
+ // instruction: {TestCaseTag, Pid}
+ mbox.send("erl_send_receive_server", erlNode, mbox.self());
+ OtpErlangObject o = mbox.receive(recTime);
+ if (o == null) System.exit(1);
+ OtpErlangTuple testCase = (OtpErlangTuple)o;
+ dbg("mbox received " + testCase);
+ int tag = (int)((OtpErlangLong)testCase.elementAt(0)).longValue();
+ OtpErlangPid erlangPid = (OtpErlangPid)testCase.elementAt(1);
+
+ switch (tag) {
+
+ case java_erlang_send_receive:
+
+ // Test1 (happened during initiation):
+ // Send mbox pid to erlang process with registered name.
+ // Erlang process sent back its pid to the mbox pid.
+
+ // Test2: Register name and sent it to the erlang pid. Erlang
+ // process shall send message back to my registered name.
+
+ mbox.registerName("java_echo_server");
+ msgArray[0] = getNameNode("java_echo_server",node);
+ msg = new OtpErlangTuple(msgArray);
+
+ dbg("java_echo_server sending " + msg);
+ mbox.send(erlangPid,msg);
+
+ o = mbox.receive(recTime);
+ dbg("java_echo_server received " + o);
+ if (o == null) System.exit(2);
+ if (!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(3);
+
+ // Test3: Same as Test2, but using a new mbox2 which
+ // got its name already when it is created - i.e. not
+ // using mbox.registerName
+ msgArray[0] = getNameNode("java_echo_server2",node);
+ msg = new OtpErlangTuple(msgArray);
+
+ dbg("java_echo_server2 sending " + msg);
+ mbox2.send(erlangPid,msg);
+
+ o = mbox2.receive(recTime);
+ dbg("java_echo_server received " + o);
+ if (o == null) System.exit(4);
+ if (!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(5);
+
+ break;
+
+ case java_internal_send_receive_same_node:
+
+ // Test1: Sending message between mboxes on same node
+ // given registered name and node without host.
+ mbox.send("java_echo_server2","javanode",msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(6);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(7);
+
+ // Test2: Sending message between mboxes on same node
+ // given registered name and node with host.
+ mbox.send("java_echo_server2",mbox2.self().node(),msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(8);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(9);
+
+ // Test3: Sending message between mboxes on same node
+ // given registered name but not node.
+ mbox.send("java_echo_server2",msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(10);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(11);
+
+ // Test4: Sending message between mboxes on same node
+ // given pid.
+ mbox.send(mbox2.self(),msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(12);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(13);
+
+ break;
+
+ case java_internal_send_receive_different_nodes:
+
+ OtpNode node2 = new OtpNode("javanode2", cookie);
+ OtpMbox mboxOtherNode = node2.createMbox("mboxOtherNode");
+
+ // Test1: Sending message between mboxes on different
+ // nodes given registered name and node without host.
+ mbox.send("mboxOtherNode","javanode2",msgArray[1]);
+ o = mboxOtherNode.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(14);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(15);
+
+ // Test2: Sending message between mboxes on different
+ // nodes given registered name and node with host.
+ mbox.send("mboxOtherNode",mboxOtherNode.self().node(),
+ msgArray[1]);
+ o = mboxOtherNode.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(16);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(17);
+
+ // Test3: Sending message between mboxes on different
+ // nodes given pid.
+ mbox.send(mboxOtherNode.self(),msgArray[1]);
+ o = mboxOtherNode.receive(recTime);
+ dbg("Mbox at same node: " + o);
+ if (o == null) System.exit(18);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(19);
+
+ break;
+
+
+ case java_internal_send_receive_self:
+
+ // Test1: Sending message to myself given registered
+ // name and node without host.
+ mbox2.send("java_echo_server2","javanode",msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Self: " + o);
+ if (o == null) System.exit(18);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(19);
+
+ // Test2: Sending message to myself given registered
+ // name and node with host.
+ mbox2.send("java_echo_server2",mbox2.self().node(),msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Self: " + o);
+ if (o == null) System.exit(20);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(21);
+
+ // Test3: Sending message to myself given registered
+ // name but not host.
+ mbox2.send("java_echo_server2",msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Self: " + o);
+ if (o == null) System.exit(22);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(23);
+
+ // Test4: Sending message to myself given pid.
+ mbox2.send(mbox2.self(),msgArray[1]);
+ o = mbox2.receive(recTime);
+ dbg("Self: " + o);
+ if (o == null) System.exit(24);
+ if(!((OtpErlangAtom)o).equals(msgArray[1])) System.exit(25);
+
+ break;
+
+ }
+
+ // Closing erl_send_receive_server by sending the atom 'done' to it.
+ mbox.send(erlangPid,new OtpErlangAtom("done"));
+ }
+ catch (Exception e) {
+ System.out.println("" + e);
+ System.exit(26);
+ }
+ }
+
+ private static OtpErlangTuple getNameNode(String mboxName,OtpNode node) {
+ OtpErlangObject[] array = {new OtpErlangAtom(mboxName),
+ new OtpErlangAtom(node.node())};
+ return new OtpErlangTuple(array);
+
+ }
+
+ private static void dbg(String str) {
+ if (dbg) System.out.println(str);
+ }
+
+
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/NodePing.java b/lib/jinterface/test/jinterface_SUITE_data/NodePing.java
new file mode 100644
index 0000000000..d0df5c46b5
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/NodePing.java
@@ -0,0 +1,83 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class NodePing {
+
+ /*
+ Implements test case jinterface_SUITE:node_ping/1
+
+ Creates three OtpNode objects. One with default cookie, one with
+ specified same cookie as the node running the test case and one
+ with a faulty cookie. From each OtpNode object the test_server
+ node is pinged.
+
+ Also the default cookie node pings itself, and the node with the
+ specified cookie pings the node with default cookie.
+ */
+
+ public static void main(String argv[]) {
+
+ String cookie = argv[0];
+ String erlNode = argv[1];
+
+ try {
+ OtpNode node1 = new OtpNode("javanode1");
+ ping(node1,erlNode,"Default cookie:",true,1);
+ ping(node1,node1.node(),"Self:",true,2);
+ ping(node1,"javanode1","Self:",true,3);
+
+ OtpNode node2 = new OtpNode("javanode2",cookie);
+ ping(node2,erlNode,"Specified cookie:",true,4);
+ ping(node2,"javanode1","Javanode (no host):",true,5);
+ ping(node2,node1.node(),"Javanode:",true,6);
+
+ OtpNode node3 = new OtpNode("javanode3","faultycookie");
+ ping(node3,erlNode,"Faulty cookie:",false,7);
+
+ // Test OtpNode.cookie() and OtpNode.setCookie(cookie) as well
+ if (!node3.cookie().equals("faultycookie"))
+ fail("Testing OtpNode.cookie()",8);
+ String old = node3.setCookie(cookie);
+ if (!old.equals("faultycookie"))
+ fail("Checking return of OtpNode.setCookie(cookie)",9);
+ ping(node3,erlNode,"setCookie:",true,10);
+ }
+ catch (Exception e) {
+ fail("" + e, 11);
+ }
+ }
+
+ private static void ping(OtpNode node, String remote, String descr,
+ boolean expected, int reason) {
+ if ( node.ping(remote,2000) == expected ) {
+ System.out.println(descr + " ping(" + remote + ") -> " + expected);
+ }
+ else {
+ fail("ERROR: " + descr + " ping(" + remote +") -> " + !expected,
+ reason);
+ }
+ }
+
+ private static void fail(String str, int reason) {
+ System.out.println(str);
+ System.exit(reason);
+ }
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java b/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java
new file mode 100644
index 0000000000..51ea15b5ef
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/NodeStatusHandler.java
@@ -0,0 +1,168 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+public class NodeStatusHandler extends OtpNodeStatus {
+ /*
+ Implements java side of test cases in jinterface_SUITE.erl
+
+ Test OtpNode.registerStatusHandler(...) and class OtpNodeStatus.
+ */
+
+ private static final boolean dbg = true;
+ private static final int recTime = 2000;
+
+ private static String erlNode = null;
+ private static String cookie = null;
+ private static OtpMbox mbox = null;
+
+ private static final int status_handler_localStatus = 1;
+ private static final int status_handler_remoteStatus = 2;
+ private static final int status_handler_connAttempt = 3;
+
+ public static void main(String argv[]) {
+
+ cookie = argv[0];
+ erlNode = argv[1];
+
+ try {
+ OtpNode javaNode = new OtpNode("javanode", cookie);
+ mbox = javaNode.createMbox();
+ }
+ catch (Exception e) {
+ dbg("EXCEPTION when creating javanode: " + e);
+ System.exit(1);
+ }
+
+ try {
+ OtpNode node1 = new OtpNode("javanode1", cookie);
+ node1.registerStatusHandler(new NodeStatusHandler());
+
+ switch (Integer.parseInt(argv[2])) {
+
+ case status_handler_localStatus:
+ dbg("java running test case \"status_handler_localStatus\"");
+
+ Thread.sleep(200); // Give 'nodeup' message a chance
+ // before closing
+ node1.close();
+ Thread.sleep(500);
+ break;
+
+ case status_handler_remoteStatus:
+ dbg("java running test case \"status_handler_remoteStatus\"");
+
+ OtpNode node2 = new OtpNode("javanode2", cookie);
+ node2.ping(node1.node(),2000);
+ node2.close();
+ Thread.sleep(500);
+ break;
+
+ case status_handler_connAttempt:
+ dbg("java running test case \"status_handler_connAttempt\"");
+
+ OtpNode node3 = new OtpNode("javanode3","othercookie");
+ node3.ping(node1.node(),2000);
+ node1.ping(node3.node(),2000);
+ break;
+
+ }
+
+ OtpErlangObject o = mbox.receive(recTime);
+ if (o == null) System.exit(2);
+ if (! ((OtpErlangAtom)o).atomValue().equals("done"))
+ System.exit(3);
+
+ }
+ catch (Exception e) {
+ dbg("EXCEPTION: " + e);
+ System.exit(4);
+ }
+
+ }
+
+
+
+ public void remoteStatus(String node, boolean up, Object info) {
+ try {
+ dbg("Got remoteStatus: " + node + " " + up + " " + info);
+ OtpErlangObject[] msgArray = new OtpErlangObject[4];
+ msgArray[0] = new OtpErlangAtom("remoteStatus");
+ msgArray[1] = new OtpErlangString(node);
+ msgArray[2] = new OtpErlangBoolean(up);
+ msgArray[3] = mbox.self();
+ OtpErlangTuple msg = new OtpErlangTuple(msgArray);
+ mbox.send("erl_status_server", erlNode, msg);
+
+ }
+ catch (Exception e) {
+ dbg("EXCEPTION in remoteStatus: " + e + "\nArgs: " +
+ node + " " + up + " " + info);
+ System.exit(5);
+ }
+ }
+
+
+ public void localStatus(String node, boolean up, Object info) {
+ try {
+ dbg("Got localStatus: " + node + " " + up + " " + info);
+ OtpErlangObject[] msgArray = new OtpErlangObject[4];
+ msgArray[0] = new OtpErlangAtom("localStatus");
+ msgArray[1] = new OtpErlangString(node);
+ msgArray[2] = new OtpErlangBoolean(up);
+ msgArray[3] = mbox.self();
+ OtpErlangTuple msg = new OtpErlangTuple(msgArray);
+ mbox.send("erl_status_server", erlNode, msg);
+
+ }
+ catch (Exception e) {
+ dbg("EXCEPTION in localStatus: " + e + "\nArgs: " +
+ node + " " + up + " " + info);
+ System.exit(6);
+ }
+ }
+
+
+
+ public void connAttempt(String node, boolean incoming, Object info) {
+ try {
+ dbg("Got connAttempt: " + node + " " + incoming + " " + info);
+ OtpErlangObject[] msgArray = new OtpErlangObject[4];
+ msgArray[0] = new OtpErlangAtom("connAttempt");
+ msgArray[1] = new OtpErlangString(node);
+ msgArray[2] = new OtpErlangBoolean(incoming);
+ msgArray[3] = mbox.self();
+ OtpErlangTuple msg = new OtpErlangTuple(msgArray);
+ mbox.send("erl_status_server", erlNode, msg);
+
+ }
+ catch (Exception e) {
+ dbg("EXCEPTION in connAttempt: " + e + "\nArgs: " +
+ node + " " + incoming + " " + info);
+ System.exit(7);
+ }
+ }
+
+
+ private static void dbg(String str) {
+ if (dbg) System.out.println(str);
+ }
+
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/Nodename.java b/lib/jinterface/test/jinterface_SUITE_data/Nodename.java
new file mode 100644
index 0000000000..dc8cb9c49f
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/Nodename.java
@@ -0,0 +1,54 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class Nodename {
+
+ /*
+ Implements test case jinterface_SUITE:nodename/1
+
+ */
+
+ public static void main(String argv[]) {
+
+ String host = argv[0];
+
+ try {
+ OtpNode node = new OtpNode("javanode");
+ System.out.println("Given host: " + host +
+ " Host: " + node.host() +
+ " Alive: " + node.alive() +
+ " Node: " + node.node());
+
+ if (!node.host().equals(host)) fail(1);
+ if (!node.alive().equals("javanode")) fail(2);
+ if (!node.node().equals("javanode@" + host)) fail(3);
+ }
+ catch (Exception e) {
+ System.out.println("" + e);
+ fail(4);
+ }
+ }
+
+ private static void fail(int reason) {
+ System.exit(reason);
+ }
+
+}
diff --git a/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java b/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java
new file mode 100644
index 0000000000..9df01981b2
--- /dev/null
+++ b/lib/jinterface/test/jinterface_SUITE_data/RegisterAndWhereis.java
@@ -0,0 +1,79 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+class RegisterAndWhereis {
+
+ /*
+ Implements test case jinterface_SUITE:register_and_whereis/1
+
+ */
+
+ public static void main(String argv[]) {
+
+ try {
+ OtpNode node = new OtpNode("javanode");
+ OtpMbox mbox1 = node.createMbox();
+ mbox1.registerName("mbox1");
+ OtpMbox mbox2 = node.createMbox("mbox2");
+ OtpMbox mbox3 = node.createMbox();
+ node.registerName("mbox3",mbox3);
+
+ OtpErlangPid pid1 = mbox1.self();
+ OtpErlangPid pid2 = mbox2.self();
+ OtpErlangPid pid3 = mbox3.self();
+
+ if (!pid1.equals(node.whereis("mbox1"))) fail(1);
+ if (!pid1.equals(mbox1.whereis("mbox1"))) fail(2);
+ if (!pid1.equals(mbox2.whereis("mbox1"))) fail(3);
+ if (!pid1.equals(mbox3.whereis("mbox1"))) fail(4);
+ if (!pid2.equals(node.whereis("mbox2"))) fail(5);
+ if (!pid2.equals(mbox2.whereis("mbox2"))) fail(6);
+ if (!pid3.equals(node.whereis("mbox3"))) fail(7);
+ if (!pid3.equals(mbox3.whereis("mbox3"))) fail(8);
+
+ node.closeMbox(mbox1);
+ mbox2.close();
+
+ if (node.whereis("mbox1") != null) fail(9);
+ if (node.whereis("mbox2") != null) fail(10);
+ if (mbox3.whereis("mbox1") != null) fail(11);
+ if (mbox3.whereis("mbox2") != null) fail(12);
+
+ mbox3.close();
+ if (mbox2.whereis("mbox3") != null) fail(13);
+
+
+
+ }
+ catch (Exception e) {
+ fail("" + e, 14);
+ }
+ }
+
+ private static void fail(int reason) {
+ System.exit(reason);
+ }
+
+ private static void fail(String str, int reason) {
+ System.out.println(str);
+ System.exit(reason);
+ }
+}
diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl
new file mode 100644
index 0000000000..c57fb9bfad
--- /dev/null
+++ b/lib/jinterface/test/jitu.erl
@@ -0,0 +1,156 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% JInterface Test Utils
+%%----------------------------------------------------------------------
+-module(jitu).
+
+
+-export([java/3,
+ java/4,
+ java/5,
+ init_all/1,
+ finish_all/1]).
+
+%%
+%% Lots of stuff here are originating from java_client_erl_server_SUITE.erl
+%% (ic) ...
+%%
+
+
+
+java(Java, Dir, ClassAndArgs) ->
+ cmd(Java++" -classpath "++classpath(Dir)++" "++ClassAndArgs).
+
+java(Java, Dir, Class, Args) ->
+ java(Java, Dir, Class++" "++to_string(Args)).
+
+java(Java, Dir, Class, Args, Props) ->
+ java(Java, Dir, Props++" "++Class, Args).
+
+
+
+
+init_all(Config) when list(Config) ->
+ case find_executable(["java"]) of
+ false -> {skip,"Found no Java VM"};
+ Path -> [{java,Path}|Config]
+ end.
+
+finish_all(Config) -> Config.
+
+%%
+%% Internal stuff...
+%%
+
+
+find_executable([]) ->
+ false;
+find_executable([E|T]) ->
+ case os:find_executable(E) of
+ false -> find_executable(T);
+ Path -> Path
+ end.
+
+to_string([H|T]) when integer(H) ->
+ integer_to_list(H)++" "++to_string(T);
+to_string([H|T]) when atom(H) ->
+ atom_to_list(H)++" "++to_string(T);
+to_string([H|T]) when pid(H) ->
+ pid_to_list(H)++" "++to_string(T);
+to_string([H|T]) when list(H) ->
+ lists:flatten(H)++" "++to_string(T);
+to_string([]) -> [].
+
+% javac(Dir, File) ->
+% cmd("javac -d "++Dir++" -classpath "++classpath(Dir)++" "++
+% filename:join(Dir, File)).
+
+classpath(Dir) ->
+ PS =
+ case os:type() of
+ {win32, _} -> ";";
+ _ -> ":"
+ end,
+ Dir++PS++
+ filename:join([code:lib_dir(jinterface),"priv","OtpErlang.jar"])++PS++
+ case os:getenv("CLASSPATH") of
+ false -> "";
+ Classpath -> Classpath
+ end.
+
+
+cmd(Cmd) ->
+ PortOpts = [{line,80},eof,exit_status,stderr_to_stdout],
+ io:format("cmd: ~s~n", [Cmd]),
+ case catch open_port({spawn,Cmd}, PortOpts) of
+ Port when port(Port) ->
+ Result = cmd_loop(Port, []),
+ io:format("cmd res: ~w~n", [Result]),
+ case Result of
+ 0 -> ok;
+ ExitCode when integer(ExitCode) -> {error,ExitCode};
+ Error -> Error
+ end;
+ {'EXIT',Reason} ->
+ {error,Reason}
+ end.
+
+cmd_loop(Port, Line) ->
+ receive
+ {Port,eof} ->
+ receive
+ {Port,{exit_status,ExitStatus}} ->
+ ExitStatus
+ after 1 ->
+ undefined
+ end;
+ {Port,{exit_status,ExitStatus}} ->
+ receive
+ {Port,eof} ->
+ ok after 1 -> ok end,
+ ExitStatus;
+ {Port,{data,{Tag,Data}}} ->
+ case Tag of
+ eol ->
+ io:put_chars([Line|cr_to_nl(Data)]),
+ io:nl(),
+ cmd_loop(Port, []);
+ noeol ->
+ cmd_loop(Port, [Line|cr_to_nl(Data)])
+ end;
+ {'EXIT',Port,Reason} ->
+ {error,Reason};
+ Other ->
+ io:format("WARNING: Unexpected at ~s:~p: ~p~n",
+ [?MODULE_STRING,?LINE,Other]),
+ cmd_loop(Port, Line)
+ end.
+
+%% Convert lonely CR to NL, and CRLF to NL
+%%
+cr_to_nl([$\r,$\n|T]) ->
+ [$\n|cr_to_nl(T)];
+cr_to_nl([$\r|T]) ->
+ [$\n|cr_to_nl(T)];
+cr_to_nl([C|T]) ->
+ [C|cr_to_nl(T)];
+cr_to_nl([]) ->
+ [].
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
new file mode 100644
index 0000000000..82dd3c2535
--- /dev/null
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -0,0 +1,736 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(nc_SUITE).
+
+
+-include("test_server.hrl").
+-include("test_server_line.hrl").
+
+
+-export([all/1,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+-export([pid_roundtrip/1,
+ port_roundtrip/1,
+ ref_roundtrip/1,
+ new_float/1,
+ old_stuff/1,
+ binary_roundtrip/1,
+ decompress_roundtrip/1,
+ compress_roundtrip/1,
+ integer_roundtrip/1,
+ fun_roundtrip/1,
+ lists_roundtrip/1,
+ lists_roundtrip_2/1,
+ lists_iterator/1,
+ unicode/1,
+ unicode_list_to_string/1,
+ unicode_string_to_list/1,
+ connect/1]).
+
+
+%% Top of cases
+
+all(doc) -> [];
+all(suite) -> [pid_roundtrip,
+ port_roundtrip,
+ ref_roundtrip,
+ new_float,
+ old_stuff,
+ binary_roundtrip,
+ decompress_roundtrip,
+ compress_roundtrip,
+ integer_roundtrip,
+ fun_roundtrip,
+ lists_roundtrip,
+ lists_roundtrip_2,
+ lists_iterator,
+ unicode,
+ unicode_list_to_string,
+ unicode_string_to_list,
+ connect].
+
+
+
+
+init_per_suite(Config) when is_list(Config) ->
+ jitu:init_all(Config).
+
+end_per_suite(Config) ->
+ jitu:finish_all(Config).
+
+
+
+%% Add/remove watchdog before/after each test case.
+%%
+init_per_testcase(Case, Config) ->
+ T = case atom_to_list(Case) of
+ "unicode"++_ -> 240;
+ _ -> 20
+ end,
+ WatchDog = test_server:timetrap(test_server:seconds(T)),
+ [{watchdog, WatchDog}| Config].
+
+end_per_testcase(_Case, Config) ->
+ WatchDog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(WatchDog).
+
+
+%%
+%% Test cases
+%%
+
+pid_roundtrip(doc) -> [];
+pid_roundtrip(suite) -> [];
+pid_roundtrip(Config) when is_list(Config)->
+ ThisNode = {node(), erlang:system_info(creation)},
+ RemNode = {gurka@sallad, 2},
+ do_echo([self(),
+ mk_pid(ThisNode, 4711, 4711),
+ mk_pid(ThisNode, 32767, 8191),
+ mk_pid(RemNode, 4711, 4711),
+ mk_pid(RemNode, 32767, 8191)],
+ Config).
+
+fun_roundtrip(doc) -> [];
+fun_roundtrip(suite) -> [];
+fun_roundtrip(Config) when is_list(Config)->
+ do_echo([fun(A, B) -> A + B end,
+ fun(A) -> lists:reverse(A) end,
+ fun() -> ok end,
+ fun fun_roundtrip/1],
+ Config).
+
+port_roundtrip(doc) -> [];
+port_roundtrip(suite) -> [];
+port_roundtrip(Config) when is_list(Config)->
+ ThisNode = {node(), erlang:system_info(creation)},
+ RemNode = {gurka@sallad, 2},
+ do_echo([hd(erlang:ports()),
+ mk_port(ThisNode, 4711),
+ mk_port(ThisNode, 268435455),
+ mk_port(RemNode, 4711),
+ mk_port(RemNode, 268435455)],
+ Config).
+
+ref_roundtrip(doc) -> [];
+ref_roundtrip(suite) -> [];
+ref_roundtrip(Config) when is_list(Config)->
+ ThisNode = {node(), erlang:system_info(creation)},
+ RemNode = {gurka@sallad, 2},
+ do_echo([make_ref(),
+ mk_ref(ThisNode, [4711]),
+ mk_ref(ThisNode, [4711, 4711, 4711]),
+ mk_ref(ThisNode, [262143, 4294967295, 4294967295]),
+ mk_ref(RemNode, [4711]),
+ mk_ref(RemNode, [4711, 4711, 4711]),
+ mk_ref(RemNode, [262143, 4294967295, 4294967295])],
+ Config).
+
+new_float(doc) -> [];
+new_float(suite) -> [];
+new_float(Config) when is_list(Config)->
+ Two16 = float(1 bsl 16),
+ X = math:sqrt(2),
+ Floats = lists:reverse(seq(1/X, 63, fun(Y) -> Y / Two16 end),
+ [0.0|seq(X, 63, fun(Y) -> Y * Two16 end)]),
+ io:format("~w", [Floats]),
+ do_echo(Floats, Config).
+
+old_stuff(doc) -> [];
+old_stuff(suite) -> [];
+old_stuff(Config) when is_list(Config)->
+ Terms = [0.0,math:sqrt(2)],
+ OutTrans =
+ fun (D) ->
+ {self(),term_to_binary(D, [{minor_version,0}]),binary}
+ end,
+ InTrans =
+ fun (Echoer, D, {Echoer,D,binary}) ->
+ ok
+ end,
+ do_echo(Terms, Config, OutTrans, InTrans).
+
+binary_roundtrip(doc) -> [];
+binary_roundtrip(suite) -> [];
+binary_roundtrip(Config) when is_list(Config) ->
+ do_echo([<<17>>,
+ <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17>>,
+ <<3:2>>,
+ <<3,7:3>>,
+ <<>>],
+ Config).
+
+decompress_roundtrip(doc) -> [];
+decompress_roundtrip(suite) -> [];
+decompress_roundtrip(Config) when is_list(Config) ->
+ Terms =
+ [0.0,
+ math:sqrt(2),
+ <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
+ make_ref()],
+ OutTrans =
+ fun (D) ->
+ {self(),term_to_binary(D, [compressed]),binary}
+ end,
+ InTrans =
+ fun (Echoer, D, {Echoer,D,binary}) ->
+ ok
+ end,
+ do_echo(Terms, Config, OutTrans, InTrans).
+
+compress_roundtrip(doc) -> [];
+compress_roundtrip(suite) -> [];
+compress_roundtrip(Config) when is_list(Config) ->
+ Terms =
+ [0.0,
+ math:sqrt(2),
+ <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
+ make_ref()],
+ OutTrans =
+ fun (D) ->
+ {self(),D,compress}
+ end,
+ InTrans =
+ fun (Echoer, D, {Echoer,B,compress}) ->
+ D = binary_to_term(B)
+ end,
+ do_echo(Terms, Config, OutTrans, InTrans).
+
+
+
+integer_roundtrip(doc) -> [];
+integer_roundtrip(suite) -> [];
+integer_roundtrip(Config) when is_list(Config) ->
+ Xs = [1 bsl X || X <- [26,27,28,29,30,31,32,33,
+ 62,63,64,65,
+ 126,127,128,129]],
+ Terms = [0,1,-1,-2]
+ ++lists:flatmap(fun (X) -> [X-2,X-1,X,-X+1,-X,-X-1] end,
+ Xs),
+ io:format("~w", [Terms]),
+ OutTrans =
+ fun (V) ->
+ {self(),V,bigint}
+ end,
+ InTrans =
+ fun (Echoer, V, {Echoer,{V,W,X,L,U},bigint}) ->
+ Bitlength = bitlength(V),
+ {w,W} = {w,signum(V) * Bitlength},
+ Y = V band 16#FFFFffffFFFFffff,
+ {y,Y} = {y,X band 16#FFFFffffFFFFffff},
+ {l,L} = {l,if V =:= X, Bitlength < 64 -> 1;
+ true -> 0 end},
+ {u,U} = {u,if V =:= Y, V >= 0, Bitlength =< 64 -> 1;
+ true -> 0 end}
+ end,
+ do_echo(Terms, Config, OutTrans, InTrans).
+
+signum(V) when is_integer(V), V > 0 -> 1;
+signum(V) when is_integer(V), V < 0 -> -1;
+signum(0) -> 0.
+
+bitlength(0) ->
+ 0;
+bitlength(-1) ->
+ 0;
+bitlength(V) when is_integer(V) ->
+ 1 + bitlength(V bsr 1).
+
+
+
+lists_roundtrip(doc) -> [];
+lists_roundtrip(suite) -> [];
+lists_roundtrip(Config) when is_list(Config) ->
+ Ls = [lists:seq(1,10),
+ lists:seq(11,17)++last_tail,
+ [{default}],
+ [car|cdr],
+ [[]],
+ []],
+ do_echo(Ls, Config).
+
+
+
+lists_roundtrip_2(doc) -> [];
+lists_roundtrip_2(suite) -> [];
+lists_roundtrip_2(Config) when is_list(Config) ->
+ Ls = [{[a,b],tail},
+ {[c,d,e],tail},
+ {[],tail},
+ {[f],tail},
+ {[g,h|i],tail},
+ {[j,k,l|m],tail},
+ {[n|o],tail},
+ {[z,1,2,3,4],tail3},
+ {[z,5,6,7],tail3},
+ {[z,8,9],tail3},
+ {[z,10],tail3},
+ {[],tail3},
+ {[z,11,12,13,14|15],tail3},
+ {[z,16,17,18|19],tail3},
+ {[z,20,21|22],tail3},
+ {[z,23|24],tail3},
+ {[z|25],tail3},
+ {"abc123",sub3atom},
+ {"abc",sub3atom}
+ ],
+ Trans =
+ fun ([_|T], tail) ->
+ T;
+ (L, tail) when is_list(L) ->
+ null;
+ ([_,_,_|T], tail3) ->
+ T;
+ (L, tail3) when is_list(L) ->
+ null;
+ ([_,_,_|L], sub3atom) ->
+ list_to_atom(L)
+ end,
+ OutTrans =
+ fun ({L,Twist}) ->
+ {self(),L,Twist}
+ end,
+ InTrans =
+ fun (Echoer, {L,Twist}, {Echoer,X,Twist}) ->
+ Y = Trans(L, Twist),
+ io:format("## ~w ~w ~w ~w~n", [L,Twist,X,Y]),
+ X = Y
+ end,
+ do_echo(Ls, Config, OutTrans, InTrans).
+
+
+
+
+lists_iterator(doc) -> [];
+lists_iterator(suite) -> [];
+lists_iterator(Config) when is_list(Config) ->
+ Ls = [["able ","was ","I ","ere ","I ","saw ","elba"]],
+ do_echo(Ls, Config,
+ fun (L) -> {self(),L,strcat} end,
+ fun (Echoer, L, {Echoer,X,strcat}) ->
+ io:format("## ~p ~p~n", [L,X]),
+ X = lists:flatten(L)
+ end).
+
+
+
+unicode(doc) -> [];
+unicode(suite) -> [];
+unicode(Config) when is_list(Config) ->
+ S1 = "plain ascii",
+ S2 = "iso-latin ��� �",
+ S3 = "Codepoints... ��� \x{1000}",
+ S4 = [0,1,31,32,63,64,127,128,255],
+ S5 = [0,1,127,128,255,256,16#d7ff,
+ 16#e000,16#fffd,16#10000,16#10ffff],
+ Ss = [S1,S2,S3,S4,S5],
+ do_echo(unicode_cp_gen([{S,valid} || S <- Ss] ++ cp_gen(71)), Config,
+ fun ({L,invalid}) -> {self(),L,utf8};
+ ({L,Tag}) -> {self(),L,Tag};
+ ({L}) -> {self(),L}
+ end,
+ fun (Echoer, {L,invalid}=Out, {Echoer,X,utf8}=In) ->
+ case L of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end;
+ (Echoer, {L,Tag}=Out, {Echoer,X,Tag}=In) ->
+ case unicode:characters_to_binary(L, utf8) of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end;
+ (Echoer, {L}=Out, {Echoer,X}=In) ->
+ case L of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end
+ end, ["unicode"]).
+
+%% Lazy wrapper to lazy list
+unicode_cp_gen([{S,valid}|Ss]) ->
+ [{S,utf8},{S}|unicode_cp_gen(Ss)];
+unicode_cp_gen([{S,invalid}=St|Ss]) ->
+ [St,{S}|unicode_cp_gen(Ss)];
+unicode_cp_gen([]) ->
+ [];
+unicode_cp_gen(Cont) when is_function(Cont, 0) ->
+ fun () ->
+ unicode_cp_gen(Cont())
+ end.
+
+
+
+unicode_list_to_string(doc) -> [];
+unicode_list_to_string(suite) -> [];
+unicode_list_to_string(Config) when is_list(Config) ->
+ do_echo(cp_gen(73), Config,
+ fun ({L,_}) -> {self(),L,to_string_neg_int_list} end,
+ fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) ->
+ case L of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end;
+ (Echoer, {L,valid}=Out, {Echoer,X,_}=In) ->
+ B = unicode:characters_to_binary(L, unicode, {utf16,big}),
+ case [-D || <<D:16/big>> <= B] of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end
+ end).
+
+
+
+unicode_string_to_list(doc) -> [];
+unicode_string_to_list(suite) -> [];
+unicode_string_to_list(Config) when is_list(Config) ->
+ do_echo(cp_gen(79), Config,
+ fun ({L,_}) -> {self(),L,to_neg_int_list} end,
+ fun (Echoer, {L,invalid}=Out, {Echoer,X,_}=In) ->
+ case L of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end;
+ (Echoer, {L,valid}=Out, {Echoer,X,_}=In) ->
+ case [-C || C <- L] of
+ X -> ok;
+ _ ->
+ ?t:fail({mismatch,Out,In})
+ end
+ end, ["unicode"]).
+
+
+%% Lazy list
+cp_gen(N) ->
+ cp_gen(N, -1, 16#110000).
+
+cp_gen(N, Start, End) ->
+ cp_gen(N, Start, End, cp_validity(Start), [], 0, [], 0).
+
+cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Len >= N ->
+ cp_gen(N, U, End, PrevValidity, [], 0, [{Acc,PrevValidity}|Ss], Ls+1);
+cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) when Ls >= N ->
+ Ss ++ fun () ->
+ cp_gen(N, U, End, PrevValidity, Acc, Len, [], 0)
+ end;
+cp_gen(_, U, End, _, Acc, _, Ss, _) when U > End ->
+ [{Acc,valid}|Ss];
+cp_gen(N, U, End, PrevValidity, Acc, Len, Ss, Ls) ->
+ Validity = cp_validity(U),
+ NextU = U+1,
+ {NextAcc,NextLen} = case Validity of
+ valid -> {[U|Acc],Len+1};
+ invalid -> {Acc,Len}
+ end,
+ {NextSs,NextLs} = case Validity of
+ PrevValidity -> {Ss,Ls};
+ valid -> {[{[U-1],PrevValidity}|Ss],Ls+1};
+ invalid -> {[{[U],Validity}|Ss],Ls+1}
+ end,
+ cp_gen(N, NextU, End, Validity, NextAcc, NextLen, NextSs, NextLs).
+
+cp_validity(UnicodeCP) ->
+ try <<UnicodeCP/big-utf32>> of
+ _ -> valid
+ catch
+ error:_ -> invalid
+ end.
+
+
+
+connect(doc) -> [];
+connect(suite) -> [];
+connect(Config) when is_list(Config) ->
+ WD = filename:dirname(code:which(?MODULE)),
+ {ok,Other} = ?t:start_node(make_name(), slave, [{args,"-pa "++WD}]),
+ Action =
+ fun (Pid) ->
+ JName = node(Pid),
+ Hidden = [JName],
+ Pid ! {self(),Other},
+ receive
+ {Pid,Other,true} ->
+ ok;
+ Unexpected1 ->
+ ?t:fail({result,Unexpected1})
+ end,
+ Hidden = erlang:nodes(hidden),
+ Hidden = rpc:call(Other, erlang, nodes, [hidden]),
+ true =
+ rpc:call(Other, erlang, disconnect_node, [JName]),
+ [] =
+ rpc:call(Other, erlang, nodes, [hidden]),
+ Hidden = erlang:nodes(hidden),
+ %% Again
+ receive after 2000 -> ok end,
+ %% We have no way of knowing when the Java node
+ %% detects the nodedown.
+ Pid ! {self(),Other},
+ receive
+ {Pid,Other,true} ->
+ ok;
+ Unexpected2->
+ ?t:fail({result,Unexpected2})
+ end,
+ Hidden = rpc:call(Other, erlang, nodes, [hidden])
+ end,
+ run_server(connection_server, Config, Action, []).
+
+
+
+seq(_, 0, _) ->
+ [];
+seq(X, N, Fun) ->
+ [X|seq(Fun(X), N-1, Fun)].
+
+do_echo(DataList, Config) ->
+ do_echo(DataList, Config,
+ fun (D) -> % OutTrans
+ {self(),D}
+ end,
+ fun (Echoer, D, {Echoer,D}) -> % InTrans
+ ok
+ end, []).
+
+do_echo(DataList, Config, OutTrans, InTrans) ->
+ do_echo(DataList, Config, OutTrans, InTrans, []).
+
+do_echo(DataList, Config, OutTrans, InTrans, ExtraArgs)
+ when is_list(DataList), is_list(Config) ->
+ run_server(echo_server, Config,
+ fun (Echoer) ->
+ echo_loop(DataList, Echoer, OutTrans, InTrans, [])
+ end,
+ ExtraArgs).
+
+echo_loop([D|Ds], Echoer, OutTrans, InTrans, TermAcc) ->
+ OutMsg = OutTrans(D),
+ Echoer ! OutMsg,
+ io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ receive
+ Reply ->
+ io:format("echo_server ~p: receive ~P~n",
+ [self(),Reply,10]),
+ InTrans(Echoer, D, Reply)
+ end,
+ Term = case OutMsg of
+ {_, T, _} -> T;
+ {_, T} -> T
+ end,
+ echo_loop(Ds, Echoer, OutTrans, InTrans, [Term | TermAcc]);
+echo_loop([], Echoer, _, _, TermAcc) ->
+ check_terms(Echoer, TermAcc);
+%% Lazy list
+echo_loop(Cont, Echoer, OutTrans, InTrans, TermAcc)
+ when is_function(Cont, 0) ->
+ check_terms(Echoer, TermAcc),
+ OutMsg = Echoer ! {self(),undefined,hash_clear},
+ io:format("echo_server ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ receive
+ {Echoer,hash_cleared,hash_clear}=Reply ->
+ io:format("echo_server ~p: receive ~P~n",
+ [self(),Reply,10]),
+ ok;
+ Other ->
+ io:format("echo_server_terms unexpected ~p: receive ~P~n",
+ [self(),Other,10]),
+ ?t:fail({unexpected, Other})
+ end,
+ echo_loop(Cont(), Echoer, OutTrans, InTrans, []).
+
+check_terms(Echoer, [Term | Rest]) ->
+ OutMsg = {self(),Term,hash_lookup},
+ Echoer ! OutMsg,
+ io:format("check_terms ~p: ~p ! ~P~n", [self(),Echoer,OutMsg,10]),
+ receive
+ {Echoer,true,hash_lookup} = ReplyMsg ->
+ io:format("check_terms ~p: receive ~P~n",
+ [self(),ReplyMsg,10]),
+ check_terms(Echoer, Rest);
+ Other ->
+ io:format("check_terms unexpected ~p: receive ~P~n",
+ [self(),Other,10]),
+ ?t:fail({unexpected, Other})
+ end;
+check_terms(_, []) ->
+ ok.
+
+run_server(Server, Config, Action, ExtraArgs) ->
+ Name = make_name(),
+ true = register(Name, self()),
+ JName = make_name(),
+ spawn_link(fun () ->
+ ok = jitu:java(?config(java, Config),
+ ?config(data_dir, Config),
+ atom_to_list(Server),
+ [JName,
+ erlang:get_cookie(),
+ node(),
+ Name]++ExtraArgs
+ ),
+ %,"-DOtpConnection.trace=3"),
+ Name ! {done, JName}
+ end),
+ receive
+ {Server, JName, Pid} ->
+ ?t:format("~w: ~p (~p)~n",
+ [Server, Pid, node(Pid)]),
+ ?t:format("nodes(hidden): ~p~n",
+ [nodes(hidden)]),
+ Action(Pid),
+ Pid ! bye,
+ receive
+ {done, JName} ->
+ ok
+ end;
+ Other ->
+ ?t:fail({unexpected,Other})
+ end.
+
+%%
+%% Utils...
+%%
+
+make_name() ->
+ {A, B, C} = now(),
+ list_to_atom(atom_to_list(?MODULE)
+ ++ "-" ++ integer_to_list(A)
+ ++ "-" ++ integer_to_list(B)
+ ++ "-" ++ integer_to_list(C)).
+
+
+
+-define(VERSION_MAGIC, 131).
+
+-define(ATOM_EXT, 100).
+-define(REFERENCE_EXT, 101).
+-define(PORT_EXT, 102).
+-define(PID_EXT, 103).
+-define(NEW_REFERENCE_EXT, 114).
+
+uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
+ [(Uint bsr 24) band 16#ff,
+ (Uint bsr 16) band 16#ff,
+ (Uint bsr 8) band 16#ff,
+ Uint band 16#ff];
+uint32_be(Uint) ->
+ exit({badarg, uint32_be, [Uint]}).
+
+
+uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 ->
+ [(Uint bsr 8) band 16#ff,
+ Uint band 16#ff];
+uint16_be(Uint) ->
+ exit({badarg, uint16_be, [Uint]}).
+
+uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
+ Uint band 16#ff;
+uint8(Uint) ->
+ exit({badarg, uint8, [Uint]}).
+
+
+
+mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
+ mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
+mk_pid({NodeName, Creation}, Number, Serial) ->
+ case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
+ ?PID_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint32_be(Serial),
+ uint8(Creation)])) of
+ Pid when is_pid(Pid) ->
+ Pid;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
+ end.
+
+mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
+ mk_port({atom_to_list(NodeName), Creation}, Number);
+mk_port({NodeName, Creation}, Number) ->
+ case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
+ ?PORT_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint8(Creation)])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_port, [{NodeName, Creation}, Number]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
+ end.
+
+mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
+ is_integer(Creation),
+ is_list(Numbers) ->
+ mk_ref({atom_to_list(NodeName), Creation}, Numbers);
+mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
+ is_integer(Creation),
+ is_integer(Number) ->
+ case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
+ ?REFERENCE_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint8(Creation)])) of
+ Ref when is_reference(Ref) ->
+ Ref;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
+ end;
+mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
+ is_integer(Creation),
+ is_list(Numbers) ->
+ case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
+ ?NEW_REFERENCE_EXT,
+ uint16_be(length(Numbers)),
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint8(Creation),
+ lists:map(fun (N) ->
+ uint32_be(N)
+ end,
+ Numbers)])) of
+ Ref when is_reference(Ref) ->
+ Ref;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
+ end.
diff --git a/lib/jinterface/test/nc_SUITE_data/Makefile.src b/lib/jinterface/test/nc_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..3d131250be
--- /dev/null
+++ b/lib/jinterface/test/nc_SUITE_data/Makefile.src
@@ -0,0 +1,53 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-2010. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+# Makefile.src for java_client_erl_server test
+# Note: This file *must* work for both Unix and Windows
+#
+# We use both `rm' (Unix) and `del' (Windows) for removing files, but
+# with a `-' in front so that the error in not finding `rm' (`del') on
+# Windows (Unix) is ignored.
+#
+# VxWorks? XXX
+#
+
+.SUFFIXES:
+.SUFFIXES: .java
+
+
+JAVAC = @JAVAC@
+ERLC = erlc
+
+JINTERFACE_CLASSPATH = @jinterface_classpath@
+
+CLASSPATH = .@PS@$(JINTERFACE_CLASSPATH)@PS@
+
+JAVA_FILES = echo_server.java connection_server.java
+CLASS_FILES = $(JAVA_FILES:.java=.class)
+
+all: $(CLASS_FILES)
+
+clean:
+ -rm -f $(CLASS_FILES)
+ -del /F /Q $(CLASS_FILES)
+
+$(CLASS_FILES) : $(JAVA_FILES)
+ $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES)
+
+#
diff --git a/lib/jinterface/test/nc_SUITE_data/connection_server.java b/lib/jinterface/test/nc_SUITE_data/connection_server.java
new file mode 100644
index 0000000000..19ed1c7d5c
--- /dev/null
+++ b/lib/jinterface/test/nc_SUITE_data/connection_server.java
@@ -0,0 +1,96 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import com.ericsson.otp.erlang.*;
+
+public class connection_server {
+ static java.lang.String Name = "connection_server";
+
+ public static void main(String[] argv) {
+ try {
+ System.out.println("connection_server booting...");
+
+ for (int j = 0; j < argv.length; j++)
+ System.out.println("argv[" + j + "] = \"" + argv[j] + "\"");
+
+ if (argv.length != 4) {
+ System.out.println("Wrong number of arguments!");
+ System.exit(1);
+ }
+
+ // Start node and mbox
+ OtpNode node = new OtpNode(argv[0], argv[1]);
+ OtpMbox mbox = node.createMbox();
+ if (! mbox.registerName(Name)) {
+ System.out.println("Could not register name " + Name);
+ System.exit(3);
+ }
+
+ // Announce our presence
+ OtpErlangObject[] amsg = new OtpErlangObject[3];
+ amsg[0] = new OtpErlangAtom(Name);
+ amsg[1] = new OtpErlangAtom(argv[0]);
+ amsg[2] = mbox.self();
+ OtpErlangTuple atuple = new OtpErlangTuple(amsg);
+ mbox.send(argv[3], argv[2], atuple);
+
+ // Do connects ...
+ while (true) {
+ OtpErlangObject o = mbox.receive();
+ if (o == null)
+ continue;
+ if (o instanceof OtpErlangTuple) {
+ OtpErlangTuple msg = (OtpErlangTuple) o;
+ OtpErlangPid from = (OtpErlangPid)(msg.elementAt(0));
+ OtpErlangAtom conn_node = (OtpErlangAtom) msg.elementAt(1);
+
+ System.out.println("Got request to connect to: "
+ + conn_node);
+ OtpErlangObject[] rmsg = new OtpErlangObject[3];
+ rmsg[0] = mbox.self();
+ rmsg[1] = conn_node;
+ if (node.ping(conn_node.atomValue(), 1000)) {
+ System.out.println("Successfully connected to "
+ + conn_node.toString());
+ rmsg[2] = new OtpErlangAtom("true");
+ }
+ else {
+ System.out.println("Failed to connect to "
+ + conn_node.toString());
+ rmsg[2] = new OtpErlangAtom("false");
+ }
+
+ OtpErlangTuple rtuple = new OtpErlangTuple(rmsg);
+
+ mbox.send(from, rtuple);
+ }
+ else { // probably 'bye'
+ System.out.println("connection_server halting...");
+ System.exit(0);
+ }
+ }
+ }
+ catch (Exception e) {
+ System.out.println("" + e);
+ System.exit(2);
+ }
+
+ }
+
+}
diff --git a/lib/jinterface/test/nc_SUITE_data/echo_server.java b/lib/jinterface/test/nc_SUITE_data/echo_server.java
new file mode 100644
index 0000000000..0550e4beb1
--- /dev/null
+++ b/lib/jinterface/test/nc_SUITE_data/echo_server.java
@@ -0,0 +1,261 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
+
+import com.ericsson.otp.erlang.OtpErlangAtom;
+import com.ericsson.otp.erlang.OtpErlangBinary;
+import com.ericsson.otp.erlang.OtpErlangBoolean;
+import com.ericsson.otp.erlang.OtpErlangException;
+import com.ericsson.otp.erlang.OtpErlangInt;
+import com.ericsson.otp.erlang.OtpErlangList;
+import com.ericsson.otp.erlang.OtpErlangLong;
+import com.ericsson.otp.erlang.OtpErlangObject;
+import com.ericsson.otp.erlang.OtpErlangPid;
+import com.ericsson.otp.erlang.OtpErlangString;
+import com.ericsson.otp.erlang.OtpErlangTuple;
+import com.ericsson.otp.erlang.OtpExternal;
+import com.ericsson.otp.erlang.OtpInputStream;
+import com.ericsson.otp.erlang.OtpMbox;
+import com.ericsson.otp.erlang.OtpNode;
+import com.ericsson.otp.erlang.OtpOutputStream;
+
+public class echo_server {
+ private static boolean debug = false;
+
+ public static void main(final String[] argv) {
+ try {
+ System.out.println("echo_server booting...");
+
+ for (int j = 0; j < argv.length; j++) {
+ System.out.println("argv[" + j + "] = \"" + argv[j] + "\"");
+ }
+
+ if (argv.length != 4 && argv.length != 5) {
+ System.out.println("Wrong number of arguments!");
+ System.exit(1);
+ }
+
+ // Start node and mbox
+ final OtpNode node = new OtpNode(argv[0], argv[1]);
+ if (argv.length == 5 && argv[4].equals("unicode")) {
+ System.out.println("Setting unicode string mode.");
+ node.setFlags(OtpInputStream.DECODE_INT_LISTS_AS_STRINGS);
+ }
+ final OtpMbox mbox = node.createMbox();
+
+ // Announce our presence
+ final OtpErlangObject[] amsg = new OtpErlangObject[3];
+ amsg[0] = new OtpErlangAtom("echo_server");
+ amsg[1] = new OtpErlangAtom(argv[0]);
+ amsg[2] = mbox.self();
+ final OtpErlangTuple atuple = new OtpErlangTuple(amsg);
+ mbox.send(argv[3], argv[2], atuple);
+
+ // Do echoing...
+ while (true) {
+ final OtpErlangObject o = mbox.receive();
+ if (o == null) {
+ continue;
+ }
+ if (o instanceof OtpErlangTuple) {
+ final OtpErlangTuple msg = (OtpErlangTuple) o;
+ final int arity = msg.arity();
+ if (arity < 2) {
+ System.out
+ .println("Arity < 2; echo_server aborting...");
+ System.exit(2);
+ } else if (arity == 2) {
+ final OtpErlangPid from = (OtpErlangPid) msg
+ .elementAt(0);
+ if (debug) System.out.println("Echoing: "
+ + msg.elementAt(1));
+
+ final OtpErlangObject[] rmsg = new OtpErlangObject[2];
+ rmsg[0] = mbox.self();
+ rmsg[1] = msg.elementAt(1);
+ final OtpErlangTuple rtuple = new OtpErlangTuple(rmsg);
+
+ mbox.send(from, rtuple);
+ continue;
+ } else if (arity == 3) {
+ echoTwisted(mbox, msg);
+ continue;
+ } else {
+ System.out
+ .println("Arity > 3; echo_server aborting...");
+ System.exit(2);
+ }
+ } else if (o instanceof OtpErlangAtom) {
+ OtpErlangAtom a = (OtpErlangAtom) o;
+ if (a.atomValue().equals("debug")) {
+ debug = true;
+ } else if (a.atomValue().equals("bye")) {
+ System.out.println("echo_server halting...");
+ System.exit(0);
+ }
+ } else { // probably 'bye'
+ }
+ System.out.println("Unexpected: " + o +
+ " echo_server aborting...");
+ System.exit(2);
+ }
+ } catch (final Exception e) {
+ System.out.println("" + e);
+ System.exit(2);
+ }
+ }
+
+ private static void echoTwisted(final OtpMbox mbox,
+ final OtpErlangTuple msg)
+ throws OtpErlangException {
+ final OtpErlangPid from = (OtpErlangPid) msg.elementAt(0);
+
+ final OtpErlangObject[] rmsg = new OtpErlangObject[3];
+ if (debug) System.out.println("Echo in: " + msg);
+ rmsg[0] = mbox.self();
+ rmsg[1] = twist(msg.elementAt(1), rmsg[2] = msg.elementAt(2));
+ final OtpErlangTuple rtuple = new OtpErlangTuple(rmsg);
+ if (debug) System.out.println("Echo out: " + rtuple);
+
+ mbox.send(from, rtuple);
+ }
+
+ private static HashSet<OtpErlangObject> hash_set =
+ new HashSet<OtpErlangObject>();
+
+ private static OtpErlangObject twist(final OtpErlangObject i,
+ final OtpErlangObject t) throws OtpErlangException {
+ hash_set.add(i);
+ if (t instanceof OtpErlangAtom) {
+ final String atomValue = ((OtpErlangAtom) t).atomValue();
+ if (atomValue.equals("binary") && i instanceof OtpErlangBinary) {
+ final OtpErlangBinary b = (OtpErlangBinary) i;
+ final OtpInputStream bis = new OtpInputStream(b.binaryValue(),
+ 0);
+ final OtpErlangObject o = bis.read_any();
+ return o;
+ } else if (atomValue.equals("compress")) {
+ final OtpOutputStream oos = new OtpOutputStream();
+ oos.write1(OtpExternal.versionTag);
+ oos.write_compressed(i);
+ final OtpErlangBinary o =
+ new OtpErlangBinary(oos.toByteArray());
+ return o;
+ } else if (atomValue.equals("bigint")
+ && i instanceof OtpErlangLong) {
+ final OtpErlangLong l = (OtpErlangLong) i;
+ final int w = l.signum() * l.bitLength();
+ final OtpErlangLong x = new OtpErlangLong(l.longValue());
+ final java.math.BigInteger b = l.bigIntegerValue();
+ System.out.println("long: " + l + ": " + w + ": " + b.signum()
+ * b.bitLength() + ": " + x + ": " + l.isLong() + ": "
+ + l.isULong());
+ return new OtpErlangTuple(new OtpErlangObject[] { l,
+ new OtpErlangInt(w), x,
+ new OtpErlangInt(l.isLong() ? 1 : 0),
+ new OtpErlangInt(l.isULong() ? 1 : 0) });
+ } else if (atomValue.equals("tail")
+ && i instanceof OtpErlangList) {
+ final OtpErlangObject o = ((OtpErlangList) i).getTail();
+ if (o == null) {
+ return new OtpErlangAtom("null");
+ }
+ return o;
+ } else if (atomValue.equals("tail3")
+ && i instanceof OtpErlangList) {
+ final OtpErlangObject o = ((OtpErlangList) i).getNthTail(3);
+ if (o == null) {
+ return new OtpErlangAtom("null");
+ }
+ return o;
+ } else if (atomValue.equals("strcat")
+ && i instanceof OtpErlangList) {
+ final java.lang.StringBuffer b = new java.lang.StringBuffer();
+ final OtpErlangList l = (OtpErlangList) i;
+ for (final OtpErlangObject j : l) {
+ final OtpErlangString k = (OtpErlangString) j;
+ b.append(k.stringValue());
+ }
+ final OtpErlangObject o = new OtpErlangString(b.toString());
+ return o;
+ } else if (atomValue.equals("sub3atom")
+ && i instanceof OtpErlangString) {
+ final OtpErlangString s = (OtpErlangString) i;
+ final OtpErlangAtom o = new OtpErlangAtom(s.stringValue()
+ .substring(3));
+ return o;
+ } else if (atomValue.equals("utf8")) {
+ if (i instanceof OtpErlangString) {
+ final OtpErlangString s = (OtpErlangString) i;
+ byte[] bytes;
+ try {
+ bytes = s.stringValue().getBytes("UTF-8");
+ } catch (final UnsupportedEncodingException e) {
+ bytes = new byte[] { 'e', 'r', 'r', 'o', 'r' };
+ }
+ final OtpErlangBinary b = new OtpErlangBinary(bytes);
+ return b;
+ }
+ } else if(atomValue.equals("to_string_neg_int_list")) {
+ OtpErlangString oes = null;
+ if (i instanceof OtpErlangString) {
+ oes = (OtpErlangString) i;
+ } else if (i instanceof OtpErlangList) {
+ OtpErlangList oel = (OtpErlangList) i;
+ try {
+ oes = new OtpErlangString(oel);
+ } catch (final Exception e) {
+ }
+ }
+ if (oes != null) {
+ String s = oes.stringValue();
+ int n = s.length();
+ OtpErlangObject l[] = new OtpErlangObject[n];
+ for (int j = 0; j < n; j++) {
+ int c = s.charAt(j);
+ l[j] = new OtpErlangInt(-c);
+ }
+ return new OtpErlangList(l);
+ }
+ } else if(atomValue.equals("to_neg_int_list")) {
+ if (i instanceof OtpErlangString) {
+ OtpErlangString oes = (OtpErlangString) i;
+ OtpErlangList oel = new OtpErlangList(oes.stringValue());
+ int n = oel.arity();
+ OtpErlangObject l[] = new OtpErlangObject[n];
+ for (int j = 0; j < n; j++) {
+ OtpErlangLong c = (OtpErlangLong) oel.elementAt(j);
+ l[j] = new OtpErlangInt(-c.intValue());
+ }
+ return new OtpErlangList(l);
+ }
+ } else if (atomValue.equals("hash_lookup")) {
+ final boolean exists = hash_set.contains(i);
+ final OtpErlangBoolean b = new OtpErlangBoolean(exists);
+ return b;
+ } else if (atomValue.equals("hash_clear")) {
+ hash_set.clear();
+ return new OtpErlangAtom("hash_cleared");
+ }
+ }
+ return i;
+ }
+}
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 19e1d3221c..b8db509fa8 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -54,7 +54,7 @@
for and tries to load the module.</p>
</item>
</list>
- <p>To prevent accidentaly reloading modules affecting the Erlang
+ <p>To prevent accidentally reloading modules affecting the Erlang
runtime system itself, the <c>kernel</c>, <c>stdlib</c> and
<c>compiler</c> directories are considered <em>sticky</em>. This
means that the system issues a warning and rejects the request if
diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml
index 4e65bf46f8..9a62b45d63 100644
--- a/lib/kernel/doc/src/erl_ddll.xml
+++ b/lib/kernel/doc/src/erl_ddll.xml
@@ -177,7 +177,7 @@
<name>demonitor(MonitorRef) -> ok</name>
<fsummary>Remove a monitor for a driver</fsummary>
<type>
- <v>MonitorRef = ref()</v>
+ <v>MonitorRef = reference()</v>
</type>
<desc>
<p>Removes a driver monitor in much the same way as
@@ -185,7 +185,7 @@
monitors. See <seealso marker="#monitor/2">monitor/2</seealso>, <seealso marker="#try_load/3">try_load/3</seealso> and <seealso marker="#try_unload/2">try_unload/2</seealso> for details
about how to create driver monitors.</p>
<p>The function throws a <c>badarg</c> exception if the
- parameter is not a ref(). </p>
+ parameter is not a reference(). </p>
</desc>
</func>
<func>
@@ -400,7 +400,7 @@
<v>Item = {Name, When}</v>
<v>Name = atom() | string()</v>
<v>When = loaded | unloaded | unloaded_only</v>
- <v>MonitorRef = ref()</v>
+ <v>MonitorRef = reference()</v>
</type>
<desc>
<p>This function creates a driver monitor and works in many
@@ -449,7 +449,7 @@
eventually lead to one of the following messages
being sent:</p>
<taglist>
- <tag><em>{'UP', ref(), driver, Name, loaded}</em></tag>
+ <tag><em>{'UP', reference(), driver, Name, loaded}</em></tag>
<item>
<p>This message is sent, either immediately if the
driver is already loaded and no reloading is
@@ -459,7 +459,7 @@
expected to know if reloading is demanded prior
to creating a monitor for loading.</p>
</item>
- <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag>
+ <tag><em>{'UP', reference(), driver, Name, permanent}</em></tag>
<item>
<p>This message will be sent if reloading was
expected, but the (old) driver made itself
@@ -467,7 +467,7 @@
sent if the driver was permanent or statically
linked in when trying to create the monitor.</p>
</item>
- <tag><em>{'DOWN', ref(), driver, Name, load_cancelled}</em></tag>
+ <tag><em>{'DOWN', reference(), driver, Name, load_cancelled}</em></tag>
<item>
<p>This message will arrive if reloading was
underway, but the <seealso marker="#users">user</seealso> having requested
@@ -476,7 +476,7 @@
(or <c>unload/1</c>/<c>unload_driver/1</c>)
again before it was reloaded.</p>
</item>
- <tag><em>{'DOWN', ref(), driver, Name, {load_failure, Failure}}</em></tag>
+ <tag><em>{'DOWN', reference(), driver, Name, {load_failure, Failure}}</em></tag>
<item>
<p>This message will arrive if reloading was
underway but the loading for some reason
@@ -500,7 +500,7 @@
<p>A driver monitor for unload will eventually result
in one of the following messages being sent:</p>
<taglist>
- <tag><em>{'DOWN', ref(), driver, Name, unloaded}</em></tag>
+ <tag><em>{'DOWN', reference(), driver, Name, unloaded}</em></tag>
<item>
<p>The driver instance monitored is now
unloaded. As the unload might have been due to a
@@ -508,7 +508,7 @@
again have been loaded when this message
arrives.</p>
</item>
- <tag><em>{'UP', ref(), driver, Name, unload_cancelled}</em></tag>
+ <tag><em>{'UP', reference(), driver, Name, unload_cancelled}</em></tag>
<item>
<p>This message will be sent if unloading was
expected, but while the driver was waiting for
@@ -525,7 +525,7 @@
similar to an <c>unloaded</c> monitor, but does
never result in this message.</p>
</item>
- <tag><em>{'UP', ref(), driver, Name, permanent}</em></tag>
+ <tag><em>{'UP', reference(), driver, Name, permanent}</em></tag>
<item>
<p>This message will be sent if unloading was
expected, but the driver made itself
@@ -539,7 +539,7 @@
<item>
<p>A monitor created as <c>unloaded_only</c> behaves
exactly as one created as <c>unloaded</c> with the
- exception that the <c>{'UP', ref(), driver, Name, unload_cancelled}</c> message will never be
+ exception that the <c>{'UP', reference(), driver, Name, unload_cancelled}</c> message will never be
sent, but the monitor instead persists until the
driver <em>really</em> gets unloaded.</p>
</item>
@@ -626,7 +626,7 @@
<v>ReloadOption = pending_driver | pending</v>
<v>Status = loaded | already_loaded | PendingStatus </v>
<v>PendingStatus = pending_driver | pending_process</v>
- <v>Ref = ref()</v>
+ <v>Ref = reference()</v>
<v>ErrorDesc = ErrorAtom | OpaqueError</v>
<v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v>
</type>
@@ -650,7 +650,7 @@
registered and a corresponding <c>try_unload</c> is
expected sometime in the future.</p>
</item>
- <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag>
+ <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, reference()}</em></tag>
<item>
<p>The load request is registered, but the loading is
delayed due to the fact that an earlier instance of the
@@ -665,7 +665,7 @@
set. In other words, this return value will always need
to be handled!</p>
</item>
- <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag>
+ <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, reference()}</em></tag>
<item>
<p>The load request is registered, but the loading is
delayed due to the fact that an earlier instance of the
@@ -683,7 +683,7 @@
about when the driver is <em>actually</em> loaded. This can
be achieved by using the <c>{monitor, PendingOption}</c> option.</p>
<p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be
- returned, the function will instead return a tuple <c>{ok, PendingStatus, ref()}</c> and the process will, at a later
+ returned, the function will instead return a tuple <c>{ok, PendingStatus, reference()}</c> and the process will, at a later
time when the driver actually gets loaded, get a monitor
message. The monitor message one can expect is described in
the <seealso marker="#monitor/2">monitor/2</seealso>
@@ -760,7 +760,7 @@
<p>A <c>MonitorOption</c> tells <c>try_load/3</c> to
trigger a driver monitor under certain
conditions. When the monitor is triggered, the
- function will return a three-tuple <c>{ok, PendingStatus, ref()}</c>, where the <c>ref()</c> is
+ function will return a three-tuple <c>{ok, PendingStatus, reference()}</c>, where the <c>reference()</c> is
the monitor ref for the driver monitor.</p>
<p>Only one <c>MonitorOption</c> can be specified and
it is either the atom <c>pending</c>, which means
@@ -891,7 +891,7 @@
<v>MonitorOption = pending_driver | pending</v>
<v>Status = unloaded | PendingStatus </v>
<v>PendingStatus = pending_driver | pending_process</v>
- <v>Ref = ref()</v>
+ <v>Ref = reference()</v>
<v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v>
</type>
<desc>
@@ -943,7 +943,7 @@
ports using it and there are no more <seealso marker="#users">users</seealso> requiring it to be
loaded.</p>
</item>
- <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, ref()}</em></tag>
+ <tag><em>{ok, pending_driver}</em>or <em>{ok, pending_driver, reference()}</em></tag>
<item>
<p>This return value indicates that this call removed the
last <seealso marker="#users">user</seealso> from the
@@ -957,7 +957,7 @@
in that case, however transient. Monitors are as always
useful to detect when the driver is really unloaded.</p>
</item>
- <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, ref()}</em></tag>
+ <tag><em>{ok, pending_process}</em>or <em>{ok, pending_process, reference()}</em></tag>
<item>
<p>The unload request is registered, but there are still
other <seealso marker="#users">users</seealso> holding
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index a9ceac0bcf..2044b074ee 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -1229,7 +1229,7 @@ f.txt: {person, "kalle", 25}.
</item>
<tag><c>{no_translation, unicode, latin1}</c></tag>
<item>
- <p>The file is was opened with another <c>encoding</c> than <c>latin1</c> and the data on the file can not be translated to the byte-oriented data that this function returns.</p>
+ <p>The file was opened with another <c>encoding</c> than <c>latin1</c> and the data in the file can not be translated to the byte-oriented data that this function returns.</p>
</item>
</taglist>
</desc>
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 3a8011e28b..fb09092f1c 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -1173,7 +1173,7 @@ client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -&gt;
<title>SEE ALSO</title>
<p><seealso marker="inet">inet(3)</seealso>,
<seealso marker="gen_tcp">gen_tcp(3)</seealso>,
- <seealso marker="gen_udp">gen_upd(3)</seealso>,
+ <seealso marker="gen_udp">gen_udp(3)</seealso>,
<url href="http://www.rfc-archive.org/getrfc.php?rfc=2960">RFC2960</url> (Stream Control Transmission Protocol),
<url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">Sockets API Extensions for SCTP.</url></p>
<marker id="authors"></marker>
diff --git a/lib/kernel/internal_doc/distribution_handshake.txt b/lib/kernel/internal_doc/distribution_handshake.txt
index f64ebe0302..6a3ee22ed3 100644
--- a/lib/kernel/internal_doc/distribution_handshake.txt
+++ b/lib/kernel/internal_doc/distribution_handshake.txt
@@ -11,7 +11,7 @@ The TCP/IP distribution uses a handshake which expects a
connection based protocol, i.e. the protocol does not include
any authentication after the handshake procedure.
-This is not entirelly safe, as it is vulnerable against takeover
+This is not entirely safe, as it is vulnerable against takeover
attacks, but it is a tradeoff between fair safety and performance.
The cookies are never sent in cleartext and the handshake procedure
@@ -23,7 +23,7 @@ random numbers.
DEFINITIONS
-----------
-A challenge is a 32 bit integer number in big endian. Below the function
+A challenge is a 32 bit integer number in big endian order. Below the function
gen_challenge() returns a random 32 bit integer used as a challenge.
A digest is a (16 bytes) MD5 hash of [the Challenge (as text) concatenated
@@ -46,19 +46,19 @@ The cookies are text strings that can be viewed as passwords.
Every message in the handshake starts with a 16 bit big endian integer
which contains the length of the message (not counting the two initial bytes).
In erlang this corresponds to the gen_tcp option {packet, 2}. Note that after
-the handshake, the distribution switches to 4 byte backet headers.
+the handshake, the distribution switches to 4 byte packet headers.
THE HANDSHAKE IN DETAIL
-----------------------
-Imagine two nodes, node A, which initiates the handshake and node B, whitch
+Imagine two nodes, node A, which initiates the handshake and node B, which
accepts the connection.
1) connect/accept: A connects to B via TCP/IP and B accepts the connection.
2) send_name/receive_name: A sends an initial identification to B.
B receives the message. The message looks
-like this (every "square" beeing one byte and the packet header removed):
+like this (every "square" being one byte and the packet header removed):
+---+--------+--------+-----+-----+-----+-----+-----+-----+-...-+-----+
|'n'|Version0|Version1|Flag0|Flag1|Flag2|Flag3|Name0|Name1| ... |NameN|
@@ -67,7 +67,7 @@ like this (every "square" beeing one byte and the packet header removed):
The 'n' is just a message tag,
Version0 & Version1 is the distribution version selected by node A,
based on information from EPMD. (16 bit big endian)
-Flag0 ... Flag3 is capability flags, the capabilities defined in dist.hrl.
+Flag0 ... Flag3 are capability flags, the capabilities defined in dist.hrl.
(32 bit big endian)
Name0 ... NameN is the full nodename of A, as a string of bytes (the
packet length denotes how long it is).
@@ -91,9 +91,9 @@ alive: A connection to the node is already active, which either means
This is the format of the status message:
-+---+-------+-------+ ... +-------+
++---+-------+-------+-...-+-------+
|'s'|Status0|Status1| ... |StatusN|
-+---+-------+-------+ ... +-------+
++---+-------+-------+-...-+-------+
's' is the message tag
Status0 ... StatusN is the status as a string (not terminated)
@@ -111,35 +111,35 @@ initially sent from A to B, with the addition of a 32 bit challenge:
+---+--------+--------+-----+-----+-----+-----+-----+-----+-----+-----+---
|'n'|Version0|Version1|Flag0|Flag1|Flag2|Flag3|Chal0|Chal1|Chal2|Chal3|
-+---+--------+--------+-----+-----+-----+-----+-----+-----+---- +-----+---
++---+--------+--------+-----+-----+-----+-----+-----+-----+-----+-----+---
------+-----+-...-+-----+
Name0|Name1| ... |NameN|
------+-----+-... +-----+
-Where Chal0 ... Chal3 is the challenge as a 32 bit biog endian integer
+Where Chal0 ... Chal3 is the challenge as a 32 bit big endian integer
and the other fields are B's version, flags and full nodename.
5) send_challenge_reply/recv_challenge_reply: Now A has generated
-a digest and it's own challenge. Those are sent together in a package
+a digest and its own challenge. Those are sent together in a package
to B:
-+---+-----+-----+-----+-----+-----+-----+-----+-----+
-|'r'|Chal0|Chal1|Chal2|Chal3|Dige0|Dige1|Dige2|Dige3|
-+---+-----+-----+-----+-----+-----+-----+---- +-----+
++---+-----+-----+-----+-----+-----+-----+-----+-----+-...-+------+
+|'r'|Chal0|Chal1|Chal2|Chal3|Dige0|Dige1|Dige2|Dige3| ... |Dige15|
++---+-----+-----+-----+-----+-----+-----+-----+-----+-...-+------+
Where 'r' is the tag, Chal0 ... Chal3 is A's challenge for B to handle and
-Dige0 ... Dige3 is the digest that A constructed from the challenge B sent
+Dige0 ... Dige15 is the digest that A constructed from the challenge B sent
in the previous step.
6) recv_challenge_ack/send_challenge_ack: B checks that the digest received
from A is correct and generates a digest from the challenge received from
A. The digest is then sent to A. The message looks like this:
-+---+-----+-----+-----+-----+
-|'a'|Dige0|Dige1|Dige2|Dige3|
-+---+-----+-----+---- +-----+
++---+-----+-----+-----+-----+-...-+------+
+|'a'|Dige0|Dige1|Dige2|Dige3| ... |Dige15|
++---+-----+-----+-----+-----+-...-+------+
-Where 'a' is the tag and Dige0 ... Dige3 is the digest calculated by B
+Where 'a' is the tag and Dige0 ... Dige15 is the digest calculated by B
for A's challenge.
7) A checks the digest from B and the connection is up.
@@ -206,7 +206,7 @@ Currently the following capability flags are defined:
%% The node implements distributed process monitoring.
-define(DFLAG_DIST_MONITOR,8).
-%% The node uses separate tag for fun's (labmdas) in the distribution protocol.
+%% The node uses separate tag for fun's (lambdas) in the distribution protocol.
-define(DFLAG_FUN_TAGS,16).
An R6 erlang node implements all of the above, while a C or Java node only
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 7fe30ae828..5c7fe2421d 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -50,6 +50,8 @@
%% Exported functions
%%----------------------------------------------------------------------
+-spec start_link() -> {'ok',pid()} | {'error', term()} | 'ignore'.
+
start_link() ->
gen_server:start_link({local, auth}, auth, [], []).
@@ -134,7 +136,9 @@ init([]) ->
%% The net kernel will let all message to the auth server
%% through as is
--type calls() :: 'echo' | 'sync_cookie' | {'set_cookie', node(), term()}.
+-type calls() :: 'echo' | 'sync_cookie'
+ | {'get_cookie', node()}
+ | {'set_cookie', node(), term()}.
-spec handle_call(calls(), {pid(), term()}, state()) ->
{'reply', 'hello' | 'true' | 'nocookie' | cookie(), state()}.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 42d4818f08..ec256d5806 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -304,6 +304,8 @@ do_start(Flags) ->
true ->
ok
end,
+ % Quietly load the native code for all modules loaded so far.
+ catch load_native_code_for_all_loaded(),
Ok2;
Other ->
Other
@@ -496,3 +498,19 @@ has_ext(Ext, Extlen,File) ->
to_path(X) ->
filename:join(packages:split(X)).
+
+-spec load_native_code_for_all_loaded() -> ok.
+load_native_code_for_all_loaded() ->
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ lists:foreach(fun({Module, BeamFilename}) ->
+ case code:is_module_native(Module) of
+ false ->
+ case beam_lib:chunks(BeamFilename, [ChunkName]) of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) ->
+ load_native_partial(Module, Bin);
+ {error, beam_lib, _} -> ok
+ end;
+ true -> ok
+ end
+ end, all_loaded()).
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 08b6477c9d..c9437df258 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -31,7 +31,7 @@
where_is_file_cached/1, where_is_file_no_cache/1,
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
code_archive/1, code_archive2/1, on_load/1,
- on_load_embedded/1, on_load_errors/1]).
+ on_load_embedded/1, on_load_errors/1, native_early_modules/1]).
-export([init_per_testcase/2, fin_per_testcase/2,
init_per_suite/1, end_per_suite/1,
@@ -53,7 +53,7 @@ all(suite) ->
where_is_file_no_cache, where_is_file_cached,
purge_stacktrace, mult_lib_roots, bad_erl_libs,
code_archive, code_archive2, on_load, on_load_embedded,
- on_load_errors].
+ on_load_errors, native_early_modules].
init_per_suite(Config) ->
%% The compiler will no longer create a Beam file if
@@ -1333,6 +1333,34 @@ do_on_load_error(ReturnValue) ->
?line {undef,[{on_load_error,main,[]}|_]} = Exit
end.
+native_early_modules(suite) -> [];
+native_early_modules(doc) -> ["Test that the native code of early loaded modules is loaded"];
+native_early_modules(Config) when is_list(Config) ->
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ {skip,"Native code support is not enabled"};
+ Architecture ->
+ native_early_modules_1(Architecture)
+ end.
+
+native_early_modules_1(Architecture) ->
+ ?line {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists),
+ ?line ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ ?line NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]),
+ ?line IsHipeCompiled = case NativeChunk of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> true;
+ {error, beam_lib, _} -> false
+ end,
+ case IsHipeCompiled of
+ false ->
+ {skip,"OTP apparently not configured with --enable-native-libs"};
+ true ->
+ ?line true = lists:all(fun code:is_module_native/1,
+ [ets,file,filename,gb_sets,gb_trees,
+ hipe_unified_loader,lists,os,packages]),
+ ok
+ end.
+
%%-----------------------------------------------------------------
%% error_logger handler.
%% (Copied from stdlib/test/proc_lib_SUITE.erl.)
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index bd5685952e..fa1991872b 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -34,12 +34,12 @@
-export([send_to_closed/1,
buffer_size/1, binary_passive_recv/1, bad_address/1,
- read_packets/1, open_fd/1]).
+ read_packets/1, open_fd/1, connect/1]).
all(suite) ->
[send_to_closed,
buffer_size, binary_passive_recv, bad_address, read_packets,
- open_fd].
+ open_fd, connect].
init_per_testcase(_Case, Config) ->
?line Dog=test_server:timetrap(?default_timeout),
@@ -408,3 +408,20 @@ start_node(Name) ->
stop_node(Node) ->
?t:stop_node(Node).
+
+
+connect(suite) ->
+ [];
+connect(doc) ->
+ ["Test that connect/3 has effect"];
+connect(Config) when is_list(Config) ->
+ Addr = {127,0,0,1},
+ {ok,S1} = gen_udp:open(0),
+ {ok,P1} = inet:port(S1),
+ {ok,S2} = gen_udp:open(0),
+ ok = inet:setopts(S2, [{active,false}]),
+ ok = gen_udp:close(S1),
+ ok = gen_udp:connect(S2, Addr, P1),
+ ok = gen_udp:send(S2, <<16#deadbeef:32>>),
+ {error,econnrefused} = gen_udp:recv(S2, 0, 5),
+ ok.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 7dd99b37dd..9a191f9aeb 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -17,4 +17,4 @@
# %CopyrightEnd%
#
-KERNEL_VSN = 2.14
+KERNEL_VSN = 2.14.1
diff --git a/lib/megaco/doc/src/megaco.xml b/lib/megaco/doc/src/megaco.xml
index ae9e250965..b9bf414299 100644
--- a/lib/megaco/doc/src/megaco.xml
+++ b/lib/megaco/doc/src/megaco.xml
@@ -662,7 +662,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
<taglist>
<tag><c><![CDATA[none]]></c></tag>
<item>
- <p>Do not segment outgoing reply messages. This is usefull when
+ <p>Do not segment outgoing reply messages. This is useful when
either it is known that messages are never to large or
that the transport protocol can handle such things
on its own (e.g. TCP or SCTP).</p>
@@ -1182,7 +1182,7 @@ megaco_incr_timer() = #megaco_incr_timer{}
<taglist>
<tag><c><![CDATA[none]]></c></tag>
<item>
- <p>Do not segment outgoing reply messages. This is usefull when
+ <p>Do not segment outgoing reply messages. This is useful when
either it is known that messages are never to large or
that the transport protocol can handle such things
on its own (e.g. TCP or SCTP).</p>
diff --git a/lib/megaco/doc/src/megaco_flex_scanner.xml b/lib/megaco/doc/src/megaco_flex_scanner.xml
index eb206e5d13..18c40bb71a 100644
--- a/lib/megaco/doc/src/megaco_flex_scanner.xml
+++ b/lib/megaco/doc/src/megaco_flex_scanner.xml
@@ -128,7 +128,7 @@ megaco_version() = integer() >= 1
<v>Boolean = boolean()</v>
</type>
<desc>
- <p>Checks if a port is a flex scanner port or not (usefull when
+ <p>Checks if a port is a flex scanner port or not (useful when
if a port exits). </p>
<marker id="scan"></marker>
diff --git a/lib/megaco/doc/src/megaco_user.xml b/lib/megaco/doc/src/megaco_user.xml
index 7332fa684d..7987ed3392 100644
--- a/lib/megaco/doc/src/megaco_user.xml
+++ b/lib/megaco/doc/src/megaco_user.xml
@@ -504,7 +504,7 @@ protocol_version() = integer() ]]></code>
not, is also included in the <c><![CDATA[UserReply]]></c>. </p>
<p>The <c><![CDATA[ReplyData]]></c> defaults to
<c><![CDATA[megaco:lookup(ConnHandle, reply_data)]]></c>,
- but may be explicitely overridden by a
+ but may be explicitly overridden by a
<c><![CDATA[megaco:cast/3]]></c> option in order to forward info about the
calling context of the originating process.</p>
<p>At <c><![CDATA[success()]]></c>, the <c><![CDATA[UserReply]]></c> either contains:</p>
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index efb46253aa..f28c89abbe 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -21,131 +21,3 @@ APPLICATION = megaco
MEGACO_VSN = 3.14.1.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
-
-TICKETS = OTP-8696
-
-TICKETS_3_14_1 = OTP-8529 OTP-8561 OTP-8627 OTP-8634
-
-TICKETS_3_14 = OTP-8317 OTP-8323 OTP-8328 OTP-8362 OTP-8403
-
-TICKETS_3_13 = OTP-8205 OTP-8239 OTP-8249
-
-TICKETS_3_12 = OTP-8183 OTP-8212
-
-TICKETS_3_11_3 = OTP-8164 OTP-8167 OTP-8191
-
-TICKETS_3_11_2 = OTP-8123
-
-TICKETS_3_11_1 = OTP-8081 OTP-8114
-
-TICKETS_3_11 = OTP-7302 OTP-7995
-
-TICKETS_3_10_1 = OTP-7926 OTP-7936
-
-TICKETS_3_10_0_1 = OTP-7851
-
-TICKETS_3_10 = OTP-7713 OTP-7743
-
-TICKETS_3_9_4 = OTP-7728 OTP-7733
-
-TICKETS_3_9_3 = OTP-7700
-
-TICKETS_3_9_2 = OTP-7671 OTP-7672
-
-TICKETS_3_9_1_1 = OTP-7614
-
-TICKETS_3_9_1 = OTP-7572 OTP-7573 OTP-7576
-
-TICKETS_3_9 = OTP-7431
-
-TICKETS_3_8_2 = OTP-7534
-
-TICKETS_3_8_1 = OTP-7398 OTP-7417 OTP-7444 OTP-7449 OTP-7455 OTP-7457 OTP-7459
-
-TICKETS_3_8 = OTP-7192 OTP-7228 OTP-7259
-
-TICKETS_3_7_5 = OTP-7286 OTP-7303
-
-TICKETS_3_7_4 = OTP-7249 OTP-7251
-
-TICKETS_3_7_3 = OTP-7168 OTP-7180 OTP-7189 OTP-7216
-
-TICKETS_3_7_2 = OTP-6972 OTP-7138
-
-TICKETS_3_7_1 = OTP-6919 OTP-6971 OTP-6992 OTP-6999 OTP-7000 OTP-7005 OTP-7124
-
-TICKETS_3_7 = OTP-5979 OTP-6753 OTP-6804 OTP-6865 OTP-6919 OTP-6976
-
-TICKETS_3_6_2 = OTP-6921
-
-TICKETS_3_6_1 = OTP-6803
-
-TICKETS_3_6_0_1 = OTP-6704
-
-TICKETS_3_6 = OTP-6185 OTP-6578 OTP-6441 OTP-6442 OTP-6544 OTP-6605 OTP-6609
-
-TICKETS_3_5_3 = OTP-6520 OTP-6549
-
-TICKETS_3_5_2 = OTP-6404 OTP-6422 OTP-6490 OTP-6503
-
-TICKETS_3_5_1 = OTP-6275 OTP-6276
-
-TICKETS_3_5 = OTP-6223 OTP-6253 OTP-6256
-
-TICKETS_3_4_4 = OTP-6181 OTP-6182 OTP-6217 OTP-6219
-
-TICKETS_3_4_3 = OTP-6170 OTP-6171 OTP-6172
-
-TICKETS_3_4_2 = OTP-6148
-
-TICKETS_3_4_1 = OTP-6113
-
-TICKETS_3_4 = \
- OTP-5769 \
- OTP-5980 \
- OTP-6009 \
- OTP-6025 \
- OTP-6028 \
- OTP-6030 \
- OTP-6048 \
- OTP-6051 \
- OTP-6052 \
- OTP-6055 \
- OTP-6089 \
- OTP-6090
-
-TICKETS_3_3_5 = OTP-6108
-
-TICKETS_3_3_4 = OTP-6076
-
-TICKETS_3_3_3 = OTP-6046
-
-TICKETS_3_3_2 = OTP-6017 OTP-6022
-
-TICKETS_3_3_1 = OTP-5993
-
-TICKETS_3_3 = OTP-5965 OTP-5973
-
-TICKETS_3_2_7 = OTP-5948 OTP-5952 OTP-5953
-
-TICKETS_3_2_6 = OTP-5918 OTP-5919 OTP-5920
-
-TICKETS_3_2_5 = OTP-5887
-
-TICKETS_3_2_4 = OTP-5867 OTP-5879 OTP-5880 OTP-5881 OTP-5882 OTP-5885 OTP-5886
-
-TICKETS_3_2_3 = OTP-5826 OTP-5830 OTP-5833 OTP-5836 OTP-5839
-
-TICKETS_3_2_2 = OTP-5799 OTP-5803 OTP-5804 OTP-5805 OTP-5816
-
-TICKETS_3_2_1 = OTP-5725 OTP-5793
-
-TICKETS_3_2 = OTP-5717 OTP-5750
-
-TICKETS_3_1 = OTP-5542 OTP-5597 OTP-5600 OTP-5601 OTP-5619 OTP-5664
-
-TICKETS_3_0_1 = \
- OTP-5401 \
- OTP-5446 \
- OTP-5447
-
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 2780b737b6..ab2bb73c33 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1,17 +1 @@
-
MNESIA_VSN = 4.4.14
-
-TICKETS = OTP-8519
-#TICKETS_4.4.13 = OTP-8402 OTP-8406
-#TICKETS_4.4.12 = OTP-8250
-#TICKETS_4.4.11 = OTP-8074
-#TICKETS_4.4.10 = OTP-7928 OTP-7968 OTP-8002
-#TICKETS_4.4.9 = OTP-7911
-#TICKETS_4.4.8 = OTP-7753 OTP-7835
-#TICKETS_4.4.7 = OTP-7524 OTP-7625
-#TICKETS_4.4.6 = OTP-7585
-#TICKETS_4.4.5 = OTP-7466
-#TICKETS_4.4.4 = OTP-7419
-#TICKETS_4.4.3 = OTP-7340 OTP-7378 OTP-7383
-#TICKETS_4.4.2 = OTP-7205 OTP-7208
-#TICKETS_4.4.1 = OTP-7170
diff --git a/lib/odbc/doc/src/databases.xml b/lib/odbc/doc/src/databases.xml
index 9776736909..a6ba0e5245 100644
--- a/lib/odbc/doc/src/databases.xml
+++ b/lib/odbc/doc/src/databases.xml
@@ -258,7 +258,7 @@ when p >= 16 </cell>
that contains more than one SQL query. For example, the
following SQLServer-specific statement creates a procedure that
returns a result set containing information about employees
- that work at the department and and a result set listing the
+ that work at the department and a result set listing the
customers of that department. </p>
<code type="none">
CREATE PROCEDURE DepartmentInfo (@DepartmentID INT) AS
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index d813466437..fac3f06d4b 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1,23 +1 @@
ODBC_VSN = 2.10.8
-
-TICKETS = OTP-7452 OTP-8511
-
-TICKETS_2.10.6 = \
- OTP-8250 \
- OTP-8291
-
-TICKETS_2.10.5 = \
- OTP-7978
-
-TICKETS_2.10.4 = \
- OTP-7720 \
- OTP-7721
-
-TICKETS_2.10.3 = \
- OTP-7418
-TICKETS_2.10.2 = \
- OTP-7297
-TICKETS_2.10.1 = \
- OTP-7019 \
- OTP-7294 \
- OTP-7307
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
index ec349ee189..cf80e27a61 100644
--- a/lib/orber/vsn.mk
+++ b/lib/orber/vsn.mk
@@ -1,21 +1 @@
-
ORBER_VSN = 3.6.16
-
-TICKETS = OTP-8489 \
- OTP-8543
-
-TICKETS_3.6.15 = OTP-8353 \
- OTP-8354 \
- OTP-8374 \
- OTP-8409 \
- OTP-8448
-
-TICKETS_3.6.14 = OTP-8201
-
-TICKETS_3.6.13 = OTP-7987
-
-TICKETS_3.6.12 = OTP-7906
-
-TICKETS_3.6.11 = OTP-7837
-
-TICKETS_3.6.10 = OTP-7595
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 33a103d95f..39dea0552d 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -26,8 +26,8 @@
parse(Tokens) ->
yeccpars0(Tokens, {no_func, no_line}, 0, [], []).
--spec parse_and_scan({function() | {atom(), atom()}, [_]} | {atom(), atom(), [_]}) ->
- yecc_ret().
+-spec parse_and_scan({function() | {atom(), atom()}, [_]}
+ | {atom(), atom(), [_]}) -> yecc_ret().
parse_and_scan({F, A}) -> % Fun or {M, F}
yeccpars0([], {{F, A}, no_line}, 0, [], []);
parse_and_scan({M, F, A}) ->
@@ -44,7 +44,7 @@ format_error(Message) ->
%% To be used in grammar files to throw an error message to the parser
%% toplevel. Doesn't have to be exported!
--compile({nowarn_unused_function,{return_error,2}}).
+-compile({nowarn_unused_function, return_error/2}).
-spec return_error(integer(), any()) -> no_return().
return_error(Line, Message) ->
throw({error, {Line, ?MODULE, Message}}).
@@ -57,10 +57,7 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) ->
error: Error ->
Stacktrace = erlang:get_stacktrace(),
try yecc_error_type(Error, Stacktrace) of
- {syntax_error, Token} ->
- yeccerror(Token);
- {missing_in_goto_table=Tag, Symbol, State} ->
- Desc = {Symbol, State, Tag},
+ Desc ->
erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
Stacktrace)
catch _:_ -> erlang:raise(error, Error, Stacktrace)
@@ -70,13 +67,15 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) ->
Error
end.
-yecc_error_type(function_clause, [{?MODULE,F,[State,_,_,_,Token,_,_]} | _]) ->
+yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) ->
case atom_to_list(F) of
- "yeccpars2" ++ _ ->
- {syntax_error, Token};
"yeccgoto_" ++ SymbolL ->
{ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL),
- {missing_in_goto_table, Symbol, State}
+ State = case ArityOrArgs of
+ [S,_,_,_,_,_,_] -> S;
+ _ -> state_is_unknown
+ end,
+ {Symbol, State, missing_in_goto_table}
end.
yeccpars1([Token | Tokens], Tzr, State, States, Vstack) ->
@@ -141,11 +140,13 @@ yecctoken_end_location(Token) ->
yecctoken_location(Token)
end.
+-compile({nowarn_unused_function, yeccerror/1}).
yeccerror(Token) ->
Text = yecctoken_to_string(Token),
Location = yecctoken_location(Token),
{error, {Location, ?MODULE, ["syntax error before: ", Text]}}.
+-compile({nowarn_unused_function, yecctoken_to_string/1}).
yecctoken_to_string(Token) ->
case catch erl_scan:token_info(Token, text) of
{text, Txt} -> Txt;
@@ -158,6 +159,7 @@ yecctoken_location(Token) ->
_ -> element(2, Token)
end.
+-compile({nowarn_unused_function, yecctoken2string/1}).
yecctoken2string({atom, _, A}) -> io_lib:write(A);
yecctoken2string({integer,_,N}) -> io_lib:write(N);
yecctoken2string({float,_,F}) -> io_lib:write(F);
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index c4a47d008f..4119e2631b 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1875,8 +1875,12 @@ format_conflict({Symbol, N, Reduce, Confl}) ->
%% - "__Stack" has been substituted for "Stack";
%% - several states can share yeccpars2_S_cont(), which reduces code size;
%% - instead if calling lists:nthtail() matching code is emitted.
+%%
+%% "1.4", parsetools-2.0.4:
+%% - yeccerror() is called when a syntax error is found (as in version 1.1).
+%% - the include file yeccpre.hrl has been changed.
--define(CODE_VERSION, "1.3").
+-define(CODE_VERSION, "1.4").
-define(YECC_BUG(M, A),
iolist_to_binary([" erlang:error({yecc_bug,\"",?CODE_VERSION,"\",",
io_lib:fwrite(M, A), "}).\n\n"])).
@@ -2106,13 +2110,11 @@ output_call_to_includefile(NewState, St) ->
fwrite(St, <<" yeccpars1(S, ~w, Ss, Stack, T, Ts, Tzr)">>,
[NewState]).
-output_state_actions_fini(State, #yecc{includefile_version = {1,1}}=St0) ->
- %% Backward compatibility.
+output_state_actions_fini(State, St0) ->
+ %% Backward compatible.
St10 = delim(St0, false),
St = fwrite(St10, <<"yeccpars2_~w(_, _, _, _, T, _, _) ->\n">>, [State]),
- fwrite(St, <<" yeccerror(T).\n\n">>, []);
-output_state_actions_fini(_State, St) ->
- fwrite(St, <<".\n\n">>, []).
+ fwrite(St, <<" yeccerror(T).\n\n">>, []).
output_reduce(St0, State, Terminal0,
#reduce{rule_nmbr = RuleNmbr,
@@ -2416,7 +2418,7 @@ include1(Line, Inport, Outport, Nmbr_of_lines) ->
include1(io:get_line(Inport, ''), Inport, Outport, Nmbr_of_lines + Incr).
includefile_version([]) ->
- {1,2};
+ {1,4};
includefile_version(Includefile) ->
case epp:open(Includefile, []) of
{ok, Epp} ->
@@ -2432,7 +2434,7 @@ includefile_version(Includefile) ->
parse_file(Epp) ->
case epp:parse_erl_form(Epp) of
{ok, {function,_Line,yeccpars1,7,_Clauses}} ->
- {1,2};
+ {1,4};
{eof,_Line} ->
{1,1};
_Form ->
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 415547b4ce..63127802ee 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -38,16 +38,16 @@ line_of(Token) ->
-type yecc_ret() :: {'error', _} | {'ok', _}.
--spec parse(_) -> yecc_ret().
+-spec parse(Tokens :: list()) -> yecc_ret().
parse(Tokens) ->
- yeccpars0(Tokens, false).
+ yeccpars0(Tokens, {no_func, no_line}, 0, [], []).
--spec parse_and_scan({function() | {atom(), atom()}, [_]} | {atom(), atom(), [_]}) ->
- yecc_ret().
+-spec parse_and_scan({function() | {atom(), atom()}, [_]}
+ | {atom(), atom(), [_]}) -> yecc_ret().
parse_and_scan({F, A}) -> % Fun or {M, F}
- yeccpars0([], {F, A});
+ yeccpars0([], {{F, A}, no_line}, 0, [], []);
parse_and_scan({M, F, A}) ->
- yeccpars0([], {{M, F}, A}).
+ yeccpars0([], {{{M, F}, A}, no_line}, 0, [], []).
-spec format_error(any()) -> [char() | list()].
format_error(Message) ->
@@ -60,54 +60,58 @@ format_error(Message) ->
%% To be used in grammar files to throw an error message to the parser
%% toplevel. Doesn't have to be exported!
--compile({nowarn_unused_function,{return_error,2}}).
+-compile({nowarn_unused_function, return_error/2}).
-spec return_error(integer(), any()) -> no_return().
return_error(Line, Message) ->
throw({error, {Line, ?MODULE, Message}}).
--define(CODE_VERSION, "1.3").
+-define(CODE_VERSION, "1.4").
-yeccpars0(Tokens, MFA) ->
- try yeccpars1(Tokens, MFA, 0, [], [])
+yeccpars0(Tokens, Tzr, State, States, Vstack) ->
+ try yeccpars1(Tokens, Tzr, State, States, Vstack)
catch
error: Error ->
Stacktrace = erlang:get_stacktrace(),
try yecc_error_type(Error, Stacktrace) of
- {syntax_error, Token} ->
- yeccerror(Token);
- {missing_in_goto_table=Tag, Symbol, State} ->
- Desc = {Symbol, State, Tag},
+ Desc ->
erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc},
- Stacktrace)
+ Stacktrace)
catch _:_ -> erlang:raise(error, Error, Stacktrace)
end;
- throw: {error, {_Line, ?MODULE, _M}} = Error ->
- Error % probably from return_error/2
+ %% Probably thrown from return_error/2:
+ throw: {error, {_Line, ?MODULE, _M}} = Error ->
+ Error
end.
-yecc_error_type(function_clause, [{?MODULE,F,[State,_,_,_,Token,_,_]} | _]) ->
+yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) ->
case atom_to_list(F) of
- "yeccpars2" ++ _ ->
- {syntax_error, Token};
"yeccgoto_" ++ SymbolL ->
{ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL),
- {missing_in_goto_table, Symbol, State}
+ State = case ArityOrArgs of
+ [S,_,_,_,_,_,_] -> S;
+ _ -> state_is_unknown
+ end,
+ {Symbol, State, missing_in_goto_table}
end.
-yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) ->
- yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens,
- Tokenizer);
-yeccpars1([], {F, A}, State, States, Vstack) ->
+yeccpars1([Token | Tokens], Tzr, State, States, Vstack) ->
+ yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr);
+yeccpars1([], {{F, A},_Line}, State, States, Vstack) ->
case apply(F, A) of
- {ok, Tokens, _Endline} ->
- yeccpars1(Tokens, {F, A}, State, States, Vstack);
- {eof, _Endline} ->
- yeccpars1([], false, State, States, Vstack);
+ {ok, Tokens, Endline} ->
+ yeccpars1(Tokens, {{F, A}, Endline}, State, States, Vstack);
+ {eof, Endline} ->
+ yeccpars1([], {no_func, Endline}, State, States, Vstack);
{error, Descriptor, _Endline} ->
{error, Descriptor}
end;
-yeccpars1([], false, State, States, Vstack) ->
- yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false).
+yeccpars1([], {no_func, no_line}, State, States, Vstack) ->
+ Line = 999999,
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [],
+ {no_func, Line});
+yeccpars1([], {no_func, Endline}, State, States, Vstack) ->
+ yeccpars2(State, '$end', States, Vstack, yecc_end(Endline), [],
+ {no_func, Endline}).
%% yeccpars1/7 is called from generated code.
%%
@@ -115,48 +119,73 @@ yeccpars1([], false, State, States, Vstack) ->
%% yeccpars1/7 can be found by parsing the file without following
%% include directives. yecc will otherwise assume that an old
%% yeccpre.hrl is included (one which defines yeccpars1/5).
-yeccpars1(State1, State, States, Vstack, Stack1, [Token | Tokens],
- Tokenizer) ->
+yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) ->
yeccpars2(State, element(1, Token), [State1 | States],
- [Stack1 | Vstack], Token, Tokens, Tokenizer);
-yeccpars1(State1, State, States, Vstack, Stack1, [], {F, A}) ->
- case apply(F, A) of
- {ok, Tokens, _Endline} ->
- yeccpars1(State1, State, States, Vstack, Stack1, Tokens, {F, A});
- {eof, _Endline} ->
- yeccpars1(State1, State, States, Vstack, Stack1, [], false);
- {error, Descriptor, _Endline} ->
- {error, Descriptor}
- end;
-yeccpars1(State1, State, States, Vstack, Stack1, [], false) ->
- yeccpars2(State, '$end', [State1 | States], [Stack1 | Vstack],
- {'$end', 999999}, [], false).
+ [Token0 | Vstack], Token, Tokens, Tzr);
+yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Line}=Tzr) ->
+ yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]);
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_line}) ->
+ Line = yecctoken_end_location(Token0),
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line});
+yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Line}) ->
+ yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack],
+ yecc_end(Line), [], {no_func, Line}).
+
+%% For internal use only.
+yecc_end({Line,_Column}) ->
+ {'$end', Line};
+yecc_end(Line) ->
+ {'$end', Line}.
+
+yecctoken_end_location(Token) ->
+ try
+ {text, Str} = erl_scan:token_info(Token, text),
+ {line, Line} = erl_scan:token_info(Token, line),
+ Parts = re:split(Str, "\n"),
+ Dline = length(Parts) - 1,
+ Yline = Line + Dline,
+ case erl_scan:token_info(Token, column) of
+ {column, Column} ->
+ Col = byte_size(lists:last(Parts)),
+ {Yline, Col + if Dline =:= 0 -> Column; true -> 1 end};
+ undefined ->
+ Yline
+ end
+ catch _:_ ->
+ yecctoken_location(Token)
+ end.
-% For internal use only.
yeccerror(Token) ->
- Text = case catch erl_scan:token_info(Token, text) of
- {text, Txt} -> Txt;
- _ -> yecctoken2string(Token)
- end,
- Location = case catch erl_scan:token_info(Token, location) of
- {location, Loc} -> Loc;
- _ -> element(2, Token)
- end,
+ Text = yecctoken_to_string(Token),
+ Location = yecctoken_location(Token),
{error, {Location, ?MODULE, ["syntax error before: ", Text]}}.
+yecctoken_to_string(Token) ->
+ case catch erl_scan:token_info(Token, text) of
+ {text, Txt} -> Txt;
+ _ -> yecctoken2string(Token)
+ end.
+
+yecctoken_location(Token) ->
+ case catch erl_scan:token_info(Token, location) of
+ {location, Loc} -> Loc;
+ _ -> element(2, Token)
+ end.
+
yecctoken2string({atom, _, A}) -> io_lib:write(A);
yecctoken2string({integer,_,N}) -> io_lib:write(N);
yecctoken2string({float,_,F}) -> io_lib:write(F);
yecctoken2string({char,_,C}) -> io_lib:write_char(C);
yecctoken2string({var,_,V}) -> io_lib:format("~s", [V]);
yecctoken2string({string,_,S}) -> io_lib:write_unicode_string(S);
-yecctoken2string({reserved_symbol, _, A}) -> io_lib:format("~w", [A]);
-yecctoken2string({_Cat, _, Val}) -> io_lib:format("~w", [Val]);
+yecctoken2string({reserved_symbol, _, A}) -> io_lib:write(A);
+yecctoken2string({_Cat, _, Val}) -> io_lib:write(Val);
yecctoken2string({dot, _}) -> "'.'";
yecctoken2string({'$end', _}) ->
[];
yecctoken2string({Other, _}) when is_atom(Other) ->
- io_lib:format("~w", [Other]);
+ io_lib:write(Other);
yecctoken2string(Other) ->
io_lib:write(Other).
@@ -164,7 +193,7 @@ yecctoken2string(Other) ->
--file("yeccparser.erl", 168).
+-file("yeccparser.erl", 196).
yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr);
@@ -248,7 +277,9 @@ yeccpars2_0(S, integer, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, reserved_word, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 8, Ss, Stack, T, Ts, Tzr);
yeccpars2_0(S, var, Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 9, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 9, Ss, Stack, T, Ts, Tzr);
+yeccpars2_0(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_1(S, atom, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 6, Ss, Stack, T, Ts, Tzr);
@@ -267,10 +298,14 @@ yeccpars2_2(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_grammar(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_3(S, '->', Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 10, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 10, Ss, Stack, T, Ts, Tzr);
+yeccpars2_3(_, _, _, _, T, _, _) ->
+ yeccerror(T).
-yeccpars2_4(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
- {ok, hd(Stack)}.
+yeccpars2_4(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
+ {ok, hd(Stack)};
+yeccpars2_4(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_5(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_grammar(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
@@ -317,7 +352,9 @@ yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_symbols(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr).
yeccpars2_14(S, dot, Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 29, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 29, Ss, Stack, T, Ts, Tzr);
+yeccpars2_14(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_15(S, '->', Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 18, Ss, Stack, T, Ts, Tzr);
@@ -338,7 +375,9 @@ yeccpars2_15(S, reserved_word, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_15(S, string, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 26, Ss, Stack, T, Ts, Tzr);
yeccpars2_15(S, var, Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 27, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 27, Ss, Stack, T, Ts, Tzr);
+yeccpars2_15(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_16(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
[_|Nss] = Ss,
@@ -414,10 +453,14 @@ yeccpars2_29(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_rule(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr).
yeccpars2_30(S, dot, Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr);
+yeccpars2_30(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_31(S, dot, Ss, Stack, T, Ts, Tzr) ->
- yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr).
+ yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr);
+yeccpars2_31(_, _, _, _, T, _, _) ->
+ yeccerror(T).
yeccpars2_32(S, string, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 32, Ss, Stack, T, Ts, Tzr);
@@ -486,7 +529,7 @@ yeccgoto_tokens(15=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_tokens(17=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr).
--compile({inline,{yeccpars2_6_,1}}).
+-compile({inline,yeccpars2_6_/1}).
-file("yeccgramm.yrl", 44).
yeccpars2_6_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -494,7 +537,7 @@ yeccpars2_6_(__Stack0) ->
symbol ( __1 )
end | __Stack].
--compile({inline,{yeccpars2_7_,1}}).
+-compile({inline,yeccpars2_7_/1}).
-file("yeccgramm.yrl", 45).
yeccpars2_7_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -502,7 +545,7 @@ yeccpars2_7_(__Stack0) ->
symbol ( __1 )
end | __Stack].
--compile({inline,{yeccpars2_8_,1}}).
+-compile({inline,yeccpars2_8_/1}).
-file("yeccgramm.yrl", 46).
yeccpars2_8_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -510,7 +553,7 @@ yeccpars2_8_(__Stack0) ->
symbol ( __1 )
end | __Stack].
--compile({inline,{yeccpars2_9_,1}}).
+-compile({inline,yeccpars2_9_/1}).
-file("yeccgramm.yrl", 43).
yeccpars2_9_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -518,14 +561,14 @@ yeccpars2_9_(__Stack0) ->
symbol ( __1 )
end | __Stack].
--compile({inline,{yeccpars2_11_,1}}).
+-compile({inline,yeccpars2_11_/1}).
-file("yeccgramm.yrl", 40).
yeccpars2_11_(__Stack0) ->
[begin
{ erlang_code , [ { atom , 0 , '$undefined' } ] }
end | __Stack0].
--compile({inline,{yeccpars2_12_,1}}).
+-compile({inline,yeccpars2_12_/1}).
-file("yeccgramm.yrl", 35).
yeccpars2_12_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -533,7 +576,7 @@ yeccpars2_12_(__Stack0) ->
[ __1 ]
end | __Stack].
--compile({inline,{yeccpars2_13_,1}}).
+-compile({inline,yeccpars2_13_/1}).
-file("yeccgramm.yrl", 36).
yeccpars2_13_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
@@ -541,7 +584,7 @@ yeccpars2_13_(__Stack0) ->
[ __1 | __2 ]
end | __Stack].
--compile({inline,{yeccpars2_16_,1}}).
+-compile({inline,yeccpars2_16_/1}).
-file("yeccgramm.yrl", 39).
yeccpars2_16_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
@@ -549,7 +592,7 @@ yeccpars2_16_(__Stack0) ->
{ erlang_code , __2 }
end | __Stack].
--compile({inline,{yeccpars2_17_,1}}).
+-compile({inline,yeccpars2_17_/1}).
-file("yeccgramm.yrl", 41).
yeccpars2_17_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -557,7 +600,7 @@ yeccpars2_17_(__Stack0) ->
[ __1 ]
end | __Stack].
--compile({inline,{yeccpars2_18_,1}}).
+-compile({inline,yeccpars2_18_/1}).
-file("yeccgramm.yrl", 55).
yeccpars2_18_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -565,7 +608,7 @@ yeccpars2_18_(__Stack0) ->
{ '->' , line_of ( __1 ) }
end | __Stack].
--compile({inline,{yeccpars2_19_,1}}).
+-compile({inline,yeccpars2_19_/1}).
-file("yeccgramm.yrl", 56).
yeccpars2_19_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -573,7 +616,7 @@ yeccpars2_19_(__Stack0) ->
{ ':' , line_of ( __1 ) }
end | __Stack].
--compile({inline,{yeccpars2_24_,1}}).
+-compile({inline,yeccpars2_24_/1}).
-file("yeccgramm.yrl", 53).
yeccpars2_24_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -581,7 +624,7 @@ yeccpars2_24_(__Stack0) ->
{ value_of ( __1 ) , line_of ( __1 ) }
end | __Stack].
--compile({inline,{yeccpars2_25_,1}}).
+-compile({inline,yeccpars2_25_/1}).
-file("yeccgramm.yrl", 54).
yeccpars2_25_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -589,7 +632,7 @@ yeccpars2_25_(__Stack0) ->
{ value_of ( __1 ) , line_of ( __1 ) }
end | __Stack].
--compile({inline,{yeccpars2_28_,1}}).
+-compile({inline,yeccpars2_28_/1}).
-file("yeccgramm.yrl", 42).
yeccpars2_28_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
@@ -597,7 +640,7 @@ yeccpars2_28_(__Stack0) ->
[ __1 | __2 ]
end | __Stack].
--compile({inline,{yeccpars2_29_,1}}).
+-compile({inline,yeccpars2_29_/1}).
-file("yeccgramm.yrl", 33).
yeccpars2_29_(__Stack0) ->
[__5,__4,__3,__2,__1 | __Stack] = __Stack0,
@@ -605,7 +648,7 @@ yeccpars2_29_(__Stack0) ->
{ rule , [ __1 | __3 ] , __4 }
end | __Stack].
--compile({inline,{yeccpars2_32_,1}}).
+-compile({inline,yeccpars2_32_/1}).
-file("yeccgramm.yrl", 37).
yeccpars2_32_(__Stack0) ->
[__1 | __Stack] = __Stack0,
@@ -613,7 +656,7 @@ yeccpars2_32_(__Stack0) ->
[ __1 ]
end | __Stack].
--compile({inline,{yeccpars2_33_,1}}).
+-compile({inline,yeccpars2_33_/1}).
-file("yeccgramm.yrl", 38).
yeccpars2_33_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
@@ -621,7 +664,7 @@ yeccpars2_33_(__Stack0) ->
[ __1 | __2 ]
end | __Stack].
--compile({inline,{yeccpars2_34_,1}}).
+-compile({inline,yeccpars2_34_/1}).
-file("yeccgramm.yrl", 32).
yeccpars2_34_(__Stack0) ->
[__3,__2,__1 | __Stack] = __Stack0,
@@ -629,7 +672,7 @@ yeccpars2_34_(__Stack0) ->
{ __1 , __2 }
end | __Stack].
--compile({inline,{yeccpars2_35_,1}}).
+-compile({inline,yeccpars2_35_/1}).
-file("yeccgramm.yrl", 31).
yeccpars2_35_(__Stack0) ->
[__3,__2,__1 | __Stack] = __Stack0,
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 61e2456323..93949a074a 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -298,8 +298,8 @@ syntax(Config) when is_list(Config) ->
{_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[]} = compile:file(Parserfile1, [basic_validation,return]),
- ?line L1 = 24 + SzYeccPre,
- ?line L2 = 31 + SzYeccPre
+ ?line L1 = 28 + SzYeccPre,
+ ?line L2 = 35 + SzYeccPre
end(),
%% Bad macro in action. OTP-7224.
@@ -316,8 +316,8 @@ syntax(Config) when is_list(Config) ->
{_,[{L1,_,{undefined_function,{yeccpars2_2_,1}}},
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[]} = compile:file(Parserfile1, [basic_validation,return]),
- ?line L1 = 24 + SzYeccPre,
- ?line L2 = 31 + SzYeccPre
+ ?line L1 = 28 + SzYeccPre,
+ ?line L2 = 35 + SzYeccPre
end(),
%% Check line numbers. OTP-7224.
@@ -1584,8 +1584,8 @@ otp_7292(Config) when is_list(Config) ->
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[{_,[{16,_,{unused_function,{foo,0}}}]}]} =
compile:file(Parserfile1, [basic_validation, return]),
- ?line L1 = 34 + SzYeccPre,
- ?line L2 = 41 + SzYeccPre
+ ?line L1 = 38 + SzYeccPre,
+ ?line L2 = 45 + SzYeccPre
end(),
YeccPre = filename:join(Dir, "yeccpre.hrl"),
@@ -1602,8 +1602,8 @@ otp_7292(Config) when is_list(Config) ->
{L2,_,{bad_inline,{yeccpars2_2_,1}}}]}],
[{_,[{16,_,{unused_function,{foo,0}}}]}]} =
compile:file(Parserfile1, [basic_validation, return]),
- ?line L1 = 33 + SzYeccPre,
- ?line L2 = 40 + SzYeccPre
+ ?line L1 = 37 + SzYeccPre,
+ ?line L2 = 44 + SzYeccPre
end(),
file:delete(YeccPre),
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index f3e2dc0fb4..46915baed6 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.0.3
+PARSETOOLS_VSN = 2.0.4
diff --git a/lib/public_key/doc/src/cert_records.xml b/lib/public_key/doc/src/cert_records.xml
index 8cfe57f670..0d6113acef 100644
--- a/lib/public_key/doc/src/cert_records.xml
+++ b/lib/public_key/doc/src/cert_records.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -37,7 +37,7 @@
<p>This chapter briefly describes erlang records derived from asn1
specifications used to handle X509 certificates. The intent is to
describe the data types and not to specify the meaning of each
- component for this we refer you to RFC 3280.
+ component for this we refer you to RFC 5280.
</p>
<p>Use the following include directive to get access to the
@@ -45,11 +45,7 @@
<code> -include_lib("public_key/include/public_key.hrl"). </code>
- <p>The used specification is available in <c>OTP-PKIX.asn1</c>,
- which is an amelioration of
- the <c>PKIX1Explicit88.asn1</c>, <c>PKIX1Implicit88.asn1</c>
- and <c>PKIX1Algorithms88.asn1</c> modules.
- You find all these modules in the <c>asn1</c> subdirectory
+ <p>The used asn1 specifications are available <c>asn1</c> subdirectory
of the application <c>public_key</c>.
</p>
@@ -62,6 +58,9 @@
marker="public_key">public key reference manual </seealso> or
follows here.</p>
+ <p><c>oid() - a tuple of integers
+ as generated by the asn1 compiler.</c></p>
+
<p><c>time() = uct_time() | general_time()</c></p>
<p><c>uct_time() = {utcTime, "YYMMDDHHMMSSZ"} </c></p>
@@ -119,9 +118,31 @@
algorithm, % oid()
parameters % asn1_der_encoded()
}.
+</code>
+
+<code>
+#'OTPCertificate'{
+ tbsCertificate, % #'OTPTBSCertificate'{}
+ signatureAlgorithm, % #'SignatureAlgorithm'
+ signature % {0, binary()} - asn1 compact bitstring
+ }.
+
+#'OTPTBSCertificate'{
+ version, % v1 | v2 | v3
+ serialNumber, % integer()
+ signature, % #'SignatureAlgorithm'
+ issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]}
+ validity, % #'Validity'{}
+ subject, % {rdnSequence, [#AttributeTypeAndValue'{}]}
+ subjectPublicKeyInfo, % #'SubjectPublicKeyInfo'{}
+ issuerUniqueID, % binary() | asn1_novalue
+ subjectUniqueID, % binary() | asn1_novalue
+ extensions % [#'Extension'{}]
+ }.
+
#'SignatureAlgorithm'{
algorithm, % id_signature_algorithm()
- parameters % public_key_params()
+ parameters % asn1_novalue | #'Dss-Parms'{}
}.
</code>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index dc9a96906f..c72719fac4 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -34,11 +34,7 @@
<modulesummary> API module for public key infrastructure.</modulesummary>
<description>
<p>This module provides functions to handle public key infrastructure
- from RFC 3280 - X.509 certificates (will later be upgraded to RFC 5280)
- and some parts of the PKCS-standard.
- Currently this application is mainly used by the new
- ssl implementation. The API is yet under construction
- and only a few of the functions are currently documented and thereby supported.
+ from RFC 5280 - X.509 certificates and some parts of the PKCS-standard.
</p>
</description>
@@ -62,37 +58,37 @@
<p><c>boolean() = true | false</c></p>
- <p><c>string = [bytes()]</c></p>
-
- <p><c>asn1_der_encoded() = binary() | [bytes()]</c></p>
+ <p><c>string = [bytes()]</c></p>
+
+ <p><c>der_encoded() = binary() </c></p>
- <p><c>der_bin() = binary() </c></p>
+ <p><c>decrypt_der() = binary() </c></p>
- <p><c>oid() - a tuple of integers
- as generated by the asn1 compiler.</c></p>
-
- <p><c>public_key() = rsa_public_key() | dsa_public_key()</c></p>
+ <p><c>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'|
+ 'DSAPrivateKey' | 'DHParameter'</c></p>
+ <p><c>pem_entry () = {pki_asn1_type(), der_encoded() | decrypt_der(), not_encrypted |
+ {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</c></p>
+
<p><c>rsa_public_key() = #'RSAPublicKey'{}</c></p>
<p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p>
- <p><c>dsa_public_key() = integer() </c></p>
-
- <p><c>public_key_params() = dsa_key_params() </c></p>
-
- <p><c>dsa_key_params() = #'Dss-Parms'{} </c></p>
-
- <p><c>private_key() = rsa_private_key() | dsa_private_key()</c></p>
+ <p><c>dsa_public_key() = {integer(), #'Dss-Parms'{}} </c></p>
<p><c>rsa_private_key() = #'RSAPrivateKey'{} </c></p>
<p><c>dsa_private_key() = #'DSAPrivateKey'{}</c></p>
+
+ <p><c> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </c></p>
- <p><c>x509_certificate() = "#Certificate{}"</c></p>
-
- <p><c>x509_tbs_certificate() = #'TBSCertificate'{} </c></p>
-
+ <p><c> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
+ | 'rsa_no_padding'</c></p>
+
+ <p><c> rsa_digest_type() = 'md5' | 'sha' </c></p>
+
+ <p><c> dss_digest_type() = 'none' | 'sha' </c></p>
+
<!-- <p><c>policy_tree() = [Root, Children]</c></p> -->
<!-- <p><c>Root = #policy_tree_node{}</c></p> -->
@@ -121,197 +117,301 @@
<!-- that would satisfy this policy in the certificate x+1. </item> -->
<!-- </taglist> -->
</section>
-
-<funcs>
- <func>
- <name>decode_private_key(KeyInfo) -> </name>
- <name>decode_private_key(KeyInfo, Password) -> {ok, PrivateKey} | {error, Reason}</name>
- <fsummary> Decodes an asn1 der encoded private key.</fsummary>
- <type>
- <v> KeyInfo = {KeyType, der_bin(), ChipherInfo} </v>
- <d> As returned from pem_to_der/1 for private keys</d>
- <v> KeyType = rsa_private_key | dsa_private_key </v>
- <v> ChipherInfo = opaque() | no_encryption </v>
- <d> ChipherInfo may contain encryption parameters if the private key is password
- protected, these are opaque to the user just pass the value returned by pem_to_der/1
- to this function.</d>
- <v> Password = string() </v>
- <d>Must be specified if CipherInfo =/= no_encryption</d>
- <v> PrivateKey = private_key() </v>
- <v> Reason = term() </v>
- </type>
- <desc>
- <p>Decodes an asn1 der encoded private key.</p>
- </desc>
- </func>
-
+
+<funcs>
+
<func>
- <name>pem_to_der(File) -> {ok, [Entry]}</name>
- <fsummary>Reads a PEM file and translates it into its asn1 der
- encoded parts.</fsummary>
+ <name>decrypt_private(CipherText, Key [, Options]) -> binary()</name>
+ <fsummary>Public key decryption.</fsummary>
<type>
- <v>File = path()</v>
- <v>Password = string()</v>
- <v>Entry = {entry_type(), der_bin(), CipherInfo}</v>
- <v> ChipherInfo = opaque() | no_encryption </v>
- <d> ChipherInfo may contain encryption parameters if the private key is password
- protected, these will be handled by the function decode_private_key/2. </d>
- <v>entry_type() = cert | cert_req | rsa_private_key | dsa_private_key |
- dh_params </v>
+ <v>CipherText = binary()</v>
+ <v>Key = rsa_private_key()</v>
+ <v>Options = public_crypt_options()</v>
</type>
<desc>
- <p>Reads a PEM file and translates it into its asn1 der
- encoded parts.</p>
+ <p>Public key decryption using the private key.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>decrypt_public(CipherText, Key [, Options]) - > binary()</name>
+ <fsummary></fsummary>
+ <type>
+ <v>CipherText = binary()</v>
+ <v>Key = rsa_public_key()</v>
+ <v>Options = public_crypt_options()</v>
+ </type>
+ <desc>
+ <p> Public key decryption using the public key.</p>
</desc>
</func>
-
- <func>
- <name>pkix_decode_cert(Cert, Type) -> {ok, DecodedCert} | {error, Reason}</name>
- <fsummary> Decodes an asn1 der encoded pkix certificate. </fsummary>
- <type>
- <v>Cert = asn1_der_encoded() </v>
- <v>Type = plain | otp</v>
- <v>DecodeCert = x509_certificate() </v>
- <d>When type is specified as otp the asn1 spec OTP-PKIX.asn1 is used to decode known
- extensions and enhance the signature field in
- #'Certificate'{} and '#TBSCertificate'{}. This is currently used by the new ssl
- implementation but not documented and supported for the public_key application.</d>
- <v>Reason = term() </v>
+
+ <func>
+ <name>der_decode(Asn1type, Der) -> term()</name>
+ <fsummary> Decodes a public key asn1 der encoded entity.</fsummary>
+ <type>
+ <v>Asn1Type = atom() -</v>
+ <d> Asn1 type present in the public_key applications
+ asn1 specifications.</d>
+ <v>Der = der_encoded()</v>
</type>
- <desc>
- <p> Decodes an asn1 encoded pkix certificate.</p>
+ <desc>
+ <p> Decodes a public key asn1 der encoded entity.</p>
</desc>
</func>
+
+ <func>
+ <name>der_encode(Asn1Type, Entity) -> der_encoded()</name>
+ <fsummary> Encodes a public key entity with asn1 DER encoding.</fsummary>
+ <type>
+ <v>Asn1Type = atom()</v>
+ <d> Asn1 type present in the public_key applications
+ asn1 specifications.</d>
+ <v>Entity = term() - The erlang representation of <c> Asn1Type</c></v>
+ </type>
+ <desc>
+ <p> Encodes a public key entity with asn1 DER encoding.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pem_decode(PemBin) -> [pem_entry()]</name>
+ <fsummary>Decode PEM binary data and return
+ entries as asn1 der encoded entities. </fsummary>
+ <type>
+ <v>PemBin = binary()</v>
+ <d>Example {ok, PemBin} = file:read_file("cert.pem").</d>
+ </type>
+ <desc>
+ <p>Decode PEM binary data and return
+ entries as asn1 der encoded entities.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pem_encode(PemEntries) -> binary()</name>
+ <fsummary>Creates a PEM binary</fsummary>
+ <type>
+ <v> PemEntries = [pem_entry()] </v>
+ </type>
+ <desc>
+ <p>Creates a PEM binary</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pem_entry_decode(PemEntry [, Password]) -> term()</name>
+ <fsummary>Decodes a pem entry.</fsummary>
+ <type>
+ <v> PemEntry = pem_entry() </v>
+ <v> Password = string() </v>
+ </type>
+ <desc>
+ <p>Decodes a pem entry. pem_decode/1 returns a list of
+ pem entries.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pem_entry_encode(Asn1Type, Entity [,{CipherInfo, Password}]) -> pem_entry()</name>
+ <fsummary> Creates a pem entry that can be feed to pem_encode/1.</fsummary>
+ <type>
+ <v>Asn1Type = atom()</v>
+ <v>Entity = term()</v>
+ <v>CipherInfo = {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}</v>
+ <v>Password = string()</v>
+ </type>
+ <desc>
+ <p> Creates a pem entry that can be feed to pem_encode/1.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>encrypt_private(PlainText, Key) -> binary()</name>
+ <fsummary> Public key encryption using the private key.</fsummary>
+ <type>
+ <v>PlainText = binary()</v>
+ <v>Key = rsa_private_key()</v>
+ </type>
+ <desc>
+ <p> Public key encryption using the private key.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>encrypt_public(PlainText, Key) -> binary()</name>
+ <fsummary> Public key encryption using the public key.</fsummary>
+ <type>
+ <v>PlainText = binary()</v>
+ <v>Key = rsa_public_key()</v>
+ </type>
+ <desc>
+ <p> Public key encryption using the public key.</p>
+ </desc>
+ </func>
-<!-- <func> -->
-<!-- <name> pkix_encode_cert(Cert) -> {ok, EncodedCert} | {error, Reason}</name> -->
-<!-- <fsummary>Encodes a certificate record using asn1. </fsummary> -->
-<!-- <type> -->
-<!-- <v>Cert = x509_certificate() </v> -->
-<!-- <v>EncodedCert = asn1_der_encoded() </v> -->
-<!-- <v>Reason = term() </v> -->
-<!-- </type> -->
-<!-- <desc> -->
-<!-- <p> Encodes a certificate record using asn1.</p> -->
-<!-- </desc> -->
-<!-- </func> -->
+ <func>
+ <name> pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name>
+ <fsummary> Decodes an asn1 der encoded pkix x509 certificate.</fsummary>
+ <type>
+ <v>Cert = der_encoded()</v>
+ </type>
+ <desc>
+ <p>Decodes an asn1 der encoded pkix certificate. The otp option
+ will use the customized asn1 specification OTP-PKIX.asn1 for
+ decoding and also recursively decode most of the standard
+ parts.</p>
+ </desc>
+ </func>
-<!-- <func> -->
-<!-- <name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, Result} | {error, Reason}</name> -->
-
-<!-- <fsummary>Performs a basic path validation according to RFC 3280</fsummary> -->
-<!-- <type> -->
-<!-- <v>TrustedCert = asn1_der_encoded()</v> -->
-<!-- <v>CertChain = [asn1_der_encoded()]</v> -->
-<!-- <v>Options = [{Option, Value}]</v> -->
-<!-- <v>Result = {{algorithm(), public_key(), -->
-<!-- public_key_params()}, policy_tree()}</v> -->
-<!-- </type> -->
+ <func>
+ <name>pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded()</name>
+ <fsummary>Der encodes a pkix x509 certificate or part of such a
+ certificate.</fsummary>
+ <type>
+ <v>Asn1Type = atom()</v>
+ <d>The asn1 type can be 'Certificate', 'OTPCertificate' or a subtype of either .</d>
+ </type>
+ <desc>
+ <p>Der encodes a pkix x509 certificate or part of such a
+ certificate. This function must be used for encoding certificates or parts of certificates
+ that are decoded/created on the otp format, whereas for the plain format this
+ function will directly call der_encode/2. </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name>
+ <fsummary> Checks if <c>IssuerCert</c> issued <c>Cert</c> </fsummary>
+ <type>
+ <v>Cert = der_encode() | #'OTPCertificate'{}</v>
+ <v>IssuerCert = der_encode() | #'OTPCertificate'{}</v>
+ </type>
+ <desc>
+ <p> Checks if <c>IssuerCert</c> issued <c>Cert</c> </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pkix_is_fixed_dh_cert(Cert) -> boolean()</name>
+ <fsummary> Checks if a Certificate is a fixed Diffie-Hellman Cert.</fsummary>
+ <type>
+ <v>Cert = der_encode() | #'OTPCertificate'{}</v>
+ </type>
+ <desc>
+ <p> Checks if a Certificate is a fixed Diffie-Hellman Cert.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pkix_is_self_signed(Cert) -> boolean()</name>
+ <fsummary> Checks if a Certificate is self signed.</fsummary>
+ <type>
+ <v>Cert = der_encode() | #'OTPCertificate'{}</v>
+ </type>
+ <desc>
+ <p> Checks if a Certificate is self signed.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pkix_issuer_id(Cert, IssuedBy) -> {ok, IssuerID} | {error, Reason}</name>
+ <fsummary> Returns the issuer id.</fsummary>
+ <type>
+ <v>Cert = der_encode() | #'OTPCertificate'{}</v>
+ <v>IssuedBy = self | other</v>
+ <v>IssuerID = {integer(), {rdnSequence, [#'AttributeTypeAndValue'{}]}}</v>
+ <d>The issuer id consists of the serial number and the issuers name.</d>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p> Returns the issuer id.</p>
+ </desc>
+ </func>
-<!-- <desc> -->
-<!-- <p>Available options are: </p> -->
-<!-- <taglist> -->
-<!-- <tag>{validate_extension_fun, fun()}</tag> -->
-<!-- <item> A fun behaving according to the following outline: -->
-<!-- <code> -->
-<!-- [...] -->
-<!-- ValidateExtensionFun = fun(Extensions, UserState) -> -->
-<!-- validate_extensions(Extensions, UserState, []) -->
-<!-- end, -->
-<!-- [...] -->
+ <func>
+ <name>pkix_normalize_name(Issuer) -> Normalized</name>
+ <fsummary>Normalizes a issuer name so that it can be easily
+ compared to another issuer name. </fsummary>
+ <type>
+ <v>Issuer = {rdnSequence,[#'AttributeTypeAndValue'{}]}</v>
+ <v>Normalized = {rdnSequence, [#'AttributeTypeAndValue'{}]}</v>
+ </type>
+ <desc>
+ <p>Normalizes a issuer name so that it can be easily
+ compared to another issuer name.</p>
+ </desc>
+ </func>
+
+ <!-- <func> -->
+ <!-- <name>pkix_path_validation()</name> -->
+ <!-- <fsummary> Performs a basic path validation according to RFC 5280.</fsummary> -->
+ <!-- <type> -->
+ <!-- <v></v> -->
+ <!-- </type> -->
+ <!-- <desc> -->
+ <!-- <p> Performs a basic path validation according to RFC 5280.</p> -->
+ <!-- </desc> -->
+ <!-- </func> -->
-<!-- validate_extensions([], UserState, UnknowExtension) -> -->
-<!-- {UserState, UnknowExtension}; -->
-<!-- validate_extensions([#'Extension'{} = Ext | Rest], UserState, UnknowExtension) -> -->
-<!-- case valid_extension(Ext) of -->
-<!-- {true, NewUserState} -> -->
-<!-- validate_extensions(Rest, NewUserState, UnknowExtension); -->
-<!-- unknown -> -->
-<!-- validate_extensions(Rest, UserState, [Ext | UnknowExtension]); -->
-<!-- {false, Reason} -> -->
-<!-- throw(bad_cert, Reason) -->
-<!-- end. -->
-<!-- </code> -->
-
-<!-- </item> -->
-
-<!-- <tag>{policy_set, [oid()]}</tag> -->
-<!-- <item>A set of certificate policy -->
-<!-- identifiers naming the policies that are acceptable to the -->
-<!-- certificate user. If the user is not concerned about -->
-<!-- certificate policy there is no need -->
-<!-- to set this option. Defaults to the -->
-<!-- special value [?anyPolicy]. -->
-<!-- </item> -->
-
-<!-- <tag>{policy_mapping, boolean()}</tag> -->
-<!-- <item>Indicates if policy -->
-<!-- mapping, initially, is allowed in the certification path. -->
-<!-- Defaults to false. -->
-<!-- </item> -->
-
-<!-- <tag> {explicit_policy, boolean()}</tag> -->
-<!-- <item>Indicates if the path, initially, must be -->
-<!-- valid for at least one of the certificate policies in the user -->
-<!-- specified policy set. -->
-<!-- Defaults to false. -->
-<!-- </item> -->
+
+ <func>
+ <name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encode()</name>
+ <fsummary>Signs certificate.</fsummary>
+ <type>
+ <v>Key = rsa_public_key() | dsa_public_key()</v>
+ </type>
+ <desc>
+ <p>Signs a 'OTPTBSCertificate'. Returns the corresponding
+ der encoded certificate.</p>
+ </desc>
+ </func>
-<!-- <tag>{inhibit_any_policy, boolean()}</tag> -->
-<!-- <item>Indicates whether the anyPolicy OID, initially, should -->
-<!-- be processed if it is included in a certificate. -->
-<!-- Defaults to false. -->
-<!-- </item> -->
-
-<!-- </taglist> -->
-
-<!-- <p>Performs a basic path validation according to RFC 3280, -->
-<!-- e.i. signature validation, time validation, issuer validation, -->
-<!-- alternative subject name validation, CRL validation, policy -->
-<!-- validation and checks that no unknown extensions -->
-<!-- are marked as critical. The option <c>validate_extension_fun</c> -->
-<!-- may be used to validate application specific extensions. If -->
-<!-- a validation criteria is found to be invalid the validation process -->
-<!-- will immediately be stopped and this functions will return -->
-<!-- {error, Reason}. -->
-<!-- </p> -->
-<!-- </desc> -->
-<!-- </func> -->
+ <func>
+ <name>pkix_verify(Cert, Key) -> boolean()</name>
+ <fsummary> Verify pkix x.509 certificate signature.</fsummary>
+ <type>
+ <v>Cert = der_encode()</v>
+ <v>Key = rsa_public_key() | dsa_public_key()</v>
+ </type>
+ <desc>
+ <p> Verify pkix x.509 certificate signature.</p>
+ </desc>
+ </func>
-<!-- <func> -->
-<!-- <name>sign(DigestOrTBSCert, Key) -> </name> -->
-<!-- <name>sign(DigestOrTBSCert, Key, KeyParams) -> {ok, SignatureOrDerCert} | {error, Reason}</name> -->
-<!-- <fsummary>Signs Digest/Certificate using Key.</fsummary> -->
-<!-- <type> -->
-<!-- <v>DigestOrTBSCert = binary() | x509_tbs_certificate()</v> -->
-<!-- <v>Key = private_key()</v> -->
-<!-- <v>SignatureORDerCert = binary() | der_bin() </v> -->
-<!-- <v>Reason = term() </v> -->
-<!-- </type> -->
-<!-- <desc> -->
-<!-- <p> Signs Digest/Certificate using Key, in the later -->
-<!-- case a der encoded x509_certificate() will be returned. </p> -->
-<!-- </desc> -->
-<!-- </func> -->
+ <func>
+ <name>sign(Msg, DigestType, Key) -> binary()</name>
+ <fsummary> Create digital signature.</fsummary>
+ <type>
+ <v>Msg = binary()</v>
+ <d>The msg is either the binary "plain text" data to be
+ signed or in the case that digest type is <c>none</c>
+ it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = rsa_digest_type() | dsa_digest_type()</v>
+ <v>Key = rsa_public_key() | dsa_public_key()</v>
+ </type>
+ <desc>
+ <p> Creates a digital signature.</p>
+ </desc>
+ </func>
-<!-- <func> -->
-<!-- <name>verify_signature(Digest, Signature, Key) -> </name> -->
-<!-- <name>verify_signature(DerCert, Key, KeyParams) -> </name> -->
-<!-- <name>verify_signature(Digest, Signature, Key, Params) -> Verified </name> -->
-<!-- <fsummary> Verifies the signature. </fsummary> -->
-<!-- <type> -->
-<!-- <v>Digest = binary() </v> -->
-<!-- <v>DerCert = der_bin() </v> -->
-<!-- <v>Signature = binary() </v> -->
-<!-- <v>Key = public_key() </v> -->
-<!-- <v>Params = key_params()</v> -->
-<!-- <v>Verified = boolean()</v> -->
-<!-- </type> -->
-<!-- <desc> -->
-<!-- <p> Verifies the signature Signature. If the key is an rsa-key no -->
-<!-- paramters are neeed.</p> -->
-<!-- </desc> -->
-<!-- </func> -->
+ <func>
+ <name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
+ <fsummary>Verifies a digital signature.</fsummary>
+ <type>
+ <v>Msg = binary()</v>
+ <d>The msg is either the binary "plain text" data
+ or in the case that digest type is <c>none</c>
+ it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = rsa_digest_type() | dsa_digest_type()</v>
+ <v>Signature = binary()</v>
+ <v>Key = rsa_public_key() | dsa_public_key()</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
+ </desc>
+ </func>
+
</funcs>
</erlref>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index fbce10f0eb..6503321042 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -59,4 +59,13 @@
interim_reasons_mask
}).
+
+-type der_encoded() :: binary().
+-type decrypt_der() :: binary().
+-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey'
+ | 'DSAPrivateKey' | 'DHParameter'.
+-type pem_entry() :: {pki_asn1_type(), der_encoded() | decrypt_der(),
+ not_encrypted | {Cipher :: string(), Salt :: binary()}}.
+-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl
+
-endif. % -ifdef(public_key).
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index c30399f33a..51f405361b 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -42,8 +42,7 @@ MODULES = \
public_key \
pubkey_pem \
pubkey_cert \
- pubkey_cert_records \
- pubkey_crypto
+ pubkey_cert_records
HRL_FILES = $(INCLUDE)/public_key.hrl
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index 0651dcec29..64fc8ab5bc 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -23,14 +23,14 @@
-include("public_key.hrl").
--export([verify_signature/3,
- init_validation_state/3, prepare_for_next_cert/2,
+-export([init_validation_state/3, prepare_for_next_cert/2,
validate_time/3, validate_signature/6,
validate_issuer/4, validate_names/6,
validate_revoked_status/3, validate_extensions/4,
validate_unknown_extensions/3,
normalize_general_name/1, digest_type/1, is_self_signed/1,
- is_issuer/2, issuer_id/2, is_fixed_dh_cert/1]).
+ is_issuer/2, issuer_id/2, is_fixed_dh_cert/1,
+ verify_data/1]).
-define(NULL, 0).
@@ -38,10 +38,22 @@
%% Internal application API
%%====================================================================
-verify_signature(DerCert, Key, KeyParams) ->
- {ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert, otp),
- verify_signature(OtpCert, DerCert, Key, KeyParams).
+%%--------------------------------------------------------------------
+-spec verify_data(der_encoded()) -> {md5 | sha, binary(), binary()}.
+%%
+%% Description: Extracts data from DerCert needed to call public_key:verify/4.
+%%--------------------------------------------------------------------
+verify_data(DerCert) ->
+ {ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert),
+ extract_verify_data(OtpCert, DerCert).
+%%--------------------------------------------------------------------
+-spec init_validation_state(#'OTPCertificate'{}, integer(), list()) ->
+ #path_validation_state{}.
+%%
+%% Description: Creates inital version of path_validation_state for
+%% basic path validation of x509 certificates.
+%%--------------------------------------------------------------------
init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen,
Options) ->
PolicyTree = #policy_tree_node{valid_policy = ?anyPolicy,
@@ -66,6 +78,12 @@ init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen,
cert_num = 0},
prepare_for_next_cert(OtpCert, State).
+%%--------------------------------------------------------------------
+-spec prepare_for_next_cert(#'OTPCertificate'{}, #path_validation_state{}) ->
+ #path_validation_state{}.
+%%
+%% Description: Update path_validation_state for next iteration.
+%%--------------------------------------------------------------------
prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{
working_public_key_algorithm = PrevAlgo,
working_public_key_parameters =
@@ -92,7 +110,13 @@ prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{
working_issuer_name = Issuer,
cert_num = ValidationState#path_validation_state.cert_num + 1
}.
-
+
+ %%--------------------------------------------------------------------
+-spec validate_time(#'OTPCertificate'{}, list(), boolean()) -> list().
+%%
+%% Description: Check that the certificate validity period includes the
+%% current time.
+%%--------------------------------------------------------------------
validate_time(OtpCert, AccErr, Verify) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
{'Validity', NotBeforeStr, NotAfterStr}
@@ -107,7 +131,12 @@ validate_time(OtpCert, AccErr, Verify) ->
false ->
not_valid({bad_cert, cert_expired}, Verify, AccErr)
end.
-
+%%--------------------------------------------------------------------
+-spec validate_issuer(#'OTPCertificate'{}, term(), list(), boolean()) -> list().
+%%
+%% Description: Check that the certificate issuer name is the working_issuer_name
+%% in path_validation_state.
+%%--------------------------------------------------------------------
validate_issuer(OtpCert, Issuer, AccErr, Verify) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
case is_issuer(Issuer, TBSCert#'OTPTBSCertificate'.issuer) of
@@ -116,7 +145,15 @@ validate_issuer(OtpCert, Issuer, AccErr, Verify) ->
_ ->
not_valid({bad_cert, invalid_issuer}, Verify, AccErr)
end.
-
+%%--------------------------------------------------------------------
+-spec validate_signature(#'OTPCertificate'{}, der_encoded(),
+ term(),term(), list(), boolean()) -> list().
+
+%%
+%% Description: Check that the signature on the certificate can be verified using
+%% working_public_key_algorithm, the working_public_key, and
+%% the working_public_key_parameters in path_validation_state.
+%%--------------------------------------------------------------------
validate_signature(OtpCert, DerCert, Key, KeyParams,
AccErr, Verify) ->
@@ -126,7 +163,12 @@ validate_signature(OtpCert, DerCert, Key, KeyParams,
false ->
not_valid({bad_cert, invalid_signature}, Verify, AccErr)
end.
-
+%%--------------------------------------------------------------------
+-spec validate_names(#'OTPCertificate'{}, list(), list(),
+ term(), list(), boolean())-> list().
+%%
+%% Description: Validate Subject Alternative Name.
+%%--------------------------------------------------------------------
validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) ->
case is_self_signed(OtpCert) andalso (not Last) of
true ->
@@ -143,8 +185,10 @@ validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) ->
Name = [{directoryName, Subject}|EmailAddress],
AltNames = case AltSubject of
- undefined -> [];
- _ -> AltSubject#'Extension'.extnValue
+ undefined ->
+ [];
+ _ ->
+ AltSubject#'Extension'.extnValue
end,
case (is_permitted(Name, Permit) andalso
@@ -159,28 +203,36 @@ validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) ->
end
end.
-
-%% See rfc3280 4.1.2.6 Subject: regarding emails.
-extract_email({rdnSequence, List}) ->
- extract_email2(List).
-extract_email2([[#'AttributeTypeAndValue'{type=?'id-emailAddress',
- value=Mail}]|_]) ->
- [{rfc822Name, Mail}];
-extract_email2([_|Rest]) ->
- extract_email2(Rest);
-extract_email2([]) -> [].
-
+%%--------------------------------------------------------------------
+-spec validate_revoked_status(#'OTPCertificate'{}, boolean(), list()) ->
+ list().
+%%
+%% Description: Check if certificate has been revoked.
+%%--------------------------------------------------------------------
validate_revoked_status(_OtpCert, _Verify, AccErr) ->
+ %% TODO: Implement or leave for application?!
%% true |
%% throw({bad_cert, cert_revoked})
AccErr.
-
+%%--------------------------------------------------------------------
+-spec validate_extensions(#'OTPCertificate'{}, #path_validation_state{},
+ boolean(), list())->
+ {#path_validation_state{},
+ UnknownExtensions :: list(), AccErrors :: list()}.
+%%
+%% Description: Check extensions included in basic path validation.
+%%--------------------------------------------------------------------
validate_extensions(OtpCert, ValidationState, Verify, AccErr) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
Extensions = TBSCert#'OTPTBSCertificate'.extensions,
validate_extensions(Extensions, ValidationState, no_basic_constraint,
is_self_signed(OtpCert), [], Verify, AccErr).
+%--------------------------------------------------------------------
+ -spec validate_unknown_extensions(list(), list(), boolean())-> list().
+%%
+%% Description: Check that all critical extensions has been handled.
+%%--------------------------------------------------------------------
validate_unknown_extensions([], AccErr, _Verify) ->
AccErr;
validate_unknown_extensions([#'Extension'{critical = true} | _],
@@ -190,27 +242,38 @@ validate_unknown_extensions([#'Extension'{critical = false} | Rest],
AccErr, Verify) ->
validate_unknown_extensions(Rest, AccErr, Verify).
+%%--------------------------------------------------------------------
+-spec normalize_general_name({rdnSequence, term()}) -> {rdnSequence, term()}.
+%%
+%% Description: Normalizes a general name so that it can be easily
+%% compared to another genral name.
+%%--------------------------------------------------------------------
normalize_general_name({rdnSequence, Issuer}) ->
- NormIssuer = normalize_general_name(Issuer),
- {rdnSequence, NormIssuer};
-
-normalize_general_name(Issuer) ->
- Normalize = fun([{Description, Type, {printableString, Value}}]) ->
- NewValue = string:to_lower(strip_spaces(Value)),
- [{Description, Type, {printableString, NewValue}}];
- (Atter) ->
- Atter
- end,
- lists:sort(lists:map(Normalize, Issuer)).
+ NormIssuer = do_normalize_general_name(Issuer),
+ {rdnSequence, NormIssuer}.
+%%--------------------------------------------------------------------
+-spec is_self_signed(#'OTPCertificate'{}) -> boolean().
+%%
+%% Description: Checks if the certificate is self signed.
+%%--------------------------------------------------------------------
is_self_signed(#'OTPCertificate'{tbsCertificate=
#'OTPTBSCertificate'{issuer = Issuer,
subject = Subject}}) ->
is_issuer(Issuer, Subject).
-
+%%--------------------------------------------------------------------
+-spec is_issuer({rdnSequence, term()}, {rdnSequence, term()}) -> boolean().
+%%
+%% Description: Checks if <Issuer> issued <Candidate>.
+%%--------------------------------------------------------------------
is_issuer({rdnSequence, Issuer}, {rdnSequence, Candidate}) ->
is_dir_name(Issuer, Candidate, true).
-
+%%--------------------------------------------------------------------
+-spec issuer_id(#'OTPCertificate'{}, self | other) ->
+ {ok, {integer(), term()}} | {error, issuer_not_found}.
+%%
+%% Description: Extracts the issuer id from a certificate if possible.
+%%--------------------------------------------------------------------
issuer_id(Otpcert, other) ->
TBSCert = Otpcert#'OTPCertificate'.tbsCertificate,
Extensions = extensions_list(TBSCert#'OTPTBSCertificate'.extensions),
@@ -227,7 +290,12 @@ issuer_id(Otpcert, self) ->
SerialNr = TBSCert#'OTPTBSCertificate'.serialNumber,
{ok, {SerialNr, normalize_general_name(Issuer)}}.
-
+%%--------------------------------------------------------------------
+-spec is_fixed_dh_cert(#'OTPCertificate'{}) -> boolean().
+%%
+%% Description: Checks if the certificate can be be used
+%% for DH key agreement.
+%%--------------------------------------------------------------------
is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate =
#'OTPTBSCertificate'{subjectPublicKeyInfo =
SubjectPublicKeyInfo,
@@ -238,6 +306,24 @@ is_fixed_dh_cert(#'OTPCertificate'{tbsCertificate =
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+do_normalize_general_name(Issuer) ->
+ Normalize = fun([{Description, Type, {printableString, Value}}]) ->
+ NewValue = string:to_lower(strip_spaces(Value)),
+ [{Description, Type, {printableString, NewValue}}];
+ (Atter) ->
+ Atter
+ end,
+ lists:sort(lists:map(Normalize, Issuer)).
+
+%% See rfc3280 4.1.2.6 Subject: regarding emails.
+extract_email({rdnSequence, List}) ->
+ extract_email2(List).
+extract_email2([[#'AttributeTypeAndValue'{type=?'id-emailAddress',
+ value=Mail}]|_]) ->
+ [{rfc822Name, Mail}];
+extract_email2([_|Rest]) ->
+ extract_email2(Rest);
+extract_email2([]) -> [].
extensions_list(asn1_NOVALUE) ->
[];
@@ -249,17 +335,22 @@ not_valid(Error, true, _) ->
not_valid(Error, false, AccErrors) ->
[Error | AccErrors].
-verify_signature(OtpCert, DerCert, Key, KeyParams) ->
- %% Signature is an ASN1 compact bit string
+extract_verify_data(OtpCert, DerCert) ->
{0, Signature} = OtpCert#'OTPCertificate'.signature,
SigAlgRec = OtpCert#'OTPCertificate'.signatureAlgorithm,
SigAlg = SigAlgRec#'SignatureAlgorithm'.algorithm,
- EncTBSCert = encoded_tbs_cert(DerCert),
- verify(SigAlg, EncTBSCert, Signature, Key, KeyParams).
+ PlainText = encoded_tbs_cert(DerCert),
+ DigestType = digest_type(SigAlg),
+ {DigestType, PlainText, Signature}.
-verify(Alg, PlainText, Signature, Key, KeyParams) ->
- public_key:verify_signature(PlainText, digest_type(Alg),
- Signature, Key, KeyParams).
+verify_signature(OtpCert, DerCert, Key, KeyParams) ->
+ {DigestType, PlainText, Signature} = extract_verify_data(OtpCert, DerCert),
+ case Key of
+ #'RSAPublicKey'{} ->
+ public_key:verify(PlainText, DigestType, Signature, Key);
+ _ ->
+ public_key:verify(PlainText, DigestType, Signature, {Key, KeyParams})
+ end.
encoded_tbs_cert(Cert) ->
{ok, PKIXCert} =
@@ -411,8 +502,8 @@ validate_extensions([#'Extension'{extnID = ?'id-ce-basicConstraints',
ValidationState =
#path_validation_state{max_path_length = Len}, _,
SelfSigned, UnknownExtensions, Verify, AccErr) ->
- Length = if SelfSigned -> min(N, Len);
- true -> min(N, Len-1)
+ Length = if SelfSigned -> erlang:min(N, Len);
+ true -> erlang:min(N, Len-1)
end,
validate_extensions(Rest,
ValidationState#path_validation_state{max_path_length =
@@ -603,11 +694,6 @@ is_valid_subject_alt_name({_, [_|_]}) ->
is_valid_subject_alt_name({_, _}) ->
false.
-min(N, M) when N =< M ->
- N;
-min(_, M) ->
- M.
-
is_ip_address(Address) ->
case inet_parse:address(Address) of
{ok, _} ->
@@ -670,10 +756,11 @@ split_auth_path(URIPart) ->
end.
split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
- case regexp:first_match(UriPart, SplitChar) of
- {match, Match, _} ->
- {string:substr(UriPart, 1, Match - SkipLeft),
- string:substr(UriPart, Match + SkipRight, length(UriPart))};
+ case re:run(UriPart, SplitChar) of
+ {match,[{Start, _}]} ->
+ StrPos = Start + 1,
+ {string:substr(UriPart, 1, StrPos - SkipLeft),
+ string:substr(UriPart, StrPos + SkipRight, length(UriPart))};
nomatch ->
NoMatchResult
end.
@@ -926,7 +1013,7 @@ add_policy_constraints(ExpPolicy, MapPolicy,
policy_constraint(Current, asn1_NOVALUE, _) ->
Current;
policy_constraint(Current, New, CertNum) ->
- min(Current, New + CertNum).
+ erlang:min(Current, New + CertNum).
process_policy_tree(_,_, ?NULL) ->
?NULL;
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index ac04e1c2cb..20b322b4a4 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -23,30 +23,61 @@
-include("public_key.hrl").
--export([decode_cert/2, encode_cert/1, encode_tbs_cert/1, transform/2]).
+-export([decode_cert/1, transform/2]).
%%====================================================================
%% Internal application API
%%====================================================================
-decode_cert(DerCert, plain) ->
- 'OTP-PUB-KEY':decode('Certificate', DerCert);
-decode_cert(DerCert, otp) ->
+%%--------------------------------------------------------------------
+-spec decode_cert(der_encoded()) -> {ok, #'OTPCertificate'{}}.
+%%
+%% Description: Recursively decodes a Certificate.
+%%--------------------------------------------------------------------
+decode_cert(DerCert) ->
{ok, Cert} = 'OTP-PUB-KEY':decode('OTPCertificate', DerCert),
#'OTPCertificate'{tbsCertificate = TBS} = Cert,
{ok, Cert#'OTPCertificate'{tbsCertificate = decode_tbs(TBS)}}.
-encode_cert(Cert = #'Certificate'{}) ->
- {ok, EncCert} = 'OTP-PUB-KEY':encode('Certificate', Cert),
- list_to_binary(EncCert);
-encode_cert(C = #'OTPCertificate'{tbsCertificate = TBS}) ->
- Cert = C#'OTPCertificate'{tbsCertificate=encode_tbs(TBS)},
- {ok, EncCert} = 'OTP-PUB-KEY':encode('OTPCertificate', Cert),
- list_to_binary(EncCert).
-
-encode_tbs_cert(TBS) ->
- {ok, EncTBSCert} = 'OTP-PUB-KEY':encode('OTPTBSCertificate', encode_tbs(TBS)),
- list_to_binary(EncTBSCert).
+%%--------------------------------------------------------------------
+-spec transform(term(), encode | decode) ->term().
+%%
+%% Description: Transforms between encoded and decode otp formated
+%% certificate parts.
+%%--------------------------------------------------------------------
+
+transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, encode) ->
+ Cert#'OTPCertificate'{tbsCertificate=encode_tbs(TBS)};
+transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, decode) ->
+ Cert#'OTPCertificate'{tbsCertificate=decode_tbs(TBS)};
+transform(#'OTPTBSCertificate'{}= TBS, encode) ->
+ encode_tbs(TBS);
+transform(#'OTPTBSCertificate'{}= TBS, decode) ->
+ decode_tbs(TBS);
+transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) ->
+ {ok, Value} =
+ case attribute_type(Id) of
+ Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0);
+ _UnknownType -> {ok, Value0}
+ end,
+ ATAV#'AttributeTypeAndValue'{value=Value};
+transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) ->
+ AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)};
+transform(List = [{directoryName, _}],Func) ->
+ [{directoryName, transform(Value,Func)} || {directoryName, Value} <- List];
+transform({directoryName, Value},Func) ->
+ {directoryName, transform(Value,Func)};
+transform({rdnSequence, SeqList},Func) when is_list(SeqList) ->
+ {rdnSequence,
+ lists:map(fun(Seq) ->
+ lists:map(fun(Element) -> transform(Element,Func) end, Seq)
+ end, SeqList)};
+transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) ->
+ #'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func),
+ excludedSubtrees=transform_sub_tree(Excluded,Func)};
+
+transform(Other,_) ->
+ Other.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -132,31 +163,6 @@ encode_extensions(Exts) ->
end
end, Exts).
-transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) ->
- {ok, Value} =
- case attribute_type(Id) of
- Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0);
- _UnknownType -> {ok, Value0}
- end,
- ATAV#'AttributeTypeAndValue'{value=Value};
-transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) ->
- AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)};
-transform(List = [{directoryName, _}],Func) ->
- [{directoryName, transform(Value,Func)} || {directoryName, Value} <- List];
-transform({directoryName, Value},Func) ->
- {directoryName, transform(Value,Func)};
-transform({rdnSequence, SeqList},Func) when is_list(SeqList) ->
- {rdnSequence,
- lists:map(fun(Seq) ->
- lists:map(fun(Element) -> transform(Element,Func) end, Seq)
- end, SeqList)};
-transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) ->
- #'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func),
- excludedSubtrees=transform_sub_tree(Excluded,Func)};
-
-transform(Other,_) ->
- Other.
-
encode_tbs(TBS=#'OTPTBSCertificate'{issuer=Issuer0,
subject=Subject0,
subjectPublicKeyInfo=Spki0,
diff --git a/lib/public_key/src/pubkey_crypto.erl b/lib/public_key/src/pubkey_crypto.erl
deleted file mode 100644
index 7b7abb1c56..0000000000
--- a/lib/public_key/src/pubkey_crypto.erl
+++ /dev/null
@@ -1,171 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%% Description: Functions that call the crypto driver.
-
--module(pubkey_crypto).
-
--include("public_key.hrl").
-
--export([encrypt_public/3, decrypt_private/3,
- encrypt_private/3, decrypt_public/3,
- sign/2, sign/3, verify/5, gen_key/2]).
-
--define(UINT32(X), X:32/unsigned-big-integer).
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-
-%%--------------------------------------------------------------------
-%% Function: encrypt(PlainText, Key, Padding) -> Encrypted
-%%
-%% PlainText = binary()
-%% Key = rsa_public_key() | rsa_private_key()
-%% Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding
-%% Encrypted = binary()
-%%
-%% Description: Public key encrypts PlainText.
-%%--------------------------------------------------------------------
-encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
- Padding) ->
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding);
-encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E},
- Padding) ->
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding).
-
-encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N,
- publicExponent = E,
- privateExponent = D}, Padding) ->
- crypto:rsa_private_encrypt(PlainText, [crypto:mpint(E),
- crypto:mpint(N),
- crypto:mpint(D)], Padding).
-
-%%--------------------------------------------------------------------
-%% Function: decrypt(CipherText, Key) -> PlainText
-%%
-%% ChipherText = binary()
-%% Key = rsa_private_key()
-%% Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding
-%% PlainText = binary()
-%%
-%% Description: Uses private key to decrypt public key encrypted data.
-%%--------------------------------------------------------------------
-decrypt_private(CipherText,
- #'RSAPrivateKey'{modulus = N,publicExponent = E,
- privateExponent = D},
- Padding) ->
- crypto:rsa_private_decrypt(CipherText,
- [crypto:mpint(E), crypto:mpint(N),
- crypto:mpint(D)], Padding).
-decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E},
- Padding) ->
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding);
-decrypt_public(CipherText, #'RSAPrivateKey'{modulus = N, publicExponent = E},
- Padding) ->
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding).
-
-%%--------------------------------------------------------------------
-%% Function: sign(PlainText, Key) ->
-%% sign(DigestType, PlainText, Key) -> Signature
-%%
-%% DigestType = sha | md5
-%% PlainText = binary()
-%% Key = rsa_private_key() | dsa_private_key()
-%% Signature = binary()
-%%
-%% Description: Signs PlainText using Key.
-%%--------------------------------------------------------------------
-sign(PlainText, Digest) ->
- sign(sha, PlainText, Digest).
-
-sign(DigestType, PlainText, #'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D}) ->
- crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E),
- crypto:mpint(N),
- crypto:mpint(D)]);
-
-sign(none, Hash, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(none, Hash,
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
-
-sign(sha, PlainText, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(sized_binary(PlainText),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]).
-
-%%--------------------------------------------------------------------
-%% Function: verify(DigestType, PlainText, Signature, Key) -> true | false
-%%
-%% DigestType = sha | md5
-%% PlainText = binary()
-%% Signature = binary()
-%% Key = rsa_public_key() | dsa_public_key()
-%%
-%% Description: Verifies the signature <Signature>.
-%%--------------------------------------------------------------------
-verify(DigestType, PlainText, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}, _) ->
- crypto:rsa_verify(DigestType,
- sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
-
-verify(none, Hash, Signature, Key, #'Dss-Parms'{p = P, q = Q, g = G}) ->
- crypto:dss_verify(none, Hash,
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]);
-
-verify(sha, PlainText, Signature, Key, #'Dss-Parms'{p = P, q = Q, g = G}) ->
- crypto:dss_verify(sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]).
-
-
-%%--------------------------------------------------------------------
-%% Function: gen_key(Type, Params) ->
-%% Type = diffie_hellman
-%% Params = [P,G] | [Y, P, G]
-%% Description: Generates keys.
-%% -----------------------------------------------------------------
-gen_key(diffie_hellman, [Y, P, G]) ->
- crypto:dh_generate_key(crypto:mpint(Y), [crypto:mpint(P),
- crypto:mpint(G)]);
-gen_key(diffie_hellman, [P, G]) ->
- crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]).
-
-%%% TODO: Support rsa, dss key_gen
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-sized_binary(Binary) when is_binary(Binary) ->
- Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>;
-sized_binary(List) ->
- sized_binary(list_to_binary(List)).
-
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 65879f1bbe..31d881973a 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -40,7 +40,10 @@
-module(pubkey_pem).
--export([read_file/1, read_file/2, write_file/2, decode/2]).
+-include("public_key.hrl").
+
+-export([encode/1, decode/1, decipher/2, cipher/3]).
+%% Backwards compatibility
-export([decode_key/2]).
-define(ENCODED_LINE_LENGTH, 64).
@@ -48,28 +51,82 @@
%%====================================================================
%% Internal application API
%%====================================================================
-read_file(File) ->
- read_file(File, no_passwd).
-read_file(File, Passwd) ->
- {ok, Bin} = file:read_file(File),
- decode(Bin, Passwd).
+%%--------------------------------------------------------------------
+-spec decode(binary()) -> [pem_entry()].
+%%
+%% Description: Decodes a PEM binary.
+%%--------------------------------------------------------------------
+decode(Bin) ->
+ decode_pem_entries(split_bin(Bin), []).
-write_file(File, Ds) ->
- file:write_file(File, encode_file(Ds)).
+%%--------------------------------------------------------------------
+-spec encode([pem_entry()]) -> iolist().
+%%
+%% Description: Encodes a list of PEM entries.
+%%--------------------------------------------------------------------
+encode(PemEntries) ->
+ encode_pem_entries(PemEntries).
-decode_key({_Type, Bin, not_encrypted}, _) ->
- Bin;
-decode_key({_Type, Bin, {Chipher,Salt}}, Password) ->
- decode_key(Bin, Password, Chipher, Salt).
+%%--------------------------------------------------------------------
+-spec decipher({pki_asn1_type(), decrypt_der(),{Cipher :: string(), Salt :: binary()}}, string()) ->
+ der_encoded().
+%%
+%% Description: Deciphers a decrypted pem entry.
+%%--------------------------------------------------------------------
+decipher({_, DecryptDer, {Cipher,Salt}}, Password) ->
+ decode_key(DecryptDer, Password, Cipher, Salt).
-decode(Bin, Passwd) ->
- decode_file(split_bin(Bin), Passwd).
+%%--------------------------------------------------------------------
+-spec cipher(der_encoded(),{Cipher :: string(), Salt :: binary()} , string()) -> binary().
+%%
+%% Description: Ciphers a PEM entry
+%%--------------------------------------------------------------------
+cipher(Der, {Cipher,Salt}, Password)->
+ encode_key(Der, Password, Cipher, Salt).
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+encode_pem_entries(Entries) ->
+ [encode_pem_entry(Entry) || Entry <- Entries].
+
+encode_pem_entry({Asn1Type, Der, not_encrypted}) ->
+ StartStr = pem_start(Asn1Type),
+ [StartStr, "\n", b64encode_and_split(Der), pem_end(StartStr) ,"\n\n"];
+encode_pem_entry({Asn1Type, Der, {Cipher, Salt}}) ->
+ StartStr = pem_start(Asn1Type),
+ [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n",
+ b64encode_and_split(Der), pem_end(StartStr) ,"\n\n"].
+
+decode_pem_entries([], Entries) ->
+ lists:reverse(Entries);
+decode_pem_entries([<<>>], Entries) ->
+ lists:reverse(Entries);
+decode_pem_entries([<<>> | Lines], Entries) ->
+ decode_pem_entries(Lines, Entries);
+decode_pem_entries([Start| Lines], Entries) ->
+ case pem_end(Start) of
+ undefined ->
+ decode_pem_entries(Lines, Entries);
+ _End ->
+ {Entry, RestLines} = join_entry(Lines, []),
+ decode_pem_entries(RestLines, [decode_pem_entry(Start, Entry) | Entries])
+ end.
+decode_pem_entry(Start, [<<"Proc-Type: 4,ENCRYPTED", _/binary>>, Line | Lines]) ->
+ Asn1Type = asn1_type(Start),
+ Cs = erlang:iolist_to_binary(Lines),
+ Decoded = base64:mime_decode(Cs),
+ [_, DekInfo0] = string:tokens(binary_to_list(Line), ": "),
+ [Cipher, Salt] = string:tokens(DekInfo0, ","),
+ {Asn1Type, Decoded, {Cipher, unhex(Salt)}};
+decode_pem_entry(Start, Lines) ->
+ Asn1Type = asn1_type(Start),
+ Cs = erlang:iolist_to_binary(Lines),
+ Der = base64:mime_decode(Cs),
+ {Asn1Type, Der, not_encrypted}.
+
split_bin(Bin) ->
split_bin(0, Bin).
@@ -85,88 +142,26 @@ split_bin(N, Bin) ->
split_bin(N+1, Bin)
end.
-decode_file(Bin, Passwd) ->
- decode_file(Bin, [], [Passwd]).
-
-decode_file([<<"-----BEGIN CERTIFICATE REQUEST-----", _/binary>>|Rest], Ens, Info) ->
- decode_file2(Rest, [], Ens, cert_req, Info);
-decode_file([<<"-----BEGIN CERTIFICATE-----", _/binary>>|Rest], Ens, Info) ->
- decode_file2(Rest, [], Ens, cert, Info);
-decode_file([<<"-----BEGIN RSA PRIVATE KEY-----", _/binary>>|Rest], Ens, Info) ->
- decode_file2(Rest, [], Ens, rsa_private_key, Info);
-decode_file([<<"-----BEGIN DSA PRIVATE KEY-----", _/binary>>|Rest], Ens, Info) ->
- decode_file2(Rest, [], Ens, dsa_private_key, Info);
-decode_file([<<"-----BEGIN DH PARAMETERS-----", _/binary>>|Rest], Ens, Info) ->
- decode_file2(Rest, [], Ens, dh_params, Info);
-decode_file([_|Rest], Ens, Info) ->
- decode_file(Rest, Ens, Info);
-decode_file([], Ens, _Info) ->
- {ok, lists:reverse(Ens)}.
-
-decode_file2([<<"Proc-Type: 4,ENCRYPTED", _/binary>>| Rest0], RLs, Ens, Tag, Info0) ->
- [InfoLine|Rest] = Rest0,
- Info = dek_info(InfoLine, Info0),
- decode_file2(Rest, RLs, Ens, Tag, Info);
-decode_file2([<<"-----END", _/binary>>| Rest], RLs, Ens, Tag, Info0) ->
- Cs = erlang:iolist_to_binary(lists:reverse(RLs)),
- Bin = base64:mime_decode(Cs),
- case Info0 of
- [Password, Cipher, SaltHex | Info1] ->
- Salt = unhex(SaltHex),
- Enc = {Cipher, Salt},
- Decoded = decode_key(Bin, Password, Cipher, Salt),
- decode_file(Rest, [{Tag, Decoded, Enc}| Ens], Info1);
- _ ->
- decode_file(Rest, [{Tag, Bin, not_encrypted}| Ens], Info0)
- end;
-decode_file2([L|Rest], RLs, Ens, Tag, Info0) ->
- decode_file2(Rest, [L|RLs], Ens, Tag, Info0);
-decode_file2([], _, Ens, _, _) ->
- {ok, lists:reverse(Ens)}.
-
-%% Support same as decode_file
-encode_file(Ds) ->
- lists:map(
- fun({cert, Bin, not_encrypted}) ->
- %% PKIX (X.509)
- ["-----BEGIN CERTIFICATE-----\n",
- b64encode_and_split(Bin),
- "-----END CERTIFICATE-----\n\n"];
- ({cert_req, Bin, not_encrypted}) ->
- %% PKCS#10
- ["-----BEGIN CERTIFICATE REQUEST-----\n",
- b64encode_and_split(Bin),
- "-----END CERTIFICATE REQUEST-----\n\n"];
- ({rsa_private_key, Bin, not_encrypted}) ->
- %% PKCS#?
- ["XXX Following key assumed not encrypted\n",
- "-----BEGIN RSA PRIVATE KEY-----\n",
- b64encode_and_split(Bin),
- "-----END RSA PRIVATE KEY-----\n\n"];
- ({dsa_private_key, Bin, not_encrypted}) ->
- %% PKCS#?
- ["XXX Following key assumed not encrypted\n",
- "-----BEGIN DSA PRIVATE KEY-----\n",
- b64encode_and_split(Bin),
- "-----END DSA PRIVATE KEY-----\n\n"]
- end, Ds).
-
-dek_info(Line0, Info) ->
- Line = binary_to_list(Line0),
- [_, DekInfo0] = string:tokens(Line, ": "),
- DekInfo1 = string:tokens(DekInfo0, ",\n"),
- Info ++ DekInfo1.
+b64encode_and_split(Bin) ->
+ split_lines(base64:encode(Bin)).
-unhex(S) ->
- unhex(S, []).
+split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) ->
+ [Text, $\n | split_lines(Rest)];
+split_lines(Bin) ->
+ [Bin, $\n].
-unhex("", Acc) ->
- list_to_binary(lists:reverse(Acc));
-unhex([D1, D2 | Rest], Acc) ->
- unhex(Rest, [erlang:list_to_integer([D1, D2], 16) | Acc]).
+%% Ignore white space at end of line
+join_entry([<<"-----END CERTIFICATE-----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
+join_entry([<<"-----END RSA PRIVATE KEY-----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
+join_entry([<<"-----END DSA PRIVATE KEY-----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
+join_entry([<<"-----END DH PARAMETERS-----", _/binary>>| Lines], Entry) ->
+ {lists:reverse(Entry), Lines};
+join_entry([Line | Lines], Entry) ->
+ join_entry(Lines, [Line | Entry]).
-decode_key(Data, no_passwd, _Alg, _Salt) ->
- Data;
decode_key(Data, Password, "DES-CBC", Salt) ->
Key = password_to_key(Password, Salt, 8),
IV = Salt,
@@ -177,6 +172,16 @@ decode_key(Data, Password, "DES-EDE3-CBC", Salt) ->
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data).
+encode_key(Data, Password, "DES-CBC", Salt) ->
+ Key = password_to_key(Password, Salt, 8),
+ IV = Salt,
+ crypto:des_cbc_encrypt(Key, IV, Data);
+encode_key(Data, Password, "DES-EDE3-CBC", Salt) ->
+ Key = password_to_key(Password, Salt, 24),
+ IV = Salt,
+ <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
+ crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data).
+
password_to_key(Data, Salt, KeyLen) ->
<<Key:KeyLen/binary, _/binary>> =
password_to_key(<<>>, Data, Salt, KeyLen, <<>>),
@@ -188,11 +193,58 @@ password_to_key(Prev, Data, Salt, Len, Acc) ->
M = crypto:md5([Prev, Data, Salt]),
password_to_key(M, Data, Salt, Len - size(M), <<Acc/binary, M/binary>>).
-b64encode_and_split(Bin) ->
- split_lines(base64:encode(Bin)).
+unhex(S) ->
+ unhex(S, []).
-split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) ->
- [Text, $\n | split_lines(Rest)];
-split_lines(Bin) ->
- [Bin, $\n].
+unhex("", Acc) ->
+ list_to_binary(lists:reverse(Acc));
+unhex([D1, D2 | Rest], Acc) ->
+ unhex(Rest, [erlang:list_to_integer([D1, D2], 16) | Acc]).
+
+hexify(L) -> [[hex_byte(B)] || B <- binary_to_list(L)].
+
+hex_byte(B) when B < 16#10 -> ["0", erlang:integer_to_list(B, 16)];
+hex_byte(B) -> erlang:integer_to_list(B, 16).
+
+pem_start('Certificate') ->
+ <<"-----BEGIN CERTIFICATE-----">>;
+pem_start('RSAPrivateKey') ->
+ <<"-----BEGIN RSA PRIVATE KEY-----">>;
+pem_start('DSAPrivateKey') ->
+ <<"-----BEGIN DSA PRIVATE KEY-----">>;
+pem_start('DHParameter') ->
+ <<"-----BEGIN DH PARAMETERS-----">>.
+
+pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
+ <<"-----END CERTIFICATE-----">>;
+pem_end(<<"-----BEGIN RSA PRIVATE KEY-----">>) ->
+ <<"-----END RSA PRIVATE KEY-----">>;
+pem_end(<<"-----BEGIN DSA PRIVATE KEY-----">>) ->
+ <<"-----END DSA PRIVATE KEY-----">>;
+pem_end(<<"-----BEGIN DH PARAMETERS-----">>) ->
+ <<"-----END DH PARAMETERS-----">>;
+pem_end(_) ->
+ undefined.
+
+asn1_type(<<"-----BEGIN CERTIFICATE-----">>) ->
+ 'Certificate';
+asn1_type(<<"-----BEGIN RSA PRIVATE KEY-----">>) ->
+ 'RSAPrivateKey';
+asn1_type(<<"-----BEGIN DSA PRIVATE KEY-----">>) ->
+ 'DSAPrivateKey';
+asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) ->
+ 'DHParameter'.
+
+pem_decrypt() ->
+ <<"Proc-Type: 4,ENCRYPTED">>.
+
+pem_decrypt_info(Cipher, Salt) ->
+ io_lib:format("DEK-Info: ~s,~s", [Cipher, lists:flatten(hexify(Salt))]).
+%%--------------------------------------------------------------------
+%%% Deprecated
+%%--------------------------------------------------------------------
+decode_key({_Type, Bin, not_encrypted}, _) ->
+ Bin;
+decode_key({_Type, Bin, {Chipher,Salt}}, Password) ->
+ decode_key(Bin, Password, Chipher, Salt).
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index d5e1705827..60487946fa 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -4,7 +4,6 @@
{modules, [
public_key,
pubkey_pem,
- pubkey_crypto,
pubkey_cert,
pubkey_cert_records,
'OTP-PUB-KEY'
diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src
index 2eb5750923..c9d15b8747 100644
--- a/lib/public_key/src/public_key.appup.src
+++ b/lib/public_key/src/public_key.appup.src
@@ -1,6 +1,15 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"0.7",
+ [
+ {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
+ {update, public_key, soft, soft_purge, soft_purge, []},
+ {update, pubkey_pem, soft, soft_purge, soft_purge, []},
+ {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
+ {update, pubkey_cert, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"0.6",
[
{update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
@@ -22,6 +31,15 @@
}
],
[
+ {"0.7",
+ [
+ {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
+ {update, public_key, soft, soft_purge, soft_purge, []},
+ {update, pubkey_pem, soft, soft_purge, soft_purge, []},
+ {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
+ {update, pubkey_cert, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"0.6",
[
{update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 12354eee5d..95c3d714d3 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -23,239 +23,396 @@
-include("public_key.hrl").
--export([decode_private_key/1, decode_private_key/2, decode_dhparams/1,
- decrypt_private/2, decrypt_private/3, encrypt_public/2,
- encrypt_public/3, decrypt_public/2, decrypt_public/3,
- encrypt_private/2, encrypt_private/3, gen_key/1, sign/2, sign/3,
- verify_signature/3, verify_signature/4, verify_signature/5,
- pem_to_der/1, pem_to_der/2, der_to_pem/2,
- pkix_decode_cert/2, pkix_encode_cert/1, pkix_transform/2,
- pkix_is_self_signed/1, pkix_is_fixed_dh_cert/1,
+-export([pem_decode/1, pem_encode/1,
+ der_decode/2, der_encode/2,
+ pem_entry_decode/1,
+ pem_entry_decode/2,
+ pem_entry_encode/2,
+ pem_entry_encode/3,
+ pkix_decode_cert/2, pkix_encode/3,
+ encrypt_private/2, encrypt_private/3,
+ decrypt_private/2, decrypt_private/3,
+ encrypt_public/2, encrypt_public/3,
+ decrypt_public/2, decrypt_public/3,
+ sign/3, verify/4,
+ pkix_sign/2, pkix_verify/2,
+ pkix_is_self_signed/1,
+ pkix_is_fixed_dh_cert/1,
+ pkix_is_issuer/2,
pkix_issuer_id/2,
- pkix_is_issuer/2, pkix_normalize_general_name/1,
+ pkix_normalize_name/1,
pkix_path_validation/3
]).
+%% Deprecated
+-export([decode_private_key/1, decode_private_key/2, pem_to_der/1]).
+
+-deprecated({pem_to_der, 1, next_major_release}).
+-deprecated({decode_private_key, 1, next_major_release}).
+-deprecated({decode_private_key, 2, next_major_release}).
+
+-type rsa_public_key() :: #'RSAPublicKey'{}.
+-type rsa_private_key() :: #'RSAPrivateKey'{}.
+-type dsa_private_key() :: #'DSAPrivateKey'{}.
+-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
+ | 'rsa_no_padding'.
+-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
+-type rsa_digest_type() :: 'md5' | 'sha'.
+-type dss_digest_type() :: 'none' | 'sha'.
+
+-define(UINT32(X), X:32/unsigned-big-integer).
+
%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: decode_private_key(KeyInfo [,Password]) ->
-%% {ok, PrivateKey} | {error, Reason}
-%%
-%% KeyInfo = {Type, der_bin(), ChipherInfo} - as returned from
-%% pem_to_der/[1,2] for private keys
-%% Type = rsa_private_key | dsa_private_key
-%% ChipherInfo = opaque() | no_encryption
+-spec pem_decode(binary()) -> [pem_entry()].
+%%
+%% Description: Decode PEM binary data and return
+%% entries as asn1 der encoded entities.
+%%--------------------------------------------------------------------
+pem_decode(PemBin) when is_binary(PemBin) ->
+ pubkey_pem:decode(PemBin).
+
+%%--------------------------------------------------------------------
+-spec pem_encode([pem_entry()]) -> binary().
%%
-%% Description: Decodes an asn1 der encoded private key.
+%% Description: Creates a PEM binary.
%%--------------------------------------------------------------------
-decode_private_key(KeyInfo) ->
- decode_private_key(KeyInfo, no_passwd).
+pem_encode(PemEntries) when is_list(PemEntries) ->
+ iolist_to_binary(pubkey_pem:encode(PemEntries)).
-decode_private_key(KeyInfo = {rsa_private_key, _, _}, Password) ->
- DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
- 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded);
-decode_private_key(KeyInfo = {dsa_private_key, _, _}, Password) ->
- DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
- 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded).
+%%--------------------------------------------------------------------
+-spec pem_entry_decode(pem_entry(), [string()]) -> term().
+%
+%% Description: Decodes a pem entry. pem_decode/1 returns a list of
+%% pem entries.
+%%--------------------------------------------------------------------
+pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
+ is_binary(Der) ->
+ der_decode(Asn1Type, Der).
+pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
+ is_binary(Der) ->
+ der_decode(Asn1Type, Der);
+pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
+ Password) when is_atom(Asn1Type),
+ is_binary(CryptDer),
+ is_list(Cipher),
+ is_binary(Salt),
+ erlang:byte_size(Salt) == 8
+ ->
+ Der = pubkey_pem:decipher(PemEntry, Password),
+ der_decode(Asn1Type, Der).
+%%--------------------------------------------------------------------
+-spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry().
+-spec pem_entry_encode(pki_asn1_type(), term(),
+ {{Cipher :: string(), Salt :: binary()}, string()}) -> pem_entry().
+%
+%% Description: Creates a pem entry that can be feed to pem_encode/1.
+%%--------------------------------------------------------------------
+pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
+ Der = der_encode(Asn1Type, Entity),
+ {Asn1Type, Der, not_encrypted}.
+pem_entry_encode(Asn1Type, Entity,
+ {{Cipher, Salt}= CipherInfo, Password}) when is_atom(Asn1Type),
+ is_list(Cipher),
+ is_binary(Salt),
+ erlang:byte_size(Salt) == 8,
+ is_list(Password)->
+ Der = der_encode(Asn1Type, Entity),
+ DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password),
+ {Asn1Type, DecryptDer, CipherInfo}.
%%--------------------------------------------------------------------
-%% Function: decode_dhparams(DhParamInfo) ->
-%% {ok, DhParams} | {error, Reason}
-%%
-%% DhParamsInfo = {Type, der_bin(), ChipherInfo} - as returned from
-%% pem_to_der/[1,2] for DH parameters.
-%% Type = dh_params
-%% ChipherInfo = opaque() | no_encryption
+-spec der_decode(asn1_type(), der_encoded()) -> term().
%%
-%% Description: Decodes an asn1 der encoded DH parameters.
+%% Description: Decodes a public key asn1 der encoded entity.
%%--------------------------------------------------------------------
-decode_dhparams({dh_params, DerEncoded, not_encrypted}) ->
- 'OTP-PUB-KEY':decode('DHParameter', DerEncoded).
+der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
+ try
+ {ok, Decoded} = 'OTP-PUB-KEY':decode(Asn1Type, Der),
+ Decoded
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end.
%%--------------------------------------------------------------------
-%% Function: decrypt_private(CipherText, Key) ->
-%% decrypt_private(CipherText, Key, Options) -> PlainTex
-%% decrypt_public(CipherText, Key) ->
-%% decrypt_public(CipherText, Key, Options) -> PlainTex
+-spec der_encode(asn1_type(), term()) -> der_encoded().
%%
-%% CipherText = binary()
-%% Key = rsa_key()
-%% PlainText = binary()
+%% Description: Encodes a public key entity with asn1 DER encoding.
+%%--------------------------------------------------------------------
+der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
+ try
+ {ok, Encoded} = 'OTP-PUB-KEY':encode(Asn1Type, Entity),
+ iolist_to_binary(Encoded)
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end.
+
+%%--------------------------------------------------------------------
+-spec pkix_decode_cert(der_encoded(), plain | otp) ->
+ #'Certificate'{} | #'OTPCertificate'{}.
%%
-%% Description: Decrypts <CipherText>.
+%% Description: Decodes an asn1 der encoded pkix certificate. The otp
+%% option will use the customized asn1 specification OTP-PKIX.asn1 for
+%% decoding and also recursively decode most of the standard
+%% extensions.
+%% --------------------------------------------------------------------
+pkix_decode_cert(DerCert, plain) when is_binary(DerCert) ->
+ der_decode('Certificate', DerCert);
+pkix_decode_cert(DerCert, otp) when is_binary(DerCert) ->
+ try
+ {ok, #'OTPCertificate'{}= Cert} =
+ pubkey_cert_records:decode_cert(DerCert),
+ Cert
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end.
+
+%%--------------------------------------------------------------------
+-spec pkix_encode(asn1_type(), term(), otp | plain) -> der_encoded().
+%%
+%% Description: Der encodes a certificate or part of a certificate.
+%% This function must be used for encoding certificates or parts of certificates
+%% that are decoded with the otp format, whereas for the plain format this
+%% function will only call der_encode/2.
+%%--------------------------------------------------------------------
+pkix_encode(Asn1Type, Term, plain) when is_atom(Asn1Type) ->
+ der_encode(Asn1Type, Term);
+
+pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) ->
+ Term = pubkey_cert_records:transform(Term0, encode),
+ der_encode(Asn1Type, Term).
+
+%%--------------------------------------------------------------------
+-spec decrypt_private(CipherText :: binary(), rsa_private_key()) ->
+ PlainText :: binary().
+-spec decrypt_private(CipherText :: binary(), rsa_private_key(),
+ public_crypt_options()) -> PlainText :: binary().
+%%
+%% Description: Public key decryption using the private key.
%%--------------------------------------------------------------------
decrypt_private(CipherText, Key) ->
decrypt_private(CipherText, Key, []).
-decrypt_private(CipherText, Key, Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- pubkey_crypto:decrypt_private(CipherText, Key, Padding).
-decrypt_public(CipherText, Key) ->
- decrypt_public(CipherText, Key, []).
-decrypt_public(CipherText, Key, Options) ->
+decrypt_private(CipherText,
+ #'RSAPrivateKey'{modulus = N,publicExponent = E,
+ privateExponent = D},
+ Options) when is_binary(CipherText),
+ is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- pubkey_crypto:decrypt_public(CipherText, Key, Padding).
+ crypto:rsa_private_decrypt(CipherText,
+ [crypto:mpint(E), crypto:mpint(N),
+ crypto:mpint(D)], Padding).
%%--------------------------------------------------------------------
-%% Function: encrypt_public(PlainText, Key, Options) -> CipherText
-%% encrypt_private(PlainText, Key, Options) -> CipherText
-%%
-%% PlainText = iolist()
-%% Key = rsa_private_key()
-%% CipherText = binary()
+-spec decrypt_public(CipherText :: binary(), rsa_public_key()) ->
+ PlainText :: binary().
+-spec decrypt_public(CipherText :: binary(), rsa_public_key(),
+ public_crypt_options()) -> PlainText :: binary().
%%
-%% Description: Encrypts <Plain>
+%% Description: Public key decryption using the public key.
%%--------------------------------------------------------------------
-encrypt_public(PlainText, Key) ->
- encrypt_public(PlainText, Key, []).
-encrypt_public(PlainText, Key, Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- pubkey_crypto:encrypt_public(PlainText, Key, Padding).
+decrypt_public(CipherText, Key) ->
+ decrypt_public(CipherText, Key, []).
-encrypt_private(PlainText, Key) ->
- encrypt_private(PlainText, Key, []).
-encrypt_private(PlainText, Key, Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- pubkey_crypto:encrypt_private(PlainText, Key, Padding).
+decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E},
+ Options) when is_binary(CipherText), is_list(Options) ->
+ decrypt_public(CipherText, N,E, Options);
-%%--------------------------------------------------------------------
-%% Function: gen_key(Params) -> Keys
-%%
-%% Params = #'DomainParameters'{} - Currently only supported option
-%% Keys = {PublicDHKey = integer(), PrivateDHKey = integer()}
-%%
-%% Description: Generates keys. Currently supports Diffie-Hellman keys.
-%%--------------------------------------------------------------------
-gen_key(#'DHParameter'{prime = P, base = G}) when is_integer(P),
- is_integer(G) ->
- pubkey_crypto:gen_key(diffie_hellman, [P, G]).
+decrypt_public(CipherText,#'RSAPrivateKey'{modulus = N, publicExponent = E},
+ Options) when is_binary(CipherText), is_list(Options) ->
+ decrypt_public(CipherText, N,E, Options).
%%--------------------------------------------------------------------
-%% Function: pem_to_der(CertSource) ->
-%% pem_to_der(CertSource, Password) -> {ok, [Entry]} |
-%% {error, Reason}
-%%
-%% CertSource = File | CertData
-%% CertData = binary()
-%% File = path()
-%% Entry = {entry_type(), der_bin(), ChipherInfo}
-%% ChipherInfo = opague() | no_encryption
-%% der_bin() = binary()
-%% entry_type() = cert | cert_req | rsa_private_key | dsa_private_key
-%% dh_params
+-spec encrypt_public(PlainText :: binary(), rsa_public_key()) ->
+ CipherText :: binary().
+-spec encrypt_public(PlainText :: binary(), rsa_public_key(),
+ public_crypt_options()) -> CipherText :: binary().
%%
-%% Description: decode PEM binary data or a PEM file and return
-%% entries as asn1 der encoded entities. Currently supported entry
-%% types are certificates, certificate requests, rsa private keys and
-%% dsa private keys. In the case of a key entry ChipherInfo will be
-%% private keys and Diffie Hellam parameters .In the case of a key
-%% entry ChipherInfo will be used by decode_private_key/2 if the key
-%% is protected by a password.
+%% Description: Public key encryption using the public key.
%%--------------------------------------------------------------------
-pem_to_der(CertSource) ->
- pem_to_der(CertSource, no_passwd).
+encrypt_public(PlainText, Key) ->
+ encrypt_public(PlainText, Key, []).
-pem_to_der(File, Password) when is_list(File) ->
- pubkey_pem:read_file(File, Password);
-pem_to_der(PemBin, Password) when is_binary(PemBin) ->
- pubkey_pem:decode(PemBin, Password).
+encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
+ Options) when is_binary(PlainText), is_list(Options) ->
+ encrypt_public(PlainText, N,E, Options);
-der_to_pem(File, TypeDerList) ->
- pubkey_pem:write_file(File, TypeDerList).
+encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E},
+ Options) when is_binary(PlainText), is_list(Options) ->
+ encrypt_public(PlainText, N,E, Options).
%%--------------------------------------------------------------------
-%% Function: pkix_decode_cert(BerCert, Type) -> {ok, Cert} | {error, Reason}
-%%
-%% BerCert = binary()
-%% Type = plain | otp
-%% Cert = certificate()
+-spec encrypt_private(PlainText :: binary(), rsa_private_key()) ->
+ CipherText :: binary().
+-spec encrypt_private(PlainText :: binary(), rsa_private_key(),
+ public_crypt_options()) -> CipherText :: binary().
%%
-%% Description: Decodes an asn1 ber encoded pkix certificate.
-%% otp - Uses OTP-PKIX.asn1 to decode known extensions and
-%% enhance the signature field in #'Certificate'{} and '#TBSCertificate'{}.
+%% Description: Public key encryption using the private key.
%%--------------------------------------------------------------------
-pkix_decode_cert(BinCert, Type) ->
- pubkey_cert_records:decode_cert(BinCert, Type).
+encrypt_private(PlainText, Key) ->
+ encrypt_private(PlainText, Key, []).
+
+encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N,
+ publicExponent = E,
+ privateExponent = D},
+ Options) when is_binary(PlainText), is_list(Options) ->
+ Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
+ crypto:rsa_private_encrypt(PlainText, [crypto:mpint(E),
+ crypto:mpint(N),
+ crypto:mpint(D)], Padding).
%%--------------------------------------------------------------------
-%% Function: pkix_encode_cert(Cert) -> {ok, binary()} | {error, Reason}
-%%
-%% Cert = #'Certificate'{}
+-spec sign(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(),
+ rsa_private_key() |
+ dsa_private_key()) -> Signature :: binary().
%%
-%% Description: Encodes a certificate record using asn1.
+%% Description: Create digital signature.
%%--------------------------------------------------------------------
-pkix_encode_cert(Cert) ->
- pubkey_cert_records:encode_cert(Cert).
+sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D})
+ when is_binary(PlainText),
+ DigestType == md5;
+ DigestType == sha ->
+
+ crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E),
+ crypto:mpint(N),
+ crypto:mpint(D)]);
+
+sign(Digest, none, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X})
+ when is_binary(Digest)->
+ crypto:dss_sign(none, Digest,
+ [crypto:mpint(P), crypto:mpint(Q),
+ crypto:mpint(G), crypto:mpint(X)]);
+
+sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X})
+ when is_binary(PlainText) ->
+ crypto:dss_sign(sized_binary(PlainText),
+ [crypto:mpint(P), crypto:mpint(Q),
+ crypto:mpint(G), crypto:mpint(X)]).
+
+%%--------------------------------------------------------------------
+-spec verify(PlainTextOrDigest :: binary(), rsa_digest_type() | dss_digest_type(),
+ Signature :: binary(), rsa_public_key()
+ | dsa_public_key()) -> boolean().
+%%
+%% Description: Verifies a digital signature.
+%%--------------------------------------------------------------------
+verify(PlainText, DigestType, Signature,
+ #'RSAPublicKey'{modulus = Mod, publicExponent = Exp})
+ when is_binary (PlainText), DigestType == sha; DigestType == md5 ->
+ crypto:rsa_verify(DigestType,
+ sized_binary(PlainText),
+ sized_binary(Signature),
+ [crypto:mpint(Exp), crypto:mpint(Mod)]);
+
+verify(Digest, none, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Digest), is_binary(Signature) ->
+ crypto:dss_verify(none,
+ Digest,
+ sized_binary(Signature),
+ [crypto:mpint(P), crypto:mpint(Q),
+ crypto:mpint(G), crypto:mpint(Key)]);
+verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
+ crypto:dss_verify(sized_binary(PlainText),
+ sized_binary(Signature),
+ [crypto:mpint(P), crypto:mpint(Q),
+ crypto:mpint(G), crypto:mpint(Key)]).
%%--------------------------------------------------------------------
-%% Function: pkix_transform(CertPart, Op) -> TransformedCertPart
+-spec pkix_sign(#'OTPTBSCertificate'{},
+ rsa_private_key() | dsa_private_key()) -> der_encoded().
%%
-%% CertPart = pkix part data
-%% Op = encode | decode
-%%
-%% Description: Transform parts of a pkix certificate between 'plain' format
-%% and the internal 'otp' format, see pkix_decode_cert/2.
-%% Decode transforms from 'plain' to 'otp' and encode from 'otp' to 'plain'
-%% format.
+%% Description: Sign a pkix x.509 certificate. Returns the corresponding
+%% der encoded 'Certificate'{}
%%--------------------------------------------------------------------
-pkix_transform(CertPart, Op) ->
- pubkey_cert_records:transform(CertPart, Op).
+pkix_sign(#'OTPTBSCertificate'{signature =
+ #'SignatureAlgorithm'{algorithm = Alg}
+ = SigAlg} = TBSCert, Key) ->
+
+ Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp),
+ DigestType = pubkey_cert:digest_type(Alg),
+ Signature = sign(Msg, DigestType, Key),
+ Cert = #'OTPCertificate'{tbsCertificate= TBSCert,
+ signatureAlgorithm = SigAlg,
+ signature = {0, Signature}
+ },
+ pkix_encode('OTPCertificate', Cert, otp).
%%--------------------------------------------------------------------
-%% Function: pkix_path_validation(TrustedCert, CertChain, Options) ->
-%% {ok, {{algorithm(), public_key(), public_key_params()} policy_tree()}} |
-%% {error, Reason}
+-spec pkix_verify(der_encoded(), rsa_public_key()|
+ dsa_public_key()) -> boolean().
%%
-%% Description: Performs a bacis path validation according to RFC 3280.
+%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
-pkix_path_validation(TrustedCert, CertChain, Options)
- when is_binary(TrustedCert) ->
- {ok, OtpCert} = pkix_decode_cert(TrustedCert, otp),
- pkix_path_validation(OtpCert, CertChain, Options);
+pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
+ when is_binary(DerCert), is_integer(Key) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, DSAKey);
+
+pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
+ when is_binary(DerCert) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, RSAKey).
-pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
- when is_list(CertChain), is_list(Options) ->
- MaxPathDefault = length(CertChain),
- ValidationState = pubkey_cert:init_validation_state(TrustedCert,
- MaxPathDefault,
- Options),
- Fun = proplists:get_value(validate_extensions_fun, Options,
- fun(Extensions, State, _, AccError) ->
- {Extensions, State, AccError}
- end),
- Verify = proplists:get_value(verify, Options, true),
- path_validation(CertChain, ValidationState, Fun, Verify).
%%--------------------------------------------------------------------
-%% Function: pkix_is_fixed_dh_cert(Cert) -> true | false
+-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{},
+ IssuerCert :: der_encoded()|
+ #'OTPCertificate'{}) -> boolean().
%%
-%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert
+%% Description: Checks if <IssuerCert> issued <Cert>.
%%--------------------------------------------------------------------
-pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) ->
- pubkey_cert:is_fixed_dh_cert(OTPCert);
-pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
- {ok, OtpCert} = pkix_decode_cert(Cert, otp),
- pkix_is_fixed_dh_cert(OtpCert).
+pkix_is_issuer(Cert, IssuerCert) when is_binary(Cert) ->
+ OtpCert = pkix_decode_cert(Cert, otp),
+ pkix_is_issuer(OtpCert, IssuerCert);
+
+pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) ->
+ OtpIssuerCert = pkix_decode_cert(IssuerCert, otp),
+ pkix_is_issuer(Cert, OtpIssuerCert);
+
+pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
+ #'OTPCertificate'{tbsCertificate = Candidate}) ->
+ pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer,
+ Candidate#'OTPTBSCertificate'.subject).
%%--------------------------------------------------------------------
-%% Function: pkix_is_self_signed(Cert) -> true | false
+-spec pkix_is_self_signed(der_encoded()| #'OTPCertificate'{}) -> boolean().
%%
%% Description: Checks if a Certificate is self signed.
%%--------------------------------------------------------------------
pkix_is_self_signed(#'OTPCertificate'{} = OTPCert) ->
pubkey_cert:is_self_signed(OTPCert);
pkix_is_self_signed(Cert) when is_binary(Cert) ->
- {ok, OtpCert} = pkix_decode_cert(Cert, otp),
+ OtpCert = pkix_decode_cert(Cert, otp),
pkix_is_self_signed(OtpCert).
-
+
%%--------------------------------------------------------------------
-%% Function: pkix_issuer_id(Cert) -> {ok, {SerialNr, Issuer}} | {error, Reason}
-%%
-%% Cert = asn1_der_encoded() | 'OTPCertificate'{}
+-spec pkix_is_fixed_dh_cert(der_encoded()| #'OTPCertificate'{}) -> boolean().
%%
+%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert.
+%%--------------------------------------------------------------------
+pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) ->
+ pubkey_cert:is_fixed_dh_cert(OTPCert);
+pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
+ OtpCert = pkix_decode_cert(Cert, otp),
+ pkix_is_fixed_dh_cert(OtpCert).
+
+%%--------------------------------------------------------------------
+-spec pkix_issuer_id(der_encoded()| #'OTPCertificate'{},
+ IssuedBy :: self | other) ->
+ {ok, {SerialNr :: integer(),
+ Issuer :: {rdnSequence,
+ [#'AttributeTypeAndValue'{}]}}}
+ | {error, Reason :: term()}.
+%
%% Description: Returns the issuer id.
%%--------------------------------------------------------------------
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, self) ->
@@ -265,115 +422,64 @@ pkix_issuer_id(#'OTPCertificate'{} = OtpCert, other) ->
pubkey_cert:issuer_id(OtpCert, other);
pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
- {ok, OtpCert} = pkix_decode_cert(Cert, otp),
+ OtpCert = pkix_decode_cert(Cert, otp),
pkix_issuer_id(OtpCert, Signed).
%%--------------------------------------------------------------------
-%% Function: pkix_is_issuer(Cert, IssuerCert) -> true | false
-%%
-%% Cert = asn1_der_encoded() | 'OTPCertificate'{}
-%% IssuerCert = asn1_der_encoded() | 'OTPCertificate'{}
+-spec pkix_normalize_name({rdnSequence,
+ [#'AttributeTypeAndValue'{}]}) ->
+ {rdnSequence,
+ [#'AttributeTypeAndValue'{}]}.
%%
-%% Description: Checks if <IssuerCert> issued <Cert>.
+%% Description: Normalizes a issuer name so that it can be easily
+%% compared to another issuer name.
%%--------------------------------------------------------------------
-pkix_is_issuer(Cert, IssuerCert) when is_binary(Cert) ->
- {ok, OtpCert} = pkix_decode_cert(Cert, otp),
- pkix_is_issuer(OtpCert, IssuerCert);
-
-pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) ->
- {ok, OtpIssuerCert} = pkix_decode_cert(IssuerCert, otp),
- pkix_is_issuer(Cert, OtpIssuerCert);
+pkix_normalize_name(Issuer) ->
+ pubkey_cert:normalize_general_name(Issuer).
-pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
- #'OTPCertificate'{tbsCertificate = Candidate}) ->
- pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer,
- Candidate#'OTPTBSCertificate'.subject).
-
-%%--------------------------------------------------------------------
-%% Function: pkix_normalize_general_name(Issuer) ->
-%%
-%% Issuer = general_name() - see PKIX
-%%
-%% Description: Normalizes a general name so that it can be easily
-%% compared to another genral name.
+%%--------------------------------------------------------------------
+-spec pkix_path_validation(der_encoded()| #'OTPCertificate'{},
+ CertChain :: [der_encoded()] ,
+ Options :: list()) ->
+ {ok, {PublicKeyInfo :: term(),
+ PolicyTree :: term(),
+ [{bad_cert, Reason :: term()}]}} |
+ {error, {bad_cert, Reason :: term()}}.
+%% Description: Performs a basic path validation according to RFC 5280.
%%--------------------------------------------------------------------
-pkix_normalize_general_name(Issuer) ->
- pubkey_cert:normalize_general_name(Issuer).
+pkix_path_validation(TrustedCert, CertChain, Options)
+ when is_binary(TrustedCert) ->
+ OtpCert = pkix_decode_cert(TrustedCert, otp),
+ pkix_path_validation(OtpCert, CertChain, Options);
+
+pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
+ when is_list(CertChain), is_list(Options) ->
+ MaxPathDefault = length(CertChain),
+ ValidationState = pubkey_cert:init_validation_state(TrustedCert,
+ MaxPathDefault,
+ Options),
+ Fun = proplists:get_value(validate_extensions_fun, Options,
+ fun(Extensions, State, _, AccError) ->
+ {Extensions, State, AccError}
+ end),
+ Verify = proplists:get_value(verify, Options, true),
+ path_validation(CertChain, ValidationState, Fun, Verify).
%%--------------------------------------------------------------------
-%% Function:sign(Msg, Key) -> {ok, Signature}
-%% sign(Msg, Key, KeyParams) -> {ok, Signature}
-%%
-%% Msg = binary() | #'TBSCertificate'{}
-%% Key = private_key()
-%% KeyParams = key_params()
-%% Signature = binary()
-%%
-%% Description: Signs plaintext Msg or #TBSCertificate{}, in the later
-%% case a der encoded "#Certificate{}" will be returned.
+%%% Internal functions
%%--------------------------------------------------------------------
-sign(Msg, #'RSAPrivateKey'{} = Key) when is_binary(Msg) ->
- pubkey_crypto:sign(Msg, Key);
-
-sign(Msg, #'DSAPrivateKey'{} = Key) when is_binary(Msg) ->
- pubkey_crypto:sign(Msg, Key);
-sign(#'OTPTBSCertificate'{signature = #'SignatureAlgorithm'{algorithm = Alg}
- = SigAlg} = TBSCert, Key) ->
- Msg = pubkey_cert_records:encode_tbs_cert(TBSCert),
- DigestType = pubkey_cert:digest_type(Alg),
- Signature = pubkey_crypto:sign(DigestType, Msg, Key),
- Cert = #'OTPCertificate'{tbsCertificate= TBSCert,
- signatureAlgorithm = SigAlg,
- signature = {0, Signature}
- },
- pkix_encode_cert(Cert).
+encrypt_public(PlainText, N, E, Options)->
+ Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
+ crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
+ Padding).
-sign(DigestType, Msg, Key) ->
- pubkey_crypto:sign(DigestType, Msg, Key).
+decrypt_public(CipherText, N,E, Options) ->
+ Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
+ crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
+ Padding).
-%%--------------------------------------------------------------------
-%% Function: verify_signature(PlainText, DigestType, Signature, Key) ->
-%% verify_signature(PlainText, DigestType,
-%% Signature, Key, KeyParams) ->
-%% verify_signature(DerCert, Key, KeyParams) ->
-%%
-%% PlainText = binary()
-%% DigestType = md5 | sha
-%% DerCert = asn1_der_encoded()
-%% Signature = binary()
-%% Key = public_key()
-%% KeyParams = key_params()
-%% Verified = boolean()
-%%
-%% Description: Verifies the signature <Signature>.
-%%--------------------------------------------------------------------
-verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key)
- when is_binary(PlainText), is_binary(Signature), DigestType == sha;
- DigestType == md5 ->
- pubkey_crypto:verify(DigestType, PlainText, Signature, Key, undefined).
-
-verify_signature(PlainText, DigestType, Signature, #'RSAPublicKey'{} = Key,
- KeyParams)
- when is_binary(PlainText), is_binary(Signature), DigestType == sha;
- DigestType == md5 ->
- pubkey_crypto:verify(DigestType, PlainText, Signature, Key, KeyParams);
-verify_signature(PlainText, sha, Signature, Key, #'Dss-Parms'{} = KeyParams)
- when is_binary(PlainText), is_binary(Signature), is_integer(Key) ->
- pubkey_crypto:verify(sha, PlainText, Signature, Key, KeyParams);
-verify_signature(Hash, none, Signature, Key, KeyParams) ->
- pubkey_crypto:verify(none, Hash, Signature, Key, KeyParams).
-
-verify_signature(DerCert, Key, #'Dss-Parms'{} = KeyParams)
- when is_binary(DerCert), is_integer(Key) ->
- pubkey_cert:verify_signature(DerCert, Key, KeyParams);
-verify_signature(DerCert, #'RSAPublicKey'{} = Key, KeyParams)
- when is_binary(DerCert) ->
- pubkey_cert:verify_signature(DerCert, Key, KeyParams).
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
working_public_key =
@@ -423,7 +529,7 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
user_state = UserState0,
acc_errors = AccErr0} =
ValidationState0, ValidateExtensionFun, Verify) ->
- {ok, OtpCert} = pkix_decode_cert(DerCert, otp),
+ OtpCert = pkix_decode_cert(DerCert, otp),
%% All validate functions will throw {bad_cert, Reason} if they
%% fail and Verify = true if Verify = false errors
%% will be accumulated in the validationstate
@@ -456,3 +562,26 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
ValidationState1#path_validation_state{user_state = UserState,
acc_errors = AccErr},
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
+
+sized_binary(Binary) when is_binary(Binary) ->
+ Size = size(Binary),
+ <<?UINT32(Size), Binary/binary>>;
+sized_binary(List) ->
+ sized_binary(list_to_binary(List)).
+
+%%--------------------------------------------------------------------
+%%% Deprecated functions
+%%--------------------------------------------------------------------
+pem_to_der(CertSource) ->
+ {ok, Bin} = file:read_file(CertSource),
+ pubkey_pem:decode(Bin).
+
+decode_private_key(KeyInfo) ->
+ decode_private_key(KeyInfo, no_passwd).
+
+decode_private_key(KeyInfo = {'RSAPrivateKey', _, _}, Password) ->
+ DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
+ 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded);
+decode_private_key(KeyInfo = {'DSAPrivateKey', _, _}, Password) ->
+ DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
+ 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded).
diff --git a/lib/public_key/test/pkey_test.erl b/lib/public_key/test/pkey_test.erl
index 4cf20f0174..deb4defd29 100644
--- a/lib/public_key/test/pkey_test.erl
+++ b/lib/public_key/test/pkey_test.erl
@@ -34,7 +34,7 @@
%% version 3
%% subject [] list of the following content
%% {name, Name}
-%% {email, Email}
+%% {email, Email}
%% {city, City}
%% {state, State}
%% {org, Org}
@@ -56,7 +56,7 @@
make_cert(Opts) ->
SubjectPrivateKey = get_key(Opts),
{TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
- Cert = public_key:sign(TBSCert, IssuerKey),
+ Cert = public_key:pkix_sign(TBSCert, IssuerKey),
true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
{Cert, encode_key(SubjectPrivateKey)}.
@@ -66,8 +66,9 @@ make_cert(Opts) ->
%% @end
%%--------------------------------------------------------------------
write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]),
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
+ ok = der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ [{'Certificate', Cert, not_encrypted}]),
+ ok = der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
%%--------------------------------------------------------------------
%% @doc Creates a rsa key (OBS: for testing only)
@@ -94,18 +95,14 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
%%--------------------------------------------------------------------
-verify_signature(DerEncodedCert, DerKey, KeyParams) ->
+verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
Key = decode_key(DerKey),
case Key of
#'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
- public_key:verify_signature(DerEncodedCert,
- #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
- 'NULL');
+ public_key:pkix_verify(DerEncodedCert,
+ #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G});
-
- _ ->
- public_key:verify_signature(DerEncodedCert, Key, KeyParams)
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -132,19 +129,18 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
-decode_key(Der = {_,_,_}, Pw) ->
- {ok, Key} = public_key:decode_private_key(Der, Pw),
- Key;
-decode_key(FileOrDer, Pw) ->
- {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer),
+decode_key(PemEntry = {_,_,_}, Pw) ->
+ public_key:pem_entry_decode(PemEntry, Pw);
+decode_key(PemBin, Pw) ->
+ [KeyInfo] = public_key:pem_decode(PemBin),
decode_key(KeyInfo, Pw).
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {rsa_private_key, list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {dsa_private_key, list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -178,7 +174,7 @@ issuer(Opts, SubjectKey) ->
end.
issuer_der(Issuer) ->
- {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp),
+ Decoded = public_key:pkix_decode_cert(Issuer, otp),
#'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
#'OTPTBSCertificate'{subject=Subject} = Tbs,
Subject.
@@ -271,7 +267,7 @@ publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
#'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
validity(Opts) ->
- DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
+ DefFrom0 = date(),
DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
{DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
@@ -410,3 +406,11 @@ extended_gcd(A, B) ->
{X, Y} = extended_gcd(B, N),
{Y, X-Y*(A div B)}
end.
+
+pem_to_der(File) ->
+ {ok, PemBin} = file:read_file(File),
+ public_key:pem_decode(PemBin).
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index 5d58b39e26..cd7b2d77db 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -187,9 +187,9 @@ run([],_) -> ok.
read_certs(Test) ->
File = test_file(Test),
%% io:format("Read ~p ",[File]),
- {ok, Ders} = public_key:pem_to_der(File),
+ Ders = pkey_test:pem_to_der(File),
%% io:format("Ders ~p ~n",[length(Ders)]),
- [Cert || {cert,Cert,not_encrypted} <- Ders].
+ [Cert || {'Certificate', Cert, not_encrypted} <- Ders].
test_file(Test) ->
file(?CONV, lists:append(string:tokens(Test, " -")) ++ ".pem").
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index dc1015969a..1d32e989a9 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -101,13 +101,12 @@ all(doc) ->
all(suite) ->
[app,
- dh,
- pem_to_der,
- decode_private_key,
+ pk_decode_encode,
encrypt_decrypt,
sign_verify,
pkix,
- pkix_path_validation
+ pkix_path_validation,
+ deprecated
].
%% Test cases starts here.
@@ -120,78 +119,93 @@ app(suite) ->
app(Config) when is_list(Config) ->
ok = test_server:app_test(public_key).
-dh(doc) ->
- "Test diffie-hellman functions file is ok";
-dh(suite) ->
+pk_decode_encode(doc) ->
+ ["Tests pem_decode/1, pem_encode/1, "
+ "der_decode/2, der_encode/2, "
+ "pem_entry_decode/1, pem_entry_decode/2,"
+ "pem_entry_encode/2, pem_entry_encode/3."];
+
+pk_decode_encode(suite) ->
[];
-dh(Config) when is_list(Config) ->
+pk_decode_encode(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
- {ok,[DerDHparams = {dh_params, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "dh.pem")),
- {ok, DHps = #'DHParameter'{prime=P,base=G}} = public_key:decode_dhparams(DerDHparams),
- DHKeys = {Private,_Public} = public_key:gen_key(DHps),
- test_server:format("DHparams = ~p~nDH Keys~p~n", [DHps, DHKeys]),
- {_Private,_Public2} = pubkey_crypto:gen_key(diffie_hellman, [crypto:erlint(Private), P, G]),
- ok.
+
+ [{'DSAPrivateKey', DerDSAKey, not_encrypted} = Entry0 ] =
+ pkey_test:pem_to_der(filename:join(Datadir, "dsa.pem")),
+
+ DSAKey = public_key:der_decode('DSAPrivateKey', DerDSAKey),
+
+ DSAKey = public_key:pem_entry_decode(Entry0),
+
+ [{'RSAPrivateKey', DerRSAKey, not_encrypted} = Entry1 ] =
+ pkey_test:pem_to_der(filename:join(Datadir, "client_key.pem")),
+
+ RSAKey0 = public_key:der_decode('RSAPrivateKey', DerRSAKey),
+
+ RSAKey0 = public_key:pem_entry_decode(Entry1),
+
+ [{'RSAPrivateKey', _, {_,_}} = Entry2] =
+ pkey_test:pem_to_der(filename:join(Datadir, "rsa.pem")),
+ true = check_entry_type(public_key:pem_entry_decode(Entry2, "abcd1234"),
+ 'RSAPrivateKey'),
-pem_to_der(doc) ->
- ["Check that supported PEM files are decoded into the expected entry type"];
-pem_to_der(suite) ->
- [];
-pem_to_der(Config) when is_list(Config) ->
- Datadir = ?config(data_dir, Config),
- {ok,DSAKey =[{dsa_private_key, _, not_encrypted}]} =
- public_key:pem_to_der(filename:join(Datadir, "dsa.pem")),
- {ok,[{rsa_private_key, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "client_key.pem")),
- {ok, [{rsa_private_key, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "rsa.pem")),
- {ok,[{rsa_private_key, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "rsa.pem"), "abcd1234"),
- {ok, Bin0} = file:read_file(filename:join(Datadir, "rsa.pem")),
- {ok, [{rsa_private_key, _, _}]} = public_key:pem_to_der(Bin0, "abcd1234"),
-
- {ok,[{dh_params, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "dh.pem")),
- {ok,[{cert, _, not_encrypted}]} =
- public_key:pem_to_der(filename:join(Datadir, "client_cert.pem")),
- {ok,[{cert_req, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "req.pem")),
- {ok, Certs = [{cert, _, _}, {cert, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "cacerts.pem")),
-
- {ok, Bin1} = file:read_file(filename:join(Datadir, "cacerts.pem")),
- {ok, [{cert, _, _}, {cert, _, _}]} = public_key:pem_to_der(Bin1),
-
- ok = public_key:der_to_pem(filename:join(Datadir, "wcacerts.pem"), Certs),
- ok = public_key:der_to_pem(filename:join(Datadir, "wdsa.pem"), DSAKey),
+ Salt0 = crypto:rand_bytes(8),
+ Entry3 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0,
+ {{"DES-EDE3-CBC", Salt0}, "1234abcd"}),
+
+ RSAKey0 = public_key:pem_entry_decode(Entry3,"1234abcd"),
- {ok, Certs} = public_key:pem_to_der(filename:join(Datadir, "wcacerts.pem")),
- {ok, DSAKey} = public_key:pem_to_der(filename:join(Datadir, "wdsa.pem")),
+ Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"),
- ok.
-%%--------------------------------------------------------------------
-decode_private_key(doc) ->
- ["Check that private keys are decode to the expected key type."];
-decode_private_key(suite) ->
- [];
-decode_private_key(Config) when is_list(Config) ->
- Datadir = ?config(data_dir, Config),
- {ok,[DsaKey = {dsa_private_key, _DsaKey, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "dsa.pem")),
- {ok,[RsaKey = {rsa_private_key, _RsaKey,_}]} =
- public_key:pem_to_der(filename:join(Datadir, "client_key.pem")),
- {ok,[ProtectedRsaKey1 = {rsa_private_key, _ProtectedRsaKey1,_}]} =
- public_key:pem_to_der(filename:join(Datadir, "rsa.pem"), "abcd1234"),
- {ok,[ProtectedRsaKey2 = {rsa_private_key, _ProtectedRsaKey2,_}]} =
- public_key:pem_to_der(filename:join(Datadir, "rsa.pem")),
+ pkey_test:der_to_pem(Des3KeyFile, [Entry3]),
- {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey),
- {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey),
- {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey1),
- {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey2, "abcd1234"),
+ [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] = pkey_test:pem_to_der(Des3KeyFile),
+
+ Salt1 = crypto:rand_bytes(8),
+ Entry4 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey0,
+ {{"DES-CBC", Salt1}, "4567efgh"}),
+
+
+ DesKeyFile = filename:join(Datadir, "des_client_key.pem"),
+
+ pkey_test:der_to_pem(DesKeyFile, [Entry4]),
+
+ [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry5] = pkey_test:pem_to_der(DesKeyFile),
+
+
+ true = check_entry_type(public_key:pem_entry_decode(Entry5, "4567efgh"),
+ 'RSAPrivateKey'),
+
+ [{'DHParameter', DerDH, not_encrypted} = Entry6] =
+ pkey_test:pem_to_der(filename:join(Datadir, "dh.pem")),
+
+ pkey_test:der_to_pem(filename:join(Datadir, "new_dh.pem"), [Entry6]),
+
+ DHParameter = public_key:der_decode('DHParameter', DerDH),
+ DHParameter = public_key:pem_entry_decode(Entry6),
+
+ Entry6 = public_key:pem_entry_encode('DHParameter', DHParameter),
+
+ [{'Certificate', DerCert, not_encrypted} = Entry7] =
+ pkey_test:pem_to_der(filename:join(Datadir, "client_cert.pem")),
+
+ Cert = public_key:der_decode('Certificate', DerCert),
+ Cert = public_key:pem_entry_decode(Entry7),
+
+ CertEntries = [{'Certificate', _, not_encrypted} = CertEntry0,
+ {'Certificate', _, not_encrypted} = CertEntry1] =
+ pkey_test:pem_to_der(filename:join(Datadir, "cacerts.pem")),
+
+ ok = pkey_test:der_to_pem(filename:join(Datadir, "wcacerts.pem"), CertEntries),
+ ok = pkey_test:der_to_pem(filename:join(Datadir, "wdsa.pem"), [Entry0]),
+
+ NewCertEntries = pkey_test:pem_to_der(filename:join(Datadir, "wcacerts.pem")),
+ true = lists:member(CertEntry0, NewCertEntries),
+ true = lists:member(CertEntry1, NewCertEntries),
+ [Entry0] = pkey_test:pem_to_der(filename:join(Datadir, "wdsa.pem")),
ok.
+
%%--------------------------------------------------------------------
encrypt_decrypt(doc) ->
[""];
@@ -220,68 +234,80 @@ sign_verify(suite) ->
sign_verify(Config) when is_list(Config) ->
%% Make cert signs and validates the signature using RSA and DSA
Ca = {_, CaKey} = pkey_test:make_cert([]),
- {ok, PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp}} =
- public_key:decode_private_key(CaKey),
+ PrivateRSA = #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} =
+ public_key:pem_entry_decode(CaKey),
CertInfo = {Cert1,CertKey1} = pkey_test:make_cert([{key, dsa}, {issuer, Ca}]),
PublicRSA = #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
- true = public_key:verify_signature(Cert1, PublicRSA, undefined),
+ true = public_key:pkix_verify(Cert1, PublicRSA),
{Cert2,_CertKey} = pkey_test:make_cert([{issuer, CertInfo}]),
- {ok, #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X}} =
- public_key:decode_private_key(CertKey1),
- true = public_key:verify_signature(Cert2, Y, #'Dss-Parms'{p=P, q=Q, g=G}),
+ #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y, x=_X} =
+ public_key:pem_entry_decode(CertKey1),
+ true = public_key:pkix_verify(Cert2, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}),
%% RSA sign
Msg0 = lists:duplicate(5, "Foo bar 100"),
Msg = list_to_binary(Msg0),
- RSASign = public_key:sign(sha, Msg0, PrivateRSA),
- RSASign = public_key:sign(Msg, PrivateRSA),
- true = public_key:verify_signature(Msg, sha, RSASign, PublicRSA),
- false = public_key:verify_signature(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA),
- false = public_key:verify_signature(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA),
- RSASign = public_key:sign(sha, Msg, PrivateRSA),
-
- RSASign1 = public_key:sign(md5, Msg, PrivateRSA),
- true = public_key:verify_signature(Msg, md5, RSASign1, PublicRSA),
+
+ RSASign = public_key:sign(Msg0, sha, PrivateRSA),
+ RSASign = public_key:sign(Msg, sha, PrivateRSA),
+ true = public_key:verify(Msg, sha, RSASign, PublicRSA),
+ false = public_key:verify(<<1:8, Msg/binary>>, sha, RSASign, PublicRSA),
+ false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA),
+
+ RSASign1 = public_key:sign(Msg, md5, PrivateRSA),
+ true = public_key:verify(Msg, md5, RSASign1, PublicRSA),
%% DSA sign
Datadir = ?config(data_dir, Config),
- {ok,[DsaKey = {dsa_private_key, _, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "dsa.pem")),
- {ok, DSAPrivateKey} = public_key:decode_private_key(DsaKey),
+ [DsaKey = {'DSAPrivateKey', _, _}] =
+ pkey_test:pem_to_der(filename:join(Datadir, "dsa.pem")),
+ DSAPrivateKey = public_key:pem_entry_decode(DsaKey),
#'DSAPrivateKey'{p=P1, q=Q1, g=G1, y=Y1, x=_X1} = DSAPrivateKey,
- DSASign = public_key:sign(Msg, DSAPrivateKey),
+ DSASign = public_key:sign(Msg, sha, DSAPrivateKey),
DSAPublicKey = Y1,
DSAParams = #'Dss-Parms'{p=P1, q=Q1, g=G1},
- true = public_key:verify_signature(Msg, sha, DSASign, DSAPublicKey, DSAParams),
- false = public_key:verify_signature(<<1:8, Msg/binary>>, sha, DSASign, DSAPublicKey, DSAParams),
- false = public_key:verify_signature(Msg, sha, <<1:8, DSASign/binary>>, DSAPublicKey, DSAParams),
+ true = public_key:verify(Msg, sha, DSASign, {DSAPublicKey, DSAParams}),
+ false = public_key:verify(<<1:8, Msg/binary>>, sha, DSASign,
+ {DSAPublicKey, DSAParams}),
+ false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>,
+ {DSAPublicKey, DSAParams}),
+
+ Digest = crypto:sha(Msg),
+ DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
+ true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}),
+ <<_:8, RestDigest/binary>> = Digest,
+ false = public_key:verify(<<1:8, RestDigest/binary>>, none, DigestSign,
+ {DSAPublicKey, DSAParams}),
+ false = public_key:verify(Digest, none, <<1:8, DigestSign/binary>>,
+ {DSAPublicKey, DSAParams}),
ok.
-
+%%--------------------------------------------------------------------
pkix(doc) ->
"Misc pkix tests not covered elsewhere";
pkix(suite) ->
[];
pkix(Config) when is_list(Config) ->
Datadir = ?config(data_dir, Config),
- {ok,Certs0} = public_key:pem_to_der(filename:join(Datadir, "cacerts.pem")),
- {ok,Certs1} = public_key:pem_to_der(filename:join(Datadir, "client_cert.pem")),
- TestTransform = fun({cert, CertDer, not_encrypted}) ->
- {ok, PlainCert} = public_key:pkix_decode_cert(CertDer, plain),
- {ok, OtpCert} = public_key:pkix_decode_cert(CertDer, otp),
- CertDer = public_key:pkix_encode_cert(OtpCert),
- CertDer = public_key:pkix_encode_cert(PlainCert),
-
- OTPSubj = (OtpCert#'OTPCertificate'.tbsCertificate)#'OTPTBSCertificate'.subject,
- Subj = public_key:pkix_transform(OTPSubj, encode),
- {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- Subj2 = (PlainCert#'Certificate'.tbsCertificate)#'TBSCertificate'.subject,
- {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj2),
- OTPSubj = public_key:pkix_transform(Subj2, decode),
+ Certs0 = pkey_test:pem_to_der(filename:join(Datadir, "cacerts.pem")),
+ Certs1 = pkey_test:pem_to_der(filename:join(Datadir, "client_cert.pem")),
+ TestTransform = fun({'Certificate', CertDer, not_encrypted}) ->
+ PlainCert = public_key:pkix_decode_cert(CertDer, plain),
+ OtpCert = public_key:pkix_decode_cert(CertDer, otp),
+ CertDer =
+ public_key:pkix_encode('OTPCertificate', OtpCert, otp),
+ CertDer =
+ public_key:pkix_encode('Certificate', PlainCert, plain),
+ OTPTBS = OtpCert#'OTPCertificate'.tbsCertificate,
+ OTPSubj = OTPTBS#'OTPTBSCertificate'.subject,
+ DNEncoded = public_key:pkix_encode('Name', OTPSubj, otp),
+ PlainTBS = PlainCert#'Certificate'.tbsCertificate,
+ Subj2 = PlainTBS#'TBSCertificate'.subject,
+ DNEncoded = public_key:pkix_encode('Name', Subj2, plain),
false = public_key:pkix_is_fixed_dh_cert(CertDer)
end,
@@ -290,19 +316,24 @@ pkix(Config) when is_list(Config) ->
true = public_key:pkix_is_self_signed(element(2,hd(Certs0))),
false = public_key:pkix_is_self_signed(element(2,hd(Certs1))),
- CaIds = [element(2, public_key:pkix_issuer_id(Cert, self)) || {cert, Cert, _} <- Certs0],
- {ok, IssuerId = {_, IssuerName}} = public_key:pkix_issuer_id(element(2,hd(Certs1)), other),
+ CaIds = [element(2, public_key:pkix_issuer_id(Cert, self)) ||
+ {'Certificate', Cert, _} <- Certs0],
+ {ok, IssuerId = {_, _IssuerName}} =
+ public_key:pkix_issuer_id(element(2,hd(Certs1)), other),
+
true = lists:member(IssuerId, CaIds),
%% Should be normalized allready
- TestStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}],
- [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]},
- VerifyStr = {rdnSequence, [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}],
- [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}]]},
- VerifyStr = public_key:pkix_normalize_general_name(TestStr),
+ TestStr = {rdnSequence,
+ [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"ERLANGCA"}}],
+ [{'AttributeTypeAndValue', {2,5,4,3},{printableString," erlang ca "}}]]},
+ VerifyStr = {rdnSequence,
+ [[{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlang ca"}}],
+ [{'AttributeTypeAndValue', {2,5,4,3},{printableString,"erlangca"}}]]},
+ VerifyStr = public_key:pkix_normalize_name(TestStr),
ok.
-
+%%--------------------------------------------------------------------
pkix_path_validation(doc) ->
"Misc pkix tests not covered elsewhere";
pkix_path_validation(suite) ->
@@ -323,23 +354,56 @@ pkix_path_validation(Config) when is_list(Config) ->
ok = pkey_test:write_pem("./", "public_key_cacert", CaK),
CertK1 = {Cert1, _} = pkey_test:make_cert([{issuer, CaK}]),
- CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1}, {digest, md5}, {extensions, false}]),
+ CertK2 = {Cert2,_} = pkey_test:make_cert([{issuer, CertK1},
+ {digest, md5}, {extensions, false}]),
ok = pkey_test:write_pem("./", "public_key_cert", CertK2),
{ok, _} = public_key:pkix_path_validation(Trusted, [Cert1], []),
- {error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], []),
- %%{error, {bad_cert,invalid_issuer}} = public_key:pkix_path_validation(Trusted, [Cert2], [{verify,false}]),
+ {error, {bad_cert,invalid_issuer}} =
+ public_key:pkix_path_validation(Trusted, [Cert2], []),
{ok, _} = public_key:pkix_path_validation(Trusted, [Cert1, Cert2], []),
{error, issuer_not_found} = public_key:pkix_issuer_id(Cert2, other),
- CertK3 = {Cert3,_} = pkey_test:make_cert([{issuer, CertK1}, {extensions, [{basic_constraints, false}]}]),
+ CertK3 = {Cert3,_} = pkey_test:make_cert([{issuer, CertK1},
+ {extensions, [{basic_constraints, false}]}]),
{Cert4,_} = pkey_test:make_cert([{issuer, CertK3}]),
{error, E={bad_cert,missing_basic_constraint}} =
public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], []),
- {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], [{verify,false}]),
+ {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4],
+ [{verify,false}]),
+ ok.
- % test_server:format("PV ~p ~n", [Result]),
+%%--------------------------------------------------------------------
+deprecated(doc) ->
+ ["Check deprecated functions."];
+deprecated(suite) ->
+ [];
+deprecated(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ [DsaKey = {'DSAPrivateKey', _DsaKey, _}] =
+ public_key:pem_to_der(filename:join(Datadir, "dsa.pem")),
+ [RsaKey = {'RSAPrivateKey', _RsaKey,_}] =
+ public_key:pem_to_der(filename:join(Datadir, "client_key.pem")),
+ [ProtectedRsaKey = {'RSAPrivateKey', _ProtectedRsaKey,_}] =
+ public_key:pem_to_der(filename:join(Datadir, "rsa.pem")),
+
+ {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey),
+ {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey),
+ {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey, "abcd1234"),
ok.
+
+%%--------------------------------------------------------------------
+
+check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') ->
+ true;
+check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') ->
+ true;
+check_entry_type(#'DHParameter'{}, 'DHParameter') ->
+ true;
+check_entry_type(#'Certificate'{}, 'Certificate') ->
+ true;
+check_entry_type(_,_) ->
+ false.
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 4b3071a85b..f70209d891 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1,11 +1 @@
-PUBLIC_KEY_VSN = 0.7
-
-TICKETS = OTP-8626 OTP-8649
-
-#TICKETS_0.6 = OTP-7046 \
-# OTP-8553
-#TICKETS_0.5 = OTP-8372
-#TICKETS_0.4 = OTP-8250
-#TICKETS_0.3 = OTP-8100 OTP-8142
-#TICKETS_0.2 = OTP-7860
-#TICKETS_0.1 = OTP-7637 \ No newline at end of file
+PUBLIC_KEY_VSN = 0.8
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 0c2b7d2a2b..598594145a 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -48,8 +48,8 @@
<c>root_dir</c> is the root directory of the analysed system and
it defaults to the system executing <c>reltool</c>. Applications
may also be located outside <c>root_dir</c>. <c>lib_dirs</c>
- defines additional library directories where applications
- additional may reside and it defaults to the the directories
+ defines library directories where additional applications
+ may reside and it defaults to the directories
listed by the operating system environment variable
<c>ERL_LIBS</c>. See the module <c>code</c> for more info.
Finally single modules and entire applications may be read from
@@ -58,10 +58,10 @@
<p>Some configuration parameters control the behavior of Reltool
on system (<c>sys</c>) level. Others provide control on
application (<c>app</c>) level and yet others are on module
- (<c>mod</c>) level. Module level parameters overrides application
- level parameters and application level parameters overrides system
+ (<c>mod</c>) level. Module level parameters override application
+ level parameters and application level parameters override system
level parameters. Escript <c>escript</c> level parameters
- overrides system level parameters.</p>
+ override system level parameters.</p>
<p>The following top level <c>options</c> are supported:</p>
@@ -74,7 +74,7 @@
a name of a <c>file</c> containing a sys tuple.</p>
</item>
- <tag><c>trap_exit></c></tag>
+ <tag><c>trap_exit</c></tag>
<item>
<p>This option controls the error handling behavior of
<c>reltool</c>. By default the window processes traps
@@ -123,10 +123,10 @@
defaults to <c>all</c> which means that if an application is
included (either explicitly or implicitly) all modules in that
application will be included. This implies that both modules
- that exists on the <c>ebin</c> directory of the application,
+ that exist in the <c>ebin</c> directory of the application,
as well as modules that are named in the <c>app</c> file will
be included. If the parameter is set to <c>ebin</c>, both
- modules on the <c>ebin</c> directory and derived modules are
+ modules in the <c>ebin</c> directory and derived modules are
included. If the parameter is set to <c>app</c>, both modules
in the <c>app</c> file and derived modules are included.
<c>derived</c> means that only modules that are used by other
@@ -138,13 +138,13 @@
<item>
<p>This parameter controls the application and escript
inclusion policy. It defaults to <c>derived</c> which means
- that the applications that not have any explicit
+ that the applications that do not have any explicit
<c>incl_cond</c> setting, will only be included if any other
(explicitly or implicitly included) application uses it. The
value <c>include</c> implies that all applications and
- escripts that that not have any explicit <c>incl_cond</c>
+ escripts that do not have any explicit <c>incl_cond</c>
setting will be included. <c>exclude</c> implies that all
- applications and escripts) that that not have any explicit
+ applications and escripts) that do not have any explicit
<c>incl_cond</c> setting will be excluded.</p>
</item>
@@ -158,7 +158,7 @@
<tag><c>rel</c></tag>
<item>
<p>Release specific configuration. Each release maps to a
- <c>rel</c>, <c>script</c> and <c>boot </c> file. See the
+ <c>rel</c>, <c>script</c> and <c>boot</c> file. See the
module <c>systools</c> for more info about the details. Each
release has a name, a version and a set of applications with a
few release specific parameters such as type and included
@@ -168,7 +168,7 @@
<tag><c>relocatable</c></tag>
<item>
<p>This parameter controls whether the <c>erl</c> executable
- in the target system automatically should determine where it
+ in the target system should automatically determine where it
is installed or if it should use a hardcoded path to the
installation. In the latter case the target system must be
installed with <c>reltool:install/2</c> before it can be
@@ -182,7 +182,7 @@
<p>The creation of the specification for a target system is
performed in two steps. In the first step a complete
specification is generated. It will likely contain much more
- files than you are interested in your customized target
+ files than you are interested in in your customized target
system. In the second step the specification will be filtered
according to your filters. There you have the ability to
specify filters per application as well as system wide
@@ -224,12 +224,12 @@
<tag><c>incl_sys_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
- expressions that controls which files in the system that
+ expressions that controls which files in the system
should be included. Each file in the target system must match
at least one of the listed regular expressions in order to be
included. Further the files may not match any filter in
<c>excl_sys_filters</c> in order to be included. Which
- application files that should be included are controlled with
+ application files should be included is controlled with
the parameters <c>incl_app_filters</c> and
<c>excl_app_filters</c>. This parameter defaults to
<c>[".*"]</c>.</p>
@@ -238,8 +238,8 @@
<tag><c>excl_sys_filters</c></tag>
<item>
<p>This parameter normally contains a list of regular
- expressions that controls which files in the system that not
- should be included in the target system. In order to be
+ expressions that controls which files in the system should
+ not be included in the target system. In order to be
included, a file must match some filter in
<c>incl_sys_filters</c> but not any filter in
<c>excl_sys_filters</c>. This parameter defaults to
@@ -260,7 +260,7 @@
<item>
<p>This parameter normally contains a list of regular
expressions that controls which application specific files
- that not should be included in the target system. In order to
+ should not be included in the target system. In order to
be included, a file must match some filter in
<c>incl_app_filters</c> but not any filter in
<c>excl_app_filters</c>. This parameter defaults to
@@ -271,8 +271,8 @@
<item>
<p>This parameter normally contains a list of regular
expressions that controls which top level directories in an
- application that should be included in an archive file (as
- opposed of beeing included as a regular directory outside the
+ application should be included in an archive file (as
+ opposed to being included as a regular directory outside the
archive). Each top directory in the application must match at
least one of the listed regular expressions in order to be
included. Further the files may not match any filter in
@@ -284,7 +284,7 @@
<item>
<p>This parameter normally contains a list of regular
expressions that controls which top level directories in an
- application that not should be included in an archive file. In
+ application should not be included in an archive file. In
order to be included in the application archive, a top
directory must match some filter in <c>incl_archive_filters</c>
but not any filter in <c>excl_archive_filters</c>. This
@@ -295,15 +295,15 @@
<item>
<p>This parameter contains a list of options that are given to
<c>zip:create/3</c> when application specific files are
- packaged into an archive. All options are not supported. The
- most useful options in this context, are the ones that
- controls which types of files that should be compressed. This
+ packaged into an archive. Only a subset of the options are
+ supported. The most useful options in this context are the ones
+ that control which types of files should be compressed. This
parameter defaults to <c>[]</c>.</p>
</item>
</taglist>
- <p>On application (<c>escript</c>) level,the following options are
+ <p>On application (<c>escript</c>) level, the following options are
supported:</p>
<taglist>
@@ -314,7 +314,7 @@
</item>
</taglist>
- <p>On application (<c>app</c>) level,the following options are
+ <p>On application (<c>app</c>) level, the following options are
supported:</p>
<taglist>
@@ -322,8 +322,8 @@
<item>
<p>The version of the application. In an installed system there may
exist several versions of an application. The <c>vsn</c> parameter
- controls which version of the application that will be choosen. If it
- is omitted, the latest version will be choosen.</p>
+ controls which version of the application will be chosen. If it
+ is omitted, the latest version will be chosen.</p>
</item>
<tag><c>mod</c></tag>
<item>
@@ -380,7 +380,7 @@
</item>
</taglist>
- <p>On module (<c>mod</c>) level,the following options are
+ <p>On module (<c>mod</c>) level, the following options are
supported:</p>
<taglist>
@@ -391,9 +391,9 @@
will be used to control whether the module is included or not. The
value of <c>incl_cond</c> overrides the module inclusion policy.
<c>include</c> implies that the module is included, while
- <c>exclude</c> implies that the module not is included.
- <c>derived</c> implies that the is included if any included uses the
- module.</p>
+ <c>exclude</c> implies that the module is not included.
+ <c>derived</c> implies that the module is included if it is used
+ by any other included module.</p>
</item>
<tag><c>debug_info</c></tag>
<item>
@@ -546,12 +546,12 @@ target_spec() = [target_spec()]
files are by default copied to the target system. The
<c>releases</c> directory contains generated <c>rel</c>,
<c>script</c>, and <c>boot</c> files. The <c>lib</c> directory
- contains the applications. Which applications that are included
+ contains the applications. Which applications are included
and if they should be customized (archived, stripped from debug
info etc.) is specified with various configuration
parameters. The files in the <c>bin</c> directory are copied
from the <c>erts-vsn/bin</c> directory, but only those files
- that was originally included in <c>bin</c> directory of the
+ that were originally included in the <c>bin</c> directory of the
source system.</p>
<p>If the configuration parameter <c>relocatable</c> was set to
@@ -584,10 +584,10 @@ target_spec() = [target_spec()]
<v>Reason = reason()</v>
</type>
<desc><p>Get reltool configuration. Normally, only the explicit
- configuration parameters with values that differs from their
+ configuration parameters with values that differ from their
defaults are interesting. But the builtin default values can be
returned by setting <c>InclDefaults</c> to <c>true</c>. The
- derived configuration can be return by setting
+ derived configuration can be returned by setting
<c>InclDerived</c> to <c>true</c>.</p></desc>
</func>
@@ -705,7 +705,7 @@ target_spec() = [target_spec()]
<v>Reason = reason()</v>
</type>
<desc><p>Start a server process with options. The server process
- identity can be given as argument to several other functions in the
+ identity can be given as an argument to several other functions in the
API.</p></desc>
</func>
diff --git a/lib/reltool/doc/src/reltool_usage.xml b/lib/reltool/doc/src/reltool_usage.xml
index 885828d1f0..0a053a014e 100644
--- a/lib/reltool/doc/src/reltool_usage.xml
+++ b/lib/reltool/doc/src/reltool_usage.xml
@@ -44,7 +44,7 @@
<section>
<title>System window</title>
<p>The system window is started with the function
- <c>reltool:start/1</c>. At startup the tool will process the all
+ <c>reltool:start/1</c>. At startup the tool will process all
<c>beam</c> files and <c>app</c> files in order to find out dependencies
between applications and their modules. Once all this information has been
derived, it will be possible to explore the tool.</p>
@@ -67,29 +67,29 @@
<section>
<title>Libraries</title>
<p>On the library page it is possible to control which sources
- that the tool will use. The page is organized as a tree which
+ the tool will use. The page is organized as a tree which
can be expanded and collapsed by clicking on the little symbol
in the beginning of the expandable/collapsible lines.</p>
<p>The <c>Root directory</c> can be edited by selecting the
line where the path of the root directory is displayed and
- clicking with the right mouse button. Choose edit in the menu
- that pops up. </p>
+ clicking the right mouse button. Choose edit in the menu
+ that pops up.</p>
<p>Library directories can be added, edited or deleted. This
is done by selecting the line where the path to a library
- directory is displayed and clicking with the right mouse
+ directory is displayed and clicking the right mouse
button. Choose add, edit or delete in the menu that pops
up. New library directories can also be added by selecting the
- line <c>Library directories</c> and clicking with the right
+ line <c>Library directories</c> and clicking the right
mouse button. Choose add in the menu that pops up.</p>
<p>Escript files can be added, edited or deleted. This is done
by selecting the line where the path to an escript file is
- displayed and clicking with the right mouse button. Choose
+ displayed and clicking the right mouse button. Choose
add, edit or delete in the menu that pops up. New escripts can
also be added by selecting the line <c>Escript files</c> and
- clicking with the right mouse button. Choose add in the menu
+ clicking the right mouse button. Choose add in the menu
that pops up.</p>
<p>When libraries and escripts are expanded, the names of
@@ -102,7 +102,7 @@
<p>On the system settings page it is possible to control some
global settings that are used as defaults for all
applications. Set the <c>Application inclusion policy</c> to
- <c>include</c> to include all applications that not are
+ <c>include</c> to include all applications that are not
explicitly excluded. See <c>incl_cond</c> (application
inclusion) and <c>mod_cond</c> (module inclusion) in the
reference manual for the module <c>reltool</c> for more
@@ -131,14 +131,14 @@
<p>The symbols in front of the application names are intended
to describe the status of the application. There are error
- symbols and warning symbols that means that there are
- something that needs attention. The tick symbol means that the
+ and warning symbols to signalize that there is
+ something which needs attention. The tick symbol means that the
application is included or derived and no problem has been
detected. The cross symbol means that the application is
excluded or available and no problem has been
detected. Applications with error symbols are listed first in
- each category, then comes the warnings and the normal ones
- (ticks and crosses) are found at the end.</p>
+ each category and are followed by the warnings and the
+ normal ones (ticks and crosses) at the end.</p>
<p>Double click on an application to launch its application
window.</p>
@@ -175,8 +175,8 @@
</item>
<item>
<p><c>Save configuration</c> - Saves the current
- configuration to file. Normally, only the explictit
- configuration parameters with values that differs from their
+ configuration to file. Normally, only the explicit
+ configuration parameters with values that differ from their
defaults are saved. But the configuration with or without
default values and with or without derived values may also
be saved.</p>
@@ -204,21 +204,21 @@
<p>It is possible to perform some limited manipulations of the
graph. Nodes can be moved, selected, locked or deleted. Move a
single node or the entire graph by moving the mouse while the
- left mouse button is pressed. A node is can be locked into a fix
+ left mouse button is pressed. A node can be locked into a fix
position by holding down the shift button when the left mouse
button is released. Select several nodes by moving the mouse
- while the control key and the left mouse button i
+ while the control key and the left mouse button are
pressed. Selected nodes can be locked, unlocked or deleted by
- klicking on a suitable button.</p>
+ clicking on a suitable button.</p>
<p>The algorithm that is used to draw a graph with as few
crossed links as possible is called force graph. A force graph
- consists of nodes and directed link between nodes. Each node is
+ consists of nodes and directed links between nodes. Each node is
associated with a repulsive force that pushes nodes away from
each other. This force can be adjusted with the left slider or
with the mouse wheel. Each link is associated with an attractive
- force that pulls the nodes nearer each other. This force can be
- adjusted with the right slider. If this force becomes to strong,
+ force that pulls the nodes nearer to each other. This force can be
+ adjusted with the right slider. If this force becomes too strong,
the graph will be unstable. The third parameter that can be
adjusted is the length of the links. It is adjusted with the
middle slider.</p>
@@ -256,7 +256,7 @@
<p>Select version of the application in the <c>Source selection
policy</c> part of the page. By default the latest version of the
application is selected, but it is possible to override this by
- explicitly select another version.</p>
+ explicitly selecting another version.</p>
<p>By default the <c>Application inclusion policy</c> on system
level is used for all applications. Set the value to
@@ -272,10 +272,10 @@
want actually used modules to be included. Set it to <c>app</c> if
you, besides derived modules, also want the modules listed in the
app file to be included. Set it to <c>ebin</c> if you, besides
- derived modules, also want the modules that exists as beam files
- on the ebin directory to be included. Set it to <c>all</c> if you
+ derived modules, also want the modules that exist as beam files
+ in the ebin directory to be included. Set it to <c>all</c> if you
want all modules to be included, that is the union of modules
- found on the ebin directory and listed in the app file.</p>
+ found in the ebin directory and listed in the app file.</p>
<p>The application settings page is rather incomplete.</p>
</section>
@@ -299,16 +299,16 @@
undone.</p>
<p>The symbols in front of the module names are intended to
- describe the status of the module. There are error symbols
- and warning symbols that means that there are something that needs
+ describe the status of the module. There are error and
+ and warning symbols to signalize that there is something that needs
attention. The tick symbol means that the module is included
or derived and no problem has been detected. The cross symbol
means that the module is excluded or available and no problem
has been detected. Modules with error symbols are listed
- first in each category, then comes the warnings and the normal
- ones (ticks and crosses) are found at the end.</p>
+ first in each category and are followed by warnings and the
+ normal ones (ticks and crosses) at the end.</p>
- <p>Double click on an module to launch its module window.</p>
+ <p>Double click on a module to launch its module window.</p>
</section>
@@ -323,7 +323,7 @@
<c>app</c> file. If the application includes other applications,
these are listed under <c>Included</c>. These applications are
listed in the <c>included_applications</c> part of the <c>app</c>
- file. If the application uses modules other applications, these
+ file. If the application uses other applications, these
are listed under <c>Uses</c>.</p>
<p>Double click on an application name to launch an application window.</p>
@@ -336,7 +336,7 @@
<p>There are two categories of modules on the <c>Module
dependencies</c> page. If the module is used by other modules,
these are listed under <c>Modules used by others</c>. If the
- module uses modules other modules, these are listed under <c>Used
+ module uses other modules, these are listed under <c>Used
modules</c>.</p>
<p>Double click on an module name to launch a module window.</p>
@@ -365,8 +365,8 @@
<p>There are two categories of modules on the <c>Dependencies</c>
page. If the module is used by other modules, these are listed
- under <c>Modules used by others</c>. If the module uses modules
- other modules, these are listed under <c>Used modules</c>.</p>
+ under <c>Modules used by others</c>. If the module uses other
+ modules, these are listed under <c>Used modules</c>.</p>
<p>Double click on an module name to launch a module window.</p>
@@ -378,7 +378,7 @@
<p>On the <c>Code</c> page the Erlang source code is displayed. It
is possible to search forwards and backwards for text in the
module. Enter a regular expression in the <c>Find</c> field and
- press enter. It is also possible to goto a certain line on the
+ press enter. It is also possible to go to a certain line in the
module. The <c>Back</c> button can be used to go back to the
previous position.</p>
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index f23a7e84a2..7bee91d428 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -17,12 +17,3 @@
# %CopyrightEnd%
RELTOOL_VSN = 0.5.4
-
-TICKETS = OTP-8521 OTP-8590
-TICKETS_0_5_3 = OTP-8057
-TICKETS_0_5_2 = OTP-8254
-TICKETS_0_5_1 = OTP-8199
-TICKETS_0_5 = OTP-7949
-TICKETS_0_2_2 = OTP-7999
-TICKETS_2_2_1 = OTP-7840
-TICKETS_0_2 = OTP-7805
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 3f4954cfbd..d5d6605b64 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -13,12 +13,12 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
<title>SNMP Release Notes</title>
@@ -33,6 +33,34 @@
</header>
<section>
+ <title>SNMP Development Toolkit 4.17.1</title>
+ <p>Version 4.17.1 supports code replacement in runtime from/to
+ version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>When the function FilterMod:accept_recv/2
+ returned false the SNMP agent stopped collecting messages from UDP.</p>
+ <p>Own Id: OTP-8761</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.17.1 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.17</title>
<p>Version 4.17 supports code replacement in runtime from/to
version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p>
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index 1be6abe6dd..f546724a78 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -1233,7 +1233,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</type>
<desc>
<p>Restart the worker process of a multi-threaded agent.</p>
- <p>This is a utility function, that can be usefull when
+ <p>This is a utility function, that can be useful when
e.g. debugging instrumentation functions.</p>
<marker id="restart_set_worker"></marker>
@@ -1249,7 +1249,7 @@ snmp_agent:register_subagent(SA1,[1,2,3], SA2).
</type>
<desc>
<p>Restart the set worker process of a multi-threaded agent.</p>
- <p>This is a utility function, that can be usefull when
+ <p>This is a utility function, that can be useful when
e.g. debugging instrumentation functions.</p>
<marker id="verbosity"></marker>
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index 3a91cf4033..97a7a63dee 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(snmpa_net_if).
@@ -478,12 +478,13 @@ update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S,
S#state{rcnt = NewRCnt}.
-maybe_handle_recv(#state{filter = FilterMod} = S,
+maybe_handle_recv(#state{usock = Sock, filter = FilterMod} = S,
Ip, Port, Packet) ->
case (catch FilterMod:accept_recv(Ip, Port)) of
false ->
%% Drop the received packet
inc(netIfMsgInDrops),
+ active_once(Sock),
S;
_ ->
handle_recv(S, Ip, Port, Packet)
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 9ad16ffad2..2bd26e11db 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -22,6 +22,11 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.17",
+ [
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []}
+ ]
+ },
{"4.16.2",
[
{load_module, snmp_log, soft_purge, soft_purge, []},
@@ -29,6 +34,7 @@
{load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]},
{load_module, snmpa_usm, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []}
]
@@ -44,6 +50,7 @@
{load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]},
{update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []},
{update, snmpm_server, soft, soft_purge, soft_purge, []}
@@ -61,6 +68,7 @@
{load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]},
{update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []},
{update, snmpm_net_if, soft, soft_purge, soft_purge, []},
@@ -149,6 +157,11 @@
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.17",
+ [
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []}
+ ]
+ },
{"4.16.2",
[
{load_module, snmp_log, soft_purge, soft_purge, []},
@@ -157,6 +170,7 @@
{load_module, snmpa_mpd, soft_purge, soft_purge, [snmpa_usm]},
{load_module, snmpa_usm, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []}
]
@@ -172,6 +186,7 @@
{load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]},
{update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []},
{update, snmpm_server, soft, soft_purge, soft_purge, []}
@@ -189,6 +204,7 @@
{load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]},
{update, snmpa_mib, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mib]},
+ {load_module, snmpa_net_if, soft_purge, soft_purge, []},
{load_module, snmpm_mpd, soft_purge, soft_purge, []},
{update, snmpm_net_if, soft, soft_purge, soft_purge, []},
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 4ca1fb7901..21b84f0dc6 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -1,57 +1,22 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
-#
+#
# Copyright Ericsson AB 1997-2010. All Rights Reserved.
-#
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
-SNMP_VSN = 4.17
+SNMP_VSN = 4.17.1
PRE_VSN =
APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)"
-
-TICKETS = OTP-8478
-
-TICKETS_4_16_2 = \
- OTP-8563 \
- OTP-8574 \
- OTP-8594 \
- OTP-8595 \
- OTP-8646 \
- OTP-8648
-
-TICKETS_4_16_1 = \
- OTP-8480 \
- OTP-8481
-
-TICKETS_4_16 = \
- OTP-8395 \
- OTP-8433 \
- OTP-8442
-
-TICKETS_4_15 = \
- OTP-8229 \
- OTP-8249
-
-TICKETS_4_14 = \
- OTP-8223 \
- OTP-8228 \
- OTP-8237
-
-TICKETS_4_13_5 = \
- OTP-8116 \
- OTP-8120 \
- OTP-8181 \
- OTP-8182
-
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 8a49a44a6c..dcb2d69290 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -238,9 +238,19 @@ handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module,
{noreply, State#state{channel_state = ChannelState}};
{ok, ChannelState, Timeout} ->
{noreply, State#state{channel_state = ChannelState}, Timeout};
+ {stop, Reason, ChannelState} when is_atom(Reason)->
+ {stop, Reason, State#state{close_sent = true,
+ channel_state = ChannelState}};
{stop, ChannelId, ChannelState} ->
- ssh_connection:close(ConnectionManager, ChannelId),
- {stop, normal, State#state{close_sent = true,
+ Reason =
+ case Msg of
+ {'EXIT', _Pid, shutdown} ->
+ shutdown;
+ _ ->
+ normal
+ end,
+ (catch ssh_connection:close(ConnectionManager, ChannelId)),
+ {stop, Reason, State#state{close_sent = true,
channel_state = ChannelState}}
end.
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
index cffeade485..9e55312e5f 100644
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ b/lib/ssh/src/ssh_connection_manager.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
%%
@@ -146,6 +146,8 @@ adjust_window(ConnectionManager, Channel, Bytes) ->
close(ConnectionManager, ChannelId) ->
try call(ConnectionManager, {close, ChannelId}) of
ok ->
+ ok;
+ {error,normal} ->
ok
catch
exit:{noproc, _} ->
@@ -155,6 +157,8 @@ close(ConnectionManager, ChannelId) ->
stop(ConnectionManager) ->
try call(ConnectionManager, stop) of
ok ->
+ ok;
+ {error,normal} ->
ok
catch
exit:{noproc, _} ->
@@ -593,7 +597,9 @@ call(Pid, Msg, Timeout) ->
Result
catch
exit:{timeout, _} ->
- {error, timeout}
+ {error, timeout};
+ exit:{normal, _} ->
+ {error, normal}
end.
cast(Pid, Msg) ->
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index ccdbfe4f9a..a8821625a2 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -2,83 +2,3 @@
SSH_VSN = 2.0
APP_VSN = "ssh-$(SSH_VSN)"
-
-TICKETS = OTP-8524 \
- OTP-8534 \
- OTP-8535 \
- OTP-8550 \
- OTP-8596 \
- OTP-8644 \
- OTP-8645
-
-TICKETS_1.1.8 = OTP-8356 \
- OTP-8401
-
-TICKETS_1.1.7 = OTP-8121 \
- OTP-8277 \
- OTP-8278 \
- OTP-8201
-
-TICKETS_1.1.6 = OTP-8110 \
- OTP-8162 \
- OTP-8173 \
- OTP-8174 \
- OTP-8175 \
- OTP-8176
-
-TICKETS_1.1.5 = OTP-8159 \
- OTP-8160 \
- OTP-8161
-
-TICKETS_1.1.4 = OTP-8071
-
-TICKETS_1.1.3 = OTP-7996 \
- OTP-8034 \
- OTP-8035
-
-TICKETS_1.1.2 = OTP-7914 \
- OTP-7917 \
- OTP-7918 \
- OTP-7921 \
- OTP-7919 \
- OTP-7930 \
- OTP-7957
-
-TICKETS_1.1.1 = OTP-7828 \
- OTP-7795 \
- OTP-7807 \
- OTP-7808 \
- OTP-7809
-
-TICKETS_1.1 = OTP-7676 \
- OTP-7683 \
- OTP-7685 \
- OTP-7766 \
- OTP-7767 \
- OTP-7768 \
- OTP-7770 \
- OTP-7456 \
- OTP-7769 \
- OTP-7516 \
- OTP-7645 \
-
-TICKETS_1.0.2 = \
- OTP-7141\
-
-TICKETS_1.0.1 = \
- OTP-7318 \
- OTP-7305 \
- OTP-7564 \
- OTP-7565 \
- OTP-7566 \
-
-TICKETS_1.0 = \
- OTP-7485 \
- OTP-7504 \
- OTP-7356 \
- OTP-7502 \
- OTP-7503
-
-TICKETS_0.9.9.6 = \
- OTP-7246 \
- OTP-7247 \ \ No newline at end of file
diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile
index b8b51270c9..8c9d78d4bc 100644
--- a/lib/ssl/Makefile
+++ b/lib/ssl/Makefile
@@ -24,21 +24,11 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
# Macros
#
-ifeq ($(findstring win32,$(TARGET)),win32)
-ifeq ($(HOST_OS),)
-HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
-endif
-ifeq ($(findstring solaris,$(HOST_OS)),solaris)
-SKIP_BUILDING_BINARIES := true
-endif
-else
-SKIP_BUILDING_BINARIES := false
-endif
-ifeq ($(SKIP_BUILDING_BINARIES), true)
SUB_DIRECTORIES = src c_src doc/src
-else
-SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src
+
+ifeq ($(CROSS_COMPILING),no)
+SUB_DIRECTORIES += examples/certs examples/src
endif
include vsn.mk
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index d6788c1633..3119d37af0 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = refman.xml
-XML_REF3_FILES = ssl.xml old_ssl.xml
+XML_REF3_FILES = ssl.xml old_ssl.xml ssl_session_cache_api.xml
XML_REF6_FILES = ssl_app.xml
XML_PART_FILES = release_notes.xml usersguide.xml
@@ -45,9 +45,7 @@ XML_CHAPTER_FILES = \
ssl_protocol.xml \
using_ssl.xml \
pkix_certs.xml \
- create_certs.xml \
ssl_distribution.xml \
- licenses.xml \
notes.xml
BOOK_FILES = book.xml
diff --git a/lib/ssl/doc/src/book.xml b/lib/ssl/doc/src/book.xml
index 9122addb74..85d6b56b26 100644
--- a/lib/ssl/doc/src/book.xml
+++ b/lib/ssl/doc/src/book.xml
@@ -28,9 +28,6 @@
<rev>A</rev>
<file>book.sgml</file>
</header>
- <insidecover>
- <include file="insidecover"></include>
- </insidecover>
<pagetext>SSL Application</pagetext>
<preamble>
<contents level="2"></contents>
diff --git a/lib/ssl/doc/src/create_certs.xml b/lib/ssl/doc/src/create_certs.xml
deleted file mode 100644
index 79cc8a0537..0000000000
--- a/lib/ssl/doc/src/create_certs.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Creating Certificates</title>
- <prepared>UAB/F/P Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-06-16</date>
- <rev>A</rev>
- <file>create_certs.xml</file>
- </header>
- <p>Here we consider the creation of example certificates.
- </p>
-
- <section>
- <title>The openssl Command</title>
- <p>The <c>openssl</c> command is a utility that comes with the
- OpenSSL distribution. It provides a variety of subcommands. Each
- subcommand is invoked as</p>
- <code type="none"><![CDATA[
- openssl subcmd <options and arguments> ]]></code>
- <p>where <c>subcmd</c> denotes the subcommand in question.
- </p>
- <p>We shall use the following subcommands to create certificates for
- the purpose of testing Erlang/OTP SSL:
- </p>
- <list type="bulleted">
- <item><em>req</em> to create certificate requests and a
- self-signed certificates,
- </item>
- <item><em>ca</em> to create certificates from certificate requests.</item>
- </list>
- <p>We create the following certificates:
- </p>
- <list type="bulleted">
- <item>the <em>erlangCA</em> root certificate (a self-signed
- certificate), </item>
- <item>the <em>otpCA</em> certificate signed by the <em>erlangCA</em>, </item>
- <item>a client certificate signed by the <em>otpCA</em>, and</item>
- <item>a server certificate signed by the <em>otpCA</em>.</item>
- </list>
-
- <section>
- <title>The openssl configuration file</title>
- <p>An <c>openssl</c> configuration file consist of a number of
- sections, where each section starts with one line containing
- <c>[ section_name ]</c>, where <c>section_name</c> is the name
- of the section. The first section of the file is either
- unnamed, or is named <c>[ default ]</c>. For further details
- see the OpenSSL config(5) manual page.
- </p>
- <p>The required sections for the subcommands we are going to
- use are as follows:
- </p>
- <table>
- <row>
- <cell align="left" valign="middle">subcommand</cell>
- <cell align="left" valign="middle">required/default section</cell>
- <cell align="left" valign="middle">override command line option</cell>
- <cell align="left" valign="middle">configuration file option</cell>
- </row>
- <row>
- <cell align="left" valign="middle">req</cell>
- <cell align="left" valign="middle">[req]</cell>
- <cell align="left" valign="middle">-</cell>
- <cell align="left" valign="middle"><c>-config FILE</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">ca</cell>
- <cell align="left" valign="middle">[ca]</cell>
- <cell align="left" valign="middle"><c>-name section</c></cell>
- <cell align="left" valign="middle"><c>-config FILE</c></cell>
- </row>
- <tcaption>openssl subcommands to use</tcaption>
- </table>
- </section>
-
- <section>
- <title>Creating the Erlang root CA</title>
- <p>The Erlang root CA is created with the command</p>
- <code type="none">
- openssl req -new -x509 -config /some/path/req.cnf \\
- -keyout /some/path/key.pem -out /some/path/cert.pem </code>
- <p>where the option <c>-new</c> indicates that we want to create
- a new certificate request and the option <c>-x509</c> implies
- that a self-signed certificate is created.
- </p>
- </section>
-
- <section>
- <title>Creating the OTP CA</title>
- <p>The OTP CA is created by first creating a certificate request
- with the command</p>
- <code type="none">
- openssl req -new -config /some/path/req.cnf \\
- -keyout /some/path/key.pem -out /some/path/req.pem </code>
- <p>and the ask the Erlang CA to sign it:</p>
- <code type="none">
- openssl ca -batch -notext -config /some/path/req.cnf \\
- -extensions ca_cert -in /some/path/req.pem -out /some/path/cert.pem </code>
- <p>where the option <c>-extensions</c> refers to a section in the
- configuration file saying that it should create a CA certificate,
- and not a plain user certificate.
- </p>
- <p>The <c>client</c> and <c>server</c> certificates are created
- similarly, except that the option <c>-extensions</c> then has the
- value <c>user_cert</c>.
- </p>
- </section>
- </section>
-
- <section>
- <title>An Example</title>
- <p>The following module <c>create_certs</c> is used by the Erlang/OTP
- SSL application for generating certificates to be used in tests. The
- source code is also found in <c>ssl-X.Y.Z/examples/certs/src</c>.
- </p>
- <p>The purpose of the <c>create_certs:all/1</c> function is to make
- it possible to provide from the <c>erl</c> command line, the
- full path name of the <c>openssl</c> command.
- </p>
- <p>Note that the module creates temporary OpenSSL configuration files
- for the <c>req</c> and <c>ca</c> subcommands.
- </p>
- <codeinclude file="../../examples/certs/src/make_certs.erl" tag="" type="erl"></codeinclude>
- </section>
-</chapter>
-
-
diff --git a/lib/ssl/doc/src/insidecover.xml b/lib/ssl/doc/src/insidecover.xml
deleted file mode 100644
index 4f3f5e5951..0000000000
--- a/lib/ssl/doc/src/insidecover.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE bookinsidecover SYSTEM "bookinsidecover.dtd">
-
-<bookinsidecover>
-The Erlang/OTP SSL application includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/). Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. <br></br>
-This product includes cryptographic software written by Eric Young ([email protected]). This product includes software written by Tim Hudson ([email protected]). Copyright (C) 1995-1998 Eric Young ([email protected]). All rights reserved. <br></br>
-For further OpenSSL and SSLeay license information se the chapter <bold>Licenses</bold>
-. <vfill></vfill>
- <br></br>
- <tt>http://www.erlang.org</tt>
- <br></br>
-</bookinsidecover>
-
-
diff --git a/lib/ssl/doc/src/licenses.xml b/lib/ssl/doc/src/licenses.xml
deleted file mode 100644
index 0969f9ad6e..0000000000
--- a/lib/ssl/doc/src/licenses.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Licenses</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-05-26</date>
- <rev>A</rev>
- <file>licenses.xml</file>
- </header>
- <p> <marker id="licenses"></marker>
-This chapter contains in extenso versions
- of the OpenSSL and SSLeay licenses.
- </p>
-
- <section>
- <title>OpenSSL License</title>
- <code type="none">
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * ([email protected]). This product includes software written by Tim
- * Hudson ([email protected]).
- *
- */ </code>
- </section>
-
- <section>
- <title>SSLeay License</title>
- <code type="none">
-/* Copyright (C) 1995-1998 Eric Young ([email protected])
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young ([email protected]).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson ([email protected]).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young ([email protected])"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson ([email protected])"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */ </code>
- </section>
-</chapter>
-
-
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 151b685941..95e968aa22 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -819,7 +819,7 @@
<title>Fixed Bugs and Malfunctions</title>
<list type="bulleted">
<item>
- <p>When a file descriptor was marked for closing, and and
+ <p>When a file descriptor was marked for closing, and
end-of-file condition had already been detected, the file
descriptor was never closed.</p>
<p>Own Id: OTP-5093 Aux Id: seq8806 </p>
diff --git a/lib/ssl/doc/src/refman.xml b/lib/ssl/doc/src/refman.xml
index 9658e229eb..68f84660f3 100644
--- a/lib/ssl/doc/src/refman.xml
+++ b/lib/ssl/doc/src/refman.xml
@@ -45,7 +45,8 @@
</description>
<xi:include href="ssl_app.xml"/>
<xi:include href="ssl.xml"/>
- <xi:include href="old_ssl.xml"/>
+ <xi:include href="old_ssl.xml"/>
+ <xi:include href="ssl_session_cache_api.xml"/>
</application>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 75aa8f2fe9..def61bcf03 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -21,13 +21,6 @@
</legalnotice>
<title>ssl</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible>Ingela Anderton Andin</responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2003-03-25</date>
- <rev></rev>
<file>ssl.xml</file>
</header>
<module>ssl</module>
@@ -185,8 +178,17 @@ end
{bad_cert, cert_expired}, {bad_cert, invalid_issuer},
{bad_cert, invalid_signature}, {bad_cert, name_not_permitted},
{bad_cert, cert_revoked} (not implemented yet),
- {bad_cert, unknown_critical_extension} or {bad_cert, term()} (Will
- be relevant later when an option is added for the user to be able to verify application specific extensions.)
+ {bad_cert, unknown_critical_extension} or {bad_cert, term()}
+ </item>
+
+
+ <tag>{validate_extensions_fun, fun()}</tag>
+ <item>
+ This options makes it possible to supply a fun to validate
+ possible application specific certificate extensions
+ during the certificat path validation. This option
+ will be better documented onec the public_key API is more
+ mature.
</item>
<tag>{depth, integer()}</tag>
@@ -231,7 +233,8 @@ end
</item>
<tag>{ssl_imp, ssl_imp()}</tag>
- <item>Specify which ssl implementation you want to use.
+ <item>Specify which ssl implementation you want to use. Defaults to
+ new.
</item>
<tag>{reuse_sessions, boolean()}</tag>
@@ -248,6 +251,15 @@ end
certificate, Compression is an enumeration integer
and CipherSuite of type ciphersuite().
</item>
+
+ <tag>{secure_renegotiate, boolean()}</tag>
+ <item>Specifies if to reject renegotiation attempt that does
+ not live up to RFC 5746. By default secure_renegotiate is
+ set to false e.i. secure renegotiation will be used if possible
+ but it will fallback to unsecure renegotiation if the peer
+ does not support RFC 5746.
+ </item>
+
</taglist>
</section>
@@ -414,7 +426,6 @@ end
<type>
<v>Socket = sslsocket()</v>
<v>Cert = binary()</v>
- <v>Subject = term()</v>
</type>
<desc>
<p>The peer certificate is returned as a DER encoded binary.
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index fac2053532..2ba6f48611 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -22,38 +22,11 @@
</legalnotice>
<title>ssl</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2005-03-10</date>
- <rev>E</rev>
<file>ssl_app.sgml</file>
</header>
<app>ssl</app>
- <appsummary>The SSL Application</appsummary>
- <description>
- <p>The Secure Socket Layer (SSL) application provides secure
- socket communication over TCP/IP. Note that this documentation
- is mainly valid for the old ssl implementation and will
- be replaced in a future release.
- </p>
- </description>
-
- <section>
- <title>Warning</title>
- <p>In previous versions of Erlang/OTP SSL it was advised, as a
- work-around, to set the operating system environment variable
- <c>SSL_CERT_FILE</c> to point at a file containing CA
- certificates. That variable is no longer needed, and is not
- recognised by Erlang/OTP SSL any more.
- </p>
- <p>However, the OpenSSL package does interpret that environment
- variable. Hence a setting of that variable might have
- unpredictable effects on the Erlang/OTP SSL application. It is
- therefore adviced to not used that environment variable at all.</p>
- </section>
+ <appsummary>The SSL application provides secure communication over
+ sockets.</appsummary>
<section>
<title>Environment</title>
@@ -63,115 +36,43 @@
</p>
<p>Note that the environment parameters can be set on the command line,
for instance,</p>
- <p><c>erl ... -ssl protocol_version '[sslv2,sslv3]' ...</c>.
+ <p><c>erl ... -ssl protocol_version '[sslv3, tlsv1]' ...</c>.
</p>
<taglist>
- <tag><c><![CDATA[ephemeral_rsa = true | false <optional>]]></c></tag>
+ <tag><c><![CDATA[protocol_version = [sslv3|tlsv1] <optional>]]></c>.</tag>
<item>
- <p>Enables all SSL servers (those that listen and accept)
- to use ephemeral RSA key generation when a clients connect with
- weak handshake cipher specifications, that need equally weak
- ciphers from the server (i.e. obsolete restrictions on export
- ciphers). Default is <c>false</c>.
- </p>
+ <p>Protocol that will be supported by started clients and
+ servers. If this option is not set it will default to all
+ protocols currently supported by the erlang ssl application.
+ Note that this option may be overridden by the version option
+ to ssl:connect/[2,3] and ssl:listen/2.
+ </p>
</item>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- output. Default is <c>false</c>.
- </p>
- </item>
- <tag><c><![CDATA[debugdir = path() | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information output controlled by <c>debug</c>
- and <c>msgdebug</c> to be printed to a file named
- <c><![CDATA[ssl_esock.<pid>.log]]></c> in the directory specified by
- <c>debugdir</c>, where <c><![CDATA[<pid>]]></c> is the operating system
- specific textual representation of the process identifier
- of the external port program of the SSL application. Default
- is <c>false</c>, i.e. no log file is produced.
- </p>
- </item>
- <tag><c><![CDATA[msgdebug = true | false <optional>]]></c></tag>
- <item>
- <p>Sets <c>debug = true</c> and causes also the contents
- of low level messages to be printed to standard output.
- Default is <c>false</c>.
- </p>
- </item>
- <tag><c><![CDATA[port_program = string() | false <optional>]]></c></tag>
- <item>
- <p>Name of port program. The default is <c>ssl_esock</c>.
- </p>
- </item>
- <tag><c><![CDATA[protocol_version = [sslv2|sslv3|tlsv1] <optional>]]></c>.</tag>
+
+ <tag><c><![CDATA[session_lifetime = integer() <optional>]]></c></tag>
<item>
- <p>Name of protocols to use. If this option is not set,
- all protocols are assumed, i.e. the default value is
- <c>[sslv2, sslv3, tlsv1]</c>.
- </p>
+ <p>The lifetime of session data in seconds.
+ </p>
</item>
- <tag><c><![CDATA[proxylsport = integer() | false <optional>]]></c></tag>
+
+ <tag><c><![CDATA[session_cb = atom() <optional>]]></c></tag>
<item>
- <p>Define the port number of the listen port of the
- SSL port program. Almost never is this option needed.
+ <p>
+ Name of session cache callback module that implements
+ the ssl_session_cache_api behavior, defaults to
+ ssl_session_cache.erl.
</p>
</item>
- <tag><c><![CDATA[proxylsbacklog = integer() | false <optional>]]></c></tag>
+
+ <tag><c><![CDATA[session_cb_init_args = list() <optional>]]></c></tag>
<item>
- <p>Set the listen queue size of the listen port of the
- SSL port program. The default is 128.
- </p>
+ <p>
+ List of arguments to the init function in session cache
+ callback module, defaults to [].
+ </p>
</item>
- </taglist>
- </section>
-
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang SSL application is
- based on the <em>OpenSSL</em> package version 0.9.7 or higher.
- There are source and binary releases on the web.
- </p>
- <p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the libraries
- <c>libcrypto.so</c> and <c>libssl.so</c> (Unix), or the
- libraries <c>libeay32.dll</c> and <c>ssleay32.dll</c> (Win32).
- </p>
- <p>For Unix The <c>ssl_esock</c> port program is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the SSL
- <c>priv/obj</c> directory, should be used as a guide to
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the libraries can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
- <section>
- <title>Restrictions</title>
- <p>Users must be aware of export restrictions and patent rights
- concerning cryptographic software.
- </p>
+ </taglist>
</section>
<section>
@@ -180,5 +81,3 @@
</section>
</appref>
-
-
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index c743cd67a3..4067fb8a22 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -32,7 +32,13 @@
<file>ssl_distribution.xml</file>
</header>
<p>This chapter describes how the Erlang distribution can use
- SSL to get additional verification and security.</p>
+ SSL to get additional verification and security.
+
+ <note><p>Note this
+ documentation is written for the old ssl implementation and
+ will be updated for the new one once this functionallity is
+ supported by the new implementation.</p></note>
+ </p>
<section>
<title>Introduction</title>
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 3dc2332795..726b9a4eeb 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -13,337 +13,138 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
- <title>The SSL Protocol</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-04-28</date>
- <rev>PA2</rev>
+ <title>Transport Layer Security (TLS) and its predecessor, Secure Socket Layer (SSL)</title>
<file>ssl_protocol.xml</file>
</header>
- <p>Here we provide a short introduction to the SSL protocol. We only
- consider those part of the protocol that are important from a
- programming point of view.
- </p>
- <p>For a very good general introduction to SSL and TLS see the book
- <cite id="rescorla"></cite>.
- </p>
- <p><em>Outline:</em></p>
- <list type="bulleted">
- <item>Two types of connections - connection: handshake, data transfer, and
- shutdown -
- SSL/TLS protocol - server must have certificate - what the the
- server sends to the client - client may verify the server -
- server may ask client for certificate - what the client sends to
- the server - server may then verify the client - verification -
- certificate chains - root certificates - public keys - key
- agreement - purpose of certificate - references</item>
- </list>
+
+ <p>The erlang ssl application currently supports SSL 3.0 and TLS 1.0
+ RFC 2246, and will in the future also support later versions of TLS.
+ SSL 2.0 is not supported.
+ </p>
- <section>
- <title>SSL Connections</title>
- <p>The SSL protocol is implemented on top of the TCP/IP protocol.
- From an endpoint view it also has the same type of connections
- as that protocol, almost always created by calls to socket
- interface functions <em>listen</em>, <em>accept</em> and
- <em>connect</em>. The endpoints are <em>servers</em> and
- <em>clients</em>.
- </p>
- <p>A <em>server</em><em>listen</em>s for connections on a
- specific address and port. This is done once. The server then
- <em>accept</em>s each connections on that same address and
- port. This is typically done indefinitely many times.
- </p>
- <p>A <em>client</em> connects to a server on a specific address
- and port. For each purpose this is done once.
- </p>
- <p>For a plain TCP/IP connection the establishment of a connection
- (through an accept or a connect) is followed by data transfer between
- the client and server, finally ended by a connection close.
- </p>
- <p>An SSL connection also consists of data transfer and connection
- close, However, the data transfer contains encrypted data, and
- in order to establish the encryption parameters, the data
- transfer is preceded by an SSL <em>handshake</em>. In this
- handshake the server plays a dominant role, and the main
- instrument used in achieving a valid SSL connection is the
- server's <em>certificate</em>. We consider certificates in the
- next section, and the SSL handshake in a subsequent section.</p>
- </section>
+ <p>By default erlang ssl is run over the TCP/IP protocol even
+ though you could plug in an other reliable transport protocol
+ with the same API as gen_tcp.</p>
+
+ <p>If a client and server wants to use an upgrade mechanism, such as
+ defined by RFC2817, to upgrade a regular TCP/IP connection to a ssl
+ connection the erlang ssl API supports this. This can be useful for
+ things such as supporting HTTP and HTTPS on the same port and
+ implementing virtual hosting.
+ </p>
<section>
- <title>Certificates</title>
- <p>A certificate is similar to a driver's license, or a
- passport. The holder of the certificate is called the
- <em>subject</em>. First of all the certificate identifies the
- subject in terms of the name of the subject, its postal address,
- country name, company name (if applicable), etc.
- </p>
- <p>Although a driver's license is always issued by a well-known and
- distinct authority, a certificate may have an <em>issuer</em>
- that is not so well-known. Therefore a certificate also always
- contains information on the issuer of the certificate. That
- information is of the same type as the information on the
- subject. The issuer of a certificate also signs the certificate
- with a <em>digital signature</em> (the signature is an inherent
- part of the certificate), which allow others to verify that the
- issuer really is the issuer of the certificate.
- </p>
- <p>Now that a certificate can be checked by verifying the
- signature of the issuer, the question is how to trust the
- issuer. The answer to this question is to require that there is
- a certificate for the issuer as well. That issuer has in turn an
- issuer, which must also have a certificate, and so on. This
- <em>certificate chain</em> has to have en end, which then must
- be a certificate that is trusted by other means. We shall cover
- this problem of <em>authentication</em> in a subsequent
- section.
- </p>
+ <title>Security overview</title>
+
+ <p>To achive authentication and privacy the client and server will
+ perform a TLS Handshake procedure before transmitting or receiving
+ any data. During the handshake they agree on a protocol version and
+ cryptographic algorithms, they generate shared secrets using public
+ key cryptographics and optionally authenticate each other with
+ digital certificates.</p>
</section>
-
+
<section>
- <title>Encryption Algorithms</title>
- <p>An encryption algorithm is a mathematical algorithm for
- encryption and decryption of messages (arrays of bytes,
- say). The algorithm as such is always required to be publicly
- known, otherwise its strength cannot be evaluated, and hence it
- cannot be used reliably. The secrecy of an encrypted message is
- not achieved by the secrecy of the algorithm used, but by the
- secrecy of the <em>keys</em> used as input to the encryption and
- decryption algorithms. For an account of cryptography in general
- see <cite id="schneier"></cite>.
- </p>
- <p>There are two classes of encryption algorithms: <em>symmetric key</em> algorithms and <em>public key</em> algorithms. Both
- types of algorithms are used in the SSL protocol.
- </p>
- <p>In the sequel we assume holders of keys keep them secret (except
- public keys) and that they in that sense are trusted. How a
- holder of a secret key is proved to be the one it claims to be
- is a question of <em>authentication</em>, which, in the context
- of the SSL protocol, is described in a section further below.
- </p>
-
- <section>
- <title>Symmetric Key Algorithms</title>
- <p>A <em>symmetric key</em> algorithm has one key only. The key
- is used for both encryption and decryption. Obviously the key
- of a symmetric key algorithm must always be kept secret by the
- users of the key. DES is an example of a symmetric key
- algorithm.
- </p>
- <p>Symmetric key algorithms are fast compared to public key
- algorithms. They are therefore typically used for encrypting
- bulk data.
- </p>
- </section>
-
- <section>
- <title>Public Key Algorithms</title>
- <p>A <em>public key</em> algorithm has two keys. Any of the two
- keys can be used for encryption. A message encrypted with one
- of the keys, can only be decrypted with the other key. One of
- the keys is public (known to the world), while the other key
- is private (i.e. kept secret) by the owner of the two keys.
- </p>
- <p>RSA is an example of a public key algorithm.
- </p>
- <p>Public key algorithms are slow compared to symmetric key
- algorithms, and they are therefore seldom used for bulk data
- encryption. They are therefore only used in cases where the
- fact that one key is public and the other is private, provides
- features that cannot be provided by symmetric algorithms.
- </p>
- </section>
-
- <section>
- <title>Digital Signature Algorithms</title>
- <p>An interesting feature of a public key algorithm is that its
- public and private keys can both be used for encryption.
- Anyone can use the public key to encrypt a message, and send
- that message to the owner of the private key, and be sure of
- that only the holder of the private key can decrypt the
- message.
- </p>
- <p>On the other hand, the owner of the private key can encrypt a
- message with the private key, thus obtaining an encrypted
- message that can decrypted by anyone having the public key.
- </p>
- <p>The last approach can be used as a digital signature
- algorithm. The holder of the private key signs an array of
- bytes by performing a specified well-known <em>message digest algorithm</em> to compute a hash of the array, encrypts the
- hash value with its private key, an then presents the original
- array, the name of the digest algorithm, and the encryption of
- the hash value as a <em>signed array of bytes</em>.
- </p>
- <p>Now anyone having the public key, can decrypt the encrypted
- hash value with that key, compute the hash with the specified
- digest algorithm, and check that the hash values compare equal
- in order to verify that the original array was indeed signed
- by the holder of the private key.
- </p>
- <p>What we have accounted for so far is by no means all that can
- be said about digital signatures (see <cite id="schneier"></cite>for
- further details).
- </p>
- </section>
-
- <section>
- <title>Message Digests Algorithms</title>
- <p>A message digest algorithm is a hash function that accepts
- an array bytes of arbitrary but finite length of input, and
- outputs an array of bytes of fixed length. Such an algorithm
- is also required to be very hard to invert.
- </p>
- <p>MD5 (16 bytes output) and SHA1 (20 bytes output) are examples
- of message digest algorithms.
- </p>
- </section>
+ <title>Data Privacy and Integrity</title>
+
+ <p>A <em>symmetric key</em> algorithm has one key only. The key is
+ used for both encryption and decryption. These algoritms are fast
+ compared to public key algorithms (using two keys, a public and a
+ private one) and are therefore typically used for encrypting bulk
+ data.
+ </p>
+
+ <p>The keys for the symmetric encryption are generated uniquely
+ for each connection and are based on a secret negotiated
+ in the TLS handshake. </p>
+
+ <p>The TLS handsake protocol and data transfer is run on top of
+ the TLS Record Protocol that uses a keyed-hash MAC (Message
+ Authenticity Code), or HMAC, to protect the message's data
+ integrity. From the TLS RFC "A Message Authentication Code is a
+ one-way hash computed from a message and some secret data. It is
+ difficult to forge without knowing the secret data. Its purpose is
+ to detect if the message has been altered."
+ </p>
+
</section>
- <section>
- <title>SSL Handshake</title>
- <p>The main purpose of the handshake performed before an an SSL
- connection is established is to negotiate the encryption
- algorithm and key to be used for the bulk data transfer between
- the client and the server. We are writing <em>the</em> key,
- since the algorithm to choose for bulk encryption one of the
- symmetric algorithms.
- </p>
- <p>There is thus only one key to agree upon, and obviously that
- key has to be kept secret between the client and the server. To
- obtain that the handshake has to be encrypted as well.
- </p>
- <p>The SSL protocol requires that the server always sends its
- certificate to the client in the beginning of the handshake. The
- client then retrieves the server's public key from the
- certificate, which means that the client can use the server's
- public key to encrypt messages to the server, and the server can
- decrypt those messages with its private key. Similarly, the
- server can encrypt messages to the client with its private key,
- and the client can decrypt messages with the server's public
- key. It is thus is with the server's public and private keys
- that messages in the handshake are encrypted and decrypted, and
- hence the key agreed upon for symmetric encryption of bulk data
- can be kept secret (there are more things to consider to really
- keep it secret, see <cite id="rescorla"></cite>).
- </p>
- <p>The above indicates that the server does not care who is
- connecting, and that only the client has the possibility to
- properly identify the server based on the server's certificate.
- That is indeed true in the minimal use of the protocol, but it
- is possible to instruct the server to request the certificate of
- the client, in order to have a means to identify the client, but
- it is by no means required to establish an SSL connection.
- </p>
- <p>If a server request the client certificate, it verifies, as a
- part of the protocol, that the client really holds the private
- key of the certificate by sending the client a string of bytes
- to encrypt with its private key, which the server then decrypts
- with the client's public key, the result of which is compared
- with the original string of bytes (a similar procedure is always
- performed by the client when it has received the server's
- certificate).
- </p>
- <p>The way clients and servers <em>authenticate</em> each other,
- i.e. proves that their respective peers are what they claim to
- be, is the topic of the next section.
- </p>
- </section>
+ <section>
+ <title>Digital Certificates</title>
+ <p>A certificate is similar to a driver's license, or a
+ passport. The holder of the certificate is called the
+ <em>subject</em>. The certificate is signed
+ with the private key of the issuer of the certificate. A chain
+ of trust is build by having the issuer in its turn being
+ certified by an other certificate and so on until you reach the
+ so called root certificate that is self signed e.i. issued
+ by itself.</p>
+
+ <p>Certificates are issued by <em>certification
+ authorities</em> (<em>CA</em>s) only. There are a handful of
+ top CAs in the world that issue root certificates. You can
+ examine the certificates of several of them by clicking
+ through the menus of your web browser.
+ </p>
+ </section>
+
+ <section>
+ <title>Authentication of Sender</title>
+
+ <p>Authentication of the sender is done by public key path
+ validation as defined in RFC 3280. Simplified that means that
+ each certificate in the certificate chain is issued by the one
+ before, the certificates attributes are valid ones, and the
+ root cert is a trusted cert that is present in the trusted
+ certs database kept by the peer.</p>
+
+ <p>The server will always send a certificate chain as part of
+ the TLS handshake, but the client will only send one if
+ the server requests it. If the client does not have
+ an appropriate certificate it may send an "empty" certificate
+ to the server.</p>
+
+ <p>The client may choose to accept some path evaluation errors
+ for instance a web browser may ask the user if they want to
+ accept an unknown CA root certificate. The server, if it request
+ a certificate, will on the other hand not accept any path validation
+ errors. It is configurable if the server should accept
+ or reject an "empty" certificate as response to
+ a certificate request.</p>
+ </section>
+
+ <section>
+ <title>TLS Sessions</title>
+
+ <p>From the TLS RFC "A TLS session is an association between a
+ client and a server. Sessions are created by the handshake
+ protocol. Sessions define a set of cryptographic security
+ parameters, which can be shared among multiple
+ connections. Sessions are used to avoid the expensive negotiation
+ of new security parameters for each connection."</p>
- <section>
- <title>Authentication</title>
- <p>As we have already seen the reception of a certificate from a
- peer is not enough to prove that the peer is authentic. More
- certificates are needed, and we have to consider how certificates
- are issued and on what grounds.
- </p>
- <p>Certificates are issued by <em>certification authorities</em>
- (<em>CA</em>s) only. They issue certificates both for other CAs
- and ordinary users (which are not CAs).
- </p>
- <p>Certain CAs are <em>top CAs</em>, i.e. they do not have a
- certificate issued by another CA. Instead they issue their own
- certificate, where the subject and issuer part of the
- certificate are identical (such a certificate is called a
- self-signed certificate). A top CA has to be well-known, and has
- to have a publicly available policy telling on what grounds it
- issues certificates.
- </p>
- <p>There are a handful of top CAs in the world. You can examine the
- certificates of several of them by clicking through the menus of
- your web browser.
- </p>
- <p>A top CA typically issues certificates for other CAs, called
- <em>intermediate CAs</em>, but possibly also to ordinary users. Thus
- the certificates derivable from a top CA constitute a tree, where
- the leaves of the tree are ordinary user certificates.
- </p>
- <p>A <em>certificate chain</em> is an ordered sequence of
- certificates, <c>C1, C2, ..., Cn</c>, say, where <c>C1</c> is a
- top CA certificate, and where <c>Cn</c> is an ordinary user
- certificate, and where the holder of <c>C1</c> is the issuer of
- <c>C2</c>, the holder of <c>C2</c> is the issuer of <c>C3</c>,
- ..., and the holder of <c>Cn-1</c> is the issuer of <c>Cn</c>,
- the ordinary user certificate. The holders of <c>C2, C3, ..., Cn-1</c> are then intermediate CAs.
- </p>
- <p>Now to verify that a certificate chain is unbroken we have to
- take the public key from each certificate <c>Ck</c>, and apply
- that key to decrypt the signature of certificate <c>Ck-1</c>,
- thus obtaining the message digest computed by the holder of the
- <c>Ck</c> certificate, compute the real message digest of the
- <c>Ck-1</c> certificate and compare the results. If they compare
- equal the link of the chain between <c>Ck</c> and <c>Ck-1</c> is
- considered to unbroken. This is done for each link k = 1, 2,
- ..., n-1. If all links are found to be unbroken, the user
- certificate <c>Cn</c> is considered authenticated.
- </p>
+ <p>Session data is by default kept by the ssl application in a
+ memory storage hence session data will be lost at application
+ restart or takeover. Users may define their own callback module
+ to handle session data storage if persistent data storage is
+ required. Session data will also be invalidated after 24 hours
+ from it was saved, for security reasons. It is of course
+ possible to configure the amount of time the session data should be
+ saved.</p>
- <section>
- <title>Trusted Certificates</title>
- <p>Now that there is a way to authenticate a certificate by
- checking that all links of a certificate chain are unbroken,
- the question is how you can be sure to trust the certificates
- in the chain, and in particular the top CA certificate of the
- chain.
- </p>
- <p>To provide an answer to that question consider the
- perspective of a client, which have just received the
- certificate of the server. In order to authenticate the server
- the client has to construct a certificate chain and to prove
- that the chain is unbroken. The client has to have a set of CA
- certificates (top CA or intermediate CA certificates) not
- obtained from the server, but obtained by other means. Those
- certificates are kept <c>locally</c> by the client, and are
- trusted by the client.
- </p>
- <p>More specifically, the client does not really have to have
- top CA certificates in its local storage. In order to
- authenticate a server it is sufficient for the client to
- posses the trusted certificate of the issuer of the server
- certificate.
- </p>
- <p>Now that is not the whole story. A server can send an
- (incomplete) certificate chain to its client, and then the
- task of the client is to construct a certificate chain that
- begins with a trusted certificate and ends with the server's
- certificate. (A client can also send a chain to its server,
- provided the server requested the client's certificate.)
- </p>
- <p>All this means that an unbroken certificate chain begins with
- a trusted certificate (top CA or not), and ends with the peer
- certificate. That is the end of the chain is obtained from the
- peer, but the beginning of the chain is obtained from local
- storage, which is considered trusted.
- </p>
- </section>
- </section>
-</chapter>
+ <p>Ssl clients will by default try to reuse an available session,
+ ssl servers will by default agree to reuse sessions when clients
+ ask to do so.</p>
+
+ </section>
+ </chapter>
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
new file mode 100644
index 0000000000..7b70c6cf34
--- /dev/null
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2010</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+ <title>ssl</title>
+ <file>ssl_session_cache_api.xml</file>
+ </header>
+ <module>ssl_session_cache_api</module>
+ <modulesummary>Defines the API for the TLS session cache so
+ that the datastorge scheme can be replaced by
+ defining a new callback module implementing this API.</modulesummary>
+
+ <section>
+ <title>Common Data Types</title>
+
+ <p>The following data types are used in the functions below:
+ </p>
+
+ <p><c>cache_ref() = opaque()</c></p>
+
+ <p><c>key() = {partialkey(), session_id()}</c></p>
+
+ <p><c>partialkey() = opaque()</c></p>
+
+ <p><c>session_id() = binary()</c></p>
+
+ <p><c>session() = opaque()</c></p>
+
+ </section>
+
+ <funcs>
+
+ <func>
+ <name>delete(Cache, Key) -> _</name>
+ <fsummary></fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ </type>
+ <desc>
+ <p> Delets a cache entry. Will only be called from the cache
+ handling process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>foldl(Fun, Acc0, Cache) -> Acc</name>
+ <fsummary></fsummary>
+ <type>
+ <v></v>
+ </type>
+ <desc>
+ <p>Calls Fun(Elem, AccIn) on successive elements of the
+ cache, starting with AccIn == Acc0. Fun/2 must return a new
+ accumulator which is passed to the next call. The function returns
+ the final value of the accumulator. Acc0 is returned if the cache is
+ empty.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>init() -> opaque() </name>
+ <fsummary>Return cache reference</fsummary>
+ <type>
+ <v></v>
+ </type>
+ <desc>
+ <p>Performes possible initializations of the cache and returns
+ a reference to it that will be used as parameter to the other
+ api functions. Will be called by the cache handling processes
+ init function, hence puting the same requierments on it as
+ a normal process init function.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>lookup(Cache, Key) -> Entry</name>
+ <fsummary> Looks up a cach entry.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ <v> Entry = session() | undefined </v>
+ </type>
+ <desc>
+ <p>Looks up a cach entry. Should be callable from any
+ process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>select_session(Cache, PartialKey) -> [session()]</name>
+ <fsummary>>Selects sessions that could be reused.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> PartialKey = partialkey()</v>
+ <v> Session = session()</v>
+ </type>
+ <desc>
+ <p>Selects sessions that could be reused. Should be callable
+ from any process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>terminate(Cache) -> _</name>
+ <fsummary>Called by the process that handles the cache when it
+ is aboute to terminat.</fsummary>
+ <type>
+ <v>Cache = term() - as returned by init/0</v>
+ </type>
+ <desc>
+ <p>Takes care of possible cleanup that is needed when the
+ cache handling process terminates.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>update(Cache, Key, Session) -> _</name>
+ <fsummary> Caches a new session or updates a already cached one.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ <v> Session = session()</v>
+ </type>
+ <desc>
+ <p> Caches a new session or updates a already cached one. Will
+ only be called from the cache handling process.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssl/doc/src/usersguide.xml b/lib/ssl/doc/src/usersguide.xml
index 76ee13dd23..6528c00a0b 100644
--- a/lib/ssl/doc/src/usersguide.xml
+++ b/lib/ssl/doc/src/usersguide.xml
@@ -23,35 +23,17 @@
<title>SSL User's Guide</title>
<prepared>OTP Team</prepared>
- <docno></docno>
<date>2003-05-26</date>
- <rev>B</rev>
<file>usersguide.sgml</file>
</header>
<description>
<p>The <em>SSL</em> application provides secure communication over
- sockets. Note that this users guide was written for
- the old ssl implementation that is now being phased out and
- will be replaced by a new guide in a future release.
- </p>
- <p>This product includes software developed by the OpenSSL Project for
- use in the OpenSSL Toolkit (http://www.openssl.org/).
- </p>
- <p>This product includes cryptographic software written by Eric Young
- </p>
- <p>This product includes software written by Tim Hudson
- </p>
- <p>For full OpenSSL and SSLeay license texts, see <seealso marker="licenses#licenses">Licenses</seealso>.
+ sockets.
</p>
</description>
<xi:include href="ssl_protocol.xml"/>
<xi:include href="using_ssl.xml"/>
- <xi:include href="pkix_certs.xml"/>
- <xi:include href="create_certs.xml"/>
<xi:include href="ssl_distribution.xml"/>
- <xi:include href="licenses.xml"/>
</part>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
new file mode 100644
index 0000000000..4bdd8f97b4
--- /dev/null
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Using the SSL API</title>
+ <file>using_ssl.xml</file>
+ </header>
+
+ <section>
+ <title>General information</title>
+ <p>To see relevant version information for ssl you can
+ call ssl:versions/0</p>
+
+ <p>To see all supported cipher suites
+ call ssl:cipher_suites/0. Note that available cipher suites
+ for a connection will depend on your certificate. It is also
+ possible to specify a specific cipher suite(s) that you
+ want your connection to use. Default is to use the strongest
+ available.</p>
+
+ </section>
+
+ <section>
+ <title>Setting up connections</title>
+
+ <p>Here follows some small example of how to set up client/server connections
+ using the erlang shell. The returned value of the sslsocket has been abbreviated with
+ <c>[...]</c> as it can be fairly large and is opaque.</p>
+
+ <section>
+ <title>Minmal example</title>
+
+ <note><p> The minimal setup is not the most secure setup of ssl.</p>
+ </note>
+
+ <p> Start server side</p>
+ <code type="erl">1 server> ssl:start().
+ok</code>
+
+ <p>Create a ssl listen socket</p>
+ <code type="erl">2 server> {ok, ListenSocket} =
+ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}]).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Do a transport accept on the ssl listen socket</p>
+ <code type="erl">3 server> {ok, Socket} = ssl:transport_accept(ListenSocket).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Start client side</p>
+ <code type="erl">1 client> ssl:start().
+ok</code>
+
+ <code type="erl">2 client> {ok, Socket} = ssl:connect("localhost", 9999, [], infinity).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Do the ssl handshake</p>
+ <code type="erl">4 server> ok = ssl:ssl_accept(Socket).
+ok</code>
+
+ <p>Send a messag over ssl</p>
+ <code type="erl">5 server> ssl:send(Socket, "foo").
+ok</code>
+
+ <p>Flush the shell message queue to see that we got the message
+ sent on the server side</p>
+ <code type="erl">3 client> flush().
+Shell got {ssl,{sslsocket,[...]},"foo"}
+ok</code>
+ </section>
+
+ <section>
+ <title>Upgrade example</title>
+
+ <note><p> To upgrade a TCP/IP connection to a ssl connection the
+ client and server have to aggre to do so. Agreement
+ may be accompliced by using a protocol such the one used by HTTP
+ specified in RFC 2817.</p> </note>
+
+ <p>Start server side</p>
+ <code type="erl">1 server> ssl:start().
+ok</code>
+
+ <p>Create a normal tcp listen socket</p>
+ <code type="erl">2 server> {ok, ListenSocket} = gen_tcp:listen(9999, [{reuseaddr, true}]).
+{ok, #Port&lt;0.475&gt;}</code>
+
+ <p>Accept client connection</p>
+ <code type="erl">3 server> {ok, Socket} = gen_tcp:accept(ListenSocket).
+{ok, #Port&lt;0.476&gt;}</code>
+
+ <p>Start client side</p>
+ <code type="erl">1 client> ssl:start().
+ok</code>
+
+ <code type="erl">2 client> {ok, Socket} = gen_tcp:connect("localhost", 9999, [], infinity).</code>
+
+ <p>Make sure active is set to false before trying
+ to upgrade a connection to a ssl connection, otherwhise
+ ssl handshake messages may be deliverd to the wrong process.</p>
+ <code type="erl">4 server> inet:setopts(Socket, [{active, false}]).
+ok</code>
+
+ <p>Do the ssl handshake.</p>
+ <code type="erl">5 server> {ok, SSLSocket} = ssl:ssl_accept(Socket, [{cacertfile, "cacerts.pem"},
+{certfile, "cert.pem"}, {keyfile, "key.pem"}]).
+{ok,{sslsocket,[...]}}</code>
+
+ <p> Upgrade to a ssl connection. Note that the client and server
+ must agree upon the upgrade and the server must call
+ ssl:accept/2 before the client calls ssl:connect/3.</p>
+ <code type="erl">3 client>{ok, SSLSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
+{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity).
+{ok,{sslsocket,[...]}}</code>
+
+ <p>Send a messag over ssl</p>
+ <code type="erl">4 client> ssl:send(SSLSocket, "foo").
+ok</code>
+
+ <p>Set active true on the ssl socket</p>
+ <code type="erl">4 server> ssl:setopts(SSLSocket, [{active, true}]).
+ok</code>
+
+ <p>Flush the shell message queue to see that we got the message
+ sent on the client side</p>
+ <code type="erl">5 server> flush().
+Shell got {ssl,{sslsocket,[...]},"foo"}
+ok</code>
+ </section>
+ </section>
+ </chapter>
diff --git a/lib/ssl/doc/src/using_ssl.xmlsrc b/lib/ssl/doc/src/using_ssl.xmlsrc
deleted file mode 100644
index ba74dcfef4..0000000000
--- a/lib/ssl/doc/src/using_ssl.xmlsrc
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Using the SSL application</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-04-23</date>
- <rev>PA2</rev>
- <file>using_ssl.xml</file>
- </header>
- <p>Here we provide an introduction to using the Erlang/OTP SSL
- application, which is accessed through the <c>ssl</c> interface
- module.
- </p>
- <p>We also present example code in the Erlang module
- <c>client_server</c>, also provided in the directory
- <c>ssl-X.Y.Z/examples</c>, with source code in <c>src</c> and the
- compiled module in <c>ebin</c> of that directory.
- </p>
-
- <section>
- <title>The ssl Module</title>
- <p>The <c>ssl</c> module provides the user interface to the Erlang/OTP
- SSL application. The interface functions provided are very similar
- to those provided by the <c>gen_tcp</c> and <c>inet</c> modules.
- </p>
- <p>Servers use the interface functions <c>listen</c> and
- <c>accept</c>. The <c>listen</c> function specifies a TCP port
- to to listen to, and each call to the <c>accept</c> function
- establishes an incoming connection.
- </p>
- <p>Clients use the <c>connect</c> function which specifies the address
- and port of a server to connect to, and a successful call establishes
- such a connection.
- </p>
- <p>The <c>listen</c> and <c>connect</c> functions have almost all
- the options that the corresponding functions in <c>gen_tcp/</c> have,
- but there are also additional options specific to the SSL protocol.
- </p>
- <p>The most important SSL specific option is the <c>cacertfile</c>
- option which specifies a local file containing trusted CA
- certificates which are and used for peer authentication. This
- option is used by clients and servers in case they want to
- authenticate their peers.
- </p>
- <p>The <c>certfile</c> option specifies a local path to a file
- containing the certificate of the holder of the connection
- endpoint. In case of a server endpoint this option is mandatory
- since the contents of the sever certificate is needed in the
- the handshake preceding the establishment of a connection.
- </p>
- <p>Similarly, the <c>keyfile</c> option points to a local file
- containing the private key of the holder of the endpoint. If the
- <c>certfile</c> option is present, this option has to be
- specified as well, unless the private key is provided in the
- same file as specified by the <c>certfile</c> option (a
- certificate and a private key can thus coexist in the same file).
- </p>
- <p>The <c>verify</c> option specifies how the peer should be verified:
- </p>
- <taglist>
- <tag>0</tag>
- <item>Do not verify the peer,</item>
- <tag>1</tag>
- <item>Verify peer,</item>
- <tag>2</tag>
- <item>Verify peer, fail the verification if the peer has no
- certificate. </item>
- </taglist>
- <p>The <c>depth</c> option specifies the maximum length of the
- verification certificate chain. Depth = 0 means the peer
- certificate, depth = 1 the CA certificate, depth = 2 the next CA
- certificate etc. If the verification process does not find a
- trusted CA certificate within the maximum length, the verification
- fails.
- </p>
- <p>The <c>ciphers</c> option specifies which ciphers to use (a
- string of colon separated cipher names). To obtain a list of
- available ciphers, evaluate the <c>ssl:ciphers/0</c> function
- (the SSL application has to be running).
- </p>
- </section>
-
- <section>
- <title>A Client-Server Example</title>
- <p>Here is a simple client server example.
- </p>
- <codeinclude file="../../examples/src/client_server.erl" tag="" type="erl"></codeinclude>
- </section>
-</chapter>
-
-
-
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 65f23e2f74..88cd73be74 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.0", [{restart_application, ssl}]},
{"3.11.1", [{restart_application, ssl}]},
{"3.11", [{restart_application, ssl}]},
{"3.10", [{restart_application, ssl}]},
@@ -15,6 +16,7 @@
{"3.10.9", [{restart_application, ssl}]}
],
[
+ {"4.0", [{restart_application, ssl}]},
{"3.11.1", [{restart_application, ssl}]},
{"3.11", [{restart_application, ssl}]},
{"3.10", [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 35d27713b8..6e26f05c3d 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -34,10 +34,12 @@
%% Should be deprecated as soon as old ssl is removed
%%-deprecated({pid, 1, next_major_release}).
+-deprecated({peercert, 2, next_major_release}).
-include("ssl_int.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -49,11 +51,11 @@
}).
%%--------------------------------------------------------------------
-%% Function: start([, Type]) -> ok
+-spec start() -> ok.
+-spec start(permanent | transient | temporary) -> ok.
%%
-%% Type = permanent | transient | temporary
-%%
-%% Description: Starts the ssl application. Default type
+%% Description: Utility function that starts the ssl,
+%% crypto and public_key applications. Default type
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
@@ -67,7 +69,7 @@ start(Type) ->
application:start(ssl, Type).
%%--------------------------------------------------------------------
-%% Function: stop() -> ok
+-spec stop() -> ok.
%%
%% Description: Stops the ssl application.
%%--------------------------------------------------------------------
@@ -75,7 +77,9 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
-%% Function: connect(Address, Port, Options[, Timeout]) -> {ok, Socket}
+-spec connect(host() | port(), list()) -> {ok, #sslsocket{}}.
+-spec connect(host() | port(), list() | port_num(), timeout() | list()) -> {ok, #sslsocket{}}.
+-spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}.
%%
%% Description: Connect to a ssl server.
%%--------------------------------------------------------------------
@@ -101,13 +105,13 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
{error, Reason}
end;
-connect(Address, Port, Options) ->
- connect(Address, Port, Options, infinity).
+connect(Host, Port, Options) ->
+ connect(Host, Port, Options, infinity).
-connect(Address, Port, Options0, Timeout) ->
+connect(Host, Port, Options0, Timeout) ->
case proplists:get_value(ssl_imp, Options0, new) of
new ->
- new_connect(Address, Port, Options0, Timeout);
+ new_connect(Host, Port, Options0, Timeout);
old ->
%% Allow the option reuseaddr to be present
%% so that new and old ssl can be run by the same
@@ -115,13 +119,14 @@ connect(Address, Port, Options0, Timeout) ->
%% that hardcodes reuseaddr to true in its portprogram.
Options1 = proplists:delete(reuseaddr, Options0),
Options = proplists:delete(ssl_imp, Options1),
- old_connect(Address, Port, Options, Timeout);
+ old_connect(Host, Port, Options, Timeout);
Value ->
{error, {eoptions, {ssl_imp, Value}}}
end.
%%--------------------------------------------------------------------
-%% Function: listen(Port, Options) -> {ok, ListenSock} | {error, Reason}
+-spec listen(port_num(), list()) ->{ok, #sslsocket{}} | {error, reason()}.
+
%%
%% Description: Creates a ssl listen socket.
%%--------------------------------------------------------------------
@@ -144,7 +149,8 @@ listen(Port, Options0) ->
end.
%%--------------------------------------------------------------------
-%% Function: transport_accept(ListenSocket[, Timeout]) -> {ok, Socket}.
+-spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}}.
+-spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}}.
%%
%% Description: Performs transport accept on a ssl listen socket
%%--------------------------------------------------------------------
@@ -182,8 +188,8 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
ssl_broker:transport_accept(Pid, ListenSocket, Timeout).
%%--------------------------------------------------------------------
-%% Function: ssl_accept(ListenSocket[, Timeout]) -> {ok, Socket} |
-%% {error, Reason}
+-spec ssl_accept(#sslsocket{}) -> {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on a ssl listen socket. e.i. performs
%% ssl handshake.
@@ -210,14 +216,14 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
{ok, #config{cb=CbInfo,ssl=SslOpts, emulated=EmOpts}} ->
{ok, Port} = inet:port(Socket),
ssl_connection:ssl_accept(Port, Socket,
- {SslOpts, EmOpts},
- self(), CbInfo, Timeout)
+ {SslOpts, EmOpts},
+ self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
end.
%%--------------------------------------------------------------------
-%% Function: close() -> ok
+-spec close(#sslsocket{}) -> term().
%%
%% Description: Close a ssl connection
%%--------------------------------------------------------------------
@@ -230,7 +236,7 @@ close(Socket = #sslsocket{}) ->
ssl_broker:close(Socket).
%%--------------------------------------------------------------------
-%% Function: send(Socket, Data) -> ok | {error, Reason}
+-spec send(#sslsocket{}, iolist()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
@@ -242,7 +248,8 @@ send(#sslsocket{} = Socket, Data) ->
ssl_broker:send(Socket, Data).
%%--------------------------------------------------------------------
-%% Function: recv(Socket, Length [,Timeout]) -> {ok, Data} | {error, reason}
+-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
+-spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
@@ -256,8 +263,8 @@ recv(Socket = #sslsocket{}, Length, Timeout) ->
ssl_broker:recv(Socket, Length, Timeout).
%%--------------------------------------------------------------------
-%% Function: controlling_process(Socket, NewOwner) -> ok | {error, Reason}
-%%
+-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+%%
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
@@ -270,11 +277,8 @@ controlling_process(Socket, NewOwner) when is_pid(NewOwner) ->
ssl_broker:controlling_process(Socket, NewOwner).
%%--------------------------------------------------------------------
-%% Function: connection_info(Socket) -> {ok, {Protocol, CipherSuite}} |
-%% {error, Reason}
-%% Protocol = sslv3 | tlsv1 | tlsv1.1
-%% CipherSuite = {KeyExchange, Chipher, Hash, Exportable}
-%%
+-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+ {error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
@@ -286,9 +290,9 @@ connection_info(#sslsocket{} = Socket) ->
ssl_broker:connection_info(Socket).
%%--------------------------------------------------------------------
-%% Function: peercert(Socket[, Opts]) -> {ok, Cert} | {error, Reason}
+-spec peercert(#sslsocket{}) ->{ok, der_cert()} | {error, reason()}.
%%
-%% Description:
+%% Description: Returns the peercert.
%%--------------------------------------------------------------------
peercert(Socket) ->
peercert(Socket, []).
@@ -323,7 +327,7 @@ decode_peercert(BinCert, Opts) ->
{ok, BinCert}
end.
-select_part(otp, {ok, Cert}, Opts) ->
+select_part(otp, Cert, Opts) ->
case lists:member(subject, Opts) of
true ->
TBS = Cert#'OTPCertificate'.tbsCertificate,
@@ -332,7 +336,7 @@ select_part(otp, {ok, Cert}, Opts) ->
{ok, Cert}
end;
-select_part(plain, {ok, Cert}, Opts) ->
+select_part(plain, Cert, Opts) ->
case lists:member(subject, Opts) of
true ->
TBS = Cert#'Certificate'.tbsCertificate,
@@ -342,9 +346,9 @@ select_part(plain, {ok, Cert}, Opts) ->
end.
%%--------------------------------------------------------------------
-%% Function: peername(Socket) -> {ok, {Address, Port}} | {error, Reason}
+-spec peername(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
-%% Description:
+%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
peername(#sslsocket{fd = new_ssl, pid = Pid}) ->
ssl_connection:peername(Pid);
@@ -354,9 +358,10 @@ peername(#sslsocket{} = Socket) ->
ssl_broker:peername(Socket).
%%--------------------------------------------------------------------
-%% Function: cipher_suites() ->
-%%
-%% Description:
+-spec cipher_suites() -> [erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+
+%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
cipher_suites() ->
cipher_suites(erlang).
@@ -370,7 +375,7 @@ cipher_suites(openssl) ->
[ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)].
%%--------------------------------------------------------------------
-%% Function: getopts(Socket, OptTags) -> {ok, Options} | {error, Reason}
+-spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}.
%%
%% Description:
%%--------------------------------------------------------------------
@@ -383,7 +388,7 @@ getopts(#sslsocket{} = Socket, Options) ->
ssl_broker:getopts(Socket, Options).
%%--------------------------------------------------------------------
-%% Function: setopts(Socket, Options) -> ok | {error, Reason}
+-spec setopts(#sslsocket{}, [{atom(), term()}]) -> ok | {error, reason()}.
%%
%% Description:
%%--------------------------------------------------------------------
@@ -398,8 +403,8 @@ setopts(#sslsocket{} = Socket, Options) ->
ssl_broker:setopts(Socket, Options).
%%---------------------------------------------------------------
-%% Function: shutdown(Socket, How) -> ok | {error, Reason}
-%%
+-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}, How) ->
@@ -408,8 +413,8 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
-%% Function: sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}
-%%
+-spec sockname(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}) ->
@@ -423,9 +428,9 @@ sockname(#sslsocket{} = Socket) ->
ssl_broker:sockname(Socket).
%%---------------------------------------------------------------
-%% Function: seed(Data) -> ok | {error, edata}
+-spec seed(term()) ->term().
%%
-%% Description:
+%% Description: Only used by old ssl.
%%--------------------------------------------------------------------
%% TODO: crypto:seed ?
seed(Data) ->
@@ -433,20 +438,17 @@ seed(Data) ->
ssl_server:seed(Data).
%%---------------------------------------------------------------
-%% Function: session_id(Socket) -> {ok, PropList} | {error, Reason}
+-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
%%
-%% Description:
+%% Description: Returns list of session info currently [{session_id, session_id(),
+%% {cipher_suite, cipher_suite()}]
%%--------------------------------------------------------------------
session_info(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:session_info(Pid).
%%---------------------------------------------------------------
-%% Function: versions() -> [{SslAppVer, SupportedSslVer, AvailableSslVsn}]
-%%
-%% SslAppVer = string() - t.ex: ssl-4.0
-%% SupportedSslVer = [SslVer]
-%% AvailableSslVsn = [SSLVer]
-%% SSLVer = sslv3 | tlsv1 | 'tlsv1.1'
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
+ {available, [tls_atom_version()]}].
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
@@ -457,6 +459,11 @@ versions() ->
[{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+%%---------------------------------------------------------------
+-spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+%%
+%% Description:
+%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:renegotiation(Pid).
@@ -660,7 +667,7 @@ validate_option(secure_renegotiate, Value) when Value == true;
Value == false ->
Value;
validate_option(renegotiate_at, Value) when is_integer(Value) ->
- min(Value, ?DEFAULT_RENEGOTIATE_AT);
+ erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
validate_option(debug, Value) when is_list(Value); Value == true ->
Value;
@@ -890,10 +897,6 @@ version() ->
end,
{ok, {SSLVsn, CompVsn, LibVsn}}.
-min(N,M) when N < M ->
- N;
-min(_, M) ->
- M.
%% Only used to remove exit messages from old ssl
%% First is a nonsense clause to provide some
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index db9a883654..eb1228afa4 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -32,6 +32,17 @@
-export([alert_txt/1, reason_code/2]).
+%%====================================================================
+%% Internal application API
+%%====================================================================
+%%--------------------------------------------------------------------
+-spec reason_code(#alert{}, client | server) -> closed | esslconnect |
+ esslaccept | string().
+%%
+%% Description: Returns the error reason that will be returned to the
+%% user.
+%%--------------------------------------------------------------------
+
reason_code(#alert{description = ?CLOSE_NOTIFY}, _) ->
closed;
reason_code(#alert{description = ?HANDSHAKE_FAILURE}, client) ->
@@ -41,10 +52,19 @@ reason_code(#alert{description = ?HANDSHAKE_FAILURE}, server) ->
reason_code(#alert{description = Description}, _) ->
description_txt(Description).
+%%--------------------------------------------------------------------
+-spec alert_txt(#alert{}) -> string().
+%%
+%% Description: Returns the error string for given alert.
+%%--------------------------------------------------------------------
+
alert_txt(#alert{level = Level, description = Description, where = {Mod,Line}}) ->
Mod ++ ":" ++ integer_to_list(Line) ++ ":" ++
level_txt(Level) ++" "++ description_txt(Description).
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
level_txt(?WARNING) ->
"Warning:";
level_txt(?FATAL) ->
@@ -96,8 +116,3 @@ description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
"no renegotiation".
-
-
-
-
-
diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl
index 6ca1c42631..8d50fd7bdb 100644
--- a/lib/ssl/src/ssl_app.erl
+++ b/lib/ssl/src/ssl_app.erl
@@ -27,14 +27,16 @@
-export([start/2, stop/1]).
-%% start/2(Type, StartArgs) -> {ok, Pid} | {ok, Pid, State} |
-%% {error, Reason}
-%%
+%%--------------------------------------------------------------------
+-spec start(normal | {takeover, node()} | {failover, node()}, list()) ->
+ ignore | {ok, pid()} | {error, term()}.
+%%--------------------------------------------------------------------
start(_Type, _StartArgs) ->
ssl_sup:start_link().
-%% stop(State) -> void()
-%%
+%--------------------------------------------------------------------
+-spec stop(term())-> ok.
+%%--------------------------------------------------------------------
stop(_State) ->
ok.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 9aa31ae8a4..917e75157b 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -46,9 +46,17 @@
%% Internal application API
%%====================================================================
+%%--------------------------------------------------------------------
+-spec trusted_cert_and_path([der_cert()], certdb_ref(), boolean()) ->
+ {der_cert(), [der_cert()], list()}.
+%%
+%% Description: Extracts the root cert (if not presents tries to
+%% look it up, if not found {bad_cert, unknown_ca} will be added verification
+%% errors. Returns {RootCert, Path, VerifyErrors}
+%%--------------------------------------------------------------------
trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
[Cert | RestPath] = lists:reverse(CertChain),
- {ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp),
+ OtpCert = public_key:pkix_decode_cert(Cert, otp),
IssuerAnPath =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
@@ -84,19 +92,31 @@ trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
end
end.
-
+%%--------------------------------------------------------------------
+-spec certificate_chain(undefined | binary(), certdb_ref()) ->
+ {error, no_cert} | {ok, [der_cert()]}.
+%%
+%% Description: Return the certificate chain to send to peer.
+%%--------------------------------------------------------------------
certificate_chain(undefined, _CertsDbRef) ->
{error, no_cert};
certificate_chain(OwnCert, CertsDbRef) ->
- {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp),
+ ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]).
-
+%%--------------------------------------------------------------------
+-spec file_to_certificats(string()) -> [der_cert()].
+%%
+%% Description: Return list of DER encoded certificates.
+%%--------------------------------------------------------------------
file_to_certificats(File) ->
{ok, List} = ssl_manager:cache_pem_file(File),
- [Bin || {cert, Bin, not_encrypted} <- List].
-
-
-%% Validates ssl/tls specific extensions
+ [Bin || {'Certificate', Bin, not_encrypted} <- List].
+%%--------------------------------------------------------------------
+-spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}],
+ boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}.
+%%
+%% Description: Validates ssl/tls specific extensions
+%%--------------------------------------------------------------------
validate_extensions([], ValidationState, UnknownExtensions, _, AccErr, _) ->
{UnknownExtensions, ValidationState, AccErr};
@@ -119,21 +139,42 @@ validate_extensions([Extension | Rest], ValidationState, UnknownExtensions,
validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions],
Verify, AccErr, Role).
+%%--------------------------------------------------------------------
+-spec is_valid_key_usage(list(), term()) -> boolean().
+%%
+%% Description: Checks if Use is a valid key usage.
+%%--------------------------------------------------------------------
is_valid_key_usage(KeyUse, Use) ->
lists:member(Use, KeyUse).
- select_extension(_, []) ->
+%%--------------------------------------------------------------------
+-spec select_extension(term(), list()) -> undefined | #'Extension'{}.
+%%
+%% Description: Selects the extension identified by Id if present in
+%% a list of extensions.
+%%--------------------------------------------------------------------
+select_extension(_, []) ->
undefined;
select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
Extension;
select_extension(Id, [_ | Extensions]) ->
select_extension(Id, Extensions).
+%%--------------------------------------------------------------------
+-spec extensions_list(asn1_NOVALUE | list()) -> list().
+%%
+%% Description: Handles that
+%%--------------------------------------------------------------------
extensions_list(asn1_NOVALUE) ->
[];
extensions_list(Extensions) ->
Extensions.
+%%--------------------------------------------------------------------
+-spec signature_type(term()) -> rsa | dsa .
+%%
+%% Description:
+%%--------------------------------------------------------------------
signature_type(RSA) when RSA == ?sha1WithRSAEncryption;
RSA == ?md5WithRSAEncryption ->
rsa;
@@ -178,7 +219,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
case ssl_manager:lookup_trusted_cert(CertsDbRef,
SerialNr, Issuer) of
{ok, {IssuerCert, ErlCert}} ->
- {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp),
+ ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
certificate_chain(ErlCert, IssuerCert,
CertsDbRef, [IssuerCert | Chain]);
_ ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index b8c3c6f6b7..00d3079cb3 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -22,7 +22,7 @@
%%----------------------------------------------------------------------
-module(ssl_certificate_db).
-
+-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([create/0, remove/1, add_trusted_certs/3,
@@ -34,8 +34,7 @@
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: create() -> Db
-%% Db = term() - Reference to the crated database
+-spec create() -> certdb_ref().
%%
%% Description: Creates a new certificate db.
%% Note: lookup_trusted_cert/3 may be called from any process but only
@@ -47,8 +46,7 @@ create() ->
ets:new(ssl_pid_to_file, [bag, private])].
%%--------------------------------------------------------------------
-%% Function: delete(Db) -> _
-%% Db = Database refererence as returned by create/0
+-spec remove(certdb_ref()) -> term().
%%
%% Description: Removes database db
%%--------------------------------------------------------------------
@@ -56,11 +54,9 @@ remove(Dbs) ->
lists:foreach(fun(Db) -> true = ets:delete(Db) end, Dbs).
%%--------------------------------------------------------------------
-%% Function: lookup_trusted_cert(Ref, SerialNumber, Issuer) -> {BinCert,DecodedCert}
-%% Ref = ref()
-%% SerialNumber = integer()
-%% Issuer = {rdnSequence, IssuerAttrs}
-%% BinCert = binary()
+-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->
+ undefined | {ok, {der_cert(), #'OTPCertificate'{}}}.
+
%%
%% Description: Retrives the trusted certificate identified by
%% <SerialNumber, Issuer>. Ref is used as it is specified
@@ -78,11 +74,7 @@ lookup_cached_certs(File) ->
ets:lookup(certificate_db_name(), {file, File}).
%%--------------------------------------------------------------------
-%% Function: add_trusted_certs(Pid, File, Db) -> {ok, Ref}
-%% Pid = pid()
-%% File = string()
-%% Db = Database refererence as returned by create/0
-%% Ref = ref()
+-spec add_trusted_certs(pid(), string(), certdb_ref()) -> {ok, certdb_ref()}.
%%
%% Description: Adds the trusted certificates from file <File> to the
%% runtime database. Returns Ref that should be handed to lookup_trusted_cert
@@ -103,18 +95,20 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
{ok, Ref}.
%%--------------------------------------------------------------------
-%% Function: cache_pem_file(Pid, File, Db) -> FileContent
+-spec cache_pem_file(pid(), string(), certdb_ref()) -> term().
%%
%% Description: Cache file as binary in DB
%%--------------------------------------------------------------------
cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) ->
- Res = {ok, Content} = public_key:pem_to_der(File),
+ {ok, PemBin} = file:read_file(File),
+ Content = public_key:pem_decode(PemBin),
insert({file, File}, Content, CertsDb),
insert(Pid, File, PidToFileDb),
- Res.
+ {ok, Content}.
%%--------------------------------------------------------------------
-%% Function: remove_trusted_certs(Pid, Db) -> _
+-spec remove_trusted_certs(pid(), certdb_ref()) -> term().
+
%%
%% Description: Removes trusted certs originating from
%% the file associated to Pid from the runtime database.
@@ -144,15 +138,13 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) ->
end.
%%--------------------------------------------------------------------
-%% Function: issuer_candidate() -> {Key, Candidate} | no_more_candidates
+-spec issuer_candidate(no_candidate | cert_key() | {file, term()}) ->
+ {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates.
%%
-%% Candidate
-%%
-%%
%% Description: If a certificat does not define its issuer through
%% the extension 'ce-authorityKeyIdentifier' we can
%% try to find the issuer in the database over known
-%% certificates.
+%% certificates.
%%--------------------------------------------------------------------
issuer_candidate(no_candidate) ->
Db = certificate_db_name(),
@@ -211,14 +203,15 @@ remove_certs(Ref, CertsDb) ->
ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}).
add_certs_from_file(File, Ref, CertsDb) ->
- Decode = fun(Cert) ->
- {ok, ErlCert} = public_key:pkix_decode_cert(Cert, otp),
+ Add = fun(Cert) ->
+ ErlCert = public_key:pkix_decode_cert(Cert, otp),
TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- Issuer = public_key:pkix_normalize_general_name(
+ Issuer = public_key:pkix_normalize_name(
TBSCertificate#'OTPTBSCertificate'.issuer),
insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
end,
- {ok,Der} = public_key:pem_to_der(File),
- [Decode(Cert) || {cert, Cert, not_encrypted} <- Der].
+ {ok, PemBin} = file:read_file(File),
+ PemEntries = public_key:pem_decode(PemBin),
+ [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries].
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 2a71df8ee1..8230149304 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -40,11 +40,8 @@
-compile(inline).
%%--------------------------------------------------------------------
-%% Function: security_parameters(CipherSuite, SecParams) ->
-%% #security_parameters{}
-%%
-%% CipherSuite - as defined in ssl_cipher.hrl
-%% SecParams - #security_parameters{}
+-spec security_parameters(cipher_suite(), #security_parameters{}) ->
+ #security_parameters{}.
%%
%% Description: Returns a security parameters record where the
%% cipher values has been updated according to <CipherSuite>
@@ -63,15 +60,11 @@ security_parameters(CipherSuite, SecParams) ->
hash_size = hash_size(Hash)}.
%%--------------------------------------------------------------------
-%% Function: cipher(Method, CipherState, Mac, Data) ->
-%% {Encrypted, UpdateCipherState}
-%%
-%% Method - integer() (as defined in ssl_cipher.hrl)
-%% CipherState, UpdatedCipherState - #cipher_state{}
-%% Data, Encrypted - binary()
+-spec cipher(cipher_enum(), #cipher_state{}, binary(), binary()) ->
+ {binary(), #cipher_state{}}.
%%
-%% Description: Encrypts the data and the mac using method, updating
-%% the cipher state
+%% Description: Encrypts the data and the MAC using chipher described
+%% by cipher_enum() and updating the cipher state
%%-------------------------------------------------------------------
cipher(?NULL, CipherState, <<>>, Fragment) ->
GenStreamCipherList = [Fragment, <<>>],
@@ -125,15 +118,11 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
{T, CS0#cipher_state{iv=NextIV}}.
%%--------------------------------------------------------------------
-%% Function: decipher(Method, CipherState, Mac, Data, Version) ->
-%% {Decrypted, UpdateCipherState}
-%%
-%% Method - integer() (as defined in ssl_cipher.hrl)
-%% CipherState, UpdatedCipherState - #cipher_state{}
-%% Data, Encrypted - binary()
+-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) ->
+ {binary(), binary(), #cipher_state{}} | #alert{}.
%%
-%% Description: Decrypts the data and the mac using method, updating
-%% the cipher state
+%% Description: Decrypts the data and the MAC using cipher described
+%% by cipher_enum() and updating the cipher state.
%%-------------------------------------------------------------------
decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
@@ -192,10 +181,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
end.
%%--------------------------------------------------------------------
-%% Function: suites(Version) -> [Suite]
-%%
-%% Version = version()
-%% Suite = binary() from ssl_cipher.hrl
+-spec suites(tls_version()) -> [cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -205,19 +191,9 @@ suites({3, N}) when N == 1; N == 2 ->
ssl_tls1:suites().
%%--------------------------------------------------------------------
-%% Function: suite_definition(CipherSuite) ->
-%% {KeyExchange, Cipher, Hash}
-%%
-%%
-%% CipherSuite - as defined in ssl_cipher.hrl
-%% KeyExchange - rsa | dh_anon | dhe_dss | dhe_rsa | kerb5
-%%
-%% Cipher - null | rc4_128 | idea_cbc | des_cbc | '3des_ede_cbc'
-%% des40_cbc | aes_128_cbc | aes_256_cbc
-%% Hash - null | md5 | sha
+-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
%%
-%% Description: Returns a security parameters tuple where the
-%% cipher values has been updated according to <CipherSuite>
+%% Description: Return erlang cipher suite definition.
%% Note: Currently not supported suites are commented away.
%% They should be supported or removed in the future.
%%-------------------------------------------------------------------
@@ -261,6 +237,12 @@ suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
{dhe_rsa, aes_256_cbc, sha}.
+%%--------------------------------------------------------------------
+-spec suite(erl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
+
%% TLS v1.1 suites
%%suite({rsa, null, md5}) ->
%% ?TLS_RSA_WITH_NULL_MD5;
@@ -309,7 +291,11 @@ suite({dhe_rsa, aes_256_cbc, sha}) ->
%% suite({dh_anon, aes_256_cbc, sha}) ->
%% ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
-
+%%--------------------------------------------------------------------
+-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
%% translate constants <-> openssl-strings
openssl_suite("DHE-RSA-AES256-SHA") ->
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
@@ -339,7 +325,11 @@ openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
?TLS_RSA_WITH_DES_CBC_SHA.
-
+%%--------------------------------------------------------------------
+-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
+%%
+%% Description: Return openssl cipher suite name.
+%%-------------------------------------------------------------------
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
"DHE-RSA-AES256-SHA";
openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
@@ -372,10 +362,15 @@ openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) ->
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
+%%--------------------------------------------------------------------
+-spec filter(undefined | binary(), [cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: .
+%%-------------------------------------------------------------------
filter(undefined, Ciphers) ->
Ciphers;
filter(DerCert, Ciphers) ->
- {ok, OtpCert} = public_key:pkix_decode_cert(DerCert, otp),
+ OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of
rsa ->
@@ -511,6 +506,12 @@ generic_stream_cipher_from_bin(T, HashSz) ->
is_correct_padding(_, {3, 0}) ->
true;
+%% For interoperability reasons we do not check the padding in TLS 1.0 as it
+%% is not strictly required and breaks interopability with for instance
+%% Google.
+is_correct_padding(_, {3, 1}) ->
+ true;
+%% Padding must be check in TLS 1.1 and after
is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) ->
list_to_binary(lists:duplicate(Len, Len)) == Padding.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 80fe527f45..8bd68cc190 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -26,6 +26,14 @@
-ifndef(ssl_cipher).
-define(ssl_cipher, true).
+-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
+ | aes_128_cbc | aes_256_cbc.
+-type hash() :: null | sha | md5.
+-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
+-type cipher_suite() :: binary().
+-type cipher_enum() :: integer().
+-type openssl_cipher_suite() :: string().
+
%%% SSL cipher protocol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(CHANGE_CIPHER_SPEC_PROTO, 1). % _PROTO to not clash with
% SSL record protocol
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 07fa101ed4..76422155a5 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -98,12 +98,17 @@
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
+-type state_name() :: hello | abbreviated | certify | cipher | connection.
+-type gen_fsm_state_return() :: {next_state, state_name(), #state{}} |
+ {next_state, state_name(), #state{}, timeout()} |
+ {stop, term(), #state{}}.
+
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: send(Pid, Data) -> ok | {error, Reason}
+-spec send(pid(), iolist()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
@@ -112,15 +117,17 @@ send(Pid, Data) ->
erlang:iolist_to_binary(Data)}, infinity).
%%--------------------------------------------------------------------
-%% Function: recv(Socket, Length Timeout) -> {ok, Data} | {error, reason}
+-spec recv(pid(), integer(), timeout()) ->
+ {ok, binary() | list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
recv(Pid, Length, Timeout) ->
sync_send_all_state_event(Pid, {recv, Length}, Timeout).
%%--------------------------------------------------------------------
-%% Function: : connect(Host, Port, Socket, Options,
-%% User, CbInfo, Timeout) -> {ok, Socket}
+-spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}},
+ pid(), tuple(), timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Connect to a ssl server.
%%--------------------------------------------------------------------
@@ -132,8 +139,9 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) ->
{error, ssl_not_started}
end.
%%--------------------------------------------------------------------
-%% Function: accept(Port, Socket, Opts, User,
-%% CbInfo, Timeout) -> {ok, Socket} | {error, Reason}
+-spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}},
+ pid(), tuple(), timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on a ssl listen socket. e.i. performs
%% ssl handshake.
@@ -147,7 +155,7 @@ ssl_accept(Port, Socket, Opts, User, CbInfo, Timeout) ->
end.
%%--------------------------------------------------------------------
-%% Function: handshake(SslSocket, Timeout) -> ok | {error, Reason}
+-spec handshake(#sslsocket{}, timeout()) -> ok | {error, reason()}.
%%
%% Description: Starts ssl handshake.
%%--------------------------------------------------------------------
@@ -159,7 +167,8 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
Error
end.
%--------------------------------------------------------------------
-%% Function: socket_control(Pid) -> {ok, SslSocket} | {error, Reason}
+-spec socket_control(port(), pid(), atom()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Set the ssl process to own the accept socket
%%--------------------------------------------------------------------
@@ -172,7 +181,7 @@ socket_control(Socket, Pid, CbModule) ->
end.
%%--------------------------------------------------------------------
-%% Function: close() -> ok
+-spec close(pid()) -> ok | {error, reason()}.
%%
%% Description: Close a ssl connection
%%--------------------------------------------------------------------
@@ -185,7 +194,7 @@ close(ConnectionPid) ->
end.
%%--------------------------------------------------------------------
-%% Function: shutdown(Socket, How) -> ok | {error, Reason}
+-spec shutdown(pid(), atom()) -> ok | {error, reason()}.
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
@@ -193,7 +202,7 @@ shutdown(ConnectionPid, How) ->
sync_send_all_state_event(ConnectionPid, {shutdown, How}).
%%--------------------------------------------------------------------
-%% Function: new_user(ConnectionPid, User) -> ok | {error, Reason}
+-spec new_user(pid(), pid()) -> ok | {error, reason()}.
%%
%% Description: Changes process that receives the messages when active = true
%% or once.
@@ -201,28 +210,28 @@ shutdown(ConnectionPid, How) ->
new_user(ConnectionPid, User) ->
sync_send_all_state_event(ConnectionPid, {new_user, User}).
%%--------------------------------------------------------------------
-%% Function: sockname(ConnectionPid) -> {ok, {Address, Port}} | {error, Reason}
+-spec sockname(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, sockname).
%%--------------------------------------------------------------------
-%% Function: peername(ConnectionPid) -> {ok, {Address, Port}} | {error, Reason}
+-spec peername(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
%% Description: Same as inet:peername/1
%%--------------------------------------------------------------------
peername(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, peername).
%%--------------------------------------------------------------------
-%% Function: get_opts(ConnectionPid, OptTags) -> {ok, Options} | {error, Reason}
+-spec get_opts(pid(), list()) -> {ok, list()} | {error, reason()}.
%%
%% Description: Same as inet:getopts/2
%%--------------------------------------------------------------------
get_opts(ConnectionPid, OptTags) ->
sync_send_all_state_event(ConnectionPid, {get_opts, OptTags}).
%%--------------------------------------------------------------------
-%% Function: setopts(Socket, Options) -> ok | {error, Reason}
+-spec set_opts(pid(), list()) -> ok | {error, reason()}.
%%
%% Description: Same as inet:setopts/2
%%--------------------------------------------------------------------
@@ -230,8 +239,7 @@ set_opts(ConnectionPid, Options) ->
sync_send_all_state_event(ConnectionPid, {set_opts, Options}).
%%--------------------------------------------------------------------
-%% Function: info(ConnectionPid) -> {ok, {Protocol, CipherSuite}} |
-%% {error, Reason}
+-spec info(pid()) -> {ok, {atom(), tuple()}} | {error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
@@ -239,7 +247,7 @@ info(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, info).
%%--------------------------------------------------------------------
-%% Function: session_info(ConnectionPid) -> {ok, PropList} | {error, Reason}
+-spec session_info(pid()) -> {ok, list()} | {error, reason()}.
%%
%% Description: Returns info about the ssl session
%%--------------------------------------------------------------------
@@ -247,7 +255,7 @@ session_info(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, session_info).
%%--------------------------------------------------------------------
-%% Function: peercert(ConnectionPid) -> {ok, Cert} | {error, Reason}
+-spec peer_certificate(pid()) -> {ok, binary()| undefined} | {error, reason()}.
%%
%% Description: Returns the peer cert
%%--------------------------------------------------------------------
@@ -255,7 +263,7 @@ peer_certificate(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, peer_certificate).
%%--------------------------------------------------------------------
-%% Function: renegotiation(ConnectionPid) -> ok | {error, Reason}
+-spec renegotiation(pid()) -> ok | {error, reason()}.
%%
%% Description: Starts a renegotiation of the ssl session.
%%--------------------------------------------------------------------
@@ -267,7 +275,8 @@ renegotiation(ConnectionPid) ->
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+-spec start_link(atom(), host(), port_num(), port(), list(), pid(), tuple()) ->
+ {ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_fsm process which calls Module:init/1 to
%% initialize. To ensure a synchronized start-up procedure, this function
@@ -281,10 +290,10 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
%% gen_fsm callbacks
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, StateName, State} |
-%% {ok, StateName, State, Timeout} |
-%% ignore |
-%% {stop, StopReason}
+-spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}.
+%% Possible return values not used now.
+%% | {ok, state_name(), #state{}, timeout()} |
+%% ignore
%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
%% gen_fsm:start_link/3,4, this function is called by the new process to
%% initialize.
@@ -309,11 +318,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
end.
%%--------------------------------------------------------------------
-%% Function:
-%% state_name(Event, State) -> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
+%% -spec state_name(event(), #state{}) -> gen_fsm_state_return()
%%
%% Description:There should be one instance of this function for each
%% possible state name. Whenever a gen_fsm receives an event sent
@@ -322,6 +327,9 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
%% the event. It is also called if a timeout occurs.
%%
%%--------------------------------------------------------------------
+-spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
hello(start, #state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
transport_cb = Transport, socket = Socket,
@@ -359,49 +367,30 @@ hello(#hello_request{}, #state{role = client} = State0) ->
hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression} = Hello,
- #state{session = Session0 = #session{session_id = OldId},
+ #state{session = #session{session_id = OldId},
connection_states = ConnectionStates0,
role = client,
negotiated_version = ReqVersion,
- host = Host, port = Port,
renegotiation = {Renegotiation, _},
- ssl_options = SslOptions,
- session_cache = Cache,
- session_cache_cb = CacheCb} = State0) ->
+ ssl_options = SslOptions} = State0) ->
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
- {Version, NewId, ConnectionStates1} ->
+ {Version, NewId, ConnectionStates} ->
{KeyAlgorithm, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
- State1 = State0#state{key_algorithm = KeyAlgorithm,
- negotiated_version = Version,
- connection_states = ConnectionStates1,
- premaster_secret = PremasterSecret},
+ State = State0#state{key_algorithm = KeyAlgorithm,
+ negotiated_version = Version,
+ connection_states = ConnectionStates,
+ premaster_secret = PremasterSecret},
case ssl_session:is_new(OldId, NewId) of
true ->
- Session = Session0#session{session_id = NewId,
- cipher_suite = CipherSuite,
- compression_method = Compression},
- {Record, State} = next_record(State1#state{session = Session}),
- next_state(certify, Record, State);
+ handle_new_session(NewId, CipherSuite, Compression, State);
false ->
- Session = CacheCb:lookup(Cache, {{Host, Port}, NewId}),
- case ssl_handshake:master_secret(Version, Session,
- ConnectionStates1, client) of
- {_, ConnectionStates2} ->
- {Record, State} =
- next_record(State1#state{
- connection_states = ConnectionStates2,
- session = Session}),
- next_state(abbreviated, Record, State);
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State1),
- {stop, normal, State1}
- end
+ handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
end;
#alert{} = Alert ->
handle_own_alert(Alert, ReqVersion, hello, State0),
@@ -431,7 +420,10 @@ hello(Hello = #client_hello{client_version = ClientVersion},
hello(Msg, State) ->
handle_unexpected_message(Msg, hello, State).
-
+%%--------------------------------------------------------------------
+-spec abbreviated(#hello_request{} | #finished{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
abbreviated(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -477,6 +469,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
abbreviated(Msg, State) ->
handle_unexpected_message(Msg, abbreviated, State).
+%%--------------------------------------------------------------------
+-spec certify(#hello_request{} | #certificate{} | #server_key_exchange{} |
+ #certificate_request{} | #server_hello_done{} | #client_key_exchange{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
certify(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -646,6 +643,10 @@ certify(#client_key_exchange{exchange_keys = #client_diffie_hellman_public{
certify(Msg, State) ->
handle_unexpected_message(Msg, certify, State).
+%%--------------------------------------------------------------------
+-spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
cipher(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -676,31 +677,14 @@ cipher(#finished{verify_data = Data} = Finished,
role = Role,
session = #session{master_secret = MasterSecret}
= Session0,
- tls_handshake_hashes = Hashes0,
- connection_states = ConnectionStates0} = State) ->
+ tls_handshake_hashes = Hashes0} = State) ->
case ssl_handshake:verify_connection(Version, Finished,
opposite_role(Role),
MasterSecret, Hashes0) of
verified ->
Session = register_session(Role, Host, Port, Session0),
- case Role of
- client ->
- ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
- next_state_connection(cipher, ack_connection(State#state{session = Session,
- connection_states = ConnectionStates}));
- server ->
- ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
- {ConnectionStates, Hashes} =
- finalize_handshake(State#state{
- connection_states = ConnectionStates1,
- session = Session}, cipher),
- next_state_connection(cipher, ack_connection(State#state{connection_states =
- ConnectionStates,
- session = Session,
- tls_handshake_hashes =
- Hashes}))
- end;
+ cipher_role(Role, Data, Session, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, cipher, State),
{stop, normal, State}
@@ -709,7 +693,10 @@ cipher(#finished{verify_data = Data} = Finished,
cipher(Msg, State) ->
handle_unexpected_message(Msg, cipher, State).
-
+%%--------------------------------------------------------------------
+-spec connection(#hello_request{} | #client_hello{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
connection(#hello_request{}, #state{host = Host, port = Port,
socket = Socket,
ssl_options = SslOpts,
@@ -736,30 +723,24 @@ connection(#client_hello{} = Hello, #state{role = server} = State) ->
connection(Msg, State) ->
handle_unexpected_message(Msg, connection, State).
%%--------------------------------------------------------------------
-%% Function:
-%% handle_event(Event, StateName, State) -> {next_state, NextStateName,
-%% NextState} |
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
+-spec handle_event(term(), state_name(), #state{}) -> term().
+%% As it is not currently used gen_fsm_state_return() makes
+%% dialyzer unhappy!
+%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:send_all_state_event/2, this function is called to handle
-%% the event.
+%% the event. Not currently used!
%%--------------------------------------------------------------------
handle_event(_Event, StateName, State) ->
{next_state, StateName, State}.
%%--------------------------------------------------------------------
-%% Function:
-%% handle_sync_event(Event, From, StateName,
-%% State) -> {next_state, NextStateName, NextState} |
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {reply, Reply, NextStateName, NextState}|
-%% {reply, Reply, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState} |
-%% {stop, Reason, Reply, NewState}
+-spec handle_sync_event(term(), from(), state_name(), #state{}) ->
+ gen_fsm_state_return() |
+ {reply, reply(), state_name(), #state{}} |
+ {reply, reply(), state_name(), #state{}, timeout()} |
+ {stop, reason(), reply(), #state{}}.
+%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
%% the event.
@@ -936,11 +917,11 @@ handle_sync_event(peer_certificate, _, StateName,
{reply, {ok, Cert}, StateName, State}.
%%--------------------------------------------------------------------
-%% Function:
-%% handle_info(Info,StateName,State)-> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState}
+-spec handle_info(msg(),state_name(), #state{}) ->
+ {next_state, state_name(), #state{}}|
+ {next_state, state_name(), #state{}, timeout()} |
+ {stop, reason(), #state{}}.
+%%
%% Description: This function is called by a gen_fsm when it receives any
%% other message than a synchronous or asynchronous event
%% (or a system message).
@@ -1000,7 +981,8 @@ handle_info(Msg, StateName, State) ->
{next_state, StateName, State}.
%%--------------------------------------------------------------------
-%% Function: terminate(Reason, StateName, State) -> void()
+-spec terminate(reason(), state_name(), #state{}) -> term().
+%%
%% Description:This function is called by a gen_fsm when it is about
%% to terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_fsm terminates with
@@ -1027,7 +1009,8 @@ terminate(_Reason, _StateName, #state{transport_cb = Transport,
Transport:close(Socket).
%%--------------------------------------------------------------------
-%% Function:
+-spec code_change(term(), state_name(), #state{}, list()) -> {ok, state_name(), #state{}}.
+%%
%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
@@ -1039,24 +1022,17 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo,
Timeout) ->
- case ssl_connection_sup:start_child([Role, Host, Port, Socket,
- Opts, User, CbInfo]) of
- {ok, Pid} ->
- case socket_control(Socket, Pid, CbModule) of
- {ok, SslSocket} ->
- case handshake(SslSocket, Timeout) of
- ok ->
- {ok, SslSocket};
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
+ try
+ {ok, Pid} = ssl_connection_sup:start_child([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = socket_control(Socket, Pid, CbModule),
+ ok = handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
end.
-
+
ssl_init(SslOpts, Role) ->
{ok, CertDbRef, CacheRef, OwnCert} = init_certificates(SslOpts, Role),
PrivateKey =
@@ -1067,20 +1043,22 @@ ssl_init(SslOpts, Role) ->
init_certificates(#ssl_options{cacertfile = CACertFile,
certfile = CertFile}, Role) ->
+ {ok, CertDbRef, CacheRef} =
+ try
+ {ok, _, _} = ssl_manager:connection_init(CACertFile, Role)
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile,
+ erlang:get_stacktrace())
+ end,
+ init_certificates(CertDbRef, CacheRef, CertFile, Role).
- case ssl_manager:connection_init(CACertFile, Role) of
- {ok, CertDbRef, CacheRef} ->
- init_certificates(CertDbRef, CacheRef, CertFile, Role);
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, CACertFile, ecacertfile,
- erlang:get_stacktrace())
- end.
init_certificates(CertDbRef, CacheRef, CertFile, client) ->
try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
- catch _E:_R ->
+ catch _Error:_Reason ->
{ok, CertDbRef, CacheRef, undefined}
end;
@@ -1097,15 +1075,15 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) ->
init_private_key(undefined, "", _Password, client) ->
undefined;
init_private_key(undefined, KeyFile, Password, _) ->
- case ssl_manager:cache_pem_file(KeyFile) of
- {ok, List} ->
- [Der] = [Der || Der = {PKey, _ , _} <- List,
- PKey =:= rsa_private_key orelse
- PKey =:= dsa_private_key],
- {ok, Decoded} = public_key:decode_private_key(Der,Password),
- Decoded;
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, KeyFile, ekeyfile,
+ try
+ {ok, List} = ssl_manager:cache_pem_file(KeyFile),
+ [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
+ PKey =:= 'RSAPrivateKey' orelse
+ PKey =:= 'DSAPrivateKey'],
+ public_key:pem_entry_decode(PemEntry, Password)
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile,
erlang:get_stacktrace())
end;
@@ -1117,6 +1095,7 @@ handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) ->
handle_file_error(Line, Error, Reason, File, Throw, Stack) ->
file_error(Line, Error, Reason, File, Throw, Stack).
+-spec(file_error/6 :: (_,_,_,_,_,_) -> no_return()).
file_error(Line, Error, Reason, File, Throw, Stack) ->
Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n",
[Line, Error, Reason, File, Stack]),
@@ -1128,17 +1107,18 @@ init_diffie_hellman(_, client) ->
init_diffie_hellman(undefined, _) ->
?DEFAULT_DIFFIE_HELLMAN_PARAMS;
init_diffie_hellman(DHParamFile, server) ->
- case ssl_manager:cache_pem_file(DHParamFile) of
- {ok, List} ->
- case [Der || Der = {dh_params, _ , _} <- List] of
- [Der] ->
- {ok, Decoded} = public_key:decode_dhparams(Der),
- Decoded;
- [] ->
- ?DEFAULT_DIFFIE_HELLMAN_PARAMS
- end;
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, DHParamFile, edhfile, erlang:get_stacktrace())
+ try
+ {ok, List} = ssl_manager:cache_pem_file(DHParamFile),
+ case [Entry || Entry = {'DHParameter', _ , _} <- List] of
+ [Entry] ->
+ public_key:pem_entry_decode(Entry);
+ [] ->
+ ?DEFAULT_DIFFIE_HELLMAN_PARAMS
+ end
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason,
+ DHParamFile, edhfile, erlang:get_stacktrace())
end.
sync_send_all_state_event(FsmPid, Event) ->
@@ -1207,7 +1187,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
tls_handshake_hashes = Hashes1};
ignore ->
State;
- #alert{} = Alert ->
+ #alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State)
end;
@@ -1215,18 +1195,19 @@ verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
do_server_hello(Type, #state{negotiated_version = Version,
- session = Session,
+ session = #session{session_id = SessId} = Session,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
+
ServerHello =
- ssl_handshake:server_hello(Session#session.session_id, Version,
+ ssl_handshake:server_hello(SessId, Version,
ConnectionStates0, Renegotiation),
State1 = server_hello(ServerHello, State0),
case Type of
new ->
- do_server_hello(ServerHello, State1);
+ new_server_hello(ServerHello, State1);
resumed ->
ConnectionStates1 = State1#state.connection_states,
case ssl_handshake:master_secret(Version, Session,
@@ -1245,9 +1226,9 @@ do_server_hello(Type, #state{negotiated_version = Version,
handle_own_alert(Alert, Version, hello, State1),
{stop, normal, State1}
end
- end;
+ end.
-do_server_hello(#server_hello{cipher_suite = CipherSuite,
+new_server_hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression,
session_id = SessionId},
#state{session = Session0,
@@ -1267,6 +1248,33 @@ do_server_hello(#server_hello{cipher_suite = CipherSuite,
{stop, normal, State0}
end.
+handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} = State0) ->
+ Session = Session0#session{session_id = NewId,
+ cipher_suite = CipherSuite,
+ compression_method = Compression},
+ {Record, State} = next_record(State0#state{session = Session}),
+ next_state(certify, Record, State).
+
+handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ host = Host, port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb} = State0) ->
+ Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
+ case ssl_handshake:master_secret(Version, Session,
+ ConnectionStates0, client) of
+ {_, ConnectionStates1} ->
+ {Record, State} =
+ next_record(State0#state{
+ connection_states = ConnectionStates1,
+ session = Session}),
+ next_state(abbreviated, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, hello, State0),
+ {stop, normal, State0}
+ end.
+
+
client_certify_and_key_exchange(#state{negotiated_version = Version} =
State0) ->
try do_client_certify_and_key_exchange(State0) of
@@ -1345,7 +1353,7 @@ certify_server(#state{transport_cb = Transport,
key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
- diffie_hellman_params = Params,
+ diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1354,11 +1362,9 @@ key_exchange(#state{role = server, key_algorithm = Algo,
transport_cb = Transport
} = State)
when Algo == dhe_dss;
- Algo == dhe_dss_export;
- Algo == dhe_rsa;
- Algo == dhe_rsa_export ->
+ Algo == dhe_rsa ->
- Keys = public_key:gen_key(Params),
+ Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
@@ -1402,9 +1408,7 @@ key_exchange(#state{role = client,
socket = Socket, transport_cb = Transport,
tls_handshake_hashes = Hashes0} = State)
when Algorithm == dhe_dss;
- Algorithm == dhe_dss_export;
- Algorithm == dhe_rsa;
- Algorithm == dhe_rsa_export ->
+ Algorithm == dhe_rsa ->
Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
@@ -1412,6 +1416,8 @@ key_exchange(#state{role = client,
State#state{connection_states = ConnectionStates1,
tls_handshake_hashes = Hashes1}.
+-spec(rsa_key_exchange/2 :: (_,_) -> no_return()).
+
rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
when Algorithm == ?rsaEncryption;
Algorithm == ?md2WithRSAEncryption;
@@ -1542,9 +1548,24 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
false
end;
verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) ->
- public_key:verify_signature(Hash, none, Signed, PublicKey, PublicKeyParams).
+ public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}).
+cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
+ next_state_connection(cipher, ack_connection(State#state{session = Session,
+ connection_states = ConnectionStates}));
+
+cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
+ {ConnectionStates, Hashes} =
+ finalize_handshake(State#state{connection_states = ConnectionStates1,
+ session = Session}, cipher),
+ next_state_connection(cipher, ack_connection(State#state{connection_states =
+ ConnectionStates,
+ session = Session,
+ tls_handshake_hashes =
+ Hashes})).
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
?DBG_TERM(Alert),
ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
@@ -1554,7 +1575,7 @@ encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) ->
- encode_handshake(HandshakeRec, undefined, Version,
+ encode_handshake(HandshakeRec, null, Version,
ConnectionStates, Hashes).
encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) ->
@@ -1717,11 +1738,13 @@ format_packet_error(#socket_options{active = _, mode = Mode}, Data) ->
format_reply(binary, _, N, Data) when N > 0 -> % Header mode
header(N, Data);
-format_reply(binary, _, _, Data) -> Data;
-format_reply(list, Packet, _, Data) when is_integer(Packet); Packet == raw ->
- binary_to_list(Data);
+format_reply(binary, _, _, Data) ->
+ Data;
+format_reply(list, Packet, _, Data)
+ when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} ->
+ Data;
format_reply(list, _,_, Data) ->
- Data.
+ binary_to_list(Data).
header(0, <<>>) ->
<<>>;
@@ -2145,7 +2168,7 @@ renegotiate(#state{role = server,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version, undefined),
+ Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null),
Hs0 = ssl_handshake:init_hashes(),
{BinMsg, ConnectionStates} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f7e3e392ec..3d831eae02 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -42,16 +42,17 @@
encode_handshake/3, init_hashes/0,
update_hashes/2, decrypt_premaster_secret/2]).
+-type tls_handshake() :: #client_hello{} | #server_hello{} |
+ #server_hello_done{} | #certificate{} | #certificate_request{} |
+ #client_key_exchange{} | #finished{} | #certificate_verify{} |
+ #hello_request{}.
+
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: client_hello(Host, Port, ConnectionStates, SslOpts, Cert, Renegotiation) ->
-%% #client_hello{}
-%% Host
-%% Port
-%% ConnectionStates = #connection_states{}
-%% SslOpts = #ssl_options{}
+-spec client_hello(host(), port_num(), #connection_states{},
+ #ssl_options{}, binary(), boolean()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
%%--------------------------------------------------------------------
@@ -65,7 +66,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
- Ciphers = available_suites(Cert, UserSuites, Version),
+ Ciphers = available_suites(UserSuites, Version),
Id = ssl_manager:client_session_id(Host, Port, SslOpts),
@@ -79,13 +80,8 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
}.
%%--------------------------------------------------------------------
-%% Function: server_hello(SessionId, Version,
-%% ConnectionStates, Renegotiation) -> #server_hello{}
-%% SessionId
-%% Version
-%% ConnectionStates
-%% Renegotiation
-%%
+-spec server_hello(session_id(), tls_version(), #connection_states{},
+ boolean()) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
@@ -103,7 +99,7 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation) ->
}.
%%--------------------------------------------------------------------
-%% Function: hello_request() -> #hello_request{}
+-spec hello_request() -> #hello_request{}.
%%
%% Description: Creates a hello request message sent by server to
%% trigger renegotiation.
@@ -112,15 +108,12 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
-%% Function: hello(Hello, Info, Renegotiation) ->
-%% {Version, Id, NewConnectionStates} |
-%% #alert{}
-%%
-%% Hello = #client_hello{} | #server_hello{}
-%% Info = ConnectionStates | {Port, #ssl_options{}, Session,
-%% Cahce, CahceCb, ConnectionStates}
-%% ConnectionStates = #connection_states{}
-%% Renegotiation = boolean()
+-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
+ #connection_states{} | {port_num(), #session{}, cache_ref(),
+ atom(), #connection_states{}, binary()},
+ boolean()) -> {tls_version(), session_id(), #connection_states{}}|
+ {tls_version(), {resumed | new, #session{}},
+ #connection_states{}} | #alert{}.
%%
%% Description: Handles a recieved hello message
%%--------------------------------------------------------------------
@@ -183,12 +176,9 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
end.
%%--------------------------------------------------------------------
-%% Function: certify(Certs, CertDbRef, MaxPathLen) ->
-%% {PeerCert, PublicKeyInfo} | #alert{}
-%%
-%% Certs = #certificate{}
-%% CertDbRef = reference()
-%% MaxPathLen = integer() | nolimit
+-spec certify(#certificate{}, term(), integer() | nolimit,
+ verify_peer | verify_none, fun(), fun(),
+ client | server) -> {der_cert(), public_key_info()} | #alert{}.
%%
%% Description: Handles a certificate handshake message
%%--------------------------------------------------------------------
@@ -244,10 +234,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
end.
%%--------------------------------------------------------------------
-%% Function: certificate(OwnCert, CertDbRef, Role) -> #certificate{}
-%%
-%% OwnCert = binary()
-%% CertDbRef = term() as returned by ssl_certificate_db:create()
+-spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}.
%%
%% Description: Creates a certificate message.
%%--------------------------------------------------------------------
@@ -273,10 +260,10 @@ certificate(OwnCert, CertDbRef, server) ->
end.
%%--------------------------------------------------------------------
-%% Function: client_certificate_verify(Cert, ConnectionStates) ->
-%% #certificate_verify{} | ignore
-%% Cert = #'OTPcertificate'{}
-%% ConnectionStates = #connection_states{}
+-spec client_certificate_verify(undefined | der_cert(), binary(),
+ tls_version(), key_algo(), private_key(),
+ {{binary(), binary()},{binary(), binary()}}) ->
+ #certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
@@ -298,10 +285,9 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
end.
%%--------------------------------------------------------------------
-%% Function: certificate_verify(Signature, PublicKeyInfo) -> valid | #alert{}
-%%
-%% Signature = binary()
-%% PublicKeyInfo = {Algorithm, PublicKey, PublicKeyParams}
+%% -spec certificate_verify(binary(), public_key_info(), tls_version(),
+%% binary(), key_algo(),
+%% {_, {binary(), binary()}}) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
@@ -320,13 +306,19 @@ certificate_verify(Signature, {_, PublicKey, _}, Version,
end;
certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version,
MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) ->
- Hashes = calc_certificate_verify(Version, MasterSecret,
- Algorithm, Hashes0),
- public_key:verify_signature(Hashes, sha, Signature, PublicKey, PublicKeyParams).
+ Hashes = calc_certificate_verify(Version, MasterSecret,
+ Algorithm, Hashes0),
+ case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of
+ true ->
+ valid;
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
+ end.
+
%%--------------------------------------------------------------------
-%% Function: certificate_request(ConnectionStates, CertDbRef) ->
-%% #certificate_request{}
+-spec certificate_request(#connection_states{}, certdb_ref()) ->
+ #certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
%%--------------------------------------------------------------------
@@ -342,11 +334,12 @@ certificate_request(ConnectionStates, CertDbRef) ->
}.
%%--------------------------------------------------------------------
-%% Function: key_exchange(Role, Secret, Params) ->
-%% #client_key_exchange{} | #server_key_exchange{}
-%%
-%% Secret -
-%% Params -
+-spec key_exchange(client | server,
+ {premaster_secret, binary(), public_key_info()} |
+ {dh, binary()} |
+ {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(),
+ binary(), binary(), private_key()}) ->
+ #client_key_exchange{} | #server_key_exchange{}.
%%
%% Description: Creates a keyexchange message.
%%--------------------------------------------------------------------
@@ -382,15 +375,9 @@ key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
signed_params = Signed}.
%%--------------------------------------------------------------------
-%% Function: master_secret(Version, Session/PremasterSecret,
-%% ConnectionStates, Role) ->
-%% {MasterSecret, NewConnectionStates} | #alert{}
-%% Version = #protocol_version{}
-%% Session = #session{} (session contains master secret)
-%% PremasterSecret = binary()
-%% ConnectionStates = #connection_states{}
-%% Role = client | server
-%%
+-spec master_secret(tls_version(), #session{} | binary(), #connection_states{},
+ client | server) -> {binary(), #connection_states{}} | #alert{}.
+%%
%% Description: Sets or calculates the master secret and calculate keys,
%% updating the pending connection states. The Mastersecret and the update
%% connection states are returned or an alert if the calculation fails.
@@ -427,9 +414,8 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
end.
%%--------------------------------------------------------------------
-%% Function: finished(Version, Role, MacSecret, Hashes) -> #finished{}
-%%
-%% ConnectionStates = #connection_states{}
+-spec finished(tls_version(), client | server, binary(), {{binary(), binary()},_}) ->
+ #finished{}.
%%
%% Description: Creates a handshake finished message
%%-------------------------------------------------------------------
@@ -438,15 +424,8 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes
calc_finished(Version, Role, MasterSecret, Hashes)}.
%%--------------------------------------------------------------------
-%% Function: verify_connection(Finished, Role,
-%% MasterSecret, Hashes) -> verified | #alert{}
-%%
-%% Finished = #finished{}
-%% Role = client | server - the role of the process that sent the finished
-%% message.
-%% MasterSecret = binary()
-%% Hashes = binary() - {md5_hash, sha_hash}
-%%
+-spec verify_connection(tls_version(), #finished{}, client | server, binary(),
+ {_, {binary(), binary()}}) -> verified | #alert{}.
%%
%% Description: Checks the ssl handshake finished message to verify
%% the connection.
@@ -462,17 +441,18 @@ verify_connection(Version, #finished{verify_data = Data},
_E ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
end.
-
+%%--------------------------------------------------------------------
+-spec server_hello_done() -> #server_hello_done{}.
+%%
+%% Description: Creates a server hello done message.
+%%--------------------------------------------------------------------
server_hello_done() ->
#server_hello_done{}.
%%--------------------------------------------------------------------
-%% Function: encode_handshake(HandshakeRec) -> BinHandshake
-%% HandshakeRec = #client_hello | #server_hello{} | server_hello_done |
-%% #certificate{} | #client_key_exchange{} | #finished{} |
-%% #client_certify_request{}
+-spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist().
%%
-%% encode a handshake packet to binary
+%% Description: Encode a handshake packet to binary
%%--------------------------------------------------------------------
encode_handshake(Package, Version, KeyAlg) ->
SigAlg = sig_alg(KeyAlg),
@@ -481,12 +461,11 @@ encode_handshake(Package, Version, KeyAlg) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
-%% Function: get_tls_handshake(Data, Buffer) -> Result
-%% Result = {[#handshake{}], [Raw], NewBuffer}
-%% Data = Buffer = NewBuffer = Raw = binary()
+-spec get_tls_handshake(binary(), binary() | iolist(), key_algo(), tls_version()) ->
+ {[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
-%% and returns it as a list of #handshake, also returns leftover
+%% and returns it as a list of handshake messages, also returns leftover
%% data.
%%--------------------------------------------------------------------
get_tls_handshake(Data, <<>>, KeyAlg, Version) ->
@@ -495,6 +474,9 @@ get_tls_handshake(Data, Buffer, KeyAlg, Version) ->
get_tls_handshake_aux(list_to_binary([Buffer, Data]),
KeyAlg, Version, []).
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
Body:Length/binary,Rest/binary>>, KeyAlg,
Version, Acc) ->
@@ -504,9 +486,6 @@ get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
get_tls_handshake_aux(Data, _KeyAlg, _Version, Acc) ->
{lists:reverse(Acc), Data}.
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
verify_bool(verify_peer) ->
true;
verify_bool(verify_none) ->
@@ -547,13 +526,16 @@ select_session(Hello, Port, Session, Version,
{resumed, CacheCb:lookup(Cache, {Port, SessionId})}
end.
-available_suites(Cert, UserSuites, Version) ->
+available_suites(UserSuites, Version) ->
case UserSuites of
[] ->
- ssl_cipher:filter(Cert, ssl_cipher:suites(Version));
+ ssl_cipher:suites(Version);
_ ->
- ssl_cipher:filter(Cert, UserSuites)
+ UserSuites
end.
+
+available_suites(ServerCert, UserSuites, Version) ->
+ ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)).
cipher_suites(Suites, false) ->
[?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites];
@@ -1065,9 +1047,10 @@ certificate_authorities(CertDbRef) ->
Authorities = certificate_authorities_from_db(CertDbRef),
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
- Subj = public_key:pkix_transform(OTPSubj, encode),
- {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- DNEncodedBin = iolist_to_binary(DNEncoded),
+ DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
+ %%Subj = public_key:pkix_transform(OTPSubj, encode),
+ %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
+ %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1091,7 +1074,7 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
[{rsa_pad, rsa_pkcs1_padding}]);
digitally_signed(Hash, #'DSAPrivateKey'{} = Key) ->
- public_key:sign(none, Hash, Key).
+ public_key:sign(Hash, none, Key).
calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index fdc0c33750..337403531e 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -23,6 +23,8 @@
-ifndef(ssl_internal).
-define(ssl_internal, true).
+-include_lib("public_key/include/public_key.hrl").
+
%% basic binary constructors
-define(BOOLEAN(X), X:8/unsigned-big-integer).
-define(BYTE(X), X:8/unsigned-big-integer).
@@ -88,6 +90,28 @@
active = true
}).
+-type reason() :: term().
+-type reply() :: term().
+-type msg() :: term().
+-type from() :: term().
+-type host() :: string() | tuple().
+-type port_num() :: integer().
+-type session_id() :: 0 | binary().
+-type tls_version() :: {integer(), integer()}.
+-type tls_atom_version() :: sslv3 | tlsv1.
+-type cache_ref() :: term().
+-type certdb_ref() :: term().
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss.
+-type enum_algo() :: integer().
+-type public_key() :: #'RSAPublicKey'{} | integer().
+-type public_key_params() :: #'Dss-Parms'{} | term().
+-type public_key_info() :: {enum_algo(), public_key(), public_key_params()}.
+-type der_cert() :: binary().
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type issuer() :: tuple().
+-type serialnumber() :: integer().
+-type cert_key() :: {reference(), integer(), issuer()}.
+
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 19bdcfa1f5..459dcefb79 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -24,10 +24,13 @@
-module(ssl_manager).
-behaviour(gen_server).
+-include("ssl_internal.hrl").
+
%% Internal application API
--export([start_link/0, start_link/1,
+-export([start_link/1,
connection_init/2, cache_pem_file/1,
- lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3, server_session_id/3,
+ lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3,
+ server_session_id/3,
register_session/2, register_session/3, invalidate_session/2,
invalidate_session/3]).
@@ -58,21 +61,25 @@
%% API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+-spec start_link(list()) -> {ok, pid()} | ignore | {error, term()}.
+%%
%% Description: Starts the server
%%--------------------------------------------------------------------
-start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
start_link(Opts) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec connection_init(string(), client | server) -> {ok, reference(), cache_ref()}.
+%%
+%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
connection_init(TrustedcertsFile, Role) ->
call({connection_init, TrustedcertsFile, Role}).
-
+%%--------------------------------------------------------------------
+-spec cache_pem_file(string()) -> {ok, term()}.
+%%
+%% Description: Cach a pem file and
+%%--------------------------------------------------------------------
cache_pem_file(File) ->
case ssl_certificate_db:lookup_cached_certs(File) of
[{_,Content}] ->
@@ -80,48 +87,54 @@ cache_pem_file(File) ->
[] ->
call({cache_pem, File})
end.
-
-%%--------------------------------------------------------------------
-%% Function:
-%% Description:
%%--------------------------------------------------------------------
+-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->
+ undefined |
+ {ok, {der_cert(), #'OTPCertificate'{}}}.
+%%
+%% Description: Lookup the trusted cert with Key = {reference(),
+%% serialnumber(), issuer()}.
+%% --------------------------------------------------------------------
lookup_trusted_cert(Ref, SerialNumber, Issuer) ->
ssl_certificate_db:lookup_trusted_cert(Ref, SerialNumber, Issuer).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec issuer_candidate(cert_key() | no_candidate) ->
+ {cert_key(), {der_cert(), #'OTPCertificate'{}}} | no_more_candidates.
+%%
+%% Description: Return next issuer candidate.
%%--------------------------------------------------------------------
issuer_candidate(PrevCandidateKey) ->
ssl_certificate_db:issuer_candidate(PrevCandidateKey).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec client_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+%%
+%% Description: Select a session id for the client.
%%--------------------------------------------------------------------
client_session_id(Host, Port, SslOpts) ->
call({client_session_id, Host, Port, SslOpts}).
-
+
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec server_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+%%
+%% Description: Select a session id for the server.
%%--------------------------------------------------------------------
server_session_id(Port, SuggestedSessionId, SslOpts) ->
call({server_session_id, Port, SuggestedSessionId, SslOpts}).
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec register_session(host(), port_num(), #session{}) -> ok.
+%%
+%% Description: Make the session available for reuse.
%%--------------------------------------------------------------------
register_session(Host, Port, Session) ->
cast({register_session, Host, Port, Session}).
register_session(Port, Session) ->
cast({register_session, Port, Session}).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec invalidate_session(host(), port_num(), #session{}) -> ok.
+%%
+%% Description: Make the session unavilable for reuse.
%%--------------------------------------------------------------------
invalidate_session(Host, Port, Session) ->
cast({invalidate_session, Host, Port, Session}).
@@ -134,10 +147,10 @@ invalidate_session(Port, Session) ->
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
+-spec init(list()) -> {ok, #state{}}.
+%% Possible return values not used now.
+%% | {ok, #state{}, timeout()} | ignore | {stop, term()}.
+%%
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Opts]) ->
@@ -156,12 +169,14 @@ init([Opts]) ->
session_validation_timer = Timer}}.
%%--------------------------------------------------------------------
-%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% {stop, Reason, State}
+-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}.
+%% Possible return values not used now.
+%% {reply, reply(), #state{}, timeout()} |
+%% {noreply, #state{}} |
+%% {noreply, #state{}, timeout()} |
+%% {stop, reason(), reply(), #state{}} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({{connection_init, "", _Role}, Pid}, _From,
@@ -207,9 +222,11 @@ handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) ->
{reply, {error, Reason}, State}
end.
%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
+-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% | {noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast({register_session, Host, Port, Session},
@@ -243,9 +260,11 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}},
{noreply, State}.
%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
+-spec handle_info(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% |{noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(validate_sessions, #state{session_cache_cb = CacheCb,
@@ -278,7 +297,8 @@ handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> void()
+-spec terminate(reason(), #state{}) -> term().
+%%
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
@@ -294,7 +314,8 @@ terminate(_Reason, #state{certificate_db = Db,
ok.
%%--------------------------------------------------------------------
-%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+-spec code_change(term(), #state{}, list()) -> {ok, #state{}}.
+%%
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
@@ -339,4 +360,3 @@ session_validation({{{Host, Port}, _}, Session}, LifeTime) ->
session_validation({{Port, _}, Session}, LifeTime) ->
validate_session(Port, Session, LifeTime),
LifeTime.
-
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 6b7cffaa7d..acd0d49c19 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -66,10 +66,9 @@
%%====================================================================
%% Internal application API
%%====================================================================
+
%%--------------------------------------------------------------------
-%% Function: init_connection_states(Role) -> #connection_states{}
-%% Role = client | server
-%% Random = binary()
+-spec init_connection_states(client | server) -> #connection_states{}.
%%
%% Description: Creates a connection_states record with appropriate
%% values for the initial SSL connection setup.
@@ -85,9 +84,8 @@ init_connection_states(Role) ->
}.
%%--------------------------------------------------------------------
-%% Function: current_connection_state(States, Type) -> #connection_state{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec current_connection_state(#connection_states{}, read | write) ->
+ #connection_state{}.
%%
%% Description: Returns the instance of the connection_state record
%% that is currently defined as the current conection state.
@@ -100,9 +98,8 @@ current_connection_state(#connection_states{current_write = Current},
Current.
%%--------------------------------------------------------------------
-%% Function: pending_connection_state(States, Type) -> #connection_state{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec pending_connection_state(#connection_states{}, read | write) ->
+ #connection_state{}.
%%
%% Description: Returns the instance of the connection_state record
%% that is currently defined as the pending conection state.
@@ -115,14 +112,11 @@ pending_connection_state(#connection_states{pending_write = Pending},
Pending.
%%--------------------------------------------------------------------
-%% Function: update_security_params(Params, States) ->
-%% #connection_states{}
-%% Params = #security_parameters{}
-%% States = #connection_states{}
+-spec update_security_params(#security_parameters{}, #security_parameters{},
+ #connection_states{}) -> #connection_states{}.
%%
%% Description: Creates a new instance of the connection_states record
-%% where the pending states gets its security parameters
-%% updated to <Params>.
+%% where the pending states gets its security parameters updated.
%%--------------------------------------------------------------------
update_security_params(ReadParams, WriteParams, States =
#connection_states{pending_read = Read,
@@ -135,14 +129,10 @@ update_security_params(ReadParams, WriteParams, States =
WriteParams}
}.
%%--------------------------------------------------------------------
-%% Function: set_mac_secret(ClientWriteMacSecret,
-%% ServerWriteMacSecret, Role, States) ->
-%% #connection_states{}
-%% MacSecret = binary()
-%% States = #connection_states{}
-%% Role = server | client
+-spec set_mac_secret(binary(), binary(), client | server,
+ #connection_states{}) -> #connection_states{}.
%%
-%% update the mac_secret field in pending connection states
+%% Description: update the mac_secret field in pending connection states
%%--------------------------------------------------------------------
set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret, client, States) ->
set_mac_secret(ServerWriteMacSecret, ClientWriteMacSecret, States);
@@ -159,12 +149,9 @@ set_mac_secret(ReadMacSecret, WriteMacSecret,
%%--------------------------------------------------------------------
-%% Function: set_master_secret(MasterSecret, States) ->
-%% #connection_states{}
-%% MacSecret =
-%% States = #connection_states{}
+-spec set_master_secret(binary(), #connection_states{}) -> #connection_states{}.
%%
-%% Set master_secret in pending connection states
+%% Description: Set master_secret in pending connection states
%%--------------------------------------------------------------------
set_master_secret(MasterSecret,
States = #connection_states{pending_read = Read,
@@ -180,12 +167,9 @@ set_master_secret(MasterSecret,
States#connection_states{pending_read = Read1, pending_write = Write1}.
%%--------------------------------------------------------------------
-%% Function: set_renegotiation_flag(Flag, States) ->
-%% #connection_states{}
-%% Flag = boolean()
-%% States = #connection_states{}
+-spec set_renegotiation_flag(boolean(), #connection_states{}) -> #connection_states{}.
%%
-%% Set master_secret in pending connection states
+%% Description: Set secure_renegotiation in pending connection states
%%--------------------------------------------------------------------
set_renegotiation_flag(Flag, #connection_states{
current_read = CurrentRead0,
@@ -203,13 +187,11 @@ set_renegotiation_flag(Flag, #connection_states{
pending_write = PendingWrite}.
%%--------------------------------------------------------------------
-%% Function: set_client_verify_data(State, Data, States) ->
-%% #connection_states{}
-%% State = atom()
-%% Data = binary()
-%% States = #connection_states{}
+-spec set_client_verify_data(current_read | current_write | current_both,
+ binary(), #connection_states{})->
+ #connection_states{}.
%%
-%% Set verify data in connection states.
+%% Description: Set verify data in connection states.
%%--------------------------------------------------------------------
set_client_verify_data(current_read, Data,
#connection_states{current_read = CurrentRead0,
@@ -235,15 +217,12 @@ set_client_verify_data(current_both, Data,
CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data},
ConnectionStates#connection_states{current_read = CurrentRead,
current_write = CurrentWrite}.
-
%%--------------------------------------------------------------------
-%% Function: set_server_verify_data(State, Data, States) ->
-%% #connection_states{}
-%% State = atom()
-%% Data = binary()
-%% States = #connection_states{}
+-spec set_server_verify_data(current_read | current_write | current_both,
+ binary(), #connection_states{})->
+ #connection_states{}.
%%
-%% Set verify data in pending connection states.
+%% Description: Set verify data in pending connection states.
%%--------------------------------------------------------------------
set_server_verify_data(current_write, Data,
#connection_states{pending_read = PendingRead0,
@@ -273,10 +252,8 @@ set_server_verify_data(current_both, Data,
current_write = CurrentWrite}.
%%--------------------------------------------------------------------
-%% Function: activate_pending_connection_state(States, Type) ->
-%% #connection_states{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec activate_pending_connection_state(#connection_states{}, read | write) ->
+ #connection_states{}.
%%
%% Description: Creates a new instance of the connection_states record
%% where the pending state of <Type> has been activated.
@@ -308,11 +285,9 @@ activate_pending_connection_state(States =
}.
%%--------------------------------------------------------------------
-%% Function: set_pending_cipher_state(States, ClientState,
-%% ServerState, Role) ->
-%% #connection_states{}
-%% ClientState = ServerState = #cipher_state{}
-%% States = #connection_states{}
+-spec set_pending_cipher_state(#connection_states{}, #cipher_state{},
+ #cipher_state{}, client | server) ->
+ #connection_states{}.
%%
%% Description: Set the cipher state in the specified pending connection state.
%%--------------------------------------------------------------------
@@ -331,12 +306,10 @@ set_pending_cipher_state(#connection_states{pending_read = Read,
pending_write = Write#connection_state{cipher_state = ClientState}}.
%%--------------------------------------------------------------------
-%% Function: get_tls_record(Data, Buffer) -> Result
-%% Result = {[#tls_compressed{}], NewBuffer}
-%% Data = Buffer = NewBuffer = binary()
-%%
-%% Description: given old buffer and new data from TCP, packs up a records
-%% and returns it as a list of #tls_compressed, also returns leftover
+-spec get_tls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}.
+%%
+%% Description: Given old buffer and new data from TCP, packs up a records
+%% and returns it as a list of tls_compressed binaries also returns leftover
%% data
%%--------------------------------------------------------------------
get_tls_records(Data, <<>>) ->
@@ -399,8 +372,8 @@ get_tls_records_aux(Data, Acc) ->
{lists:reverse(Acc), Data}.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Version) -> #protocol_version{}
-%% Version = atom()
+-spec protocol_version(tls_atom_version() | tls_version()) ->
+ tls_version() | tls_atom_version().
%%
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
@@ -420,8 +393,7 @@ protocol_version({3, 1}) ->
protocol_version({3, 0}) ->
sslv3.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Version1, Version2) -> #protocol_version{}
-%% Version1 = Version2 = #protocol_version{}
+-spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
%%
%% Description: Lowes protocol version of two given versions
%%--------------------------------------------------------------------
@@ -436,8 +408,7 @@ lowest_protocol_version(Version = {M,_},
lowest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Versions) -> #protocol_version{}
-%% Versions = [#protocol_version{}]
+-spec highest_protocol_version([tls_version()]) -> tls_version().
%%
%% Description: Highest protocol version present in a list
%%--------------------------------------------------------------------
@@ -459,9 +430,8 @@ highest_protocol_version(_, [Version | Rest]) ->
highest_protocol_version(Version, Rest).
%%--------------------------------------------------------------------
-%% Function: supported_protocol_versions() -> Versions
-%% Versions = [#protocol_version{}]
-%%
+-spec supported_protocol_versions() -> [tls_version()].
+%%
%% Description: Protocol versions supported
%%--------------------------------------------------------------------
supported_protocol_versions() ->
@@ -487,8 +457,7 @@ supported_protocol_versions([_|_] = Vsns) ->
Vsns.
%%--------------------------------------------------------------------
-%% Function: is_acceptable_version(Version) -> true | false
-%% Version = #protocol_version{}
+-spec is_acceptable_version(tls_version()) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
%%--------------------------------------------------------------------
@@ -499,7 +468,7 @@ is_acceptable_version(_) ->
false.
%%--------------------------------------------------------------------
-%% Function: compressions() -> binary()
+-spec compressions() -> [binary()].
%%
%% Description: return a list of compressions supported (currently none)
%%--------------------------------------------------------------------
@@ -507,8 +476,8 @@ compressions() ->
[?byte(?NULL)].
%%--------------------------------------------------------------------
-%% Function: decode_cipher_text(CipherText, ConnectionStates0) ->
-%% {Plain, ConnectionStates}
+-spec decode_cipher_text(#ssl_tls{}, #connection_states{}) ->
+ {#ssl_tls{}, #connection_states{}}| #alert{}.
%%
%% Description: Decode cipher text
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index bcb10daf69..6db13e5b7a 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -32,11 +32,10 @@
-define(GEN_UNIQUE_ID_MAX_TRIES, 10).
+-type seconds() :: integer().
+
%%--------------------------------------------------------------------
-%% Function: is_new(ClientSuggestedId, ServerDecidedId) -> true | false
-%%
-%% ClientSuggestedId = binary()
-%% ServerDecidedId = binary()
+-spec is_new(session_id(), session_id()) -> boolean().
%%
%% Description: Checks if the session id decided by the server is a
%% new or resumed sesion id.
@@ -45,17 +44,11 @@ is_new(<<>>, _) ->
true;
is_new(SessionId, SessionId) ->
false;
-is_new(_, _) ->
+is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
-%% Function: id(ClientInfo, Cache, CacheCb) -> SessionId
-%%
-%% ClientInfo = {HostIP, Port, SslOpts}
-%% HostIP = ipadress()
-%% Port = integer()
-%% CacheCb = atom()
-%% SessionId = binary()
+-spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom()) -> binary().
%%
%% Description: Should be called by the client side to get an id
%% for the client hello message.
@@ -69,14 +62,8 @@ id(ClientInfo, Cache, CacheCb) ->
end.
%%--------------------------------------------------------------------
-%% Function: id(Port, SuggestedSessionId, ReuseFun, CacheCb,
-%% SecondLifeTime) -> SessionId
-%%
-%% Port = integer()
-%% SuggestedSessionId = SessionId = binary()
-%% ReuseFun = fun(SessionId, PeerCert, Compression, CipherSuite) ->
-%% true | false
-%% CacheCb = atom()
+-spec id(port_num(), binary(), #ssl_options{}, cache_ref(),
+ atom(), seconds()) -> binary().
%%
%% Description: Should be called by the server side to get an id
%% for the server hello message.
@@ -95,10 +82,7 @@ id(Port, SuggestedSessionId, #ssl_options{reuse_sessions = ReuseEnabled,
new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb)
end.
%%--------------------------------------------------------------------
-%% Function: valid_session(Session, LifeTime) -> true | false
-%%
-%% Session = #session{}
-%% LifeTime = integer() - seconds
+-spec valid_session(#session{}, seconds()) -> boolean().
%%
%% Description: Check that the session has not expired
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index 1f2d1fc7d3..823bf7acfa 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -22,13 +22,16 @@
-behaviour(ssl_session_cache_api).
+-include("ssl_handshake.hrl").
+-include("ssl_internal.hrl").
+
-export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3,
select_session/2]).
+-type key() :: {{host(), port_num()}, session_id()} | {port_num(), session_id()}.
+
%%--------------------------------------------------------------------
-%% Function: init() -> Cache
-%%
-%% Cache - Reference to the cash (opaque)
+-spec init(list()) -> cache_ref(). %% Returns reference to the cache (opaque)
%%
%% Description: Return table reference. Called by ssl_manager process.
%%--------------------------------------------------------------------
@@ -36,9 +39,7 @@ init(_) ->
ets:new(cache_name(), [set, protected]).
%%--------------------------------------------------------------------
-%% Function: terminate(Cache) ->
-%%
-%% Cache - as returned by create/0
+-spec terminate(cache_ref()) -> any(). %%
%%
%% Description: Handles cache table at termination of ssl manager.
%%--------------------------------------------------------------------
@@ -46,9 +47,7 @@ terminate(Cache) ->
ets:delete(Cache).
%%--------------------------------------------------------------------
-%% Function: lookup(Cache, Key) -> Session | undefined
-%% Cache - as returned by create/0
-%% Session = #session{}
+-spec lookup(cache_ref(), key()) -> #session{} | undefined.
%%
%% Description: Looks up a cach entry. Should be callable from any
%% process.
@@ -62,9 +61,7 @@ lookup(Cache, Key) ->
end.
%%--------------------------------------------------------------------
-%% Function: update(Cache, Key, Session) -> _
-%% Cache - as returned by create/0
-%% Session = #session{}
+-spec update(cache_ref(), key(), #session{}) -> any().
%%
%% Description: Caches a new session or updates a already cached one.
%% Will only be called from the ssl_manager process.
@@ -73,11 +70,7 @@ update(Cache, Key, Session) ->
ets:insert(Cache, {Key, Session}).
%%--------------------------------------------------------------------
-%% Function: delete(Cache, HostIP, Port, Id) -> _
-%% Cache - as returned by create/0
-%% HostIP = Host = string() | ipadress()
-%% Port = integer()
-%% Id =
+-spec delete(cache_ref(), key()) -> any().
%%
%% Description: Delets a cache entry.
%% Will only be called from the ssl_manager process.
@@ -86,28 +79,19 @@ delete(Cache, Key) ->
ets:delete(Cache, Key).
%%--------------------------------------------------------------------
-%% Function: foldl(Fun, Acc0, Cache) -> Acc
-%%
-%% Fun - fun()
-%% Acc0 - term()
-%% Cache - cache_ref()
-%%
+-spec foldl(fun(), term(), cache_ref()) -> term().
%%
%% Description: Calls Fun(Elem, AccIn) on successive elements of the
%% cache, starting with AccIn == Acc0. Fun/2 must return a new
%% accumulator which is passed to the next call. The function returns
-%% the final value of the accumulator. Acc0 is returned if the cache is
-%% empty.
-%% Should be callable from any process
+%% the final value of the accumulator. Acc0 is returned if the cache
+%% is empty.Should be callable from any process
%%--------------------------------------------------------------------
foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
%%--------------------------------------------------------------------
-%% Function: select_session(Cache, PartialKey) -> [Sessions]
-%%
-%% Cache - as returned by create/0
-%% PartialKey - opaque Key = {PartialKey, SessionId}
+-spec select_session(cache_ref(), {host(), port_num()} | port_num()) -> [#session{}].
%%
%% Description: Selects a session that could be reused. Should be callable
%% from any process.
@@ -119,6 +103,5 @@ select_session(Cache, PartialKey) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-
cache_name() ->
ssl_otp_session_cache.
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index 88b801d46b..1add203fb0 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -38,6 +38,8 @@
%% Internal application API
%%====================================================================
+-spec master_secret(binary(), binary(), binary()) -> binary().
+
master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
?DBG_HEX(PremasterSecret),
?DBG_HEX(ClientRandom),
@@ -57,6 +59,8 @@ master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
?DBG_HEX(B),
B.
+-spec finished(client | server, binary(), {binary(), binary()}) -> binary().
+
finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
%% draft-ietf-tls-ssl-version3-00 - 5.6.9 Finished
%% struct {
@@ -75,6 +79,8 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash),
<<MD5/binary, SHA/binary>>.
+-spec certificate_verify(key_algo(), binary(), {binary(), binary()}) -> binary().
+
certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
when Algorithm == rsa; Algorithm == dhe_rsa ->
%% md5_hash
@@ -94,6 +100,8 @@ certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) ->
%% SHA(handshake_messages + master_secret + pad_1));
handshake_hash(?SHA, MasterSecret, undefined, SHAHash).
+-spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary().
+
mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
%% draft-ietf-tls-ssl-version3-00 - 5.2.3.1
%% hash(MAC_write_secret + pad_2 +
@@ -113,6 +121,11 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
?DBG_HEX(Mac),
Mac.
+-spec setup_keys(binary(), binary(), binary(),
+ integer(), integer(), term(), integer()) ->
+ {binary(), binary(), binary(),
+ binary(), binary(), binary()}.
+
setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom,
2*(HS+KML+IVS)),
@@ -136,6 +149,8 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
+-spec suites() -> [cipher_suite()].
+
suites() ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index b7cb5c3ab3..316ed8a4e9 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -32,14 +32,17 @@
%%%=========================================================================
%%% API
%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-%% init([]) -> {ok, {SupFlags, [ChildSpec]}}
-%%
+-spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}.
+
init([]) ->
%% OLD ssl - moved start to ssl.erl only if old
%% ssl is acctualy run!
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 70db632835..d1bc0730ba 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -36,6 +36,8 @@
%% Internal application API
%%====================================================================
+-spec master_secret(binary(), binary(), binary()) -> binary().
+
master_secret(PreMasterSecret, ClientRandom, ServerRandom) ->
%% RFC 2246 & 4346 - 8.1 %% master_secret = PRF(pre_master_secret,
%% "master secret", ClientHello.random +
@@ -43,6 +45,8 @@ master_secret(PreMasterSecret, ClientRandom, ServerRandom) ->
prf(PreMasterSecret, <<"master secret">>,
[ClientRandom, ServerRandom], 48).
+-spec finished(client | server, binary(), {binary(), binary()}) -> binary().
+
finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
%% RFC 2246 & 4346 - 7.4.9. Finished
%% struct {
@@ -56,6 +60,7 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = hash_final(?SHA, SHAHash),
prf(MasterSecret, finished_label(Role), [MD5, SHA], 12).
+-spec certificate_verify(key_algo(), {binary(), binary()}) -> binary().
certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
Algorithm == dhe_rsa ->
@@ -65,7 +70,11 @@ certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
certificate_verify(dhe_dss, {_, SHAHash}) ->
hash_final(?SHA, SHAHash).
-
+
+-spec setup_keys(binary(), binary(), binary(), integer(),
+ integer(), integer()) -> {binary(), binary(), binary(),
+ binary(), binary(), binary()}.
+
setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize) ->
%% RFC 2246 - 6.3. Key calculation
@@ -112,6 +121,9 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize,
%% {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
%% ServerWriteKey, undefined, undefined}.
+-spec mac_hash(integer(), binary(), integer(), integer(), tls_version(),
+ integer(), binary()) -> binary().
+
mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Length, Fragment) ->
%% RFC 2246 & 4346 - 6.2.3.1.
@@ -132,6 +144,8 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
?DBG_HEX(Mac),
Mac.
+-spec suites() -> [cipher_suite()].
+
suites() ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 1d2cea6c72..c9db0d3851 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -56,7 +56,7 @@
make_cert(Opts) ->
SubjectPrivateKey = get_key(Opts),
{TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
- Cert = public_key:sign(TBSCert, IssuerKey),
+ Cert = public_key:pkix_sign(TBSCert, IssuerKey),
true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
{Cert, encode_key(SubjectPrivateKey)}.
@@ -66,8 +66,9 @@ make_cert(Opts) ->
%% @end
%%--------------------------------------------------------------------
write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]),
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
+ ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ [{'Certificate', Cert, not_encrypted}]),
+ ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
%%--------------------------------------------------------------------
%% @doc Creates a rsa key (OBS: for testing only)
@@ -94,18 +95,14 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
%%--------------------------------------------------------------------
-verify_signature(DerEncodedCert, DerKey, KeyParams) ->
+verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
Key = decode_key(DerKey),
case Key of
#'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
- public_key:verify_signature(DerEncodedCert,
- #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
- 'NULL');
+ public_key:pkix_verify(DerEncodedCert,
+ #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G});
-
- _ ->
- public_key:verify_signature(DerEncodedCert, Key, KeyParams)
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -132,19 +129,18 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
-decode_key(Der = {_,_,_}, Pw) ->
- {ok, Key} = public_key:decode_private_key(Der, Pw),
- Key;
-decode_key(FileOrDer, Pw) ->
- {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer),
+decode_key(PemEntry = {_,_,_}, Pw) ->
+ public_key:pem_entry_decode(PemEntry, Pw);
+decode_key(PemBin, Pw) ->
+ [KeyInfo] = public_key:pem_decode(PemBin),
decode_key(KeyInfo, Pw).
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {rsa_private_key, list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {dsa_private_key, list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -178,7 +174,7 @@ issuer(Opts, SubjectKey) ->
end.
issuer_der(Issuer) ->
- {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp),
+ Decoded = public_key:pkix_decode_cert(Issuer, otp),
#'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
#'OTPTBSCertificate'{subject=Subject} = Tbs,
Subject.
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 0cdf33c3e2..3c18a905b4 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -90,8 +90,10 @@ enduser(Root, OpenSSLCmd, CA, User) ->
KeyFile = filename:join([UsrRoot, "key.pem"]),
ReqFile = filename:join([UsrRoot, "req.pem"]),
create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
- CertFile = filename:join([UsrRoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFile).
+ CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
collect_certs(Root, CAs, Users) ->
Bins = lists:foldr(
@@ -255,6 +257,7 @@ ca_cnf(CA) ->
"RANDFILE = $dir/private/RAND\n"
"\n"
"x509_extensions = user_cert\n"
+ "unique_subject = no\n"
"default_days = 3600\n"
"default_md = sha1\n"
"preserve = no\n"
@@ -279,6 +282,15 @@ ca_cnf(CA) ->
"issuerAltName = issuer:copy\n"
"\n"
+ "[user_cert_digital_signature_only]\n"
+ "basicConstraints = CA:false\n"
+ "keyUsage = digitalSignature\n"
+ "subjectKeyIdentifier = hash\n"
+ "authorityKeyIdentifier = keyid,issuer:always\n"
+ "subjectAltName = email:copy\n"
+ "issuerAltName = issuer:copy\n"
+ "\n"
+
"[ca_cert]\n"
"basicConstraints = critical,CA:true\n"
"keyUsage = cRLSign, keyCertSign\n"
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8a1b90ed98..53142250e8 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -233,7 +233,8 @@ all(suite) ->
server_renegotiate_reused_session, client_no_wrap_sequence_number,
server_no_wrap_sequence_number, extended_key_usage,
validate_extensions_fun, no_authority_key_identifier,
- invalid_signature_client, invalid_signature_server, cert_expired
+ invalid_signature_client, invalid_signature_server, cert_expired,
+ client_with_cert_cipher_suites_handshake
].
%% Test cases starts here.
@@ -578,8 +579,8 @@ peercert(Config) when is_list(Config) ->
{options, ClientOpts}]),
CertFile = proplists:get_value(certfile, ServerOpts),
- {ok, [{cert, BinCert, _}]} = public_key:pem_to_der(CertFile),
- {ok, ErlCert} = public_key:pkix_decode_cert(BinCert, otp),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+ ErlCert = public_key:pkix_decode_cert(BinCert, otp),
ServerMsg = {{error, no_peercert}, {error, no_peercert}},
ClientMsg = {{ok, BinCert}, {ok, ErlCert}},
@@ -2525,35 +2526,35 @@ extended_key_usage(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
[ServerExtKeyUsageExt |
ServerExtensions]},
- NewServerDerCert = public_key:sign(NewServerOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile),
- {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
[ClientExtKeyUsageExt |
ClientExtensions]},
- NewClientDerCert = public_key:sign(NewClientOTPTbsCert, Key),
- public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]),
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2621,13 +2622,13 @@ no_authority_key_identifier(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
CertFile = proplists:get_value(certfile, ServerOpts),
NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile),
- {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
NewExtensions = delete_authority_key_extension(Extensions, []),
@@ -2635,8 +2636,8 @@ no_authority_key_identifier(Config) when is_list(Config) ->
test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
- NewDerCert = public_key:sign(NewOTPTbsCert, Key),
- public_key:der_to_pem(NewCertFile, [{cert, NewDerCert, not_encrypted}]),
+ NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2679,16 +2680,16 @@ invalid_signature_server(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "server/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
- {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- NewServerDerCert = public_key:sign(ServerOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2719,16 +2720,16 @@ invalid_signature_client(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "client/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
- {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile),
- {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- NewClientDerCert = public_key:sign(ClientOTPTbsCert, Key),
- public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]),
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2796,13 +2797,13 @@ cert_expired(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
- {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
{Year, Month, Day} = date(),
@@ -2825,8 +2826,8 @@ cert_expired(Config) when is_list(Config) ->
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
- NewServerDerCert = public_key:sign(NewOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2849,6 +2850,39 @@ two_digits_str(N) ->
lists:flatten(io_lib:format("~p", [N])).
%%--------------------------------------------------------------------
+
+client_with_cert_cipher_suites_handshake(doc) ->
+ ["Test that client with a certificate without keyEncipherment usage "
+ " extension can connect to a server with restricted cipher suites "];
+
+client_with_cert_cipher_suites_handshake(suite) ->
+ [];
+
+client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts_digital_signature_only, Config),
+ ServerOpts = ?config(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,
+ send_recv_result_active, []}},
+ {options, [{active, true},
+ {ciphers, ssl_test_lib:rsa_non_signed_suites()}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options, [{active, true}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 1b8754afe9..9553241ad4 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -145,14 +145,19 @@ all(suite) ->
packet_baddata_passive, packet_baddata_active,
packet_size_passive, packet_size_active,
packet_cdr_decode,
+ packet_cdr_decode_list,
packet_http_decode,
packet_http_decode_list,
packet_http_bin_decode_multi,
packet_line_decode,
- packet_asn1_decode,
+ packet_line_decode_list,
+ packet_asn1_decode,
+ packet_asn1_decode_list,
packet_tpkt_decode,
+ packet_tpkt_decode_list,
%packet_fcgi_decode,
packet_sunrm_decode,
+ packet_sunrm_decode_list,
header_decode_one_byte,
header_decode_two_bytes,
header_decode_two_bytes_one_sent,
@@ -1429,7 +1434,7 @@ packet_size_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
packet_cdr_decode(doc) ->
- ["Test setting the packet option {packet, cdr}"];
+ ["Test setting the packet option {packet, cdr}, {mode, binary}"];
packet_cdr_decode(suite) ->
[];
packet_cdr_decode(Config) when is_list(Config) ->
@@ -1463,8 +1468,44 @@ packet_cdr_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+packet_cdr_decode_list(doc) ->
+ ["Test setting the packet option {packet, cdr} {mode, list}"];
+packet_cdr_decode_list(suite) ->
+ [];
+packet_cdr_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% A valid cdr packet
+ Data = [71,73,79,80,1,2,2,1,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,1,78,
+ 69,79,0,0,0,0,2,0,10,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,4,49],
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, cdr}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, cdr},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
packet_http_decode(doc) ->
- ["Test setting the packet option {packet, http} {mode, binary}"];
+ ["Test setting the packet option {packet, http} {mode, binary} "
+ "(Body will be binary http strings are lists)"];
packet_http_decode(suite) ->
[];
@@ -1485,7 +1526,7 @@ packet_http_decode(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, server_http_decode,
[Response]}},
- {options, [{active, true}, binary,
+ {options, [{active, true},binary,
{packet, http} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -1494,7 +1535,7 @@ packet_http_decode(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, client_http_decode,
[Request]}},
- {options, [{active, true}, binary,
+ {options, [{active, true}, binary,
{packet, http} |
ClientOpts]}]),
@@ -1548,7 +1589,8 @@ client_http_decode(Socket, HttpRequest) ->
%%--------------------------------------------------------------------
packet_http_decode_list(doc) ->
- ["Test setting the packet option {packet, http}, {mode, list}"];
+ ["Test setting the packet option {packet, http}, {mode, list}"
+ "(Body will be litst too)"];
packet_http_decode_list(suite) ->
[];
packet_http_decode_list(Config) when is_list(Config) ->
@@ -1697,7 +1739,7 @@ client_http_bin_decode(_, _, _) ->
ok.
%%--------------------------------------------------------------------
packet_line_decode(doc) ->
- ["Test setting the packet option {packet, line}"];
+ ["Test setting the packet option {packet, line}, {mode, binary}"];
packet_line_decode(suite) ->
[];
packet_line_decode(Config) when is_list(Config) ->
@@ -1731,30 +1773,44 @@ packet_line_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
-server_line_packet_decode(Socket, Lines) ->
- receive
- {ssl, Socket, <<"Line ends here.\n">>} -> ok;
- Other1 -> exit({?LINE, Other1})
- end,
- receive
- {ssl, Socket, <<"Now it is a new line.\n">>} -> ok;
- Other2 -> exit({?LINE, Other2})
- end,
- ok = ssl:send(Socket, Lines).
+packet_line_decode_list(doc) ->
+ ["Test setting the packet option {packet, line}, {mode, list}"];
+packet_line_decode_list(suite) ->
+ [];
+packet_line_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = lists:flatten(io_lib:format("Line ends here.~n"
+ "Now it is a new line.~n", [])),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ server_line_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, line}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ client_line_packet_decode,
+ [Data]}},
+ {options, [{active, true},
+ {packet, line},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
-client_line_packet_decode(Socket, Lines) ->
- <<P1:10/binary, P2/binary>> = Lines,
- ok = ssl:send(Socket, P1),
- ok = ssl:send(Socket, P2),
- receive
- {ssl, Socket, <<"Line ends here.\n">>} -> ok;
- Other1 -> exit({?LINE, Other1})
- end,
- receive
- {ssl, Socket, <<"Now it is a new line.\n">>} -> ok;
- Other2 -> exit({?LINE, Other2})
- end.
%%--------------------------------------------------------------------
@@ -1770,7 +1826,7 @@ packet_asn1_decode(Config) when is_list(Config) ->
File = proplists:get_value(certfile, ServerOpts),
%% A valid asn1 BER packet (DER is stricter BER)
- {ok,[{cert, Data, _}]} = public_key:pem_to_der(File),
+ [{'Certificate', Data, _}] = ssl_test_lib:pem_to_der(File),
Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
@@ -1794,6 +1850,44 @@ packet_asn1_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+packet_asn1_decode_list(doc) ->
+ ["Test setting the packet option {packet, asn1}"];
+packet_asn1_decode_list(suite) ->
+ [];
+packet_asn1_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ File = proplists:get_value(certfile, ServerOpts),
+
+ %% A valid asn1 BER packet (DER is stricter BER)
+ [{'Certificate', BinData, _}] = ssl_test_lib:pem_to_der(File),
+
+ Data = binary_to_list(BinData),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, asn1}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, asn1},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
packet_tpkt_decode(doc) ->
["Test setting the packet option {packet, tpkt}"];
packet_tpkt_decode(suite) ->
@@ -1826,6 +1920,38 @@ packet_tpkt_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+packet_tpkt_decode_list(doc) ->
+ ["Test setting the packet option {packet, tpkt}"];
+packet_tpkt_decode_list(suite) ->
+ [];
+packet_tpkt_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = binary_to_list(list_to_binary(add_tpkt_header("TPKT data"))),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, tpkt}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, tpkt},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
@@ -1895,6 +2021,39 @@ packet_sunrm_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+packet_sunrm_decode_list(doc) ->
+ ["Test setting the packet option {packet, sunrm}"];
+packet_sunrm_decode_list(suite) ->
+ [];
+packet_sunrm_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = binary_to_list(list_to_binary([<<11:32>>, "Hello world"])),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, sunrm}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, sunrm},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
header_decode_one_byte(doc) ->
@@ -2155,8 +2314,14 @@ server_packet_decode(Socket, Packet) ->
end,
ok = ssl:send(Socket, Packet).
-client_packet_decode(Socket, Packet) ->
+client_packet_decode(Socket, Packet) when is_binary(Packet)->
<<P1:10/binary, P2/binary>> = Packet,
+ client_packet_decode(Socket, P1, P2, Packet);
+client_packet_decode(Socket, [Head | Tail] = Packet) ->
+ client_packet_decode(Socket, [Head], Tail, Packet).
+
+client_packet_decode(Socket, P1, P2, Packet) ->
+ test_server:format("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
@@ -2176,7 +2341,7 @@ server_header_decode(Socket, Packet, Result) ->
end,
ok = ssl:send(Socket, Packet),
receive
- {ssl, Socket, Result} -> ok;
+ {ssl, Socket, Result} -> ok;
Other2 -> exit({?LINE, Other2})
end,
ok = ssl:send(Socket, Packet).
@@ -2192,6 +2357,44 @@ client_header_decode(Socket, Packet, Result) ->
{ssl, Socket, Result} -> ok;
Other2 -> exit({?LINE, Other2})
end.
+
+server_line_packet_decode(Socket, Packet) when is_binary(Packet) ->
+ [L1, L2] = string:tokens(binary_to_list(Packet), "\n"),
+ server_line_packet_decode(Socket, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n"), Packet);
+server_line_packet_decode(Socket, Packet) ->
+ [L1, L2] = string:tokens(Packet, "\n"),
+ server_line_packet_decode(Socket, L1 ++ "\n", L2 ++ "\n", Packet).
+
+server_line_packet_decode(Socket, L1, L2, Packet) ->
+ receive
+ {ssl, Socket, L1} -> ok;
+ Other1 -> exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, L2} -> ok;
+ Other2 -> exit({?LINE, Other2})
+ end,
+ ok = ssl:send(Socket, Packet).
+
+client_line_packet_decode(Socket, Packet) when is_binary(Packet)->
+ <<P1:10/binary, P2/binary>> = Packet,
+ [L1, L2] = string:tokens(binary_to_list(Packet), "\n"),
+ client_line_packet_decode(Socket, P1, P2, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n"));
+client_line_packet_decode(Socket, [Head | Tail] = Packet) ->
+ [L1, L2] = string:tokens(Packet, "\n"),
+ client_line_packet_decode(Socket, [Head], Tail, L1 ++ "\n", L2 ++ "\n").
+
+client_line_packet_decode(Socket, P1, P2, L1, L2) ->
+ ok = ssl:send(Socket, P1),
+ ok = ssl:send(Socket, P2),
+ receive
+ {ssl, Socket, L1} -> ok;
+ Other1 -> exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, L2} -> ok;
+ Other2 -> exit({?LINE, Other2})
+ end.
add_tpkt_header(Data) when is_binary(Data) ->
L = size(Data) + 4,
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 40715dbf30..c7ff015034 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -268,6 +268,8 @@ cert_options(Config) ->
"client", "cacerts.pem"]),
ClientCertFile = filename:join([?config(priv_dir, Config),
"client", "cert.pem"]),
+ ClientCertFileDigitalSignatureOnly = filename:join([?config(priv_dir, Config),
+ "client", "digital_signature_only_cert.pem"]),
ServerCaCertFile = filename:join([?config(priv_dir, Config),
"server", "cacerts.pem"]),
ServerCertFile = filename:join([?config(priv_dir, Config),
@@ -292,6 +294,10 @@ cert_options(Config) ->
{certfile, ClientCertFile},
{keyfile, ClientKeyFile},
{ssl_imp, new}]},
+ {client_verification_opts_digital_signature_only, [{cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFileDigitalSignatureOnly},
+ {keyfile, ClientKeyFile},
+ {ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
@@ -325,6 +331,10 @@ make_dsa_cert(Config) ->
[{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_dsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
@@ -342,9 +352,9 @@ make_dsa_cert_files(RoleStr, Config) ->
KeyFile = filename:join([?config(priv_dir, Config),
RoleStr, "dsa_key.pem"]),
- public_key:der_to_pem(CaCertFile, [{cert, CaCert, not_encrypted}]),
- public_key:der_to_pem(CertFile, [{cert, Cert, not_encrypted}]),
- public_key:der_to_pem(KeyFile, [CertKey]),
+ der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
+ der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
+ der_to_pem(KeyFile, [CertKey]),
{CaCertFile, CertFile, KeyFile}.
start_upgrade_server(Args) ->
@@ -567,6 +577,14 @@ rsa_suites() ->
end,
ssl:cipher_suites()).
+rsa_non_signed_suites() ->
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
dsa_suites() ->
lists:filter(fun({dhe_dss, _, _}) ->
true;
@@ -597,3 +615,11 @@ openssl_dsa_suites() ->
true
end
end, Ciphers).
+
+pem_to_der(File) ->
+ {ok, PemBin} = file:read_file(File),
+ public_key:pem_decode(PemBin).
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index d2a4ca8db5..75cfce0052 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -309,7 +309,7 @@ tls1_erlang_server_openssl_client_dsa_cert(suite) ->
tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
@@ -398,7 +398,7 @@ ssl3_erlang_server_openssl_client_dsa_cert(suite) ->
ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 74b1cf4c78..6c40a4529c 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -17,45 +17,4 @@
# %CopyrightEnd%
#
-SSL_VSN = 4.0
-
-TICKETS = OTP-8587\
- OTP-8695
-
-#TICKETS = OTP-8679 \
-# OTP-7047 \
-# OTP-7049 \
-# OTP-8568 \
-# OTP-8588
-
-#TICKETS_3.11 = OTP-8517 \
-# OTP-7046 \
-# OTP-8557 \
-# OTP-8560 \
-# OTP-8545 \
-# OTP-8554
-
-#TICKETS_3.10.9 = OTP-8510
-
-#TICKETS_3.10.8 = OTP-8372 OTP-8441 OTP-8459
-#TICKETS_3.10.7 = OTP-8260 OTP-8218 OTP-8250
-
-#TICKETS_3.10.6 = OTP-8275
-
-#TICKETS_3.10.5 = OTP-8224 OTP-8244
-
-#TICKETS_3.10.4 = OTP-8137
-
-#TICKETS_3.10.3 = OTP-8011
-#TICKETS_3.10.2 = OTP-7963
-
-# TICKETS_3.10.1 = OTP-7878 \
-# OTP-7656 \
-# OTP-7870 \
-# OTP-7871
-
-# TICKETS_3.10 = OTP-7258 \
-# OTP-6894 \
-# OTP-7037 \
-# OTP-7039 \
-# OTP-7150
+SSL_VSN = 4.0.1
diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml
index 27308e02f3..adc411e272 100644
--- a/lib/stdlib/doc/src/beam_lib.xml
+++ b/lib/stdlib/doc/src/beam_lib.xml
@@ -341,6 +341,7 @@ chunkref() = chunkname() | chunkid()</code>
<v>Beam1 = Beam2 = beam()</v>
<v>Reason = {modules_different, Module1, Module2}</v>
<v>&nbsp;&nbsp;| {chunks_different, ChunkId}</v>
+ <v>&nbsp;&nbsp;| different_chunks</v>
<v>&nbsp;&nbsp;| Reason1 -- see info/1</v>
<v>&nbsp;Module1 = Module2 = atom()</v>
<v>&nbsp;ChunkId = chunkid()</v>
diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml
index 8d1398d3b7..ad100d2cf5 100644
--- a/lib/stdlib/doc/src/dets.xml
+++ b/lib/stdlib/doc/src/dets.xml
@@ -109,7 +109,7 @@ bool() = true | false
file() = string()
int() = integer() >= 0
keypos() = integer() >= 1
-name() = atom() | ref()
+name() = atom() | reference()
no_slots() = integer() >= 0 | default
object() = tuple()
object_cont() = tuple()
@@ -759,7 +759,7 @@ ok
<fsummary>Open an existing Dets table.</fsummary>
<type>
<v>FileName = file()</v>
- <v>Reference = ref()</v>
+ <v>Reference = reference()</v>
</type>
<desc>
<p>Opens an existing table. If the table has not been properly
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index ee1befc882..5df60a92e5 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -1039,15 +1039,22 @@ ets:select(Table,MatchSpec),</code>
the owner terminates.</p>
</item>
<item>
+ <marker id="new_2_write_concurrency"></marker>
<p><c>{write_concurrency,bool()}</c>
- Performance tuning. Default is <c>false</c>, which means that the table
- is optimized towards concurrent read access. An operation that
+ Performance tuning. Default is <c>false</c>. An operation that
mutates (writes to) the table will obtain exclusive access,
blocking any concurrent access of the same table until finished.
If set to <c>true</c>, the table is optimized towards concurrent
write access. Different objects of the same table can be mutated
(and read) by concurrent processes. This is achieved to some degree
at the expense of single access and concurrent reader performance.
+ The <c>write_concurrency</c> option can be combined with the
+ <seealso marker="#new_2_read_concurrency">read_concurrency</seealso>
+ option. You typically want to combine these when large concurrent
+ read bursts and large concurrent write bursts are common (see the
+ documentation of the
+ <seealso marker="#new_2_read_concurrency">read_concurrency</seealso>
+ option for more information).
Note that this option does not change any guarantees about
<seealso marker="#concurrency">atomicy and isolation</seealso>.
Functions that makes such promises over several objects (like
@@ -1055,6 +1062,29 @@ ets:select(Table,MatchSpec),</code>
<p>Table type <c>ordered_set</c> is not affected by this option in current
implementation.</p>
</item>
+ <item>
+ <marker id="new_2_read_concurrency"></marker>
+ <p><c>{read_concurrency,bool()}</c>
+ Performance tuning. Default is <c>false</c>. When set to
+ <c>true</c>, the table is optimized for concurrent read
+ operations. When this option is enabled on a runtime system with
+ SMP support, read operations become much cheaper; especially on
+ systems with multiple physical processors. However, switching
+ between read and write operations becomes more expensive. You
+ typically want to enable this option when concurrent read
+ operations are much more frequent than write operations, or when
+ concurrent reads and writes comes in large read and write
+ bursts (i.e., lots of reads not interrupted by writes, and lots
+ of writes not interrupted by reads). You typically do
+ <em>not</em> want to enable this option when the common access
+ pattern is a few read operations interleaved with a few write
+ operations repeatedly. In this case you will get a performance
+ degradation by enabling this option. The <c>read_concurrency</c>
+ option can be combined with the
+ <seealso marker="#new_2_write_concurrency">write_concurrency</seealso>
+ option. You typically want to combine these when large concurrent
+ read bursts and large concurrent write bursts are common.</p>
+ </item>
</list>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index 0cf82fa48b..fe6c6f898e 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -49,7 +49,7 @@
<title>DATA TYPES</title>
<code type="none">
name() = string() | atom() | DeepList
- DeepList = [char() | atom() | DeepList]</code>
+DeepList = [char() | atom() | DeepList]</code>
</section>
<funcs>
<func>
diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml
index b52e862a5c..a97d996d98 100644
--- a/lib/stdlib/doc/src/io_protocol.xml
+++ b/lib/stdlib/doc/src/io_protocol.xml
@@ -79,7 +79,7 @@ sends the reply to.</item>
io_reply. The io-module in the Erlang standard library simply uses the pid()
of the io_server as the ReplyAs datum, but a more complicated client
could have several outstanding io-requests to the same server and
-would then use i.e. a ref() or something else to differentiate among
+would then use i.e. a reference() or something else to differentiate among
the incoming io_reply's. The ReplyAs element should be considered
opaque by the io_server. Note that the pid() of the server is not
explicitly present in the io_reply. The reply can be sent from any
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index a273a2301f..b3ad7aaf46 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -48,7 +48,7 @@
<item><p>if x <c>F</c> y and y <c>F</c> x then x = y (<c>F</c>
is antisymmetric);</p>
</item>
- <item><p>if x <c>F</c> y and and y <c>F</c> z then x <c>F</c> z
+ <item><p>if x <c>F</c> y and y <c>F</c> z then x <c>F</c> z
(<c>F</c> is transitive);</p>
</item>
<item><p>x <c>F</c> y or y <c>F</c> x (<c>F</c> is total).</p>
diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml
index 8c8ae51262..729df1e678 100644
--- a/lib/stdlib/doc/src/sofs.xml
+++ b/lib/stdlib/doc/src/sofs.xml
@@ -210,7 +210,7 @@
X[i] to Y[i] and S a subset of
X[1]&nbsp;&times;&nbsp;...&nbsp;&times;&nbsp;X[n].
The <marker id="multiple_relative_product"></marker><em>multiple
- relative product</em> of TR and and S is defined to be the
+ relative product</em> of TR and S is defined to be the
set {z&nbsp;: z&nbsp;= ((x[1],&nbsp;...,&nbsp;x[n]), (y[1],...,y[n]))
for some (x[1],&nbsp;...,&nbsp;x[n])&nbsp;in&nbsp;S and for some
(x[i],&nbsp;y[i]) in R[i],
diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml
index 0b6807dd6c..1b34e71490 100644
--- a/lib/stdlib/doc/src/timer.xml
+++ b/lib/stdlib/doc/src/timer.xml
@@ -202,18 +202,33 @@
</func>
<func>
<name>tc(Module, Function, Arguments) -> {Time, Value}</name>
- <fsummary>Measure the real time it takes to evaluate <c>apply(Module, Function, Arguments)</c></fsummary>
+ <name>tc(Fun, Arguments) -> {Time, Value}</name>
+ <fsummary>Measure the real time it takes to evaluate <c>apply(Module,
+ Function, Arguments)</c> or <c>apply(Fun, Arguments)</c></fsummary>
<type>
<v>Module = Function = atom()</v>
+ <v>Fun = fun()</v>
<v>Arguments = [term()]</v>
<v>Time = integer() in microseconds</v>
<v>Value = term()</v>
</type>
<desc>
- <p>Evaluates <c>apply(Module, Function, Arguments)</c> and measures
- the elapsed real time. Returns <c>{Time, Value}</c>, where
- <c>Time</c> is the elapsed real time in <em>microseconds</em>,
- and <c>Value</c> is what is returned from the apply.</p>
+ <p></p>
+ <taglist>
+ <tag><c>tc/3</c></tag>
+ <item>
+ <p>Evaluates <c>apply(Module, Function, Arguments)</c> and measures
+ the elapsed real time as reported by <c>now/0</c>.
+ Returns <c>{Time, Value}</c>, where
+ <c>Time</c> is the elapsed real time in <em>microseconds</em>,
+ and <c>Value</c> is what is returned from the apply.</p>
+ </item>
+ <tag><c>tc/2</c></tag>
+ <item>
+ <p>Evaluates <c>apply(Fun, Arguments)</c>. Otherwise works
+ like <c>tc/3</c>.</p>
+ </item>
+ </taglist>
</desc>
</func>
<func>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 91ff2438c6..e612bf71e7 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -105,6 +105,7 @@
| info_rsn().
-type cmp_rsn() :: {'modules_different', module(), module()}
| {'chunks_different', chunkid()}
+ | 'different_chunks'
| info_rsn().
%%-------------------------------------------------------------------------
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index d26443f277..99e454f593 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -24,35 +24,41 @@
%% Internal API.
-export([start/0, start/1]).
--include_lib("kernel/include/file.hrl").
+%%-----------------------------------------------------------------------
-define(SHEBANG, "/usr/bin/env escript").
-define(COMMENT, "This is an -*- erlang -*- file").
--record(state, {file,
- module,
+%%-----------------------------------------------------------------------
+
+-type mode() :: 'compile' | 'debug' | 'interpret' | 'run'.
+-type source() :: 'archive' | 'beam' | 'text'.
+
+-record(state, {file :: file:filename(),
+ module :: module(),
forms_or_bin,
- source,
- n_errors,
- mode,
- exports_main,
- has_records}).
--record(sections, {type,
- shebang,
- comment,
- emu_args,
- body}).
--record(extract_options, {compile_source}).
+ source :: source(),
+ n_errors :: non_neg_integer(),
+ mode :: mode(),
+ exports_main :: boolean(),
+ has_records :: boolean()}).
-type shebang() :: string().
-type comment() :: string().
-type emu_args() :: string().
--type escript_filename() :: string().
--type filename() :: string().
+
+-record(sections, {type,
+ shebang :: shebang(),
+ comment :: comment(),
+ emu_args :: emu_args(),
+ body}).
+
+-record(extract_options, {compile_source}).
+
-type zip_file() ::
- filename()
- | {filename(), binary()}
- | {filename(), binary(), #file_info{}}.
+ file:filename()
+ | {file:filename(), binary()}
+ | {file:filename(), binary(), file:file_info()}.
-type zip_create_option() :: term().
-type section() ::
shebang
@@ -60,13 +66,15 @@
| comment
| {comment, comment()}
| {emu_args, emu_args()}
- | {source, filename() | binary()}
- | {beam, filename() | binary()}
- | {archive, filename() | binary()}
+ | {source, file:filename() | binary()}
+ | {beam, file:filename() | binary()}
+ | {archive, file:filename() | binary()}
| {archive, [zip_file()], [zip_create_option()]}.
+%%-----------------------------------------------------------------------
+
%% Create a complete escript file with both header and body
--spec create(escript_filename() | binary, [section()]) ->
+-spec create(file:filename() | binary, [section()]) ->
ok | {ok, binary()} | {error, term()}.
create(File, Options) when is_list(Options) ->
@@ -149,7 +157,9 @@ prepare(BadOptions, _) ->
-type section_name() :: shebang | comment | emu_args | body .
-type extract_option() :: compile_source | {section, [section_name()]}.
--spec extract(filename(), [extract_option()]) -> {ok, [section()]} | {error, term()}.
+-spec extract(file:filename(), [extract_option()]) ->
+ {ok, [section()]} | {error, term()}.
+
extract(File, Options) when is_list(File), is_list(Options) ->
try
EO = parse_extract_options(Options,
@@ -239,6 +249,7 @@ normalize_section(Name, Chars) ->
{Name, Chars}.
-spec script_name() -> string().
+
script_name() ->
[ScriptName|_] = init:get_plain_arguments(),
ScriptName.
@@ -248,10 +259,12 @@ script_name() ->
%%
-spec start() -> no_return().
+
start() ->
start([]).
-spec start([string()]) -> no_return().
+
start(EscriptOptions) ->
try
%% Commands run using -run or -s are run in a process
@@ -484,18 +497,12 @@ find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, Sections) ->
classify_line(Line) ->
case Line of
- [$\#, $\! | _] ->
- shebang;
- [$P, $K | _] ->
- archive;
- [$F, $O, $R, $1 | _] ->
- beam;
- [$%, $%, $\! | _] ->
- emu_args;
- [$% | _] ->
- comment;
- _ ->
- undefined
+ "#!" ++ _ -> shebang;
+ "PK" ++ _ -> archive;
+ "FOR1" ++ _ -> beam;
+ "%%!" ++ _ -> emu_args;
+ "%" ++ _ -> comment;
+ _ -> undefined
end.
guess_type(Line) ->
@@ -531,7 +538,6 @@ parse_archive(S, File, HeaderSz) ->
end,
list_to_atom(lists:reverse(RevBase2))
end,
-
S#state{source = archive,
mode = run,
module = Mod,
@@ -587,8 +593,8 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) ->
epp_parse_file2(Epp, S2, [ModForm, FileForm], OptModRes);
{error, _} ->
epp_parse_file2(Epp, S2, [FileForm], OptModRes);
- {eof,LastLine} ->
- S#state{forms_or_bin = [FileForm, {eof,LastLine}]}
+ {eof, _LastLine} = Eof ->
+ S#state{forms_or_bin = [FileForm, Eof]}
end,
ok = epp:close(Epp),
ok = file:close(Fd),
@@ -683,8 +689,8 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
io:format("~s:~w: ~s\n",
[S#state.file,Ln,Mod:format_error(Args)]),
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
- {eof,LastLine} ->
- S#state{forms_or_bin = lists:reverse([{eof, LastLine} | Forms])}
+ {eof, _LastLine} = Eof ->
+ S#state{forms_or_bin = lists:reverse([Eof | Forms])}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 78b1de6e16..a249dea525 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -43,6 +43,7 @@
-define(ERR_GENREMOTECALL,22).
-define(ERR_GENBINCONSTRUCT,23).
-define(ERR_GENDISALLOWEDOP,24).
+-define(WARN_SHADOW_VAR,50).
-define(ERR_GUARDMATCH,?ERR_GENMATCH+?ERROR_BASE_GUARD).
-define(ERR_BODYMATCH,?ERR_GENMATCH+?ERROR_BASE_BODY).
-define(ERR_GUARDLOCALCALL,?ERR_GENLOCALCALL+?ERROR_BASE_GUARD).
@@ -63,8 +64,13 @@
-define(ERR_BODYDISALLOWEDOP,?ERR_GENDISALLOWEDOP+?ERROR_BASE_BODY).
%%
-%% Called by compiler or ets/dbg:fun2ms when errors occur
+%% Called by compiler or ets/dbg:fun2ms when errors/warnings occur
%%
+format_error({?WARN_SHADOW_VAR,Name}) ->
+ lists:flatten(
+ io_lib:format("variable ~p shadowed in ms_transform fun head",
+ [Name]));
+
format_error(?ERR_NOFUN) ->
"Parameter of ets/dbg:fun2ms/1 is not a literal fun";
format_error(?ERR_ETS_HEAD) ->
@@ -182,7 +188,7 @@ format_error(Else) ->
%%
transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
SaveFilename = setup_filename(),
- case catch ms_clause_list(1,Clauses,Dialect) of
+ case catch ms_clause_list(1,Clauses,Dialect,gb_sets:new()) of
{'EXIT',Reason} ->
cleanup_filename(SaveFilename),
exit(Reason);
@@ -207,6 +213,7 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%%
parse_transform(Forms, _Options) ->
SaveFilename = setup_filename(),
+ %io:format("Forms: ~p~n",[Forms]),
case catch forms(Forms) of
{'EXIT',Reason} ->
cleanup_filename(SaveFilename),
@@ -215,12 +222,31 @@ parse_transform(Forms, _Options) ->
{error, [{cleanup_filename(SaveFilename),
[{Line, ?MODULE, R}]}], []};
Else ->
- cleanup_filename(SaveFilename),
+ %io:format("Transformed into: ~p~n",[Else]),
+ case get_warnings() of
+ [] ->
+ cleanup_filename(SaveFilename),
+ Else;
+ WL ->
+ FName = cleanup_filename(SaveFilename) ,
+ WList = [ {FName, [{L, ?MODULE, R}]} || {L,R} <- WL ],
+ {warning, Else, WList}
+ end
+ end.
+
+get_warnings() ->
+ case get(warnings) of
+ undefined ->
+ [];
+ Else ->
Else
end.
+add_warning(Line,R) ->
+ put(warnings,[{Line,R}| get_warnings()]).
+
setup_filename() ->
- {erase(filename),erase(records)}.
+ {erase(filename),erase(records),erase(warnings)}.
put_filename(Name) ->
put(filename,Name).
@@ -235,7 +261,7 @@ get_records() ->
Else ->
Else
end.
-cleanup_filename({Old,OldRec}) ->
+cleanup_filename({Old,OldRec,OldWarnings}) ->
Ret = case erase(filename) of
undefined ->
"TOP_LEVEL";
@@ -248,6 +274,12 @@ cleanup_filename({Old,OldRec}) ->
Rec ->
put(records,Rec)
end,
+ case OldWarnings of
+ undefined ->
+ erase(warnings);
+ Warn ->
+ put(warnings,Warn)
+ end,
case Old of
undefined ->
Ret;
@@ -285,42 +317,77 @@ form({function,Line,Name0,Arity0,Clauses0}) ->
form(AnyOther) ->
AnyOther.
function(Name, Arity, Clauses0) ->
- Clauses1 = clauses(Clauses0),
+ {Clauses1,_} = clauses(Clauses0,gb_sets:new()),
{Name,Arity,Clauses1}.
-clauses([C0|Cs]) ->
- C1 = clause(C0),
- [C1|clauses(Cs)];
-clauses([]) -> [].
-clause({clause,Line,H0,G0,B0}) ->
- B1 = copy(B0),
- {clause,Line,H0,G0,B1}.
+clauses([C0|Cs],Bound) ->
+ {C1,Bound1} = clause(C0,Bound),
+ {C2,Bound2} = clauses(Cs,Bound1),
+ {[C1|C2],Bound2};
+clauses([],Bound) -> {[],Bound}.
+clause({clause,Line,H0,G0,B0},Bound) ->
+ {H1,Bound1} = copy(H0,Bound),
+ {B1,Bound2} = copy(B0,Bound1),
+ {{clause,Line,H1,G0,B1},Bound2}.
copy({call,Line,{remote,_Line2,{atom,_Line3,ets},{atom,_Line4,fun2ms}},
- As0}) ->
- transform_call(ets,Line,As0);
+ As0},Bound) ->
+ {transform_call(ets,Line,As0,Bound),Bound};
copy({call,Line,{remote,_Line2,{record_field,_Line3,
{atom,_Line4,''},{atom,_Line5,ets}},
- {atom,_Line6,fun2ms}}, As0}) ->
+ {atom,_Line6,fun2ms}}, As0},Bound) ->
%% Packages...
- transform_call(ets,Line,As0);
+ {transform_call(ets,Line,As0,Bound),Bound};
copy({call,Line,{remote,_Line2,{atom,_Line3,dbg},{atom,_Line4,fun2ms}},
- As0}) ->
- transform_call(dbg,Line,As0);
-copy(T) when is_tuple(T) ->
- list_to_tuple(copy_list(tuple_to_list(T)));
-copy(L) when is_list(L) ->
- copy_list(L);
-copy(AnyOther) ->
- AnyOther.
+ As0},Bound) ->
+ {transform_call(dbg,Line,As0,Bound),Bound};
+copy({match,Line,A,B},Bound) ->
+ {B1,Bound1} = copy(B,Bound),
+ {A1,Bound2} = copy(A,Bound),
+ {{match,Line,A1,B1},gb_sets:union(Bound1,Bound2)};
+copy({var,_Line,'_'} = VarDef,Bound) ->
+ {VarDef,Bound};
+copy({var,_Line,Name} = VarDef,Bound) ->
+ Bound1 = gb_sets:add(Name,Bound),
+ {VarDef,Bound1};
+copy({'fun',Line,{clauses,Clauses}},Bound) -> % Dont export bindings from funs
+ {NewClauses,_IgnoredBindings} = copy_list(Clauses,Bound),
+ {{'fun',Line,{clauses,NewClauses}},Bound};
+copy({'case',Line,Of,ClausesList},Bound) -> % Dont export bindings from funs
+ {NewOf,NewBind0} = copy(Of,Bound),
+ {NewClausesList,NewBindings} = copy_case_clauses(ClausesList,NewBind0,[]),
+ {{'case',Line,NewOf,NewClausesList},NewBindings};
+copy(T,Bound) when is_tuple(T) ->
+ {L,Bound1} = copy_list(tuple_to_list(T),Bound),
+ {list_to_tuple(L),Bound1};
+copy(L,Bound) when is_list(L) ->
+ copy_list(L,Bound);
+copy(AnyOther,Bound) ->
+ {AnyOther,Bound}.
-copy_list([H|T]) ->
- [copy(H)|copy_list(T)];
-copy_list([]) ->
- [].
+copy_case_clauses([],Bound,AddSets) ->
+ ReallyAdded = gb_sets:intersection(AddSets),
+ {[],gb_sets:union(Bound,ReallyAdded)};
+copy_case_clauses([{clause,Line,Match,Guard,Clauses}|T],Bound,AddSets) ->
+ {NewMatch,MatchBinds} = copy(Match,Bound),
+ {NewGuard,GuardBinds} = copy(Guard,MatchBinds), %% Really no new binds
+ {NewClauses,AllBinds} = copy(Clauses,GuardBinds),
+ %% To limit the setsizes, I subtract what I had before the case clause
+ %% and add it in the end
+ AddedBinds = gb_sets:subtract(AllBinds,Bound),
+ {NewTail,ExportedBindings} =
+ copy_case_clauses(T,Bound,[AddedBinds | AddSets]),
+ {[{clause,Line,NewMatch,NewGuard,NewClauses}|NewTail],ExportedBindings}.
-transform_call(Type,_Line,[{'fun',Line2,{clauses, ClauseList}}]) ->
- ms_clause_list(Line2, ClauseList,Type);
-transform_call(_Type,Line,_NoAbstractFun) ->
+copy_list([H|T],Bound) ->
+ {C1,Bound1} = copy(H,Bound),
+ {C2,Bound2} = copy_list(T,Bound1),
+ {[C1|C2],Bound2};
+copy_list([],Bound) ->
+ {[],Bound}.
+
+transform_call(Type,_Line,[{'fun',Line2,{clauses, ClauseList}}],Bound) ->
+ ms_clause_list(Line2, ClauseList,Type,Bound);
+transform_call(_Type,Line,_NoAbstractFun,_) ->
throw({error,Line,?ERR_NOFUN}).
% Fixup semicolons in guards
@@ -329,18 +396,19 @@ ms_clause_expand({clause, Line, Parameters, Guard = [_,_|_], Body}) ->
ms_clause_expand(_Other) ->
false.
-ms_clause_list(Line,[H|T],Type) ->
+ms_clause_list(Line,[H|T],Type,Bound) ->
case ms_clause_expand(H) of
NewHead when is_list(NewHead) ->
- ms_clause_list(Line,NewHead ++ T, Type);
+ ms_clause_list(Line,NewHead ++ T, Type, Bound);
false ->
- {cons, Line, ms_clause(H,Type), ms_clause_list(Line, T,Type)}
+ {cons, Line, ms_clause(H, Type, Bound),
+ ms_clause_list(Line, T, Type, Bound)}
end;
-ms_clause_list(Line,[],_) ->
+ms_clause_list(Line,[],_,_) ->
{nil,Line}.
-ms_clause({clause, Line, Parameters, Guards, Body},Type) ->
+ms_clause({clause, Line, Parameters, Guards, Body},Type,Bound) ->
check_type(Line,Parameters,Type),
- {MSHead,Bindings} = transform_head(Parameters),
+ {MSHead,Bindings} = transform_head(Parameters,Bound),
MSGuards = transform_guards(Line, Guards, Bindings),
MSBody = transform_body(Line,Body,Bindings),
{tuple, Line, [MSHead,MSGuards,MSBody]}.
@@ -627,29 +695,31 @@ tg(Other,B) ->
Element = io_lib:format("unknown element ~w", [Other]),
throw({error,unknown,{?ERR_GENELEMENT+B#tgd.eb,Element}}).
-transform_head([V]) ->
+transform_head([V],OuterBound) ->
Bind = cre_bind(),
- {NewV,NewBind} = toplevel_head_match(V,Bind),
- th(NewV,NewBind).
+ {NewV,NewBind} = toplevel_head_match(V,Bind,OuterBound),
+ th(NewV,NewBind,OuterBound).
-toplevel_head_match({match,_,{var,_,VName},Expr},B) ->
+toplevel_head_match({match,Line,{var,_,VName},Expr},B,OB) ->
+ warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
-toplevel_head_match({match,_,Expr,{var,_,VName}},B) ->
+toplevel_head_match({match,Line,Expr,{var,_,VName}},B,OB) ->
+ warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
-toplevel_head_match(Other,B) ->
+toplevel_head_match(Other,B,_OB) ->
{Other,B}.
-th({record,Line,RName,RFields},B) ->
+th({record,Line,RName,RFields},B,OB) ->
% youch...
RDefs = get_records(),
{KeyList0,NewB} = lists:foldl(fun({record_field,_,{atom,_,Key},Value},
{L,B0}) ->
- {NV,B1} = th(Value,B0),
+ {NV,B1} = th(Value,B0,OB),
{[{Key,NV}|L],B1};
({record_field,_,{var,_,'_'},Value},
{L,B0}) ->
- {NV,B1} = th(Value,B0),
+ {NV,B1} = th(Value,B0,OB),
{[{{default},NV}|L],B1};
(_,_) ->
throw({error,Line,{?ERR_HEADBADREC,
@@ -692,9 +762,9 @@ th({record,Line,RName,RFields},B) ->
_ ->
throw({error,Line,{?ERR_HEADBADREC,RName}})
end;
-th({match,Line,_,_},_) ->
+th({match,Line,_,_},_,_) ->
throw({error,Line,?ERR_HEADMATCH});
-th({atom,Line,A},B) ->
+th({atom,Line,A},B,_OB) ->
case atom_to_list(A) of
[$$|NL] ->
case (catch list_to_integer(NL)) of
@@ -706,10 +776,11 @@ th({atom,Line,A},B) ->
_ ->
{{atom,Line,A},B}
end;
-th({bin_element,_Line0,{var, Line, A},_,_},_) ->
+th({bin_element,_Line0,{var, Line, A},_,_},_,_) ->
throw({error,Line,{?ERR_HEADBINMATCH,A}});
-th({var,Line,Name},B) ->
+th({var,Line,Name},B,OB) ->
+ warn_var_clash(Line,Name,OB),
case lkup_bind(Name,B) of
undefined ->
NewB = new_bind(Name,B),
@@ -717,16 +788,24 @@ th({var,Line,Name},B) ->
Trans ->
{{atom,Line,Trans},B}
end;
-th([H|T],B) ->
- {NH,NB} = th(H,B),
- {NT,NNB} = th(T,NB),
+th([H|T],B,OB) ->
+ {NH,NB} = th(H,B,OB),
+ {NT,NNB} = th(T,NB,OB),
{[NH|NT],NNB};
-th(T,B) when is_tuple(T) ->
- {L,NB} = th(tuple_to_list(T),B),
+th(T,B,OB) when is_tuple(T) ->
+ {L,NB} = th(tuple_to_list(T),B,OB),
{list_to_tuple(L),NB};
-th(Nonstruct,B) ->
+th(Nonstruct,B,_OB) ->
{Nonstruct,B}.
+warn_var_clash(Line,Name,OuterBound) ->
+ case gb_sets:is_member(Name,OuterBound) of
+ true ->
+ add_warning(Line,{?WARN_SHADOW_VAR,Name});
+ _ ->
+ ok
+ end.
+
%% Could be more efficient...
check_multi_field(_, _, [], _) ->
ok;
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 1514414e48..5c52dfcbf0 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -361,6 +361,12 @@ obsolete_1(erlang, concat_binary, 1) ->
obsolete_1(ssl, peercert, 2) ->
{deprecated,"deprecated (will be removed in R15A); use ssl:peercert/1 and public_key:pkix_decode_cert/2 instead"};
+%% Added in R14B.
+obsolete_1(public_key, pem_to_der, 1) ->
+ {deprecated,"deprecated (will be removed in R15A); use file:read_file/1 and public_key:pem_decode/1"};
+obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 ->
+ {deprecated,{public_key,pem_entry_decode,1},"R15A"};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index 6ee837c3e6..24e14caa69 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -22,7 +22,7 @@
send_after/3, send_after/2,
exit_after/3, exit_after/2, kill_after/2, kill_after/1,
apply_interval/4, send_interval/3, send_interval/2,
- cancel/1, sleep/1, tc/3, now_diff/2,
+ cancel/1, sleep/1, tc/2, tc/3, now_diff/2,
seconds/1, minutes/1, hours/1, hms/3]).
-export([start_link/0, start/0,
@@ -98,6 +98,17 @@ sleep(T) ->
after T -> ok
end.
+
+%%
+%% Measure the execution time (in microseconds) for Fun(Args).
+%%
+-spec tc(function(), [_]) -> {time(), term()}.
+tc(F, A) ->
+ Before = erlang:now(),
+ Val = (catch apply(F, A)),
+ After = erlang:now(),
+ {now_diff(After, Before), Val}.
+
%%
%% Measure the execution time (in microseconds) for an MFA.
%%
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 13c87ca005..5d7e558601 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -33,7 +33,7 @@
-export([misc/1, dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
-export([files/1, tab2file/1, tab2file2/1, tab2file3/1, tabfile_ext1/1,
tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1]).
--export([heavy/1, heavy_lookup/1, heavy_lookup_element/1]).
+-export([heavy/1, heavy_lookup/1, heavy_lookup_element/1, heavy_concurrent/1]).
-export([lookup_element/1, lookup_element_mult/1]).
-export([fold/1]).
-export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]).
@@ -63,7 +63,8 @@
meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1,
meta_lookup_named_read/1, meta_lookup_named_write/1,
meta_newdel_unnamed/1, meta_newdel_named/1]).
--export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, otp_8166/1]).
+-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
+ otp_8166/1, otp_8732/1]).
-export([exit_large_table_owner/1,
exit_many_large_table_owner/1,
exit_many_tables_owner/1,
@@ -89,7 +90,8 @@
match_delete_do/1, match_delete3_do/1, firstnext_do/1,
slot_do/1, match1_do/1, match2_do/1, match_object_do/1, match_object2_do/1,
misc1_do/1, safe_fixtable_do/1, info_do/1, dups_do/1, heavy_lookup_do/1,
- heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1
+ heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1,
+ do_heavy_concurrent/1
]).
-include("test_server.hrl").
@@ -129,7 +131,7 @@ all(suite) ->
t_select_delete, t_ets_dets, memory,
t_bucket_disappears,
select_fail,t_insert_new, t_repair_continuation, otp_5340, otp_6338,
- otp_6842_select_1000, otp_7665,
+ otp_6842_select_1000, otp_7665, otp_8732,
meta_wb,
grow_shrink, grow_pseudo_deleted, shrink_pseudo_deleted,
meta_smp,
@@ -391,7 +393,7 @@ memory(Config) when is_list(Config) ->
?line erts_debug:set_internal_state(available_internal_state, true),
?line ok = chk_normal_tab_struct_size(),
?line L = [T1,T2,T3,T4] = fill_sets_int(1000),
- ?line XRes1 = adjust_xmem(L, {16862,16072,16072,16078}),
+ ?line XRes1 = adjust_xmem(L, {14862,14072,14072,14078}),
?line Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)},
?line lists:foreach(fun(T) ->
Before = ets:info(T,size),
@@ -402,7 +404,7 @@ memory(Config) when is_list(Config) ->
[Key, ets:info(T,type), Before, ets:info(T,size), Objs])
end,
L),
- ?line XRes2 = adjust_xmem(L, {16849,16060,16048,16054}),
+ ?line XRes2 = adjust_xmem(L, {14851,14062,14052,14058}),
?line Res2 = {?S(T1),?S(T2),?S(T3),?S(T4)},
?line lists:foreach(fun(T) ->
Before = ets:info(T,size),
@@ -413,7 +415,7 @@ memory(Config) when is_list(Config) ->
[Key, ets:info(T,type), Before, ets:info(T,size), Objs])
end,
L),
- ?line XRes3 = adjust_xmem(L, {16836,16048,16024,16030}),
+ ?line XRes3 = adjust_xmem(L, {14840,14052,14032,14038}),
?line Res3 = {?S(T1),?S(T2),?S(T3),?S(T4)},
?line lists:foreach(fun(T) ->
?line ets:delete_all_objects(T)
@@ -3877,7 +3879,7 @@ make_sub_binary(List, Num) when is_list(List) ->
{_,B} = split_binary(Bin, N+1),
B.
-heavy(suite) -> [heavy_lookup, heavy_lookup_element].
+heavy(suite) -> [heavy_lookup, heavy_lookup_element, heavy_concurrent].
%% Lookup stuff like crazy...
heavy_lookup(doc) -> ["Performs multiple lookups for every key ",
@@ -3940,6 +3942,44 @@ do_lookup_element(Tab, N, M) ->
end.
+heavy_concurrent(Config) ->
+ repeat_for_opts(do_heavy_concurrent).
+
+do_heavy_concurrent(Opts) ->
+ ?line Size = 20000,
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(blupp, [set, public, {keypos, 2} | Opts]),
+ ?line ok = fill_tab2(Tab, 0, Size),
+ ?line Procs = lists:map(
+ fun (N) ->
+ spawn_link(
+ fun () ->
+ do_heavy_concurrent_proc(Tab, Size, N)
+ end)
+ end,
+ lists:seq(1, 500)),
+ ?line lists:foreach(fun (P) ->
+ M = erlang:monitor(process, P),
+ receive
+ {'DOWN', Mon, process, P, _} ->
+ ok
+ end
+ end,
+ Procs),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+do_heavy_concurrent_proc(_Tab, 0, _Offs) ->
+ done;
+do_heavy_concurrent_proc(Tab, N, Offs) when (N+Offs) rem 100 == 0 ->
+ Data = {"here", are, "S O M E ", data, "toooooooooooooooooo", insert,
+ make_ref(), make_ref(), make_ref()},
+ true=ets:insert(Tab, {{self(),Data}, N}),
+ do_heavy_concurrent_proc(Tab, N-1, Offs);
+do_heavy_concurrent_proc(Tab, N, Offs) ->
+ _ = ets:lookup(Tab, N),
+ do_heavy_concurrent_proc(Tab, N-1, Offs).
+
fold(suite) -> [foldl_ordered, foldr_ordered,
foldl, foldr,
fold_empty].
@@ -5010,8 +5050,14 @@ verify_table_load(T) ->
end.
-
-
+otp_8732(doc) -> ["ets:select on a tree with NIL key object"];
+otp_8732(Config) when is_list(Config) ->
+ Tab = ets:new(noname,[ordered_set]),
+ filltabstr(Tab,999),
+ ets:insert(Tab,{[],"nasty NIL object"}),
+ ?line [] = ets:match(Tab,{'_',nomatch}), %% Will hang if bug not fixed
+ ok.
+
smp_select_delete(suite) -> [];
smp_select_delete(doc) ->
@@ -5336,7 +5382,7 @@ only_if_smp(Schedulers, Func) ->
%% Repeat test function with different combination of table options
%%
repeat_for_opts(F) ->
- repeat_for_opts(F, [write_concurrency]).
+ repeat_for_opts(F, [write_concurrency, read_concurrency]).
repeat_for_opts(F, OptGenList) when is_atom(F) ->
repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts) end, OptGenList);
@@ -5356,6 +5402,7 @@ repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) ->
repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList).
repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag];
-repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}].
+repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}];
+repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}].
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index 79a0a9af89..2d90d5b823 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -37,6 +37,7 @@
-export([andalso_orelse/1]).
-export([float_1_function/1]).
-export([action_function/1]).
+-export([warnings/1]).
-export([init_per_testcase/2, fin_per_testcase/2]).
init_per_testcase(_Func, Config) ->
@@ -50,8 +51,90 @@ fin_per_testcase(_Func, Config) ->
all(suite) -> [from_shell,basic_ets,basic_dbg,records,record_index,multipass,
bitsyntax, record_defaults, andalso_orelse,
float_1_function, action_function,
+ warnings,
top_match, old_guards, autoimported, semicolon].
+%% This may be subject to change
+-define(WARN_NUMBER_SHADOW,50).
+warnings(suite) ->
+ [];
+warnings(doc) ->
+ ["Check that shadowed variables in fun head generate warning"];
+warnings(Config) when is_list(Config) ->
+ ?line setup(Config),
+ Prog = <<"A=5, "
+ "ets:fun2ms(fun({A,B}) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " A andalso B "
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}}]}] =
+ compile_ww(Prog),
+ Prog2 = <<"C=5, "
+ "ets:fun2ms(fun({A,B} = C) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " {A andalso B,C} "
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ compile_ww(Prog2),
+ Rec3 = <<"-record(a,{a,b,c,d=foppa}).">>,
+ Prog3 = <<"A=3,C=5, "
+ "ets:fun2ms(fun(#a{a = A, b = B} = C) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " {A andalso B,C} "
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}},
+ {_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ compile_ww(Rec3,Prog3),
+ Rec4 = <<"-record(a,{a,b,c,d=foppa}).">>,
+ Prog4 = <<"A=3,C=5, "
+ "F = fun(B) -> B*3 end,"
+ "erlang:display(F(A)),"
+ "ets:fun2ms(fun(#a{a = A, b = B} = C) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " {A andalso B,C} "
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}},
+ {_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ compile_ww(Rec4,Prog4),
+ Rec5 = <<"-record(a,{a,b,c,d=foppa}).">>,
+ Prog5 = <<"A=3,C=5, "
+ "F = fun(B) -> B*3 end,"
+ "erlang:display(F(A)),"
+ "B = ets:fun2ms(fun(#a{a = A, b = B} = C) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " {A andalso B,C} "
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'A'}},
+ {_,ms_transform,{?WARN_NUMBER_SHADOW,'C'}}]}] =
+ compile_ww(Rec5,Prog5),
+ Prog6 = <<" X=bar, "
+ " A = case X of"
+ " foo ->"
+ " foo;"
+ " Y ->"
+ " ets:fun2ms(fun(Y) ->" % This is a warning
+ " 3*Y"
+ " end)"
+ " end,"
+ " ets:fun2ms(fun(Y) ->" % Y out of "scope" here, so no warning
+ " {3*Y,A}"
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'Y'}}]}] =
+ compile_ww(Prog6),
+ Prog7 = <<" X=bar, "
+ " A = case X of"
+ " foo ->"
+ " Y = foo;"
+ " Y ->"
+ " bar"
+ " end,"
+ " ets:fun2ms(fun(Y) ->" % Y exported from case and safe, so warn
+ " {3*Y,A}"
+ " end)">>,
+ ?line [{_,[{_,ms_transform,{?WARN_NUMBER_SHADOW,'Y'}}]}] =
+ compile_ww(Prog7),
+ ok.
+
andalso_orelse(suite) ->
[];
andalso_orelse(doc) ->
@@ -721,6 +804,24 @@ compile_and_run(Records,Expr) ->
code:load_binary(tmp,FN,Bin),
tmp:tmp().
+compile_ww(Expr) ->
+ compile_ww(<<>>,Expr).
+compile_ww(Records,Expr) ->
+ Prog = <<
+ "-module(tmp).\n",
+ "-include_lib(\"stdlib/include/ms_transform.hrl\").\n",
+ "-export([tmp/0]).\n",
+ Records/binary,"\n",
+ "tmp() ->\n",
+ Expr/binary,".\n">>,
+ FN=temp_name(),
+ file:write_file(FN,Prog),
+ {ok,Forms} = epp:parse_file(FN,"",""),
+ {ok,tmp,_Bin,Wlist} = compile:forms(Forms,[return_warnings,
+ nowarn_unused_vars,
+ nowarn_unused_record]),
+ Wlist.
+
do_eval(String) ->
{done,{ok,T,_},[]} = erl_scan:tokens(
[],
diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl
index 021a22c61b..6aa2b7b945 100644
--- a/lib/stdlib/test/timer_simple_SUITE.erl
+++ b/lib/stdlib/test/timer_simple_SUITE.erl
@@ -224,11 +224,19 @@ cancel2(Config) when is_list(Config) ->
tc(doc) -> "Test sleep/1 and tc/3.";
tc(suite) -> [];
tc(Config) when is_list(Config) ->
- % This should both sleep and tc
- ?line {Res, ok} = timer:tc(timer, sleep, [500]),
- ?line ok = if
- Res < 500*1000 -> {too_early, Res}; % Too early
- Res > 800*1000 -> {too_late, Res}; % Too much time
+ % This should both sleep and tc/3
+ ?line {Res1, ok} = timer:tc(timer, sleep, [500]),
+ ?line ok = if
+ Res1 < 500*1000 -> {too_early, Res1}; % Too early
+ Res1 > 800*1000 -> {too_late, Res1}; % Too much time
+ true -> ok
+ end,
+
+ % This should both sleep and tc/2
+ ?line {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]),
+ ?line ok = if
+ Res2 < 500*1000 -> {too_early, Res2}; % Too early
+ Res2 > 800*1000 -> {too_late, Res2}; % Too much time
true -> ok
end,
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index f081bd60e2..02ea6d9d68 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -17,5 +17,4 @@
# %CopyrightEnd%
#
-STDLIB_VSN = 1.17
-
+STDLIB_VSN = 1.17.1
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 1245c10a01..72f274d63a 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -151,10 +151,12 @@
%%% OPERATOR INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([add_spec/1, add_dir/2, add_dir/3]).
--export([add_module/1, add_module/2, add_case/2, add_case/3, add_cases/2,
- add_cases/3]).
+-export([add_module/1, add_module/2,
+ add_conf/3,
+ add_case/2, add_case/3, add_cases/2, add_cases/3]).
-export([add_dir_with_skip/3, add_dir_with_skip/4, add_tests_with_skip/3]).
-export([add_module_with_skip/2, add_module_with_skip/3,
+ add_conf_with_skip/4,
add_case_with_skip/3, add_case_with_skip/4,
add_cases_with_skip/3, add_cases_with_skip/4]).
-export([jobs/0, run_test/1, wait_finish/0, idle_notify/1,
@@ -236,9 +238,16 @@ add_dir(Name, Dir, Pattern) ->
add_module(Mod) when is_atom(Mod) ->
add_job(atom_to_list(Mod), {Mod,all}).
+
add_module(Name, Mods) when is_list(Mods) ->
add_job(cast_to_list(Name), lists:map(fun(Mod) -> {Mod,all} end, Mods)).
+add_conf(Name, Mod, Conf) when is_tuple(Conf) ->
+ add_job(cast_to_list(Name), {Mod,[Conf]});
+
+add_conf(Name, Mod, Confs) when is_list(Confs) ->
+ add_job(cast_to_list(Name), {Mod,Confs}).
+
add_case(Mod, Case) when is_atom(Mod), is_atom(Case) ->
add_job(atom_to_list(Mod), {Mod,Case}).
@@ -283,6 +292,12 @@ add_module_with_skip(Mod, Skip) when is_atom(Mod) ->
add_module_with_skip(Name, Mods, Skip) when is_list(Mods) ->
add_job(cast_to_list(Name), lists:map(fun(Mod) -> {Mod,all} end, Mods), Skip).
+add_conf_with_skip(Name, Mod, Conf, Skip) when is_tuple(Conf) ->
+ add_job(cast_to_list(Name), {Mod,[Conf]}, Skip);
+
+add_conf_with_skip(Name, Mod, Confs, Skip) when is_list(Confs) ->
+ add_job(cast_to_list(Name), {Mod,Confs}, Skip).
+
add_case_with_skip(Mod, Case, Skip) when is_atom(Mod), is_atom(Case) ->
add_job(atom_to_list(Mod), {Mod,Case}, Skip).
@@ -1549,8 +1564,8 @@ temp_nodename([Chr|Base], Acc) ->
%% of cases can not be calculated and NoOfCases = unknown.
count_test_cases(TopCases, SkipCases) when is_list(TopCases) ->
case collect_all_cases(TopCases, SkipCases) of
- {error,_} ->
- error;
+ {error,_Why} = Error ->
+ Error;
TestSpec ->
{get_suites(TestSpec, []),
case remove_conf(TestSpec) of
@@ -1656,22 +1671,31 @@ do_test_cases(TopCases, SkipCases,
put(test_server_case_num, 0),
TestSpec =
add_init_and_end_per_suite(TestSpec0, undefined, undefined),
+
TI = get_target_info(),
print(1, "Starting test~s", [print_if_known(N, {", ~w test cases",[N]},
{" (with repeated test cases)",[]})]),
- test_server_sup:framework_call(report, [tests_start,
- {get(test_server_name),N}]),
- print(html,
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<html>\n"
- "<head><title>Test ~p results</title>\n"
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n"
- "</head>\n"
- "<body bgcolor=\"white\" text=\"black\" "
- "link=\"blue\" vlink=\"purple\" alink=\"red\">"
- "<h2>Results from test ~p</h2>\n",
- [get(test_server_name),get(test_server_name)]),
+ Test = get(test_server_name),
+ test_server_sup:framework_call(report, [tests_start,{Test,N}]),
+
+ Header =
+ case test_server_sup:framework_call(overview_html_header, [Test], "") of
+ "" ->
+ TestName = lists:flatten(io_lib:format("~p", [Test])),
+ ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
+ "<html>\n",
+ "<head><title>Test ", TestName, " results</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">",
+ "<h2>Results from test ", TestName, "</h2>\n"];
+ Html ->
+ ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n" | Html]
+ end,
+ print(html, Header, []),
print_timestamp(html, "Test started at "),
print(html, "<p>Host:<br>\n"),
@@ -1702,7 +1726,7 @@ do_test_cases(TopCases, SkipCases,
[?suitelog_name,?coverlog_name]),
print(html,"<p>~s"
"<p>\n"
- "<table border=3 cellpadding=5>"
+ "<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">"
"<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>"
"<th>Time</th><th>Result</th><th>Comment</th></tr>\n",
[print_if_known(N, {"Suite contains ~p test cases.\n",[N]},
@@ -2052,10 +2076,6 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
html_convert_modules(TestSpec, Config),
- %%! For readable tracing...
- %%! Config1 = [{data_dir,""},{priv_dir,""},{nodes,[]}],
- %%! run_test_cases_loop(TestSpec, [[]], TimetrapData, [], []),
-
run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []),
maybe_get_privdir(),
@@ -3537,7 +3557,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
case test_server_sup:framework_call(warn, [nodes], true) of
true ->
case catch controller_call(kill_slavenodes) of
- {'EXIT',_}=Exit ->
+ {'EXIT',_} = Exit ->
print(minor,
"WARNING: There might be slavenodes left in the"
" system. I tried to kill them, but I failed: ~p\n",
@@ -4417,7 +4437,7 @@ collect_all_cases(Top, Skip) when is_list(Skip) ->
Result =
case collect_cases(Top, #cc{mod=[],skip=Skip}) of
{ok,Cases,_St} -> Cases;
- Other -> Other
+ Other -> Other
end,
Result.
@@ -4429,9 +4449,9 @@ collect_cases([Case|Cs0], St0) ->
case collect_cases(Cs0, St1) of
{ok,FlatCases2,St} ->
{ok,FlatCases1 ++ FlatCases2,St};
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
@@ -4467,39 +4487,55 @@ collect_cases({conf,Props,InitMF,CaseList,FinF}, St) when is_atom(FinF) ->
Props1 ->
collect_cases({conf,Props1,InitMF,CaseList,{St#cc.mod,FinF}}, St)
end;
-collect_cases({conf,Props,InitMF,CaseList,FinMF}, St0) ->
- case collect_cases(CaseList, St0) of
- {ok,[],_St}=Empty ->
- Empty;
- {ok,FlatCases,St} ->
+collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) ->
+ case init_props(Props) of
+ {error,_} ->
+ {ok,[],St};
+ Props1 ->
Ref = make_ref(),
- case in_skip_list(InitMF, St#cc.skip) of
- {true,Comment} ->
+ Skips = St#cc.skip,
+ case in_skip_list({St#cc.mod,Conf}, Skips) of
+ {true,Comment} -> % conf init skipped
{ok,[{skip_case,{conf,Ref,InitMF,Comment}} |
- FlatCases ++ [{conf,Ref,[],FinMF}]],St};
+ [] ++ [{conf,Ref,[],FinMF}]],St};
+ {true,Name,Comment} when is_atom(Name) -> % all cases skipped
+ {ok,[{skip_case,{{St#cc.mod,{group,Name}},Comment}}],St};
+ {true,ToSkip,_} when is_list(ToSkip) -> % some cases skipped
+ case collect_cases(CaseList,
+ St#cc{skip=ToSkip++Skips}) of
+ {ok,[],_St} = Empty ->
+ Empty;
+ {ok,FlatCases,St1} ->
+ {ok,[{conf,Ref,Props1,InitMF} |
+ FlatCases ++ [{conf,Ref,
+ keep_name(Props1),
+ FinMF}]],St1#cc{skip=Skips}};
+ {error,_Reason} = Error ->
+ Error
+ end;
false ->
- case init_props(Props) of
- {error,_} ->
- {ok,[],St};
- Props1 ->
+ case collect_cases(CaseList, St) of
+ {ok,[],_St} = Empty ->
+ Empty;
+ {ok,FlatCases,St1} ->
{ok,[{conf,Ref,Props1,InitMF} |
FlatCases ++ [{conf,Ref,
keep_name(Props1),
- FinMF}]],St}
+ FinMF}]],St1};
+ {error,_Reason} = Error ->
+ Error
end
- end;
- {error,_Reason}=Error ->
- Error
+ end
end;
collect_cases({make,InitMFA,CaseList,FinMFA}, St0) ->
case collect_cases(CaseList, St0) of
- {ok,[],_St}=Empty -> Empty;
+ {ok,[],_St} = Empty -> Empty;
{ok,FlatCases,St} ->
Ref = make_ref(),
{ok,[{make,Ref,InitMFA}|FlatCases ++
[{make,Ref,FinMFA}]],St};
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
collect_cases({Module, Cases}, St) when is_list(Cases) ->
@@ -4517,8 +4553,11 @@ collect_cases({_Mod,_Case,_Args}=Spec, St) ->
collect_case(Spec, St);
collect_cases(Case, St) when is_atom(Case), is_atom(St#cc.mod) ->
collect_case({St#cc.mod,Case}, St);
-collect_cases(Other, _St) ->
- {error,{bad_subtest_spec,Other}}.
+collect_cases(Other, St) ->
+ {error,{bad_subtest_spec,St#cc.mod,Other}}.
+
+collect_case({Mod,{conf,_,_,_,_}=Conf}, St) ->
+ collect_case_invoke(Mod, Conf, [], St);
collect_case(MFA, St) ->
case in_skip_list(MFA, St#cc.skip) of
@@ -4555,6 +4594,7 @@ collect_case_invoke(Mod, Case, MFA, St) ->
collect_subcases(Mod, Case, MFA, St, Suite) ->
case Suite of
[] when Case == all -> {ok,[],St};
+ [] when element(1, Case) == conf -> {ok,[],St};
[] -> {ok,[MFA],St};
%%%! --- START Kept for backwards compatibilty ---
%%%! Requirements are not used
@@ -4565,6 +4605,8 @@ collect_subcases(Mod, Case, MFA, St, Suite) ->
%%%! --- END Kept for backwards compatibilty ---
{Skip,Reason} when Skip==skip; Skip==skipped ->
{ok,[{skip_case,{MFA,Reason}}],St};
+ {error,Reason} ->
+ throw(Reason);
SubCases ->
collect_case_subcases(Mod, Case, SubCases, St)
end.
@@ -4626,6 +4668,47 @@ check_deny_req(Req, DenyList) ->
false -> granted
end.
+in_skip_list({Mod,{conf,Props,InitMF,_CaseList,_FinMF}}, SkipList) ->
+ case in_skip_list(InitMF, SkipList) of
+ {true,_} = Yes ->
+ Yes;
+ _ ->
+ case proplists:get_value(name, Props) of
+ undefined ->
+ false;
+ Name ->
+ ToSkip =
+ lists:flatmap(
+ fun({M,{conf,SProps,_,SCaseList,_},Cmt}) when
+ M == Mod ->
+ case proplists:get_value(name, SProps) of
+ all ->
+ [{M,all,Cmt}];
+ Name ->
+ case SCaseList of
+ all ->
+ [{M,all,Cmt}];
+ _ ->
+ [{M,F,Cmt} || F <- SCaseList]
+ end;
+ _ ->
+ []
+ end;
+ (_) ->
+ []
+ end, SkipList),
+ case ToSkip of
+ [] ->
+ false;
+ _ ->
+ case lists:keysearch(all, 2, ToSkip) of
+ {value,{_,_,Cmt}} -> {true,Name,Cmt};
+ _ -> {true,ToSkip,""}
+ end
+ end
+ end
+ end;
+
in_skip_list({Mod,Func,_Args}, SkipList) ->
in_skip_list({Mod,Func}, SkipList);
in_skip_list({Mod,Func}, [{Mod,Funcs,Comment}|SkipList]) when is_list(Funcs) ->
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index e23b891392..fcd955345f 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -71,7 +71,7 @@
%%% ts_erl_config Finds out information about the Erlang system,
%%% for instance the location of erl_interface.
%%% This works for either an installed OTP or an Erlang
-%%% system running from Clearcase.
+%%% system running in a git repository/source tree.
%%% ts_make Interface to run the `make' program on Unix
%%% and other platforms.
%%% ts_make_erl A corrected version of the standar Erlang module
diff --git a/lib/test_server/src/ts_erl_config.erl b/lib/test_server/src/ts_erl_config.erl
index 14c36a2c35..640c8ddc9f 100644
--- a/lib/test_server/src/ts_erl_config.erl
+++ b/lib/test_server/src/ts_erl_config.erl
@@ -107,7 +107,7 @@ erts_lib(Vars,OsType) ->
ErtsIncludeInternal,
ErtsLib,
ErtsLibInternal};
- {Type, Root, Target} when Type == clearcase; Type == srctree ->
+ {srctree, Root, Target} ->
Erts = filename:join([Root, "erts"]),
ErtsInclude = filename:join([Erts, "include"]),
ErtsIncludeTarget = filename:join([ErtsInclude, Target]),
@@ -146,7 +146,7 @@ erl_include(Vars) ->
case erl_root(Vars) of
{installed, Root} ->
filename:join([Root, "usr", "include"]);
- {Type, Root, Target} when Type == clearcase; Type == srctree ->
+ {srctree, Root, Target} ->
filename:join([Root, "erts", "emulator", "beam"])
++ " -I" ++ filename:join([Root, "erts", "emulator"])
++ system_include(Root, Vars)
@@ -179,7 +179,7 @@ erl_interface(Vars,OsType) ->
{srctree, _Root, _Target} when OsType =:= vxworks ->
{filename:join(Dir, "lib"),
filename:join([Dir, "src"])};
- {Type, _Root, Target} when Type == clearcase; Type == srctree ->
+ {srctree, _Root, Target} ->
{filename:join([Dir, "obj", Target]),
filename:join([Dir, "src", Target])}
end}
@@ -246,7 +246,7 @@ ic(Vars, OsType) ->
case erl_root(Vars) of
{installed, _Root} ->
filename:join([Dir, "priv", "lib"]);
- {Type, _Root, Target} when Type == clearcase; Type == srctree ->
+ {srctree, _Root, Target} ->
filename:join([Dir, "priv", "lib", Target])
end,
filename:join(Dir, "include")}
@@ -266,21 +266,6 @@ jinterface(Vars, _OsType) ->
end,
[{jinterface_classpath, filename:nativename(ClassPath)}|Vars].
-%% Unused!
-% ig_vars(Vars) ->
-% {Lib0, Incl} =
-% case erl_root(Vars) of
-% {installed, Root} ->
-% Base = filename:join([Root, "usr"]),
-% {filename:join([Base, "lib"]),
-% filename:join([Base, "include"])};
-% {Type, Root, Target} when Type == clearcase; Type == srctree ->
-% {filename:join([Root, "lib", "ig", "obj", Target]),
-% filename:join([Root, "lib", "ig", "include"])}
-% end,
-% [{ig_libdir, filename:nativename(Lib0)},
-% {ig_include, filename:nativename(Incl)}|Vars].
-
lib_dir(Vars, Lib) ->
LibLibDir = case Lib of
erts ->
@@ -317,9 +302,6 @@ lib_dir(Vars, Lib) ->
erl_root(Vars) ->
Root = code:root_dir(),
case ts_lib:erlang_type() of
- {clearcase, _Version} ->
- Target = get_var(target, Vars),
- {clearcase, Root, Target};
{srctree, _Version} ->
Target = get_var(target, Vars),
{srctree, Root, Target};
diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl
index 94926eba80..bbbb7883db 100644
--- a/lib/test_server/src/ts_install.erl
+++ b/lib/test_server/src/ts_install.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(ts_install).
@@ -175,15 +175,8 @@ get_testcase_callback() ->
get_rsh_name() ->
case os:getenv("ERL_RSH") of
- false ->
- case ts_lib:erlang_type() of
- {clearcase, _} ->
- "ctrsh";
- {_, _} ->
- "rsh"
- end;
- Str ->
- Str
+ false -> "rsh";
+ Str -> Str
end.
platform_id(Vars) ->
diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl
index 082c9e0519..c90f4e511b 100644
--- a/lib/test_server/src/ts_lib.erl
+++ b/lib/test_server/src/ts_lib.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(ts_lib).
@@ -72,12 +72,10 @@ progress(Vars, Level, Format, Args) ->
erlang_type() ->
{_, Version} = init:script_id(),
- RelDir = filename:join([code:root_dir(), "releases"]), % Only in installed
- SysDir = filename:join([code:root_dir(), "system"]), % Nonexisting link/dir outside ClearCase
- case {filelib:is_file(RelDir),filelib:is_file(SysDir)} of
- {true,_} -> {otp, Version}; % installed OTP
- {_,true} -> {clearcase, Version};
- _ -> {srctree, Version}
+ RelDir = filename:join(code:root_dir(), "releases"), % Only in installed
+ case filelib:is_file(RelDir) of
+ true -> {otp,Version}; % installed OTP
+ false -> {srctree,Version} % source code tree
end.
%% Upcases the first letter in a string.
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index ee3c957d59..4c3df28814 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1,2 +1,2 @@
-TEST_SERVER_VSN = 3.4
+TEST_SERVER_VSN = 3.4.1
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index e6b76e2238..65a7f5f424 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -128,12 +128,13 @@ EMEM_ERTS_LIB=erts_r$(TYPEMARKER)
endif
+EMEM_ETHR_LIBS=$(subst -l$(ETHR_LIB_NAME),-l$(ETHR_LIB_NAME)$(TYPEMARKER),$(subst -lerts_internal_r,-lerts_internal_r$(TYPEMARKER),$(ETHR_LIBS)))
+
EMEM_LIBS = $(LIBS) \
-L$(ERL_TOP)/erts/lib/$(TARGET) \
-L$(ERL_TOP)/erts/lib/internal/$(TARGET) \
-l$(EMEM_ERTS_LIB) \
- -l$(ETHR_LIB_NAME)$(TYPEMARKER) \
- $(ETHR_X_LIBS)
+ $(EMEM_ETHR_LIBS)
EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o)))
diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c
index a0e139f059..872d55e789 100644
--- a/lib/tools/c_src/erl_memory.c
+++ b/lib/tools/c_src/erl_memory.c
@@ -1,22 +1,22 @@
-/* ``The contents of this file are subject to the Erlang Public License,
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2010. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
- * retrieved via the world wide web at http://www.erlang.org/.
- *
+ * retrieved online at http://www.erlang.org/.
+ *
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
- *
- * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
- * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
- * AB. All Rights Reserved.''
- *
- * $Id$
+ *
+ * %CopyrightEnd%
*/
-
/*
* Description:
*
@@ -281,17 +281,13 @@ mutex_destroy(ethr_mutex *mtx)
static INLINE void
mutex_lock(ethr_mutex *mtx)
{
- int res = ethr_mutex_lock(mtx);
- if (res)
- error_msg(res, "Mutex lock");
+ ethr_mutex_lock(mtx);
}
static INLINE void
mutex_unlock(ethr_mutex *mtx)
{
- int res = ethr_mutex_unlock(mtx);
- if (res)
- error_msg(res, "Mutex unlock");
+ ethr_mutex_unlock(mtx);
}
static INLINE void
@@ -314,16 +310,14 @@ static INLINE void
cond_wait(ethr_cond *cnd, ethr_mutex *mtx)
{
int res = ethr_cond_wait(cnd, mtx);
- if (res)
+ if (res != 0 && res != EINTR)
error_msg(res, "Cond wait");
}
static INLINE void
cond_signal(ethr_cond *cnd)
{
- int res = ethr_cond_signal(cnd);
- if (res)
- error_msg(res, "Cond signal");
+ ethr_cond_signal(cnd);
}
@@ -2774,7 +2768,7 @@ main(int argc, char *argv[])
exit(1);
}
- if (ethr_init(NULL) != 0) {
+ if (ethr_init(NULL) != 0 || ethr_late_init(NULL) != 0) {
fprintf(stderr, "emem: failed to initialize thread package\n");
exit(1);
}
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 6501e05a6e..c4d1bd1d2f 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -2174,6 +2174,8 @@ escape_lt_and_gt1([$<|T],Acc) ->
escape_lt_and_gt1(T,[$;,$t,$l,$&|Acc]);
escape_lt_and_gt1([$>|T],Acc) ->
escape_lt_and_gt1(T,[$;,$t,$g,$&|Acc]);
+escape_lt_and_gt1([$&|T],Acc) ->
+ escape_lt_and_gt1(T,[$;,$p,$m,$a,$&|Acc]);
escape_lt_and_gt1([],Acc) ->
lists:reverse(Acc);
escape_lt_and_gt1([H|T],Acc) ->
diff --git a/lib/tv/src/tv_pg_gridfcns.erl b/lib/tv/src/tv_pg_gridfcns.erl
index ab88e2864f..3d23c8a69f 100644
--- a/lib/tv/src/tv_pg_gridfcns.erl
+++ b/lib/tv/src/tv_pg_gridfcns.erl
@@ -205,8 +205,8 @@ resize_grid(NewWidth, NewHeight, ProcVars) ->
check_nof_cols(ColsShown, (NofColsShown - NofCols), ColFrameIds, ColIds,
RowIds, NofRows, RowHeight, FgColor, BgColor ),
- clear_fields(lists:nthtail(NofColsShown, NewColIds),
- lists:nthtail(NofRowsShown, NewRowIds)),
+ clear_fields(safe_nthtail(NofColsShown, NewColIds),
+ safe_nthtail(NofRowsShown, NewRowIds)),
RowsToUpdate = lists:sublist(NewRowIds, NofRowsShown),
@@ -279,7 +279,7 @@ resize_grid_column(RealCol, VirtualCol, Xdiff, ProcVars) ->
% Update the ColWidths list.
TempColWidths = lists:sublist(ColWidths, VirtualCol - 1) ++
- [NewWidthOfCol | lists:nthtail(VirtualCol, ColWidths)],
+ [NewWidthOfCol | safe_nthtail(VirtualCol, ColWidths)],
% Check the other columns, whether a new column has to be created.
ColsShown = compute_cols_shown(FirstColShown, TempColWidths, GridWidth,
@@ -455,8 +455,8 @@ scroll_grid_horizontally(NewFirstColShown, ProcVars) ->
refresh_visible_rows(RowsToUpdate, NewFirstColShown, NofColsShown, RowDataList, ListAsStr),
% Clear fields currently not visible.
- clear_fields(lists:nthtail(NofColsShown, NewColIds),
- lists:nthtail(NofRowsShown, NewRowIds)),
+ clear_fields(safe_nthtail(NofColsShown, NewColIds),
+ safe_nthtail(NofRowsShown, NewRowIds)),
NewGridP = GridP#grid_params{nof_cols = NewNofCols,
@@ -1565,7 +1565,7 @@ update_col_widths(ColsShown, ColWidths, FirstColShown, DefaultColWidth) ->
if
NecessaryNofVirtualCols > NofVirtualCols ->
TailNo = NofVirtualCols - FirstColShown + 1, % Always >= 0 !!!
- NewColWidths ++ lists:nthtail(TailNo, ColsShown);
+ NewColWidths ++ safe_nthtail(TailNo, ColsShown);
true ->
NewColWidths
end.
@@ -1653,7 +1653,7 @@ compute_cols_shown(FirstColShown, ColWidths, GridWidth, _NofCols, DefaultColWidt
ColWidthsLength < FirstColShown ->
[];
true ->
- lists:nthtail(FirstColShown - 1, ColWidths)
+ safe_nthtail(FirstColShown - 1, ColWidths)
end,
compute_cols_shown(UsedColWidths, GridWidth, DefaultColWidth).
@@ -1894,3 +1894,21 @@ extract_ids_for_one_row(N, [ColIds | Tail]) ->
%%%---------------------------------------------------------------------
%%% END of functions used to create the grid.
%%%---------------------------------------------------------------------
+
+
+%%======================================================================
+%% Function:
+%%
+%% Return Value:
+%%
+%% Description:
+%%
+%% Parameters:
+%%======================================================================
+
+
+safe_nthtail(_, []) -> [];
+safe_nthtail(1, [_|T]) -> T;
+safe_nthtail(N, [_|T]) when N > 1 ->
+ safe_nthtail(N - 1, T);
+safe_nthtail(0, L) when is_list(L) -> L.
diff --git a/lib/wx/.gitignore b/lib/wx/.gitignore
new file mode 100644
index 0000000000..fd76f078d7
--- /dev/null
+++ b/lib/wx/.gitignore
@@ -0,0 +1,2 @@
+test_log_*
+wx_test_case_info
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index c91a9d7fff..6bafda5b9d 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -902,8 +902,8 @@
['wxTreeCtrl','~wxTreeCtrl','AddRoot','AppendItem',
%% Not on Windows 'AssignButtonsImageList','GetButtonsImageList','SetButtonsImageList'
'AssignImageList','AssignStateImageList','Collapse','CollapseAndReset',
- 'Create','Delete','DeleteAllItems','DeleteChildren',{'EditLabel',1},
- %'EndEditLabel',
+ 'Create','Delete','DeleteAllItems','DeleteChildren',
+ {'EditLabel', [{"textCtrlClass", [nowhere]}]}, %'EndEditLabel',
'EnsureVisible','Expand','GetBoundingRect',
'GetChildrenCount','GetCount','GetEditControl',
{'GetFirstChild',[{"cookie", out}]}, {'GetNextChild',[{"cookie", [both]}]},
@@ -1740,6 +1740,11 @@
%% 'GetItemRect', 'SetItemRect', 'GetToolId', 'SetToolId'
%% ]}.
+{class, wxSystemSettings, object, [],
+ [
+ 'GetColour','GetFont','GetMetric','GetScreenType'
+ ]}.
+
{class, wxAuiNotebookEvent, wxNotifyEvent,
[{acc, [{old_selection, "GetOldSelection()"},
{selection, "GetSelection()"},
diff --git a/lib/wx/c_src/gen/wxe_derived_dest.h b/lib/wx/c_src/gen/wxe_derived_dest.h
index 57b0faa2cb..ad46a98c90 100644
--- a/lib/wx/c_src/gen/wxe_derived_dest.h
+++ b/lib/wx/c_src/gen/wxe_derived_dest.h
@@ -736,7 +736,7 @@ void WxeApp::delete_object(void *ptr, wxeRefData *refd) {
case 211: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break;
case 212: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break;
case 213: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 222: delete (wxLogNull *) ptr; break;
+ case 223: delete (wxLogNull *) ptr; break;
default: delete (wxObject *) ptr;
}}
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index a6857442c9..692eef858c 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -266,41 +266,41 @@ void initEventTable()
{wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 217, "command_splitter_doubleclicked"},
{wxEVT_COMMAND_SPLITTER_UNSPLIT, 217, "command_splitter_unsplit"},
{wxEVT_COMMAND_HTML_LINK_CLICKED, 219, "command_html_link_clicked"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 220, "command_auinotebook_page_close"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 220, "command_auinotebook_page_changed"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 220, "command_auinotebook_page_changing"},
- {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 220, "command_auinotebook_button"},
- {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 220, "command_auinotebook_begin_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 220, "command_auinotebook_end_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 220, "command_auinotebook_drag_motion"},
- {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 220, "command_auinotebook_allow_dnd"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 221, "command_auinotebook_page_close"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 221, "command_auinotebook_page_changed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 221, "command_auinotebook_page_changing"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 221, "command_auinotebook_button"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 221, "command_auinotebook_begin_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 221, "command_auinotebook_end_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 221, "command_auinotebook_drag_motion"},
+ {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 221, "command_auinotebook_allow_dnd"},
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 220, "command_auinotebook_tab_middle_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 221, "command_auinotebook_tab_middle_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 220, "command_auinotebook_tab_middle_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 221, "command_auinotebook_tab_middle_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 220, "command_auinotebook_tab_right_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 221, "command_auinotebook_tab_right_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 220, "command_auinotebook_tab_right_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 221, "command_auinotebook_tab_right_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 220, "command_auinotebook_page_closed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 221, "command_auinotebook_page_closed"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 220, "command_auinotebook_drag_done"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 221, "command_auinotebook_drag_done"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 220, "command_auinotebook_bg_dclick"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 221, "command_auinotebook_bg_dclick"},
#endif
- {wxEVT_AUI_PANE_BUTTON, 221, "aui_pane_button"},
- {wxEVT_AUI_PANE_CLOSE, 221, "aui_pane_close"},
- {wxEVT_AUI_PANE_MAXIMIZE, 221, "aui_pane_maximize"},
- {wxEVT_AUI_PANE_RESTORE, 221, "aui_pane_restore"},
- {wxEVT_AUI_RENDER, 221, "aui_render"},
- {wxEVT_AUI_FIND_MANAGER, 221, "aui_find_manager"},
+ {wxEVT_AUI_PANE_BUTTON, 222, "aui_pane_button"},
+ {wxEVT_AUI_PANE_CLOSE, 222, "aui_pane_close"},
+ {wxEVT_AUI_PANE_MAXIMIZE, 222, "aui_pane_maximize"},
+ {wxEVT_AUI_PANE_RESTORE, 222, "aui_pane_restore"},
+ {wxEVT_AUI_RENDER, 222, "aui_render"},
+ {wxEVT_AUI_FIND_MANAGER, 222, "aui_find_manager"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -778,7 +778,7 @@ case 219: {// wxHtmlLinkEvent
rt.addTupleCount(3);
break;
}
-case 220: {// wxAuiNotebookEvent
+case 221: {// wxAuiNotebookEvent
wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event;
wxAuiNotebook * GetDragSource = ev->GetDragSource();
evClass = (char*)"wxAuiNotebookEvent";
@@ -790,7 +790,7 @@ case 220: {// wxAuiNotebookEvent
rt.addTupleCount(5);
break;
}
-case 221: {// wxAuiManagerEvent
+case 222: {// wxAuiManagerEvent
wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event;
wxAuiManager * GetManager = ev->GetManager();
wxAuiPaneInfo * GetPane = ev->GetPane();
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index fd496c2ccc..8c056bbb91 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -18501,6 +18501,15 @@ case wxTreeCtrl_DeleteChildren: { // wxTreeCtrl::DeleteChildren
This->DeleteChildren(item);
break;
}
+case wxTreeCtrl_EditLabel: { // wxTreeCtrl::EditLabel
+ wxTreeCtrl *This = (wxTreeCtrl *) getPtr(bp,memenv); bp += 4;
+ bp += 4; /* Align */
+ wxTreeItemId item = wxTreeItemId((void *) *(wxUint64 *) bp); bp += 8;
+ if(!This) throw wxe_badarg(0);
+ wxTextCtrl * Result = (wxTextCtrl*)This->EditLabel(item);
+ rt.addRef(getRef((void *)Result,memenv), "wxTextCtrl");
+ break;
+}
case wxTreeCtrl_EnsureVisible: { // wxTreeCtrl::EnsureVisible
wxTreeCtrl *This = (wxTreeCtrl *) getPtr(bp,memenv); bp += 4;
bp += 4; /* Align */
@@ -30976,6 +30985,36 @@ case wxHtmlLinkEvent_GetLinkInfo: { // wxHtmlLinkEvent::GetLinkInfo
rt.add(Result);
break;
}
+case wxSystemSettings_GetColour: { // wxSystemSettings::GetColour
+ wxSystemColour index = *(wxSystemColour *) bp; bp += 4;;
+ wxColour Result = wxSystemSettings::GetColour((wxSystemColour) index);
+ rt.add(Result);
+ break;
+}
+case wxSystemSettings_GetFont: { // wxSystemSettings::GetFont
+ wxSystemFont index = *(wxSystemFont *) bp; bp += 4;;
+ wxFont * Result = new wxFont(wxSystemSettings::GetFont((wxSystemFont) index)); newPtr((void *) Result,3, memenv);;
+ rt.addRef(getRef((void *)Result,memenv), "wxFont");
+ break;
+}
+case wxSystemSettings_GetMetric: { // wxSystemSettings::GetMetric
+ wxWindow * win=NULL;
+ wxSystemMetric index = *(wxSystemMetric *) bp; bp += 4;;
+ bp += 4; /* Align */
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+win = (wxWindow *) getPtr(bp,memenv); bp += 4;
+ } break;
+ }};
+ int Result = wxSystemSettings::GetMetric((wxSystemMetric) index,win);
+ rt.addInt(Result);
+ break;
+}
+case wxSystemSettings_GetScreenType: { // wxSystemSettings::GetScreenType
+ int Result = wxSystemSettings::GetScreenType();
+ rt.addInt(Result);
+ break;
+}
case wxAuiNotebookEvent_SetSelection: { // wxAuiNotebookEvent::SetSelection
wxAuiNotebookEvent *This = (wxAuiNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * s = (int *) bp; bp += 4;
@@ -31110,7 +31149,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto
}
case wxLogNull_new: { // wxLogNull::wxLogNull
wxLogNull * Result = new wxLogNull();
- newPtr((void *) Result, 222, memenv);
+ newPtr((void *) Result, 223, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxLogNull");
break;
}
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index 415b7f0b29..4fb76f960b 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -1882,1444 +1882,1449 @@
#define wxTreeCtrl_Delete 2007
#define wxTreeCtrl_DeleteAllItems 2008
#define wxTreeCtrl_DeleteChildren 2009
-#define wxTreeCtrl_EnsureVisible 2010
-#define wxTreeCtrl_Expand 2011
-#define wxTreeCtrl_GetBoundingRect 2012
-#define wxTreeCtrl_GetChildrenCount 2014
-#define wxTreeCtrl_GetCount 2015
-#define wxTreeCtrl_GetEditControl 2016
-#define wxTreeCtrl_GetFirstChild 2017
-#define wxTreeCtrl_GetNextChild 2018
-#define wxTreeCtrl_GetFirstVisibleItem 2019
-#define wxTreeCtrl_GetImageList 2020
-#define wxTreeCtrl_GetIndent 2021
-#define wxTreeCtrl_GetItemBackgroundColour 2022
-#define wxTreeCtrl_GetItemData 2023
-#define wxTreeCtrl_GetItemFont 2024
-#define wxTreeCtrl_GetItemImage_1 2025
-#define wxTreeCtrl_GetItemImage_2 2026
-#define wxTreeCtrl_GetItemText 2027
-#define wxTreeCtrl_GetItemTextColour 2028
-#define wxTreeCtrl_GetLastChild 2029
-#define wxTreeCtrl_GetNextSibling 2030
-#define wxTreeCtrl_GetNextVisible 2031
-#define wxTreeCtrl_GetItemParent 2032
-#define wxTreeCtrl_GetPrevSibling 2033
-#define wxTreeCtrl_GetPrevVisible 2034
-#define wxTreeCtrl_GetRootItem 2035
-#define wxTreeCtrl_GetSelection 2036
-#define wxTreeCtrl_GetSelections 2037
-#define wxTreeCtrl_GetStateImageList 2038
-#define wxTreeCtrl_HitTest 2039
-#define wxTreeCtrl_InsertItem 2041
-#define wxTreeCtrl_IsBold 2042
-#define wxTreeCtrl_IsExpanded 2043
-#define wxTreeCtrl_IsSelected 2044
-#define wxTreeCtrl_IsVisible 2045
-#define wxTreeCtrl_ItemHasChildren 2046
-#define wxTreeCtrl_PrependItem 2047
-#define wxTreeCtrl_ScrollTo 2048
-#define wxTreeCtrl_SelectItem_1 2049
-#define wxTreeCtrl_SelectItem_2 2050
-#define wxTreeCtrl_SetIndent 2051
-#define wxTreeCtrl_SetImageList 2052
-#define wxTreeCtrl_SetItemBackgroundColour 2053
-#define wxTreeCtrl_SetItemBold 2054
-#define wxTreeCtrl_SetItemData 2055
-#define wxTreeCtrl_SetItemDropHighlight 2056
-#define wxTreeCtrl_SetItemFont 2057
-#define wxTreeCtrl_SetItemHasChildren 2058
-#define wxTreeCtrl_SetItemImage_2 2059
-#define wxTreeCtrl_SetItemImage_3 2060
-#define wxTreeCtrl_SetItemText 2061
-#define wxTreeCtrl_SetItemTextColour 2062
-#define wxTreeCtrl_SetStateImageList 2063
-#define wxTreeCtrl_SetWindowStyle 2064
-#define wxTreeCtrl_SortChildren 2065
-#define wxTreeCtrl_Toggle 2066
-#define wxTreeCtrl_ToggleItemSelection 2067
-#define wxTreeCtrl_Unselect 2068
-#define wxTreeCtrl_UnselectAll 2069
-#define wxTreeCtrl_UnselectItem 2070
-#define wxScrollBar_new_0 2071
-#define wxScrollBar_new_3 2072
-#define wxScrollBar_destruct 2073
-#define wxScrollBar_Create 2074
-#define wxScrollBar_GetRange 2075
-#define wxScrollBar_GetPageSize 2076
-#define wxScrollBar_GetThumbPosition 2077
-#define wxScrollBar_GetThumbSize 2078
-#define wxScrollBar_SetThumbPosition 2079
-#define wxScrollBar_SetScrollbar 2080
-#define wxSpinButton_new_2 2082
-#define wxSpinButton_new_0 2083
-#define wxSpinButton_Create 2084
-#define wxSpinButton_GetMax 2085
-#define wxSpinButton_GetMin 2086
-#define wxSpinButton_GetValue 2087
-#define wxSpinButton_SetRange 2088
-#define wxSpinButton_SetValue 2089
-#define wxSpinButton_destroy 2090
-#define wxSpinCtrl_new_0 2091
-#define wxSpinCtrl_new_2 2092
-#define wxSpinCtrl_Create 2094
-#define wxSpinCtrl_SetValue_1_1 2097
-#define wxSpinCtrl_SetValue_1_0 2098
-#define wxSpinCtrl_GetValue 2100
-#define wxSpinCtrl_SetRange 2102
-#define wxSpinCtrl_SetSelection 2103
-#define wxSpinCtrl_GetMin 2105
-#define wxSpinCtrl_GetMax 2107
-#define wxSpinCtrl_destroy 2108
-#define wxStaticText_new_0 2109
-#define wxStaticText_new_4 2110
-#define wxStaticText_Create 2111
-#define wxStaticText_GetLabel 2112
-#define wxStaticText_SetLabel 2113
-#define wxStaticText_Wrap 2114
-#define wxStaticText_destroy 2115
-#define wxStaticBitmap_new_0 2116
-#define wxStaticBitmap_new_4 2117
-#define wxStaticBitmap_Create 2118
-#define wxStaticBitmap_GetBitmap 2119
-#define wxStaticBitmap_SetBitmap 2120
-#define wxStaticBitmap_destroy 2121
-#define wxRadioBox_new 2122
-#define wxRadioBox_destruct 2124
-#define wxRadioBox_Create 2125
-#define wxRadioBox_Enable_2 2126
-#define wxRadioBox_Enable_1 2127
-#define wxRadioBox_GetSelection 2128
-#define wxRadioBox_GetString 2129
-#define wxRadioBox_SetSelection 2130
-#define wxRadioBox_Show_2 2131
-#define wxRadioBox_Show_1 2132
-#define wxRadioBox_GetColumnCount 2133
-#define wxRadioBox_GetItemHelpText 2134
-#define wxRadioBox_GetItemToolTip 2135
-#define wxRadioBox_GetItemFromPoint 2137
-#define wxRadioBox_GetRowCount 2138
-#define wxRadioBox_IsItemEnabled 2139
-#define wxRadioBox_IsItemShown 2140
-#define wxRadioBox_SetItemHelpText 2141
-#define wxRadioBox_SetItemToolTip 2142
-#define wxRadioButton_new_0 2143
-#define wxRadioButton_new_4 2144
-#define wxRadioButton_Create 2145
-#define wxRadioButton_GetValue 2146
-#define wxRadioButton_SetValue 2147
-#define wxRadioButton_destroy 2148
-#define wxSlider_new_6 2150
-#define wxSlider_new_0 2151
-#define wxSlider_Create 2152
-#define wxSlider_GetLineSize 2153
-#define wxSlider_GetMax 2154
-#define wxSlider_GetMin 2155
-#define wxSlider_GetPageSize 2156
-#define wxSlider_GetThumbLength 2157
-#define wxSlider_GetValue 2158
-#define wxSlider_SetLineSize 2159
-#define wxSlider_SetPageSize 2160
-#define wxSlider_SetRange 2161
-#define wxSlider_SetThumbLength 2162
-#define wxSlider_SetValue 2163
-#define wxSlider_destroy 2164
-#define wxDialog_new_4 2166
-#define wxDialog_new_0 2167
-#define wxDialog_destruct 2169
-#define wxDialog_Create 2170
-#define wxDialog_CreateButtonSizer 2171
-#define wxDialog_CreateStdDialogButtonSizer 2172
-#define wxDialog_EndModal 2173
-#define wxDialog_GetAffirmativeId 2174
-#define wxDialog_GetReturnCode 2175
-#define wxDialog_IsModal 2176
-#define wxDialog_SetAffirmativeId 2177
-#define wxDialog_SetReturnCode 2178
-#define wxDialog_Show 2179
-#define wxDialog_ShowModal 2180
-#define wxColourDialog_new_0 2181
-#define wxColourDialog_new_2 2182
-#define wxColourDialog_destruct 2183
-#define wxColourDialog_Create 2184
-#define wxColourDialog_GetColourData 2185
-#define wxColourData_new_0 2186
-#define wxColourData_new_1 2187
-#define wxColourData_destruct 2188
-#define wxColourData_GetChooseFull 2189
-#define wxColourData_GetColour 2190
-#define wxColourData_GetCustomColour 2192
-#define wxColourData_SetChooseFull 2193
-#define wxColourData_SetColour 2194
-#define wxColourData_SetCustomColour 2195
-#define wxPalette_new_0 2196
-#define wxPalette_new_4 2197
-#define wxPalette_destruct 2199
-#define wxPalette_Create 2200
-#define wxPalette_GetColoursCount 2201
-#define wxPalette_GetPixel 2202
-#define wxPalette_GetRGB 2203
-#define wxPalette_IsOk 2204
-#define wxDirDialog_new 2208
-#define wxDirDialog_destruct 2209
-#define wxDirDialog_GetPath 2210
-#define wxDirDialog_GetMessage 2211
-#define wxDirDialog_SetMessage 2212
-#define wxDirDialog_SetPath 2213
-#define wxFileDialog_new 2217
-#define wxFileDialog_destruct 2218
-#define wxFileDialog_GetDirectory 2219
-#define wxFileDialog_GetFilename 2220
-#define wxFileDialog_GetFilenames 2221
-#define wxFileDialog_GetFilterIndex 2222
-#define wxFileDialog_GetMessage 2223
-#define wxFileDialog_GetPath 2224
-#define wxFileDialog_GetPaths 2225
-#define wxFileDialog_GetWildcard 2226
-#define wxFileDialog_SetDirectory 2227
-#define wxFileDialog_SetFilename 2228
-#define wxFileDialog_SetFilterIndex 2229
-#define wxFileDialog_SetMessage 2230
-#define wxFileDialog_SetPath 2231
-#define wxFileDialog_SetWildcard 2232
-#define wxPickerBase_SetInternalMargin 2233
-#define wxPickerBase_GetInternalMargin 2234
-#define wxPickerBase_SetTextCtrlProportion 2235
-#define wxPickerBase_SetPickerCtrlProportion 2236
-#define wxPickerBase_GetTextCtrlProportion 2237
-#define wxPickerBase_GetPickerCtrlProportion 2238
-#define wxPickerBase_HasTextCtrl 2239
-#define wxPickerBase_GetTextCtrl 2240
-#define wxPickerBase_IsTextCtrlGrowable 2241
-#define wxPickerBase_SetPickerCtrlGrowable 2242
-#define wxPickerBase_SetTextCtrlGrowable 2243
-#define wxPickerBase_IsPickerCtrlGrowable 2244
-#define wxFilePickerCtrl_new_0 2245
-#define wxFilePickerCtrl_new_3 2246
-#define wxFilePickerCtrl_Create 2247
-#define wxFilePickerCtrl_GetPath 2248
-#define wxFilePickerCtrl_SetPath 2249
-#define wxFilePickerCtrl_destroy 2250
-#define wxDirPickerCtrl_new_0 2251
-#define wxDirPickerCtrl_new_3 2252
-#define wxDirPickerCtrl_Create 2253
-#define wxDirPickerCtrl_GetPath 2254
-#define wxDirPickerCtrl_SetPath 2255
-#define wxDirPickerCtrl_destroy 2256
-#define wxColourPickerCtrl_new_0 2257
-#define wxColourPickerCtrl_new_3 2258
-#define wxColourPickerCtrl_Create 2259
-#define wxColourPickerCtrl_GetColour 2260
-#define wxColourPickerCtrl_SetColour_1_1 2261
-#define wxColourPickerCtrl_SetColour_1_0 2262
-#define wxColourPickerCtrl_destroy 2263
-#define wxDatePickerCtrl_new_0 2264
-#define wxDatePickerCtrl_new_3 2265
-#define wxDatePickerCtrl_GetRange 2266
-#define wxDatePickerCtrl_GetValue 2267
-#define wxDatePickerCtrl_SetRange 2268
-#define wxDatePickerCtrl_SetValue 2269
-#define wxDatePickerCtrl_destroy 2270
-#define wxFontPickerCtrl_new_0 2271
-#define wxFontPickerCtrl_new_3 2272
-#define wxFontPickerCtrl_Create 2273
-#define wxFontPickerCtrl_GetSelectedFont 2274
-#define wxFontPickerCtrl_SetSelectedFont 2275
-#define wxFontPickerCtrl_GetMaxPointSize 2276
-#define wxFontPickerCtrl_SetMaxPointSize 2277
-#define wxFontPickerCtrl_destroy 2278
-#define wxFindReplaceDialog_new_0 2281
-#define wxFindReplaceDialog_new_4 2282
-#define wxFindReplaceDialog_destruct 2283
-#define wxFindReplaceDialog_Create 2284
-#define wxFindReplaceDialog_GetData 2285
-#define wxFindReplaceData_new_0 2286
-#define wxFindReplaceData_new_1 2287
-#define wxFindReplaceData_GetFindString 2288
-#define wxFindReplaceData_GetReplaceString 2289
-#define wxFindReplaceData_GetFlags 2290
-#define wxFindReplaceData_SetFlags 2291
-#define wxFindReplaceData_SetFindString 2292
-#define wxFindReplaceData_SetReplaceString 2293
-#define wxFindReplaceData_destroy 2294
-#define wxMultiChoiceDialog_new_0 2295
-#define wxMultiChoiceDialog_new_5 2297
-#define wxMultiChoiceDialog_GetSelections 2298
-#define wxMultiChoiceDialog_SetSelections 2299
-#define wxMultiChoiceDialog_destroy 2300
-#define wxSingleChoiceDialog_new_0 2301
-#define wxSingleChoiceDialog_new_5 2303
-#define wxSingleChoiceDialog_GetSelection 2304
-#define wxSingleChoiceDialog_GetStringSelection 2305
-#define wxSingleChoiceDialog_SetSelection 2306
-#define wxSingleChoiceDialog_destroy 2307
-#define wxTextEntryDialog_new 2308
-#define wxTextEntryDialog_GetValue 2309
-#define wxTextEntryDialog_SetValue 2310
-#define wxTextEntryDialog_destroy 2311
-#define wxPasswordEntryDialog_new 2312
-#define wxPasswordEntryDialog_destroy 2313
-#define wxFontData_new_0 2314
-#define wxFontData_new_1 2315
-#define wxFontData_destruct 2316
-#define wxFontData_EnableEffects 2317
-#define wxFontData_GetAllowSymbols 2318
-#define wxFontData_GetColour 2319
-#define wxFontData_GetChosenFont 2320
-#define wxFontData_GetEnableEffects 2321
-#define wxFontData_GetInitialFont 2322
-#define wxFontData_GetShowHelp 2323
-#define wxFontData_SetAllowSymbols 2324
-#define wxFontData_SetChosenFont 2325
-#define wxFontData_SetColour 2326
-#define wxFontData_SetInitialFont 2327
-#define wxFontData_SetRange 2328
-#define wxFontData_SetShowHelp 2329
-#define wxFontDialog_new_0 2333
-#define wxFontDialog_new_2 2335
-#define wxFontDialog_Create 2337
-#define wxFontDialog_GetFontData 2338
-#define wxFontDialog_destroy 2340
-#define wxProgressDialog_new 2341
-#define wxProgressDialog_destruct 2342
-#define wxProgressDialog_Resume 2343
-#define wxProgressDialog_Update_2 2344
-#define wxProgressDialog_Update_0 2345
-#define wxMessageDialog_new 2346
-#define wxMessageDialog_destruct 2347
-#define wxPageSetupDialog_new 2348
-#define wxPageSetupDialog_destruct 2349
-#define wxPageSetupDialog_GetPageSetupData 2350
-#define wxPageSetupDialog_ShowModal 2351
-#define wxPageSetupDialogData_new_0 2352
-#define wxPageSetupDialogData_new_1_0 2353
-#define wxPageSetupDialogData_new_1_1 2354
-#define wxPageSetupDialogData_destruct 2355
-#define wxPageSetupDialogData_EnableHelp 2356
-#define wxPageSetupDialogData_EnableMargins 2357
-#define wxPageSetupDialogData_EnableOrientation 2358
-#define wxPageSetupDialogData_EnablePaper 2359
-#define wxPageSetupDialogData_EnablePrinter 2360
-#define wxPageSetupDialogData_GetDefaultMinMargins 2361
-#define wxPageSetupDialogData_GetEnableMargins 2362
-#define wxPageSetupDialogData_GetEnableOrientation 2363
-#define wxPageSetupDialogData_GetEnablePaper 2364
-#define wxPageSetupDialogData_GetEnablePrinter 2365
-#define wxPageSetupDialogData_GetEnableHelp 2366
-#define wxPageSetupDialogData_GetDefaultInfo 2367
-#define wxPageSetupDialogData_GetMarginTopLeft 2368
-#define wxPageSetupDialogData_GetMarginBottomRight 2369
-#define wxPageSetupDialogData_GetMinMarginTopLeft 2370
-#define wxPageSetupDialogData_GetMinMarginBottomRight 2371
-#define wxPageSetupDialogData_GetPaperId 2372
-#define wxPageSetupDialogData_GetPaperSize 2373
-#define wxPageSetupDialogData_GetPrintData 2375
-#define wxPageSetupDialogData_IsOk 2376
-#define wxPageSetupDialogData_SetDefaultInfo 2377
-#define wxPageSetupDialogData_SetDefaultMinMargins 2378
-#define wxPageSetupDialogData_SetMarginTopLeft 2379
-#define wxPageSetupDialogData_SetMarginBottomRight 2380
-#define wxPageSetupDialogData_SetMinMarginTopLeft 2381
-#define wxPageSetupDialogData_SetMinMarginBottomRight 2382
-#define wxPageSetupDialogData_SetPaperId 2383
-#define wxPageSetupDialogData_SetPaperSize_1_1 2384
-#define wxPageSetupDialogData_SetPaperSize_1_0 2385
-#define wxPageSetupDialogData_SetPrintData 2386
-#define wxPrintDialog_new_2_0 2387
-#define wxPrintDialog_new_2_1 2388
-#define wxPrintDialog_destruct 2389
-#define wxPrintDialog_GetPrintDialogData 2390
-#define wxPrintDialog_GetPrintDC 2391
-#define wxPrintDialogData_new_0 2392
-#define wxPrintDialogData_new_1_1 2393
-#define wxPrintDialogData_new_1_0 2394
-#define wxPrintDialogData_destruct 2395
-#define wxPrintDialogData_EnableHelp 2396
-#define wxPrintDialogData_EnablePageNumbers 2397
-#define wxPrintDialogData_EnablePrintToFile 2398
-#define wxPrintDialogData_EnableSelection 2399
-#define wxPrintDialogData_GetAllPages 2400
-#define wxPrintDialogData_GetCollate 2401
-#define wxPrintDialogData_GetFromPage 2402
-#define wxPrintDialogData_GetMaxPage 2403
-#define wxPrintDialogData_GetMinPage 2404
-#define wxPrintDialogData_GetNoCopies 2405
-#define wxPrintDialogData_GetPrintData 2406
-#define wxPrintDialogData_GetPrintToFile 2407
-#define wxPrintDialogData_GetSelection 2408
-#define wxPrintDialogData_GetToPage 2409
-#define wxPrintDialogData_IsOk 2410
-#define wxPrintDialogData_SetCollate 2411
-#define wxPrintDialogData_SetFromPage 2412
-#define wxPrintDialogData_SetMaxPage 2413
-#define wxPrintDialogData_SetMinPage 2414
-#define wxPrintDialogData_SetNoCopies 2415
-#define wxPrintDialogData_SetPrintData 2416
-#define wxPrintDialogData_SetPrintToFile 2417
-#define wxPrintDialogData_SetSelection 2418
-#define wxPrintDialogData_SetToPage 2419
-#define wxPrintData_new_0 2420
-#define wxPrintData_new_1 2421
-#define wxPrintData_destruct 2422
-#define wxPrintData_GetCollate 2423
-#define wxPrintData_GetBin 2424
-#define wxPrintData_GetColour 2425
-#define wxPrintData_GetDuplex 2426
-#define wxPrintData_GetNoCopies 2427
-#define wxPrintData_GetOrientation 2428
-#define wxPrintData_GetPaperId 2429
-#define wxPrintData_GetPrinterName 2430
-#define wxPrintData_GetQuality 2431
-#define wxPrintData_IsOk 2432
-#define wxPrintData_SetBin 2433
-#define wxPrintData_SetCollate 2434
-#define wxPrintData_SetColour 2435
-#define wxPrintData_SetDuplex 2436
-#define wxPrintData_SetNoCopies 2437
-#define wxPrintData_SetOrientation 2438
-#define wxPrintData_SetPaperId 2439
-#define wxPrintData_SetPrinterName 2440
-#define wxPrintData_SetQuality 2441
-#define wxPrintPreview_new_2 2444
-#define wxPrintPreview_new_3 2445
-#define wxPrintPreview_destruct 2447
-#define wxPrintPreview_GetCanvas 2448
-#define wxPrintPreview_GetCurrentPage 2449
-#define wxPrintPreview_GetFrame 2450
-#define wxPrintPreview_GetMaxPage 2451
-#define wxPrintPreview_GetMinPage 2452
-#define wxPrintPreview_GetPrintout 2453
-#define wxPrintPreview_GetPrintoutForPrinting 2454
-#define wxPrintPreview_IsOk 2455
-#define wxPrintPreview_PaintPage 2456
-#define wxPrintPreview_Print 2457
-#define wxPrintPreview_RenderPage 2458
-#define wxPrintPreview_SetCanvas 2459
-#define wxPrintPreview_SetCurrentPage 2460
-#define wxPrintPreview_SetFrame 2461
-#define wxPrintPreview_SetPrintout 2462
-#define wxPrintPreview_SetZoom 2463
-#define wxPreviewFrame_new 2464
-#define wxPreviewFrame_destruct 2465
-#define wxPreviewFrame_CreateControlBar 2466
-#define wxPreviewFrame_CreateCanvas 2467
-#define wxPreviewFrame_Initialize 2468
-#define wxPreviewFrame_OnCloseWindow 2469
-#define wxPreviewControlBar_new 2470
-#define wxPreviewControlBar_destruct 2471
-#define wxPreviewControlBar_CreateButtons 2472
-#define wxPreviewControlBar_GetPrintPreview 2473
-#define wxPreviewControlBar_GetZoomControl 2474
-#define wxPreviewControlBar_SetZoomControl 2475
-#define wxPrinter_new 2477
-#define wxPrinter_CreateAbortWindow 2478
-#define wxPrinter_GetAbort 2479
-#define wxPrinter_GetLastError 2480
-#define wxPrinter_GetPrintDialogData 2481
-#define wxPrinter_Print 2482
-#define wxPrinter_PrintDialog 2483
-#define wxPrinter_ReportError 2484
-#define wxPrinter_Setup 2485
-#define wxPrinter_destroy 2486
-#define wxXmlResource_new_1 2487
-#define wxXmlResource_new_2 2488
-#define wxXmlResource_destruct 2489
-#define wxXmlResource_AttachUnknownControl 2490
-#define wxXmlResource_ClearHandlers 2491
-#define wxXmlResource_CompareVersion 2492
-#define wxXmlResource_Get 2493
-#define wxXmlResource_GetFlags 2494
-#define wxXmlResource_GetVersion 2495
-#define wxXmlResource_GetXRCID 2496
-#define wxXmlResource_InitAllHandlers 2497
-#define wxXmlResource_Load 2498
-#define wxXmlResource_LoadBitmap 2499
-#define wxXmlResource_LoadDialog_2 2500
-#define wxXmlResource_LoadDialog_3 2501
-#define wxXmlResource_LoadFrame_2 2502
-#define wxXmlResource_LoadFrame_3 2503
-#define wxXmlResource_LoadIcon 2504
-#define wxXmlResource_LoadMenu 2505
-#define wxXmlResource_LoadMenuBar_2 2506
-#define wxXmlResource_LoadMenuBar_1 2507
-#define wxXmlResource_LoadPanel_2 2508
-#define wxXmlResource_LoadPanel_3 2509
-#define wxXmlResource_LoadToolBar 2510
-#define wxXmlResource_Set 2511
-#define wxXmlResource_SetFlags 2512
-#define wxXmlResource_Unload 2513
-#define wxXmlResource_xrcctrl 2514
-#define wxHtmlEasyPrinting_new 2515
-#define wxHtmlEasyPrinting_destruct 2516
-#define wxHtmlEasyPrinting_GetPrintData 2517
-#define wxHtmlEasyPrinting_GetPageSetupData 2518
-#define wxHtmlEasyPrinting_PreviewFile 2519
-#define wxHtmlEasyPrinting_PreviewText 2520
-#define wxHtmlEasyPrinting_PrintFile 2521
-#define wxHtmlEasyPrinting_PrintText 2522
-#define wxHtmlEasyPrinting_PageSetup 2523
-#define wxHtmlEasyPrinting_SetFonts 2524
-#define wxHtmlEasyPrinting_SetHeader 2525
-#define wxHtmlEasyPrinting_SetFooter 2526
-#define wxGLCanvas_new_2 2528
-#define wxGLCanvas_new_3_1 2529
-#define wxGLCanvas_new_3_0 2530
-#define wxGLCanvas_GetContext 2531
-#define wxGLCanvas_SetCurrent 2533
-#define wxGLCanvas_SwapBuffers 2534
-#define wxGLCanvas_destroy 2535
-#define wxAuiManager_new 2536
-#define wxAuiManager_destruct 2537
-#define wxAuiManager_AddPane_2_1 2538
-#define wxAuiManager_AddPane_3 2539
-#define wxAuiManager_AddPane_2_0 2540
-#define wxAuiManager_DetachPane 2541
-#define wxAuiManager_GetAllPanes 2542
-#define wxAuiManager_GetArtProvider 2543
-#define wxAuiManager_GetDockSizeConstraint 2544
-#define wxAuiManager_GetFlags 2545
-#define wxAuiManager_GetManagedWindow 2546
-#define wxAuiManager_GetManager 2547
-#define wxAuiManager_GetPane_1_1 2548
-#define wxAuiManager_GetPane_1_0 2549
-#define wxAuiManager_HideHint 2550
-#define wxAuiManager_InsertPane 2551
-#define wxAuiManager_LoadPaneInfo 2552
-#define wxAuiManager_LoadPerspective 2553
-#define wxAuiManager_SavePaneInfo 2554
-#define wxAuiManager_SavePerspective 2555
-#define wxAuiManager_SetArtProvider 2556
-#define wxAuiManager_SetDockSizeConstraint 2557
-#define wxAuiManager_SetFlags 2558
-#define wxAuiManager_SetManagedWindow 2559
-#define wxAuiManager_ShowHint 2560
-#define wxAuiManager_UnInit 2561
-#define wxAuiManager_Update 2562
-#define wxAuiPaneInfo_new_0 2563
-#define wxAuiPaneInfo_new_1 2564
-#define wxAuiPaneInfo_destruct 2565
-#define wxAuiPaneInfo_BestSize_1 2566
-#define wxAuiPaneInfo_BestSize_2 2567
-#define wxAuiPaneInfo_Bottom 2568
-#define wxAuiPaneInfo_BottomDockable 2569
-#define wxAuiPaneInfo_Caption 2570
-#define wxAuiPaneInfo_CaptionVisible 2571
-#define wxAuiPaneInfo_Centre 2572
-#define wxAuiPaneInfo_CentrePane 2573
-#define wxAuiPaneInfo_CloseButton 2574
-#define wxAuiPaneInfo_DefaultPane 2575
-#define wxAuiPaneInfo_DestroyOnClose 2576
-#define wxAuiPaneInfo_Direction 2577
-#define wxAuiPaneInfo_Dock 2578
-#define wxAuiPaneInfo_Dockable 2579
-#define wxAuiPaneInfo_Fixed 2580
-#define wxAuiPaneInfo_Float 2581
-#define wxAuiPaneInfo_Floatable 2582
-#define wxAuiPaneInfo_FloatingPosition_1 2583
-#define wxAuiPaneInfo_FloatingPosition_2 2584
-#define wxAuiPaneInfo_FloatingSize_1 2585
-#define wxAuiPaneInfo_FloatingSize_2 2586
-#define wxAuiPaneInfo_Gripper 2587
-#define wxAuiPaneInfo_GripperTop 2588
-#define wxAuiPaneInfo_HasBorder 2589
-#define wxAuiPaneInfo_HasCaption 2590
-#define wxAuiPaneInfo_HasCloseButton 2591
-#define wxAuiPaneInfo_HasFlag 2592
-#define wxAuiPaneInfo_HasGripper 2593
-#define wxAuiPaneInfo_HasGripperTop 2594
-#define wxAuiPaneInfo_HasMaximizeButton 2595
-#define wxAuiPaneInfo_HasMinimizeButton 2596
-#define wxAuiPaneInfo_HasPinButton 2597
-#define wxAuiPaneInfo_Hide 2598
-#define wxAuiPaneInfo_IsBottomDockable 2599
-#define wxAuiPaneInfo_IsDocked 2600
-#define wxAuiPaneInfo_IsFixed 2601
-#define wxAuiPaneInfo_IsFloatable 2602
-#define wxAuiPaneInfo_IsFloating 2603
-#define wxAuiPaneInfo_IsLeftDockable 2604
-#define wxAuiPaneInfo_IsMovable 2605
-#define wxAuiPaneInfo_IsOk 2606
-#define wxAuiPaneInfo_IsResizable 2607
-#define wxAuiPaneInfo_IsRightDockable 2608
-#define wxAuiPaneInfo_IsShown 2609
-#define wxAuiPaneInfo_IsToolbar 2610
-#define wxAuiPaneInfo_IsTopDockable 2611
-#define wxAuiPaneInfo_Layer 2612
-#define wxAuiPaneInfo_Left 2613
-#define wxAuiPaneInfo_LeftDockable 2614
-#define wxAuiPaneInfo_MaxSize_1 2615
-#define wxAuiPaneInfo_MaxSize_2 2616
-#define wxAuiPaneInfo_MaximizeButton 2617
-#define wxAuiPaneInfo_MinSize_1 2618
-#define wxAuiPaneInfo_MinSize_2 2619
-#define wxAuiPaneInfo_MinimizeButton 2620
-#define wxAuiPaneInfo_Movable 2621
-#define wxAuiPaneInfo_Name 2622
-#define wxAuiPaneInfo_PaneBorder 2623
-#define wxAuiPaneInfo_PinButton 2624
-#define wxAuiPaneInfo_Position 2625
-#define wxAuiPaneInfo_Resizable 2626
-#define wxAuiPaneInfo_Right 2627
-#define wxAuiPaneInfo_RightDockable 2628
-#define wxAuiPaneInfo_Row 2629
-#define wxAuiPaneInfo_SafeSet 2630
-#define wxAuiPaneInfo_SetFlag 2631
-#define wxAuiPaneInfo_Show 2632
-#define wxAuiPaneInfo_ToolbarPane 2633
-#define wxAuiPaneInfo_Top 2634
-#define wxAuiPaneInfo_TopDockable 2635
-#define wxAuiPaneInfo_Window 2636
-#define wxAuiNotebook_new_0 2637
-#define wxAuiNotebook_new_2 2638
-#define wxAuiNotebook_AddPage 2639
-#define wxAuiNotebook_Create 2640
-#define wxAuiNotebook_DeletePage 2641
-#define wxAuiNotebook_GetArtProvider 2642
-#define wxAuiNotebook_GetPage 2643
-#define wxAuiNotebook_GetPageBitmap 2644
-#define wxAuiNotebook_GetPageCount 2645
-#define wxAuiNotebook_GetPageIndex 2646
-#define wxAuiNotebook_GetPageText 2647
-#define wxAuiNotebook_GetSelection 2648
-#define wxAuiNotebook_InsertPage 2649
-#define wxAuiNotebook_RemovePage 2650
-#define wxAuiNotebook_SetArtProvider 2651
-#define wxAuiNotebook_SetFont 2652
-#define wxAuiNotebook_SetPageBitmap 2653
-#define wxAuiNotebook_SetPageText 2654
-#define wxAuiNotebook_SetSelection 2655
-#define wxAuiNotebook_SetTabCtrlHeight 2656
-#define wxAuiNotebook_SetUniformBitmapSize 2657
-#define wxAuiNotebook_destroy 2658
-#define wxMDIParentFrame_new_0 2659
-#define wxMDIParentFrame_new_4 2660
-#define wxMDIParentFrame_destruct 2661
-#define wxMDIParentFrame_ActivateNext 2662
-#define wxMDIParentFrame_ActivatePrevious 2663
-#define wxMDIParentFrame_ArrangeIcons 2664
-#define wxMDIParentFrame_Cascade 2665
-#define wxMDIParentFrame_Create 2666
-#define wxMDIParentFrame_GetActiveChild 2667
-#define wxMDIParentFrame_GetClientWindow 2668
-#define wxMDIParentFrame_Tile 2669
-#define wxMDIChildFrame_new_0 2670
-#define wxMDIChildFrame_new_4 2671
-#define wxMDIChildFrame_destruct 2672
-#define wxMDIChildFrame_Activate 2673
-#define wxMDIChildFrame_Create 2674
-#define wxMDIChildFrame_Maximize 2675
-#define wxMDIChildFrame_Restore 2676
-#define wxMDIClientWindow_new_0 2677
-#define wxMDIClientWindow_new_2 2678
-#define wxMDIClientWindow_destruct 2679
-#define wxMDIClientWindow_CreateClient 2680
-#define wxLayoutAlgorithm_new 2681
-#define wxLayoutAlgorithm_LayoutFrame 2682
-#define wxLayoutAlgorithm_LayoutMDIFrame 2683
-#define wxLayoutAlgorithm_LayoutWindow 2684
-#define wxLayoutAlgorithm_destroy 2685
-#define wxEvent_GetId 2686
-#define wxEvent_GetSkipped 2687
-#define wxEvent_GetTimestamp 2688
-#define wxEvent_IsCommandEvent 2689
-#define wxEvent_ResumePropagation 2690
-#define wxEvent_ShouldPropagate 2691
-#define wxEvent_Skip 2692
-#define wxEvent_StopPropagation 2693
-#define wxCommandEvent_getClientData 2694
-#define wxCommandEvent_GetExtraLong 2695
-#define wxCommandEvent_GetInt 2696
-#define wxCommandEvent_GetSelection 2697
-#define wxCommandEvent_GetString 2698
-#define wxCommandEvent_IsChecked 2699
-#define wxCommandEvent_IsSelection 2700
-#define wxCommandEvent_SetInt 2701
-#define wxCommandEvent_SetString 2702
-#define wxScrollEvent_GetOrientation 2703
-#define wxScrollEvent_GetPosition 2704
-#define wxScrollWinEvent_GetOrientation 2705
-#define wxScrollWinEvent_GetPosition 2706
-#define wxMouseEvent_AltDown 2707
-#define wxMouseEvent_Button 2708
-#define wxMouseEvent_ButtonDClick 2709
-#define wxMouseEvent_ButtonDown 2710
-#define wxMouseEvent_ButtonUp 2711
-#define wxMouseEvent_CmdDown 2712
-#define wxMouseEvent_ControlDown 2713
-#define wxMouseEvent_Dragging 2714
-#define wxMouseEvent_Entering 2715
-#define wxMouseEvent_GetButton 2716
-#define wxMouseEvent_GetPosition 2719
-#define wxMouseEvent_GetLogicalPosition 2720
-#define wxMouseEvent_GetLinesPerAction 2721
-#define wxMouseEvent_GetWheelRotation 2722
-#define wxMouseEvent_GetWheelDelta 2723
-#define wxMouseEvent_GetX 2724
-#define wxMouseEvent_GetY 2725
-#define wxMouseEvent_IsButton 2726
-#define wxMouseEvent_IsPageScroll 2727
-#define wxMouseEvent_Leaving 2728
-#define wxMouseEvent_LeftDClick 2729
-#define wxMouseEvent_LeftDown 2730
-#define wxMouseEvent_LeftIsDown 2731
-#define wxMouseEvent_LeftUp 2732
-#define wxMouseEvent_MetaDown 2733
-#define wxMouseEvent_MiddleDClick 2734
-#define wxMouseEvent_MiddleDown 2735
-#define wxMouseEvent_MiddleIsDown 2736
-#define wxMouseEvent_MiddleUp 2737
-#define wxMouseEvent_Moving 2738
-#define wxMouseEvent_RightDClick 2739
-#define wxMouseEvent_RightDown 2740
-#define wxMouseEvent_RightIsDown 2741
-#define wxMouseEvent_RightUp 2742
-#define wxMouseEvent_ShiftDown 2743
-#define wxSetCursorEvent_GetCursor 2744
-#define wxSetCursorEvent_GetX 2745
-#define wxSetCursorEvent_GetY 2746
-#define wxSetCursorEvent_HasCursor 2747
-#define wxSetCursorEvent_SetCursor 2748
-#define wxKeyEvent_AltDown 2749
-#define wxKeyEvent_CmdDown 2750
-#define wxKeyEvent_ControlDown 2751
-#define wxKeyEvent_GetKeyCode 2752
-#define wxKeyEvent_GetModifiers 2753
-#define wxKeyEvent_GetPosition 2756
-#define wxKeyEvent_GetRawKeyCode 2757
-#define wxKeyEvent_GetRawKeyFlags 2758
-#define wxKeyEvent_GetUnicodeKey 2759
-#define wxKeyEvent_GetX 2760
-#define wxKeyEvent_GetY 2761
-#define wxKeyEvent_HasModifiers 2762
-#define wxKeyEvent_MetaDown 2763
-#define wxKeyEvent_ShiftDown 2764
-#define wxSizeEvent_GetSize 2765
-#define wxMoveEvent_GetPosition 2766
-#define wxEraseEvent_GetDC 2767
-#define wxFocusEvent_GetWindow 2768
-#define wxChildFocusEvent_GetWindow 2769
-#define wxMenuEvent_GetMenu 2770
-#define wxMenuEvent_GetMenuId 2771
-#define wxMenuEvent_IsPopup 2772
-#define wxCloseEvent_CanVeto 2773
-#define wxCloseEvent_GetLoggingOff 2774
-#define wxCloseEvent_SetCanVeto 2775
-#define wxCloseEvent_SetLoggingOff 2776
-#define wxCloseEvent_Veto 2777
-#define wxShowEvent_SetShow 2778
-#define wxShowEvent_GetShow 2779
-#define wxIconizeEvent_Iconized 2780
-#define wxJoystickEvent_ButtonDown 2781
-#define wxJoystickEvent_ButtonIsDown 2782
-#define wxJoystickEvent_ButtonUp 2783
-#define wxJoystickEvent_GetButtonChange 2784
-#define wxJoystickEvent_GetButtonState 2785
-#define wxJoystickEvent_GetJoystick 2786
-#define wxJoystickEvent_GetPosition 2787
-#define wxJoystickEvent_GetZPosition 2788
-#define wxJoystickEvent_IsButton 2789
-#define wxJoystickEvent_IsMove 2790
-#define wxJoystickEvent_IsZMove 2791
-#define wxUpdateUIEvent_CanUpdate 2792
-#define wxUpdateUIEvent_Check 2793
-#define wxUpdateUIEvent_Enable 2794
-#define wxUpdateUIEvent_Show 2795
-#define wxUpdateUIEvent_GetChecked 2796
-#define wxUpdateUIEvent_GetEnabled 2797
-#define wxUpdateUIEvent_GetShown 2798
-#define wxUpdateUIEvent_GetSetChecked 2799
-#define wxUpdateUIEvent_GetSetEnabled 2800
-#define wxUpdateUIEvent_GetSetShown 2801
-#define wxUpdateUIEvent_GetSetText 2802
-#define wxUpdateUIEvent_GetText 2803
-#define wxUpdateUIEvent_GetMode 2804
-#define wxUpdateUIEvent_GetUpdateInterval 2805
-#define wxUpdateUIEvent_ResetUpdateTime 2806
-#define wxUpdateUIEvent_SetMode 2807
-#define wxUpdateUIEvent_SetText 2808
-#define wxUpdateUIEvent_SetUpdateInterval 2809
-#define wxMouseCaptureChangedEvent_GetCapturedWindow 2810
-#define wxPaletteChangedEvent_SetChangedWindow 2811
-#define wxPaletteChangedEvent_GetChangedWindow 2812
-#define wxQueryNewPaletteEvent_SetPaletteRealized 2813
-#define wxQueryNewPaletteEvent_GetPaletteRealized 2814
-#define wxNavigationKeyEvent_GetDirection 2815
-#define wxNavigationKeyEvent_SetDirection 2816
-#define wxNavigationKeyEvent_IsWindowChange 2817
-#define wxNavigationKeyEvent_SetWindowChange 2818
-#define wxNavigationKeyEvent_IsFromTab 2819
-#define wxNavigationKeyEvent_SetFromTab 2820
-#define wxNavigationKeyEvent_GetCurrentFocus 2821
-#define wxNavigationKeyEvent_SetCurrentFocus 2822
-#define wxHelpEvent_GetOrigin 2823
-#define wxHelpEvent_GetPosition 2824
-#define wxHelpEvent_SetOrigin 2825
-#define wxHelpEvent_SetPosition 2826
-#define wxContextMenuEvent_GetPosition 2827
-#define wxContextMenuEvent_SetPosition 2828
-#define wxIdleEvent_CanSend 2829
-#define wxIdleEvent_GetMode 2830
-#define wxIdleEvent_RequestMore 2831
-#define wxIdleEvent_MoreRequested 2832
-#define wxIdleEvent_SetMode 2833
-#define wxGridEvent_AltDown 2834
-#define wxGridEvent_ControlDown 2835
-#define wxGridEvent_GetCol 2836
-#define wxGridEvent_GetPosition 2837
-#define wxGridEvent_GetRow 2838
-#define wxGridEvent_MetaDown 2839
-#define wxGridEvent_Selecting 2840
-#define wxGridEvent_ShiftDown 2841
-#define wxNotifyEvent_Allow 2842
-#define wxNotifyEvent_IsAllowed 2843
-#define wxNotifyEvent_Veto 2844
-#define wxSashEvent_GetEdge 2845
-#define wxSashEvent_GetDragRect 2846
-#define wxSashEvent_GetDragStatus 2847
-#define wxListEvent_GetCacheFrom 2848
-#define wxListEvent_GetCacheTo 2849
-#define wxListEvent_GetKeyCode 2850
-#define wxListEvent_GetIndex 2851
-#define wxListEvent_GetColumn 2852
-#define wxListEvent_GetPoint 2853
-#define wxListEvent_GetLabel 2854
-#define wxListEvent_GetText 2855
-#define wxListEvent_GetImage 2856
-#define wxListEvent_GetData 2857
-#define wxListEvent_GetMask 2858
-#define wxListEvent_GetItem 2859
-#define wxListEvent_IsEditCancelled 2860
-#define wxDateEvent_GetDate 2861
-#define wxCalendarEvent_GetWeekDay 2862
-#define wxFileDirPickerEvent_GetPath 2863
-#define wxColourPickerEvent_GetColour 2864
-#define wxFontPickerEvent_GetFont 2865
-#define wxStyledTextEvent_GetPosition 2866
-#define wxStyledTextEvent_GetKey 2867
-#define wxStyledTextEvent_GetModifiers 2868
-#define wxStyledTextEvent_GetModificationType 2869
-#define wxStyledTextEvent_GetText 2870
-#define wxStyledTextEvent_GetLength 2871
-#define wxStyledTextEvent_GetLinesAdded 2872
-#define wxStyledTextEvent_GetLine 2873
-#define wxStyledTextEvent_GetFoldLevelNow 2874
-#define wxStyledTextEvent_GetFoldLevelPrev 2875
-#define wxStyledTextEvent_GetMargin 2876
-#define wxStyledTextEvent_GetMessage 2877
-#define wxStyledTextEvent_GetWParam 2878
-#define wxStyledTextEvent_GetLParam 2879
-#define wxStyledTextEvent_GetListType 2880
-#define wxStyledTextEvent_GetX 2881
-#define wxStyledTextEvent_GetY 2882
-#define wxStyledTextEvent_GetDragText 2883
-#define wxStyledTextEvent_GetDragAllowMove 2884
-#define wxStyledTextEvent_GetDragResult 2885
-#define wxStyledTextEvent_GetShift 2886
-#define wxStyledTextEvent_GetControl 2887
-#define wxStyledTextEvent_GetAlt 2888
-#define utils_wxGetKeyState 2889
-#define utils_wxGetMousePosition 2890
-#define utils_wxGetMouseState 2891
-#define utils_wxSetDetectableAutoRepeat 2892
-#define utils_wxBell 2893
-#define utils_wxFindMenuItemId 2894
-#define utils_wxGenericFindWindowAtPoint 2895
-#define utils_wxFindWindowAtPoint 2896
-#define utils_wxBeginBusyCursor 2897
-#define utils_wxEndBusyCursor 2898
-#define utils_wxIsBusy 2899
-#define utils_wxShutdown 2900
-#define utils_wxShell 2901
-#define utils_wxLaunchDefaultBrowser 2902
-#define utils_wxGetEmailAddress 2903
-#define utils_wxGetUserId 2904
-#define utils_wxGetHomeDir 2905
-#define utils_wxNewId 2906
-#define utils_wxRegisterId 2907
-#define utils_wxGetCurrentId 2908
-#define utils_wxGetOsDescription 2909
-#define utils_wxIsPlatformLittleEndian 2910
-#define utils_wxIsPlatform64Bit 2911
-#define wxPrintout_new 2912
-#define wxPrintout_destruct 2913
-#define wxPrintout_GetDC 2914
-#define wxPrintout_GetPageSizeMM 2915
-#define wxPrintout_GetPageSizePixels 2916
-#define wxPrintout_GetPaperRectPixels 2917
-#define wxPrintout_GetPPIPrinter 2918
-#define wxPrintout_GetPPIScreen 2919
-#define wxPrintout_GetTitle 2920
-#define wxPrintout_IsPreview 2921
-#define wxPrintout_FitThisSizeToPaper 2922
-#define wxPrintout_FitThisSizeToPage 2923
-#define wxPrintout_FitThisSizeToPageMargins 2924
-#define wxPrintout_MapScreenSizeToPaper 2925
-#define wxPrintout_MapScreenSizeToPage 2926
-#define wxPrintout_MapScreenSizeToPageMargins 2927
-#define wxPrintout_MapScreenSizeToDevice 2928
-#define wxPrintout_GetLogicalPaperRect 2929
-#define wxPrintout_GetLogicalPageRect 2930
-#define wxPrintout_GetLogicalPageMarginsRect 2931
-#define wxPrintout_SetLogicalOrigin 2932
-#define wxPrintout_OffsetLogicalOrigin 2933
-#define wxStyledTextCtrl_new_2 2934
-#define wxStyledTextCtrl_new_0 2935
-#define wxStyledTextCtrl_destruct 2936
-#define wxStyledTextCtrl_Create 2937
-#define wxStyledTextCtrl_AddText 2938
-#define wxStyledTextCtrl_AddStyledText 2939
-#define wxStyledTextCtrl_InsertText 2940
-#define wxStyledTextCtrl_ClearAll 2941
-#define wxStyledTextCtrl_ClearDocumentStyle 2942
-#define wxStyledTextCtrl_GetLength 2943
-#define wxStyledTextCtrl_GetCharAt 2944
-#define wxStyledTextCtrl_GetCurrentPos 2945
-#define wxStyledTextCtrl_GetAnchor 2946
-#define wxStyledTextCtrl_GetStyleAt 2947
-#define wxStyledTextCtrl_Redo 2948
-#define wxStyledTextCtrl_SetUndoCollection 2949
-#define wxStyledTextCtrl_SelectAll 2950
-#define wxStyledTextCtrl_SetSavePoint 2951
-#define wxStyledTextCtrl_GetStyledText 2952
-#define wxStyledTextCtrl_CanRedo 2953
-#define wxStyledTextCtrl_MarkerLineFromHandle 2954
-#define wxStyledTextCtrl_MarkerDeleteHandle 2955
-#define wxStyledTextCtrl_GetUndoCollection 2956
-#define wxStyledTextCtrl_GetViewWhiteSpace 2957
-#define wxStyledTextCtrl_SetViewWhiteSpace 2958
-#define wxStyledTextCtrl_PositionFromPoint 2959
-#define wxStyledTextCtrl_PositionFromPointClose 2960
-#define wxStyledTextCtrl_GotoLine 2961
-#define wxStyledTextCtrl_GotoPos 2962
-#define wxStyledTextCtrl_SetAnchor 2963
-#define wxStyledTextCtrl_GetCurLine 2964
-#define wxStyledTextCtrl_GetEndStyled 2965
-#define wxStyledTextCtrl_ConvertEOLs 2966
-#define wxStyledTextCtrl_GetEOLMode 2967
-#define wxStyledTextCtrl_SetEOLMode 2968
-#define wxStyledTextCtrl_StartStyling 2969
-#define wxStyledTextCtrl_SetStyling 2970
-#define wxStyledTextCtrl_GetBufferedDraw 2971
-#define wxStyledTextCtrl_SetBufferedDraw 2972
-#define wxStyledTextCtrl_SetTabWidth 2973
-#define wxStyledTextCtrl_GetTabWidth 2974
-#define wxStyledTextCtrl_SetCodePage 2975
-#define wxStyledTextCtrl_MarkerDefine 2976
-#define wxStyledTextCtrl_MarkerSetForeground 2977
-#define wxStyledTextCtrl_MarkerSetBackground 2978
-#define wxStyledTextCtrl_MarkerAdd 2979
-#define wxStyledTextCtrl_MarkerDelete 2980
-#define wxStyledTextCtrl_MarkerDeleteAll 2981
-#define wxStyledTextCtrl_MarkerGet 2982
-#define wxStyledTextCtrl_MarkerNext 2983
-#define wxStyledTextCtrl_MarkerPrevious 2984
-#define wxStyledTextCtrl_MarkerDefineBitmap 2985
-#define wxStyledTextCtrl_MarkerAddSet 2986
-#define wxStyledTextCtrl_MarkerSetAlpha 2987
-#define wxStyledTextCtrl_SetMarginType 2988
-#define wxStyledTextCtrl_GetMarginType 2989
-#define wxStyledTextCtrl_SetMarginWidth 2990
-#define wxStyledTextCtrl_GetMarginWidth 2991
-#define wxStyledTextCtrl_SetMarginMask 2992
-#define wxStyledTextCtrl_GetMarginMask 2993
-#define wxStyledTextCtrl_SetMarginSensitive 2994
-#define wxStyledTextCtrl_GetMarginSensitive 2995
-#define wxStyledTextCtrl_StyleClearAll 2996
-#define wxStyledTextCtrl_StyleSetForeground 2997
-#define wxStyledTextCtrl_StyleSetBackground 2998
-#define wxStyledTextCtrl_StyleSetBold 2999
-#define wxStyledTextCtrl_StyleSetItalic 3000
-#define wxStyledTextCtrl_StyleSetSize 3001
-#define wxStyledTextCtrl_StyleSetFaceName 3002
-#define wxStyledTextCtrl_StyleSetEOLFilled 3003
-#define wxStyledTextCtrl_StyleResetDefault 3004
-#define wxStyledTextCtrl_StyleSetUnderline 3005
-#define wxStyledTextCtrl_StyleSetCase 3006
-#define wxStyledTextCtrl_StyleSetHotSpot 3007
-#define wxStyledTextCtrl_SetSelForeground 3008
-#define wxStyledTextCtrl_SetSelBackground 3009
-#define wxStyledTextCtrl_GetSelAlpha 3010
-#define wxStyledTextCtrl_SetSelAlpha 3011
-#define wxStyledTextCtrl_SetCaretForeground 3012
-#define wxStyledTextCtrl_CmdKeyAssign 3013
-#define wxStyledTextCtrl_CmdKeyClear 3014
-#define wxStyledTextCtrl_CmdKeyClearAll 3015
-#define wxStyledTextCtrl_SetStyleBytes 3016
-#define wxStyledTextCtrl_StyleSetVisible 3017
-#define wxStyledTextCtrl_GetCaretPeriod 3018
-#define wxStyledTextCtrl_SetCaretPeriod 3019
-#define wxStyledTextCtrl_SetWordChars 3020
-#define wxStyledTextCtrl_BeginUndoAction 3021
-#define wxStyledTextCtrl_EndUndoAction 3022
-#define wxStyledTextCtrl_IndicatorSetStyle 3023
-#define wxStyledTextCtrl_IndicatorGetStyle 3024
-#define wxStyledTextCtrl_IndicatorSetForeground 3025
-#define wxStyledTextCtrl_IndicatorGetForeground 3026
-#define wxStyledTextCtrl_SetWhitespaceForeground 3027
-#define wxStyledTextCtrl_SetWhitespaceBackground 3028
-#define wxStyledTextCtrl_GetStyleBits 3029
-#define wxStyledTextCtrl_SetLineState 3030
-#define wxStyledTextCtrl_GetLineState 3031
-#define wxStyledTextCtrl_GetMaxLineState 3032
-#define wxStyledTextCtrl_GetCaretLineVisible 3033
-#define wxStyledTextCtrl_SetCaretLineVisible 3034
-#define wxStyledTextCtrl_GetCaretLineBackground 3035
-#define wxStyledTextCtrl_SetCaretLineBackground 3036
-#define wxStyledTextCtrl_AutoCompShow 3037
-#define wxStyledTextCtrl_AutoCompCancel 3038
-#define wxStyledTextCtrl_AutoCompActive 3039
-#define wxStyledTextCtrl_AutoCompPosStart 3040
-#define wxStyledTextCtrl_AutoCompComplete 3041
-#define wxStyledTextCtrl_AutoCompStops 3042
-#define wxStyledTextCtrl_AutoCompSetSeparator 3043
-#define wxStyledTextCtrl_AutoCompGetSeparator 3044
-#define wxStyledTextCtrl_AutoCompSelect 3045
-#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3046
-#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3047
-#define wxStyledTextCtrl_AutoCompSetFillUps 3048
-#define wxStyledTextCtrl_AutoCompSetChooseSingle 3049
-#define wxStyledTextCtrl_AutoCompGetChooseSingle 3050
-#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3051
-#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3052
-#define wxStyledTextCtrl_UserListShow 3053
-#define wxStyledTextCtrl_AutoCompSetAutoHide 3054
-#define wxStyledTextCtrl_AutoCompGetAutoHide 3055
-#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3056
-#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3057
-#define wxStyledTextCtrl_RegisterImage 3058
-#define wxStyledTextCtrl_ClearRegisteredImages 3059
-#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3060
-#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3061
-#define wxStyledTextCtrl_AutoCompSetMaxWidth 3062
-#define wxStyledTextCtrl_AutoCompGetMaxWidth 3063
-#define wxStyledTextCtrl_AutoCompSetMaxHeight 3064
-#define wxStyledTextCtrl_AutoCompGetMaxHeight 3065
-#define wxStyledTextCtrl_SetIndent 3066
-#define wxStyledTextCtrl_GetIndent 3067
-#define wxStyledTextCtrl_SetUseTabs 3068
-#define wxStyledTextCtrl_GetUseTabs 3069
-#define wxStyledTextCtrl_SetLineIndentation 3070
-#define wxStyledTextCtrl_GetLineIndentation 3071
-#define wxStyledTextCtrl_GetLineIndentPosition 3072
-#define wxStyledTextCtrl_GetColumn 3073
-#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3074
-#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3075
-#define wxStyledTextCtrl_SetIndentationGuides 3076
-#define wxStyledTextCtrl_GetIndentationGuides 3077
-#define wxStyledTextCtrl_SetHighlightGuide 3078
-#define wxStyledTextCtrl_GetHighlightGuide 3079
-#define wxStyledTextCtrl_GetLineEndPosition 3080
-#define wxStyledTextCtrl_GetCodePage 3081
-#define wxStyledTextCtrl_GetCaretForeground 3082
-#define wxStyledTextCtrl_GetReadOnly 3083
-#define wxStyledTextCtrl_SetCurrentPos 3084
-#define wxStyledTextCtrl_SetSelectionStart 3085
-#define wxStyledTextCtrl_GetSelectionStart 3086
-#define wxStyledTextCtrl_SetSelectionEnd 3087
-#define wxStyledTextCtrl_GetSelectionEnd 3088
-#define wxStyledTextCtrl_SetPrintMagnification 3089
-#define wxStyledTextCtrl_GetPrintMagnification 3090
-#define wxStyledTextCtrl_SetPrintColourMode 3091
-#define wxStyledTextCtrl_GetPrintColourMode 3092
-#define wxStyledTextCtrl_FindText 3093
-#define wxStyledTextCtrl_FormatRange 3094
-#define wxStyledTextCtrl_GetFirstVisibleLine 3095
-#define wxStyledTextCtrl_GetLine 3096
-#define wxStyledTextCtrl_GetLineCount 3097
-#define wxStyledTextCtrl_SetMarginLeft 3098
-#define wxStyledTextCtrl_GetMarginLeft 3099
-#define wxStyledTextCtrl_SetMarginRight 3100
-#define wxStyledTextCtrl_GetMarginRight 3101
-#define wxStyledTextCtrl_GetModify 3102
-#define wxStyledTextCtrl_SetSelection 3103
-#define wxStyledTextCtrl_GetSelectedText 3104
-#define wxStyledTextCtrl_GetTextRange 3105
-#define wxStyledTextCtrl_HideSelection 3106
-#define wxStyledTextCtrl_LineFromPosition 3107
-#define wxStyledTextCtrl_PositionFromLine 3108
-#define wxStyledTextCtrl_LineScroll 3109
-#define wxStyledTextCtrl_EnsureCaretVisible 3110
-#define wxStyledTextCtrl_ReplaceSelection 3111
-#define wxStyledTextCtrl_SetReadOnly 3112
-#define wxStyledTextCtrl_CanPaste 3113
-#define wxStyledTextCtrl_CanUndo 3114
-#define wxStyledTextCtrl_EmptyUndoBuffer 3115
-#define wxStyledTextCtrl_Undo 3116
-#define wxStyledTextCtrl_Cut 3117
-#define wxStyledTextCtrl_Copy 3118
-#define wxStyledTextCtrl_Paste 3119
-#define wxStyledTextCtrl_Clear 3120
-#define wxStyledTextCtrl_SetText 3121
-#define wxStyledTextCtrl_GetText 3122
-#define wxStyledTextCtrl_GetTextLength 3123
-#define wxStyledTextCtrl_GetOvertype 3124
-#define wxStyledTextCtrl_SetCaretWidth 3125
-#define wxStyledTextCtrl_GetCaretWidth 3126
-#define wxStyledTextCtrl_SetTargetStart 3127
-#define wxStyledTextCtrl_GetTargetStart 3128
-#define wxStyledTextCtrl_SetTargetEnd 3129
-#define wxStyledTextCtrl_GetTargetEnd 3130
-#define wxStyledTextCtrl_ReplaceTarget 3131
-#define wxStyledTextCtrl_SearchInTarget 3132
-#define wxStyledTextCtrl_SetSearchFlags 3133
-#define wxStyledTextCtrl_GetSearchFlags 3134
-#define wxStyledTextCtrl_CallTipShow 3135
-#define wxStyledTextCtrl_CallTipCancel 3136
-#define wxStyledTextCtrl_CallTipActive 3137
-#define wxStyledTextCtrl_CallTipPosAtStart 3138
-#define wxStyledTextCtrl_CallTipSetHighlight 3139
-#define wxStyledTextCtrl_CallTipSetBackground 3140
-#define wxStyledTextCtrl_CallTipSetForeground 3141
-#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3142
-#define wxStyledTextCtrl_CallTipUseStyle 3143
-#define wxStyledTextCtrl_VisibleFromDocLine 3144
-#define wxStyledTextCtrl_DocLineFromVisible 3145
-#define wxStyledTextCtrl_WrapCount 3146
-#define wxStyledTextCtrl_SetFoldLevel 3147
-#define wxStyledTextCtrl_GetFoldLevel 3148
-#define wxStyledTextCtrl_GetLastChild 3149
-#define wxStyledTextCtrl_GetFoldParent 3150
-#define wxStyledTextCtrl_ShowLines 3151
-#define wxStyledTextCtrl_HideLines 3152
-#define wxStyledTextCtrl_GetLineVisible 3153
-#define wxStyledTextCtrl_SetFoldExpanded 3154
-#define wxStyledTextCtrl_GetFoldExpanded 3155
-#define wxStyledTextCtrl_ToggleFold 3156
-#define wxStyledTextCtrl_EnsureVisible 3157
-#define wxStyledTextCtrl_SetFoldFlags 3158
-#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3159
-#define wxStyledTextCtrl_SetTabIndents 3160
-#define wxStyledTextCtrl_GetTabIndents 3161
-#define wxStyledTextCtrl_SetBackSpaceUnIndents 3162
-#define wxStyledTextCtrl_GetBackSpaceUnIndents 3163
-#define wxStyledTextCtrl_SetMouseDwellTime 3164
-#define wxStyledTextCtrl_GetMouseDwellTime 3165
-#define wxStyledTextCtrl_WordStartPosition 3166
-#define wxStyledTextCtrl_WordEndPosition 3167
-#define wxStyledTextCtrl_SetWrapMode 3168
-#define wxStyledTextCtrl_GetWrapMode 3169
-#define wxStyledTextCtrl_SetWrapVisualFlags 3170
-#define wxStyledTextCtrl_GetWrapVisualFlags 3171
-#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3172
-#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3173
-#define wxStyledTextCtrl_SetWrapStartIndent 3174
-#define wxStyledTextCtrl_GetWrapStartIndent 3175
-#define wxStyledTextCtrl_SetLayoutCache 3176
-#define wxStyledTextCtrl_GetLayoutCache 3177
-#define wxStyledTextCtrl_SetScrollWidth 3178
-#define wxStyledTextCtrl_GetScrollWidth 3179
-#define wxStyledTextCtrl_TextWidth 3180
-#define wxStyledTextCtrl_GetEndAtLastLine 3181
-#define wxStyledTextCtrl_TextHeight 3182
-#define wxStyledTextCtrl_SetUseVerticalScrollBar 3183
-#define wxStyledTextCtrl_GetUseVerticalScrollBar 3184
-#define wxStyledTextCtrl_AppendText 3185
-#define wxStyledTextCtrl_GetTwoPhaseDraw 3186
-#define wxStyledTextCtrl_SetTwoPhaseDraw 3187
-#define wxStyledTextCtrl_TargetFromSelection 3188
-#define wxStyledTextCtrl_LinesJoin 3189
-#define wxStyledTextCtrl_LinesSplit 3190
-#define wxStyledTextCtrl_SetFoldMarginColour 3191
-#define wxStyledTextCtrl_SetFoldMarginHiColour 3192
-#define wxStyledTextCtrl_LineDown 3193
-#define wxStyledTextCtrl_LineDownExtend 3194
-#define wxStyledTextCtrl_LineUp 3195
-#define wxStyledTextCtrl_LineUpExtend 3196
-#define wxStyledTextCtrl_CharLeft 3197
-#define wxStyledTextCtrl_CharLeftExtend 3198
-#define wxStyledTextCtrl_CharRight 3199
-#define wxStyledTextCtrl_CharRightExtend 3200
-#define wxStyledTextCtrl_WordLeft 3201
-#define wxStyledTextCtrl_WordLeftExtend 3202
-#define wxStyledTextCtrl_WordRight 3203
-#define wxStyledTextCtrl_WordRightExtend 3204
-#define wxStyledTextCtrl_Home 3205
-#define wxStyledTextCtrl_HomeExtend 3206
-#define wxStyledTextCtrl_LineEnd 3207
-#define wxStyledTextCtrl_LineEndExtend 3208
-#define wxStyledTextCtrl_DocumentStart 3209
-#define wxStyledTextCtrl_DocumentStartExtend 3210
-#define wxStyledTextCtrl_DocumentEnd 3211
-#define wxStyledTextCtrl_DocumentEndExtend 3212
-#define wxStyledTextCtrl_PageUp 3213
-#define wxStyledTextCtrl_PageUpExtend 3214
-#define wxStyledTextCtrl_PageDown 3215
-#define wxStyledTextCtrl_PageDownExtend 3216
-#define wxStyledTextCtrl_EditToggleOvertype 3217
-#define wxStyledTextCtrl_Cancel 3218
-#define wxStyledTextCtrl_DeleteBack 3219
-#define wxStyledTextCtrl_Tab 3220
-#define wxStyledTextCtrl_BackTab 3221
-#define wxStyledTextCtrl_NewLine 3222
-#define wxStyledTextCtrl_FormFeed 3223
-#define wxStyledTextCtrl_VCHome 3224
-#define wxStyledTextCtrl_VCHomeExtend 3225
-#define wxStyledTextCtrl_ZoomIn 3226
-#define wxStyledTextCtrl_ZoomOut 3227
-#define wxStyledTextCtrl_DelWordLeft 3228
-#define wxStyledTextCtrl_DelWordRight 3229
-#define wxStyledTextCtrl_LineCut 3230
-#define wxStyledTextCtrl_LineDelete 3231
-#define wxStyledTextCtrl_LineTranspose 3232
-#define wxStyledTextCtrl_LineDuplicate 3233
-#define wxStyledTextCtrl_LowerCase 3234
-#define wxStyledTextCtrl_UpperCase 3235
-#define wxStyledTextCtrl_LineScrollDown 3236
-#define wxStyledTextCtrl_LineScrollUp 3237
-#define wxStyledTextCtrl_DeleteBackNotLine 3238
-#define wxStyledTextCtrl_HomeDisplay 3239
-#define wxStyledTextCtrl_HomeDisplayExtend 3240
-#define wxStyledTextCtrl_LineEndDisplay 3241
-#define wxStyledTextCtrl_LineEndDisplayExtend 3242
-#define wxStyledTextCtrl_HomeWrapExtend 3243
-#define wxStyledTextCtrl_LineEndWrap 3244
-#define wxStyledTextCtrl_LineEndWrapExtend 3245
-#define wxStyledTextCtrl_VCHomeWrap 3246
-#define wxStyledTextCtrl_VCHomeWrapExtend 3247
-#define wxStyledTextCtrl_LineCopy 3248
-#define wxStyledTextCtrl_MoveCaretInsideView 3249
-#define wxStyledTextCtrl_LineLength 3250
-#define wxStyledTextCtrl_BraceHighlight 3251
-#define wxStyledTextCtrl_BraceBadLight 3252
-#define wxStyledTextCtrl_BraceMatch 3253
-#define wxStyledTextCtrl_GetViewEOL 3254
-#define wxStyledTextCtrl_SetViewEOL 3255
-#define wxStyledTextCtrl_SetModEventMask 3256
-#define wxStyledTextCtrl_GetEdgeColumn 3257
-#define wxStyledTextCtrl_SetEdgeColumn 3258
-#define wxStyledTextCtrl_GetEdgeMode 3259
-#define wxStyledTextCtrl_GetEdgeColour 3260
-#define wxStyledTextCtrl_SetEdgeColour 3261
-#define wxStyledTextCtrl_SearchAnchor 3262
-#define wxStyledTextCtrl_SearchNext 3263
-#define wxStyledTextCtrl_SearchPrev 3264
-#define wxStyledTextCtrl_LinesOnScreen 3265
-#define wxStyledTextCtrl_UsePopUp 3266
-#define wxStyledTextCtrl_SelectionIsRectangle 3267
-#define wxStyledTextCtrl_SetZoom 3268
-#define wxStyledTextCtrl_GetZoom 3269
-#define wxStyledTextCtrl_GetModEventMask 3270
-#define wxStyledTextCtrl_SetSTCFocus 3271
-#define wxStyledTextCtrl_GetSTCFocus 3272
-#define wxStyledTextCtrl_SetStatus 3273
-#define wxStyledTextCtrl_GetStatus 3274
-#define wxStyledTextCtrl_SetMouseDownCaptures 3275
-#define wxStyledTextCtrl_GetMouseDownCaptures 3276
-#define wxStyledTextCtrl_SetSTCCursor 3277
-#define wxStyledTextCtrl_GetSTCCursor 3278
-#define wxStyledTextCtrl_SetControlCharSymbol 3279
-#define wxStyledTextCtrl_GetControlCharSymbol 3280
-#define wxStyledTextCtrl_WordPartLeft 3281
-#define wxStyledTextCtrl_WordPartLeftExtend 3282
-#define wxStyledTextCtrl_WordPartRight 3283
-#define wxStyledTextCtrl_WordPartRightExtend 3284
-#define wxStyledTextCtrl_SetVisiblePolicy 3285
-#define wxStyledTextCtrl_DelLineLeft 3286
-#define wxStyledTextCtrl_DelLineRight 3287
-#define wxStyledTextCtrl_GetXOffset 3288
-#define wxStyledTextCtrl_ChooseCaretX 3289
-#define wxStyledTextCtrl_SetXCaretPolicy 3290
-#define wxStyledTextCtrl_SetYCaretPolicy 3291
-#define wxStyledTextCtrl_GetPrintWrapMode 3292
-#define wxStyledTextCtrl_SetHotspotActiveForeground 3293
-#define wxStyledTextCtrl_SetHotspotActiveBackground 3294
-#define wxStyledTextCtrl_SetHotspotActiveUnderline 3295
-#define wxStyledTextCtrl_SetHotspotSingleLine 3296
-#define wxStyledTextCtrl_ParaDownExtend 3297
-#define wxStyledTextCtrl_ParaUp 3298
-#define wxStyledTextCtrl_ParaUpExtend 3299
-#define wxStyledTextCtrl_PositionBefore 3300
-#define wxStyledTextCtrl_PositionAfter 3301
-#define wxStyledTextCtrl_CopyRange 3302
-#define wxStyledTextCtrl_CopyText 3303
-#define wxStyledTextCtrl_SetSelectionMode 3304
-#define wxStyledTextCtrl_GetSelectionMode 3305
-#define wxStyledTextCtrl_LineDownRectExtend 3306
-#define wxStyledTextCtrl_LineUpRectExtend 3307
-#define wxStyledTextCtrl_CharLeftRectExtend 3308
-#define wxStyledTextCtrl_CharRightRectExtend 3309
-#define wxStyledTextCtrl_HomeRectExtend 3310
-#define wxStyledTextCtrl_VCHomeRectExtend 3311
-#define wxStyledTextCtrl_LineEndRectExtend 3312
-#define wxStyledTextCtrl_PageUpRectExtend 3313
-#define wxStyledTextCtrl_PageDownRectExtend 3314
-#define wxStyledTextCtrl_StutteredPageUp 3315
-#define wxStyledTextCtrl_StutteredPageUpExtend 3316
-#define wxStyledTextCtrl_StutteredPageDown 3317
-#define wxStyledTextCtrl_StutteredPageDownExtend 3318
-#define wxStyledTextCtrl_WordLeftEnd 3319
-#define wxStyledTextCtrl_WordLeftEndExtend 3320
-#define wxStyledTextCtrl_WordRightEnd 3321
-#define wxStyledTextCtrl_WordRightEndExtend 3322
-#define wxStyledTextCtrl_SetWhitespaceChars 3323
-#define wxStyledTextCtrl_SetCharsDefault 3324
-#define wxStyledTextCtrl_AutoCompGetCurrent 3325
-#define wxStyledTextCtrl_Allocate 3326
-#define wxStyledTextCtrl_FindColumn 3327
-#define wxStyledTextCtrl_GetCaretSticky 3328
-#define wxStyledTextCtrl_SetCaretSticky 3329
-#define wxStyledTextCtrl_ToggleCaretSticky 3330
-#define wxStyledTextCtrl_SetPasteConvertEndings 3331
-#define wxStyledTextCtrl_GetPasteConvertEndings 3332
-#define wxStyledTextCtrl_SelectionDuplicate 3333
-#define wxStyledTextCtrl_SetCaretLineBackAlpha 3334
-#define wxStyledTextCtrl_GetCaretLineBackAlpha 3335
-#define wxStyledTextCtrl_StartRecord 3336
-#define wxStyledTextCtrl_StopRecord 3337
-#define wxStyledTextCtrl_SetLexer 3338
-#define wxStyledTextCtrl_GetLexer 3339
-#define wxStyledTextCtrl_Colourise 3340
-#define wxStyledTextCtrl_SetProperty 3341
-#define wxStyledTextCtrl_SetKeyWords 3342
-#define wxStyledTextCtrl_SetLexerLanguage 3343
-#define wxStyledTextCtrl_GetProperty 3344
-#define wxStyledTextCtrl_GetStyleBitsNeeded 3345
-#define wxStyledTextCtrl_GetCurrentLine 3346
-#define wxStyledTextCtrl_StyleSetSpec 3347
-#define wxStyledTextCtrl_StyleSetFont 3348
-#define wxStyledTextCtrl_StyleSetFontAttr 3349
-#define wxStyledTextCtrl_StyleSetCharacterSet 3350
-#define wxStyledTextCtrl_StyleSetFontEncoding 3351
-#define wxStyledTextCtrl_CmdKeyExecute 3352
-#define wxStyledTextCtrl_SetMargins 3353
-#define wxStyledTextCtrl_GetSelection 3354
-#define wxStyledTextCtrl_PointFromPosition 3355
-#define wxStyledTextCtrl_ScrollToLine 3356
-#define wxStyledTextCtrl_ScrollToColumn 3357
-#define wxStyledTextCtrl_SendMsg 3358
-#define wxStyledTextCtrl_SetVScrollBar 3359
-#define wxStyledTextCtrl_SetHScrollBar 3360
-#define wxStyledTextCtrl_GetLastKeydownProcessed 3361
-#define wxStyledTextCtrl_SetLastKeydownProcessed 3362
-#define wxStyledTextCtrl_SaveFile 3363
-#define wxStyledTextCtrl_LoadFile 3364
-#define wxStyledTextCtrl_DoDragOver 3365
-#define wxStyledTextCtrl_DoDropText 3366
-#define wxStyledTextCtrl_GetUseAntiAliasing 3367
-#define wxStyledTextCtrl_AddTextRaw 3368
-#define wxStyledTextCtrl_InsertTextRaw 3369
-#define wxStyledTextCtrl_GetCurLineRaw 3370
-#define wxStyledTextCtrl_GetLineRaw 3371
-#define wxStyledTextCtrl_GetSelectedTextRaw 3372
-#define wxStyledTextCtrl_GetTextRangeRaw 3373
-#define wxStyledTextCtrl_SetTextRaw 3374
-#define wxStyledTextCtrl_GetTextRaw 3375
-#define wxStyledTextCtrl_AppendTextRaw 3376
-#define wxArtProvider_GetBitmap 3377
-#define wxArtProvider_GetIcon 3378
-#define wxTreeEvent_GetKeyCode 3379
-#define wxTreeEvent_GetItem 3380
-#define wxTreeEvent_GetKeyEvent 3381
-#define wxTreeEvent_GetLabel 3382
-#define wxTreeEvent_GetOldItem 3383
-#define wxTreeEvent_GetPoint 3384
-#define wxTreeEvent_IsEditCancelled 3385
-#define wxTreeEvent_SetToolTip 3386
-#define wxNotebookEvent_GetOldSelection 3387
-#define wxNotebookEvent_GetSelection 3388
-#define wxNotebookEvent_SetOldSelection 3389
-#define wxNotebookEvent_SetSelection 3390
-#define wxFileDataObject_new 3391
-#define wxFileDataObject_AddFile 3392
-#define wxFileDataObject_GetFilenames 3393
-#define wxFileDataObject_destroy 3394
-#define wxTextDataObject_new 3395
-#define wxTextDataObject_GetTextLength 3396
-#define wxTextDataObject_GetText 3397
-#define wxTextDataObject_SetText 3398
-#define wxTextDataObject_destroy 3399
-#define wxBitmapDataObject_new_1_1 3400
-#define wxBitmapDataObject_new_1_0 3401
-#define wxBitmapDataObject_GetBitmap 3402
-#define wxBitmapDataObject_SetBitmap 3403
-#define wxBitmapDataObject_destroy 3404
-#define wxClipboard_new 3406
-#define wxClipboard_destruct 3407
-#define wxClipboard_AddData 3408
-#define wxClipboard_Clear 3409
-#define wxClipboard_Close 3410
-#define wxClipboard_Flush 3411
-#define wxClipboard_GetData 3412
-#define wxClipboard_IsOpened 3413
-#define wxClipboard_Open 3414
-#define wxClipboard_SetData 3415
-#define wxClipboard_UsePrimarySelection 3417
-#define wxClipboard_IsSupported 3418
-#define wxClipboard_Get 3419
-#define wxSpinEvent_GetPosition 3420
-#define wxSpinEvent_SetPosition 3421
-#define wxSplitterWindow_new_0 3422
-#define wxSplitterWindow_new_2 3423
-#define wxSplitterWindow_destruct 3424
-#define wxSplitterWindow_Create 3425
-#define wxSplitterWindow_GetMinimumPaneSize 3426
-#define wxSplitterWindow_GetSashGravity 3427
-#define wxSplitterWindow_GetSashPosition 3428
-#define wxSplitterWindow_GetSplitMode 3429
-#define wxSplitterWindow_GetWindow1 3430
-#define wxSplitterWindow_GetWindow2 3431
-#define wxSplitterWindow_Initialize 3432
-#define wxSplitterWindow_IsSplit 3433
-#define wxSplitterWindow_ReplaceWindow 3434
-#define wxSplitterWindow_SetSashGravity 3435
-#define wxSplitterWindow_SetSashPosition 3436
-#define wxSplitterWindow_SetSashSize 3437
-#define wxSplitterWindow_SetMinimumPaneSize 3438
-#define wxSplitterWindow_SetSplitMode 3439
-#define wxSplitterWindow_SplitHorizontally 3440
-#define wxSplitterWindow_SplitVertically 3441
-#define wxSplitterWindow_Unsplit 3442
-#define wxSplitterWindow_UpdateSize 3443
-#define wxSplitterEvent_GetSashPosition 3444
-#define wxSplitterEvent_GetX 3445
-#define wxSplitterEvent_GetY 3446
-#define wxSplitterEvent_GetWindowBeingRemoved 3447
-#define wxSplitterEvent_SetSashPosition 3448
-#define wxHtmlWindow_new_0 3449
-#define wxHtmlWindow_new_2 3450
-#define wxHtmlWindow_AppendToPage 3451
-#define wxHtmlWindow_GetOpenedAnchor 3452
-#define wxHtmlWindow_GetOpenedPage 3453
-#define wxHtmlWindow_GetOpenedPageTitle 3454
-#define wxHtmlWindow_GetRelatedFrame 3455
-#define wxHtmlWindow_HistoryBack 3456
-#define wxHtmlWindow_HistoryCanBack 3457
-#define wxHtmlWindow_HistoryCanForward 3458
-#define wxHtmlWindow_HistoryClear 3459
-#define wxHtmlWindow_HistoryForward 3460
-#define wxHtmlWindow_LoadFile 3461
-#define wxHtmlWindow_LoadPage 3462
-#define wxHtmlWindow_SelectAll 3463
-#define wxHtmlWindow_SelectionToText 3464
-#define wxHtmlWindow_SelectLine 3465
-#define wxHtmlWindow_SelectWord 3466
-#define wxHtmlWindow_SetBorders 3467
-#define wxHtmlWindow_SetFonts 3468
-#define wxHtmlWindow_SetPage 3469
-#define wxHtmlWindow_SetRelatedFrame 3470
-#define wxHtmlWindow_SetRelatedStatusBar 3471
-#define wxHtmlWindow_ToText 3472
-#define wxHtmlWindow_destroy 3473
-#define wxHtmlLinkEvent_GetLinkInfo 3474
-#define wxAuiNotebookEvent_SetSelection 3475
-#define wxAuiNotebookEvent_GetSelection 3476
-#define wxAuiNotebookEvent_SetOldSelection 3477
-#define wxAuiNotebookEvent_GetOldSelection 3478
-#define wxAuiNotebookEvent_SetDragSource 3479
-#define wxAuiNotebookEvent_GetDragSource 3480
-#define wxAuiManagerEvent_SetManager 3481
-#define wxAuiManagerEvent_GetManager 3482
-#define wxAuiManagerEvent_SetPane 3483
-#define wxAuiManagerEvent_GetPane 3484
-#define wxAuiManagerEvent_SetButton 3485
-#define wxAuiManagerEvent_GetButton 3486
-#define wxAuiManagerEvent_SetDC 3487
-#define wxAuiManagerEvent_GetDC 3488
-#define wxAuiManagerEvent_Veto 3489
-#define wxAuiManagerEvent_GetVeto 3490
-#define wxAuiManagerEvent_SetCanVeto 3491
-#define wxAuiManagerEvent_CanVeto 3492
-#define wxLogNull_new 3493
-#define wxLogNull_destroy 3494
+#define wxTreeCtrl_EditLabel 2010
+#define wxTreeCtrl_EnsureVisible 2011
+#define wxTreeCtrl_Expand 2012
+#define wxTreeCtrl_GetBoundingRect 2013
+#define wxTreeCtrl_GetChildrenCount 2015
+#define wxTreeCtrl_GetCount 2016
+#define wxTreeCtrl_GetEditControl 2017
+#define wxTreeCtrl_GetFirstChild 2018
+#define wxTreeCtrl_GetNextChild 2019
+#define wxTreeCtrl_GetFirstVisibleItem 2020
+#define wxTreeCtrl_GetImageList 2021
+#define wxTreeCtrl_GetIndent 2022
+#define wxTreeCtrl_GetItemBackgroundColour 2023
+#define wxTreeCtrl_GetItemData 2024
+#define wxTreeCtrl_GetItemFont 2025
+#define wxTreeCtrl_GetItemImage_1 2026
+#define wxTreeCtrl_GetItemImage_2 2027
+#define wxTreeCtrl_GetItemText 2028
+#define wxTreeCtrl_GetItemTextColour 2029
+#define wxTreeCtrl_GetLastChild 2030
+#define wxTreeCtrl_GetNextSibling 2031
+#define wxTreeCtrl_GetNextVisible 2032
+#define wxTreeCtrl_GetItemParent 2033
+#define wxTreeCtrl_GetPrevSibling 2034
+#define wxTreeCtrl_GetPrevVisible 2035
+#define wxTreeCtrl_GetRootItem 2036
+#define wxTreeCtrl_GetSelection 2037
+#define wxTreeCtrl_GetSelections 2038
+#define wxTreeCtrl_GetStateImageList 2039
+#define wxTreeCtrl_HitTest 2040
+#define wxTreeCtrl_InsertItem 2042
+#define wxTreeCtrl_IsBold 2043
+#define wxTreeCtrl_IsExpanded 2044
+#define wxTreeCtrl_IsSelected 2045
+#define wxTreeCtrl_IsVisible 2046
+#define wxTreeCtrl_ItemHasChildren 2047
+#define wxTreeCtrl_PrependItem 2048
+#define wxTreeCtrl_ScrollTo 2049
+#define wxTreeCtrl_SelectItem_1 2050
+#define wxTreeCtrl_SelectItem_2 2051
+#define wxTreeCtrl_SetIndent 2052
+#define wxTreeCtrl_SetImageList 2053
+#define wxTreeCtrl_SetItemBackgroundColour 2054
+#define wxTreeCtrl_SetItemBold 2055
+#define wxTreeCtrl_SetItemData 2056
+#define wxTreeCtrl_SetItemDropHighlight 2057
+#define wxTreeCtrl_SetItemFont 2058
+#define wxTreeCtrl_SetItemHasChildren 2059
+#define wxTreeCtrl_SetItemImage_2 2060
+#define wxTreeCtrl_SetItemImage_3 2061
+#define wxTreeCtrl_SetItemText 2062
+#define wxTreeCtrl_SetItemTextColour 2063
+#define wxTreeCtrl_SetStateImageList 2064
+#define wxTreeCtrl_SetWindowStyle 2065
+#define wxTreeCtrl_SortChildren 2066
+#define wxTreeCtrl_Toggle 2067
+#define wxTreeCtrl_ToggleItemSelection 2068
+#define wxTreeCtrl_Unselect 2069
+#define wxTreeCtrl_UnselectAll 2070
+#define wxTreeCtrl_UnselectItem 2071
+#define wxScrollBar_new_0 2072
+#define wxScrollBar_new_3 2073
+#define wxScrollBar_destruct 2074
+#define wxScrollBar_Create 2075
+#define wxScrollBar_GetRange 2076
+#define wxScrollBar_GetPageSize 2077
+#define wxScrollBar_GetThumbPosition 2078
+#define wxScrollBar_GetThumbSize 2079
+#define wxScrollBar_SetThumbPosition 2080
+#define wxScrollBar_SetScrollbar 2081
+#define wxSpinButton_new_2 2083
+#define wxSpinButton_new_0 2084
+#define wxSpinButton_Create 2085
+#define wxSpinButton_GetMax 2086
+#define wxSpinButton_GetMin 2087
+#define wxSpinButton_GetValue 2088
+#define wxSpinButton_SetRange 2089
+#define wxSpinButton_SetValue 2090
+#define wxSpinButton_destroy 2091
+#define wxSpinCtrl_new_0 2092
+#define wxSpinCtrl_new_2 2093
+#define wxSpinCtrl_Create 2095
+#define wxSpinCtrl_SetValue_1_1 2098
+#define wxSpinCtrl_SetValue_1_0 2099
+#define wxSpinCtrl_GetValue 2101
+#define wxSpinCtrl_SetRange 2103
+#define wxSpinCtrl_SetSelection 2104
+#define wxSpinCtrl_GetMin 2106
+#define wxSpinCtrl_GetMax 2108
+#define wxSpinCtrl_destroy 2109
+#define wxStaticText_new_0 2110
+#define wxStaticText_new_4 2111
+#define wxStaticText_Create 2112
+#define wxStaticText_GetLabel 2113
+#define wxStaticText_SetLabel 2114
+#define wxStaticText_Wrap 2115
+#define wxStaticText_destroy 2116
+#define wxStaticBitmap_new_0 2117
+#define wxStaticBitmap_new_4 2118
+#define wxStaticBitmap_Create 2119
+#define wxStaticBitmap_GetBitmap 2120
+#define wxStaticBitmap_SetBitmap 2121
+#define wxStaticBitmap_destroy 2122
+#define wxRadioBox_new 2123
+#define wxRadioBox_destruct 2125
+#define wxRadioBox_Create 2126
+#define wxRadioBox_Enable_2 2127
+#define wxRadioBox_Enable_1 2128
+#define wxRadioBox_GetSelection 2129
+#define wxRadioBox_GetString 2130
+#define wxRadioBox_SetSelection 2131
+#define wxRadioBox_Show_2 2132
+#define wxRadioBox_Show_1 2133
+#define wxRadioBox_GetColumnCount 2134
+#define wxRadioBox_GetItemHelpText 2135
+#define wxRadioBox_GetItemToolTip 2136
+#define wxRadioBox_GetItemFromPoint 2138
+#define wxRadioBox_GetRowCount 2139
+#define wxRadioBox_IsItemEnabled 2140
+#define wxRadioBox_IsItemShown 2141
+#define wxRadioBox_SetItemHelpText 2142
+#define wxRadioBox_SetItemToolTip 2143
+#define wxRadioButton_new_0 2144
+#define wxRadioButton_new_4 2145
+#define wxRadioButton_Create 2146
+#define wxRadioButton_GetValue 2147
+#define wxRadioButton_SetValue 2148
+#define wxRadioButton_destroy 2149
+#define wxSlider_new_6 2151
+#define wxSlider_new_0 2152
+#define wxSlider_Create 2153
+#define wxSlider_GetLineSize 2154
+#define wxSlider_GetMax 2155
+#define wxSlider_GetMin 2156
+#define wxSlider_GetPageSize 2157
+#define wxSlider_GetThumbLength 2158
+#define wxSlider_GetValue 2159
+#define wxSlider_SetLineSize 2160
+#define wxSlider_SetPageSize 2161
+#define wxSlider_SetRange 2162
+#define wxSlider_SetThumbLength 2163
+#define wxSlider_SetValue 2164
+#define wxSlider_destroy 2165
+#define wxDialog_new_4 2167
+#define wxDialog_new_0 2168
+#define wxDialog_destruct 2170
+#define wxDialog_Create 2171
+#define wxDialog_CreateButtonSizer 2172
+#define wxDialog_CreateStdDialogButtonSizer 2173
+#define wxDialog_EndModal 2174
+#define wxDialog_GetAffirmativeId 2175
+#define wxDialog_GetReturnCode 2176
+#define wxDialog_IsModal 2177
+#define wxDialog_SetAffirmativeId 2178
+#define wxDialog_SetReturnCode 2179
+#define wxDialog_Show 2180
+#define wxDialog_ShowModal 2181
+#define wxColourDialog_new_0 2182
+#define wxColourDialog_new_2 2183
+#define wxColourDialog_destruct 2184
+#define wxColourDialog_Create 2185
+#define wxColourDialog_GetColourData 2186
+#define wxColourData_new_0 2187
+#define wxColourData_new_1 2188
+#define wxColourData_destruct 2189
+#define wxColourData_GetChooseFull 2190
+#define wxColourData_GetColour 2191
+#define wxColourData_GetCustomColour 2193
+#define wxColourData_SetChooseFull 2194
+#define wxColourData_SetColour 2195
+#define wxColourData_SetCustomColour 2196
+#define wxPalette_new_0 2197
+#define wxPalette_new_4 2198
+#define wxPalette_destruct 2200
+#define wxPalette_Create 2201
+#define wxPalette_GetColoursCount 2202
+#define wxPalette_GetPixel 2203
+#define wxPalette_GetRGB 2204
+#define wxPalette_IsOk 2205
+#define wxDirDialog_new 2209
+#define wxDirDialog_destruct 2210
+#define wxDirDialog_GetPath 2211
+#define wxDirDialog_GetMessage 2212
+#define wxDirDialog_SetMessage 2213
+#define wxDirDialog_SetPath 2214
+#define wxFileDialog_new 2218
+#define wxFileDialog_destruct 2219
+#define wxFileDialog_GetDirectory 2220
+#define wxFileDialog_GetFilename 2221
+#define wxFileDialog_GetFilenames 2222
+#define wxFileDialog_GetFilterIndex 2223
+#define wxFileDialog_GetMessage 2224
+#define wxFileDialog_GetPath 2225
+#define wxFileDialog_GetPaths 2226
+#define wxFileDialog_GetWildcard 2227
+#define wxFileDialog_SetDirectory 2228
+#define wxFileDialog_SetFilename 2229
+#define wxFileDialog_SetFilterIndex 2230
+#define wxFileDialog_SetMessage 2231
+#define wxFileDialog_SetPath 2232
+#define wxFileDialog_SetWildcard 2233
+#define wxPickerBase_SetInternalMargin 2234
+#define wxPickerBase_GetInternalMargin 2235
+#define wxPickerBase_SetTextCtrlProportion 2236
+#define wxPickerBase_SetPickerCtrlProportion 2237
+#define wxPickerBase_GetTextCtrlProportion 2238
+#define wxPickerBase_GetPickerCtrlProportion 2239
+#define wxPickerBase_HasTextCtrl 2240
+#define wxPickerBase_GetTextCtrl 2241
+#define wxPickerBase_IsTextCtrlGrowable 2242
+#define wxPickerBase_SetPickerCtrlGrowable 2243
+#define wxPickerBase_SetTextCtrlGrowable 2244
+#define wxPickerBase_IsPickerCtrlGrowable 2245
+#define wxFilePickerCtrl_new_0 2246
+#define wxFilePickerCtrl_new_3 2247
+#define wxFilePickerCtrl_Create 2248
+#define wxFilePickerCtrl_GetPath 2249
+#define wxFilePickerCtrl_SetPath 2250
+#define wxFilePickerCtrl_destroy 2251
+#define wxDirPickerCtrl_new_0 2252
+#define wxDirPickerCtrl_new_3 2253
+#define wxDirPickerCtrl_Create 2254
+#define wxDirPickerCtrl_GetPath 2255
+#define wxDirPickerCtrl_SetPath 2256
+#define wxDirPickerCtrl_destroy 2257
+#define wxColourPickerCtrl_new_0 2258
+#define wxColourPickerCtrl_new_3 2259
+#define wxColourPickerCtrl_Create 2260
+#define wxColourPickerCtrl_GetColour 2261
+#define wxColourPickerCtrl_SetColour_1_1 2262
+#define wxColourPickerCtrl_SetColour_1_0 2263
+#define wxColourPickerCtrl_destroy 2264
+#define wxDatePickerCtrl_new_0 2265
+#define wxDatePickerCtrl_new_3 2266
+#define wxDatePickerCtrl_GetRange 2267
+#define wxDatePickerCtrl_GetValue 2268
+#define wxDatePickerCtrl_SetRange 2269
+#define wxDatePickerCtrl_SetValue 2270
+#define wxDatePickerCtrl_destroy 2271
+#define wxFontPickerCtrl_new_0 2272
+#define wxFontPickerCtrl_new_3 2273
+#define wxFontPickerCtrl_Create 2274
+#define wxFontPickerCtrl_GetSelectedFont 2275
+#define wxFontPickerCtrl_SetSelectedFont 2276
+#define wxFontPickerCtrl_GetMaxPointSize 2277
+#define wxFontPickerCtrl_SetMaxPointSize 2278
+#define wxFontPickerCtrl_destroy 2279
+#define wxFindReplaceDialog_new_0 2282
+#define wxFindReplaceDialog_new_4 2283
+#define wxFindReplaceDialog_destruct 2284
+#define wxFindReplaceDialog_Create 2285
+#define wxFindReplaceDialog_GetData 2286
+#define wxFindReplaceData_new_0 2287
+#define wxFindReplaceData_new_1 2288
+#define wxFindReplaceData_GetFindString 2289
+#define wxFindReplaceData_GetReplaceString 2290
+#define wxFindReplaceData_GetFlags 2291
+#define wxFindReplaceData_SetFlags 2292
+#define wxFindReplaceData_SetFindString 2293
+#define wxFindReplaceData_SetReplaceString 2294
+#define wxFindReplaceData_destroy 2295
+#define wxMultiChoiceDialog_new_0 2296
+#define wxMultiChoiceDialog_new_5 2298
+#define wxMultiChoiceDialog_GetSelections 2299
+#define wxMultiChoiceDialog_SetSelections 2300
+#define wxMultiChoiceDialog_destroy 2301
+#define wxSingleChoiceDialog_new_0 2302
+#define wxSingleChoiceDialog_new_5 2304
+#define wxSingleChoiceDialog_GetSelection 2305
+#define wxSingleChoiceDialog_GetStringSelection 2306
+#define wxSingleChoiceDialog_SetSelection 2307
+#define wxSingleChoiceDialog_destroy 2308
+#define wxTextEntryDialog_new 2309
+#define wxTextEntryDialog_GetValue 2310
+#define wxTextEntryDialog_SetValue 2311
+#define wxTextEntryDialog_destroy 2312
+#define wxPasswordEntryDialog_new 2313
+#define wxPasswordEntryDialog_destroy 2314
+#define wxFontData_new_0 2315
+#define wxFontData_new_1 2316
+#define wxFontData_destruct 2317
+#define wxFontData_EnableEffects 2318
+#define wxFontData_GetAllowSymbols 2319
+#define wxFontData_GetColour 2320
+#define wxFontData_GetChosenFont 2321
+#define wxFontData_GetEnableEffects 2322
+#define wxFontData_GetInitialFont 2323
+#define wxFontData_GetShowHelp 2324
+#define wxFontData_SetAllowSymbols 2325
+#define wxFontData_SetChosenFont 2326
+#define wxFontData_SetColour 2327
+#define wxFontData_SetInitialFont 2328
+#define wxFontData_SetRange 2329
+#define wxFontData_SetShowHelp 2330
+#define wxFontDialog_new_0 2334
+#define wxFontDialog_new_2 2336
+#define wxFontDialog_Create 2338
+#define wxFontDialog_GetFontData 2339
+#define wxFontDialog_destroy 2341
+#define wxProgressDialog_new 2342
+#define wxProgressDialog_destruct 2343
+#define wxProgressDialog_Resume 2344
+#define wxProgressDialog_Update_2 2345
+#define wxProgressDialog_Update_0 2346
+#define wxMessageDialog_new 2347
+#define wxMessageDialog_destruct 2348
+#define wxPageSetupDialog_new 2349
+#define wxPageSetupDialog_destruct 2350
+#define wxPageSetupDialog_GetPageSetupData 2351
+#define wxPageSetupDialog_ShowModal 2352
+#define wxPageSetupDialogData_new_0 2353
+#define wxPageSetupDialogData_new_1_0 2354
+#define wxPageSetupDialogData_new_1_1 2355
+#define wxPageSetupDialogData_destruct 2356
+#define wxPageSetupDialogData_EnableHelp 2357
+#define wxPageSetupDialogData_EnableMargins 2358
+#define wxPageSetupDialogData_EnableOrientation 2359
+#define wxPageSetupDialogData_EnablePaper 2360
+#define wxPageSetupDialogData_EnablePrinter 2361
+#define wxPageSetupDialogData_GetDefaultMinMargins 2362
+#define wxPageSetupDialogData_GetEnableMargins 2363
+#define wxPageSetupDialogData_GetEnableOrientation 2364
+#define wxPageSetupDialogData_GetEnablePaper 2365
+#define wxPageSetupDialogData_GetEnablePrinter 2366
+#define wxPageSetupDialogData_GetEnableHelp 2367
+#define wxPageSetupDialogData_GetDefaultInfo 2368
+#define wxPageSetupDialogData_GetMarginTopLeft 2369
+#define wxPageSetupDialogData_GetMarginBottomRight 2370
+#define wxPageSetupDialogData_GetMinMarginTopLeft 2371
+#define wxPageSetupDialogData_GetMinMarginBottomRight 2372
+#define wxPageSetupDialogData_GetPaperId 2373
+#define wxPageSetupDialogData_GetPaperSize 2374
+#define wxPageSetupDialogData_GetPrintData 2376
+#define wxPageSetupDialogData_IsOk 2377
+#define wxPageSetupDialogData_SetDefaultInfo 2378
+#define wxPageSetupDialogData_SetDefaultMinMargins 2379
+#define wxPageSetupDialogData_SetMarginTopLeft 2380
+#define wxPageSetupDialogData_SetMarginBottomRight 2381
+#define wxPageSetupDialogData_SetMinMarginTopLeft 2382
+#define wxPageSetupDialogData_SetMinMarginBottomRight 2383
+#define wxPageSetupDialogData_SetPaperId 2384
+#define wxPageSetupDialogData_SetPaperSize_1_1 2385
+#define wxPageSetupDialogData_SetPaperSize_1_0 2386
+#define wxPageSetupDialogData_SetPrintData 2387
+#define wxPrintDialog_new_2_0 2388
+#define wxPrintDialog_new_2_1 2389
+#define wxPrintDialog_destruct 2390
+#define wxPrintDialog_GetPrintDialogData 2391
+#define wxPrintDialog_GetPrintDC 2392
+#define wxPrintDialogData_new_0 2393
+#define wxPrintDialogData_new_1_1 2394
+#define wxPrintDialogData_new_1_0 2395
+#define wxPrintDialogData_destruct 2396
+#define wxPrintDialogData_EnableHelp 2397
+#define wxPrintDialogData_EnablePageNumbers 2398
+#define wxPrintDialogData_EnablePrintToFile 2399
+#define wxPrintDialogData_EnableSelection 2400
+#define wxPrintDialogData_GetAllPages 2401
+#define wxPrintDialogData_GetCollate 2402
+#define wxPrintDialogData_GetFromPage 2403
+#define wxPrintDialogData_GetMaxPage 2404
+#define wxPrintDialogData_GetMinPage 2405
+#define wxPrintDialogData_GetNoCopies 2406
+#define wxPrintDialogData_GetPrintData 2407
+#define wxPrintDialogData_GetPrintToFile 2408
+#define wxPrintDialogData_GetSelection 2409
+#define wxPrintDialogData_GetToPage 2410
+#define wxPrintDialogData_IsOk 2411
+#define wxPrintDialogData_SetCollate 2412
+#define wxPrintDialogData_SetFromPage 2413
+#define wxPrintDialogData_SetMaxPage 2414
+#define wxPrintDialogData_SetMinPage 2415
+#define wxPrintDialogData_SetNoCopies 2416
+#define wxPrintDialogData_SetPrintData 2417
+#define wxPrintDialogData_SetPrintToFile 2418
+#define wxPrintDialogData_SetSelection 2419
+#define wxPrintDialogData_SetToPage 2420
+#define wxPrintData_new_0 2421
+#define wxPrintData_new_1 2422
+#define wxPrintData_destruct 2423
+#define wxPrintData_GetCollate 2424
+#define wxPrintData_GetBin 2425
+#define wxPrintData_GetColour 2426
+#define wxPrintData_GetDuplex 2427
+#define wxPrintData_GetNoCopies 2428
+#define wxPrintData_GetOrientation 2429
+#define wxPrintData_GetPaperId 2430
+#define wxPrintData_GetPrinterName 2431
+#define wxPrintData_GetQuality 2432
+#define wxPrintData_IsOk 2433
+#define wxPrintData_SetBin 2434
+#define wxPrintData_SetCollate 2435
+#define wxPrintData_SetColour 2436
+#define wxPrintData_SetDuplex 2437
+#define wxPrintData_SetNoCopies 2438
+#define wxPrintData_SetOrientation 2439
+#define wxPrintData_SetPaperId 2440
+#define wxPrintData_SetPrinterName 2441
+#define wxPrintData_SetQuality 2442
+#define wxPrintPreview_new_2 2445
+#define wxPrintPreview_new_3 2446
+#define wxPrintPreview_destruct 2448
+#define wxPrintPreview_GetCanvas 2449
+#define wxPrintPreview_GetCurrentPage 2450
+#define wxPrintPreview_GetFrame 2451
+#define wxPrintPreview_GetMaxPage 2452
+#define wxPrintPreview_GetMinPage 2453
+#define wxPrintPreview_GetPrintout 2454
+#define wxPrintPreview_GetPrintoutForPrinting 2455
+#define wxPrintPreview_IsOk 2456
+#define wxPrintPreview_PaintPage 2457
+#define wxPrintPreview_Print 2458
+#define wxPrintPreview_RenderPage 2459
+#define wxPrintPreview_SetCanvas 2460
+#define wxPrintPreview_SetCurrentPage 2461
+#define wxPrintPreview_SetFrame 2462
+#define wxPrintPreview_SetPrintout 2463
+#define wxPrintPreview_SetZoom 2464
+#define wxPreviewFrame_new 2465
+#define wxPreviewFrame_destruct 2466
+#define wxPreviewFrame_CreateControlBar 2467
+#define wxPreviewFrame_CreateCanvas 2468
+#define wxPreviewFrame_Initialize 2469
+#define wxPreviewFrame_OnCloseWindow 2470
+#define wxPreviewControlBar_new 2471
+#define wxPreviewControlBar_destruct 2472
+#define wxPreviewControlBar_CreateButtons 2473
+#define wxPreviewControlBar_GetPrintPreview 2474
+#define wxPreviewControlBar_GetZoomControl 2475
+#define wxPreviewControlBar_SetZoomControl 2476
+#define wxPrinter_new 2478
+#define wxPrinter_CreateAbortWindow 2479
+#define wxPrinter_GetAbort 2480
+#define wxPrinter_GetLastError 2481
+#define wxPrinter_GetPrintDialogData 2482
+#define wxPrinter_Print 2483
+#define wxPrinter_PrintDialog 2484
+#define wxPrinter_ReportError 2485
+#define wxPrinter_Setup 2486
+#define wxPrinter_destroy 2487
+#define wxXmlResource_new_1 2488
+#define wxXmlResource_new_2 2489
+#define wxXmlResource_destruct 2490
+#define wxXmlResource_AttachUnknownControl 2491
+#define wxXmlResource_ClearHandlers 2492
+#define wxXmlResource_CompareVersion 2493
+#define wxXmlResource_Get 2494
+#define wxXmlResource_GetFlags 2495
+#define wxXmlResource_GetVersion 2496
+#define wxXmlResource_GetXRCID 2497
+#define wxXmlResource_InitAllHandlers 2498
+#define wxXmlResource_Load 2499
+#define wxXmlResource_LoadBitmap 2500
+#define wxXmlResource_LoadDialog_2 2501
+#define wxXmlResource_LoadDialog_3 2502
+#define wxXmlResource_LoadFrame_2 2503
+#define wxXmlResource_LoadFrame_3 2504
+#define wxXmlResource_LoadIcon 2505
+#define wxXmlResource_LoadMenu 2506
+#define wxXmlResource_LoadMenuBar_2 2507
+#define wxXmlResource_LoadMenuBar_1 2508
+#define wxXmlResource_LoadPanel_2 2509
+#define wxXmlResource_LoadPanel_3 2510
+#define wxXmlResource_LoadToolBar 2511
+#define wxXmlResource_Set 2512
+#define wxXmlResource_SetFlags 2513
+#define wxXmlResource_Unload 2514
+#define wxXmlResource_xrcctrl 2515
+#define wxHtmlEasyPrinting_new 2516
+#define wxHtmlEasyPrinting_destruct 2517
+#define wxHtmlEasyPrinting_GetPrintData 2518
+#define wxHtmlEasyPrinting_GetPageSetupData 2519
+#define wxHtmlEasyPrinting_PreviewFile 2520
+#define wxHtmlEasyPrinting_PreviewText 2521
+#define wxHtmlEasyPrinting_PrintFile 2522
+#define wxHtmlEasyPrinting_PrintText 2523
+#define wxHtmlEasyPrinting_PageSetup 2524
+#define wxHtmlEasyPrinting_SetFonts 2525
+#define wxHtmlEasyPrinting_SetHeader 2526
+#define wxHtmlEasyPrinting_SetFooter 2527
+#define wxGLCanvas_new_2 2529
+#define wxGLCanvas_new_3_1 2530
+#define wxGLCanvas_new_3_0 2531
+#define wxGLCanvas_GetContext 2532
+#define wxGLCanvas_SetCurrent 2534
+#define wxGLCanvas_SwapBuffers 2535
+#define wxGLCanvas_destroy 2536
+#define wxAuiManager_new 2537
+#define wxAuiManager_destruct 2538
+#define wxAuiManager_AddPane_2_1 2539
+#define wxAuiManager_AddPane_3 2540
+#define wxAuiManager_AddPane_2_0 2541
+#define wxAuiManager_DetachPane 2542
+#define wxAuiManager_GetAllPanes 2543
+#define wxAuiManager_GetArtProvider 2544
+#define wxAuiManager_GetDockSizeConstraint 2545
+#define wxAuiManager_GetFlags 2546
+#define wxAuiManager_GetManagedWindow 2547
+#define wxAuiManager_GetManager 2548
+#define wxAuiManager_GetPane_1_1 2549
+#define wxAuiManager_GetPane_1_0 2550
+#define wxAuiManager_HideHint 2551
+#define wxAuiManager_InsertPane 2552
+#define wxAuiManager_LoadPaneInfo 2553
+#define wxAuiManager_LoadPerspective 2554
+#define wxAuiManager_SavePaneInfo 2555
+#define wxAuiManager_SavePerspective 2556
+#define wxAuiManager_SetArtProvider 2557
+#define wxAuiManager_SetDockSizeConstraint 2558
+#define wxAuiManager_SetFlags 2559
+#define wxAuiManager_SetManagedWindow 2560
+#define wxAuiManager_ShowHint 2561
+#define wxAuiManager_UnInit 2562
+#define wxAuiManager_Update 2563
+#define wxAuiPaneInfo_new_0 2564
+#define wxAuiPaneInfo_new_1 2565
+#define wxAuiPaneInfo_destruct 2566
+#define wxAuiPaneInfo_BestSize_1 2567
+#define wxAuiPaneInfo_BestSize_2 2568
+#define wxAuiPaneInfo_Bottom 2569
+#define wxAuiPaneInfo_BottomDockable 2570
+#define wxAuiPaneInfo_Caption 2571
+#define wxAuiPaneInfo_CaptionVisible 2572
+#define wxAuiPaneInfo_Centre 2573
+#define wxAuiPaneInfo_CentrePane 2574
+#define wxAuiPaneInfo_CloseButton 2575
+#define wxAuiPaneInfo_DefaultPane 2576
+#define wxAuiPaneInfo_DestroyOnClose 2577
+#define wxAuiPaneInfo_Direction 2578
+#define wxAuiPaneInfo_Dock 2579
+#define wxAuiPaneInfo_Dockable 2580
+#define wxAuiPaneInfo_Fixed 2581
+#define wxAuiPaneInfo_Float 2582
+#define wxAuiPaneInfo_Floatable 2583
+#define wxAuiPaneInfo_FloatingPosition_1 2584
+#define wxAuiPaneInfo_FloatingPosition_2 2585
+#define wxAuiPaneInfo_FloatingSize_1 2586
+#define wxAuiPaneInfo_FloatingSize_2 2587
+#define wxAuiPaneInfo_Gripper 2588
+#define wxAuiPaneInfo_GripperTop 2589
+#define wxAuiPaneInfo_HasBorder 2590
+#define wxAuiPaneInfo_HasCaption 2591
+#define wxAuiPaneInfo_HasCloseButton 2592
+#define wxAuiPaneInfo_HasFlag 2593
+#define wxAuiPaneInfo_HasGripper 2594
+#define wxAuiPaneInfo_HasGripperTop 2595
+#define wxAuiPaneInfo_HasMaximizeButton 2596
+#define wxAuiPaneInfo_HasMinimizeButton 2597
+#define wxAuiPaneInfo_HasPinButton 2598
+#define wxAuiPaneInfo_Hide 2599
+#define wxAuiPaneInfo_IsBottomDockable 2600
+#define wxAuiPaneInfo_IsDocked 2601
+#define wxAuiPaneInfo_IsFixed 2602
+#define wxAuiPaneInfo_IsFloatable 2603
+#define wxAuiPaneInfo_IsFloating 2604
+#define wxAuiPaneInfo_IsLeftDockable 2605
+#define wxAuiPaneInfo_IsMovable 2606
+#define wxAuiPaneInfo_IsOk 2607
+#define wxAuiPaneInfo_IsResizable 2608
+#define wxAuiPaneInfo_IsRightDockable 2609
+#define wxAuiPaneInfo_IsShown 2610
+#define wxAuiPaneInfo_IsToolbar 2611
+#define wxAuiPaneInfo_IsTopDockable 2612
+#define wxAuiPaneInfo_Layer 2613
+#define wxAuiPaneInfo_Left 2614
+#define wxAuiPaneInfo_LeftDockable 2615
+#define wxAuiPaneInfo_MaxSize_1 2616
+#define wxAuiPaneInfo_MaxSize_2 2617
+#define wxAuiPaneInfo_MaximizeButton 2618
+#define wxAuiPaneInfo_MinSize_1 2619
+#define wxAuiPaneInfo_MinSize_2 2620
+#define wxAuiPaneInfo_MinimizeButton 2621
+#define wxAuiPaneInfo_Movable 2622
+#define wxAuiPaneInfo_Name 2623
+#define wxAuiPaneInfo_PaneBorder 2624
+#define wxAuiPaneInfo_PinButton 2625
+#define wxAuiPaneInfo_Position 2626
+#define wxAuiPaneInfo_Resizable 2627
+#define wxAuiPaneInfo_Right 2628
+#define wxAuiPaneInfo_RightDockable 2629
+#define wxAuiPaneInfo_Row 2630
+#define wxAuiPaneInfo_SafeSet 2631
+#define wxAuiPaneInfo_SetFlag 2632
+#define wxAuiPaneInfo_Show 2633
+#define wxAuiPaneInfo_ToolbarPane 2634
+#define wxAuiPaneInfo_Top 2635
+#define wxAuiPaneInfo_TopDockable 2636
+#define wxAuiPaneInfo_Window 2637
+#define wxAuiNotebook_new_0 2638
+#define wxAuiNotebook_new_2 2639
+#define wxAuiNotebook_AddPage 2640
+#define wxAuiNotebook_Create 2641
+#define wxAuiNotebook_DeletePage 2642
+#define wxAuiNotebook_GetArtProvider 2643
+#define wxAuiNotebook_GetPage 2644
+#define wxAuiNotebook_GetPageBitmap 2645
+#define wxAuiNotebook_GetPageCount 2646
+#define wxAuiNotebook_GetPageIndex 2647
+#define wxAuiNotebook_GetPageText 2648
+#define wxAuiNotebook_GetSelection 2649
+#define wxAuiNotebook_InsertPage 2650
+#define wxAuiNotebook_RemovePage 2651
+#define wxAuiNotebook_SetArtProvider 2652
+#define wxAuiNotebook_SetFont 2653
+#define wxAuiNotebook_SetPageBitmap 2654
+#define wxAuiNotebook_SetPageText 2655
+#define wxAuiNotebook_SetSelection 2656
+#define wxAuiNotebook_SetTabCtrlHeight 2657
+#define wxAuiNotebook_SetUniformBitmapSize 2658
+#define wxAuiNotebook_destroy 2659
+#define wxMDIParentFrame_new_0 2660
+#define wxMDIParentFrame_new_4 2661
+#define wxMDIParentFrame_destruct 2662
+#define wxMDIParentFrame_ActivateNext 2663
+#define wxMDIParentFrame_ActivatePrevious 2664
+#define wxMDIParentFrame_ArrangeIcons 2665
+#define wxMDIParentFrame_Cascade 2666
+#define wxMDIParentFrame_Create 2667
+#define wxMDIParentFrame_GetActiveChild 2668
+#define wxMDIParentFrame_GetClientWindow 2669
+#define wxMDIParentFrame_Tile 2670
+#define wxMDIChildFrame_new_0 2671
+#define wxMDIChildFrame_new_4 2672
+#define wxMDIChildFrame_destruct 2673
+#define wxMDIChildFrame_Activate 2674
+#define wxMDIChildFrame_Create 2675
+#define wxMDIChildFrame_Maximize 2676
+#define wxMDIChildFrame_Restore 2677
+#define wxMDIClientWindow_new_0 2678
+#define wxMDIClientWindow_new_2 2679
+#define wxMDIClientWindow_destruct 2680
+#define wxMDIClientWindow_CreateClient 2681
+#define wxLayoutAlgorithm_new 2682
+#define wxLayoutAlgorithm_LayoutFrame 2683
+#define wxLayoutAlgorithm_LayoutMDIFrame 2684
+#define wxLayoutAlgorithm_LayoutWindow 2685
+#define wxLayoutAlgorithm_destroy 2686
+#define wxEvent_GetId 2687
+#define wxEvent_GetSkipped 2688
+#define wxEvent_GetTimestamp 2689
+#define wxEvent_IsCommandEvent 2690
+#define wxEvent_ResumePropagation 2691
+#define wxEvent_ShouldPropagate 2692
+#define wxEvent_Skip 2693
+#define wxEvent_StopPropagation 2694
+#define wxCommandEvent_getClientData 2695
+#define wxCommandEvent_GetExtraLong 2696
+#define wxCommandEvent_GetInt 2697
+#define wxCommandEvent_GetSelection 2698
+#define wxCommandEvent_GetString 2699
+#define wxCommandEvent_IsChecked 2700
+#define wxCommandEvent_IsSelection 2701
+#define wxCommandEvent_SetInt 2702
+#define wxCommandEvent_SetString 2703
+#define wxScrollEvent_GetOrientation 2704
+#define wxScrollEvent_GetPosition 2705
+#define wxScrollWinEvent_GetOrientation 2706
+#define wxScrollWinEvent_GetPosition 2707
+#define wxMouseEvent_AltDown 2708
+#define wxMouseEvent_Button 2709
+#define wxMouseEvent_ButtonDClick 2710
+#define wxMouseEvent_ButtonDown 2711
+#define wxMouseEvent_ButtonUp 2712
+#define wxMouseEvent_CmdDown 2713
+#define wxMouseEvent_ControlDown 2714
+#define wxMouseEvent_Dragging 2715
+#define wxMouseEvent_Entering 2716
+#define wxMouseEvent_GetButton 2717
+#define wxMouseEvent_GetPosition 2720
+#define wxMouseEvent_GetLogicalPosition 2721
+#define wxMouseEvent_GetLinesPerAction 2722
+#define wxMouseEvent_GetWheelRotation 2723
+#define wxMouseEvent_GetWheelDelta 2724
+#define wxMouseEvent_GetX 2725
+#define wxMouseEvent_GetY 2726
+#define wxMouseEvent_IsButton 2727
+#define wxMouseEvent_IsPageScroll 2728
+#define wxMouseEvent_Leaving 2729
+#define wxMouseEvent_LeftDClick 2730
+#define wxMouseEvent_LeftDown 2731
+#define wxMouseEvent_LeftIsDown 2732
+#define wxMouseEvent_LeftUp 2733
+#define wxMouseEvent_MetaDown 2734
+#define wxMouseEvent_MiddleDClick 2735
+#define wxMouseEvent_MiddleDown 2736
+#define wxMouseEvent_MiddleIsDown 2737
+#define wxMouseEvent_MiddleUp 2738
+#define wxMouseEvent_Moving 2739
+#define wxMouseEvent_RightDClick 2740
+#define wxMouseEvent_RightDown 2741
+#define wxMouseEvent_RightIsDown 2742
+#define wxMouseEvent_RightUp 2743
+#define wxMouseEvent_ShiftDown 2744
+#define wxSetCursorEvent_GetCursor 2745
+#define wxSetCursorEvent_GetX 2746
+#define wxSetCursorEvent_GetY 2747
+#define wxSetCursorEvent_HasCursor 2748
+#define wxSetCursorEvent_SetCursor 2749
+#define wxKeyEvent_AltDown 2750
+#define wxKeyEvent_CmdDown 2751
+#define wxKeyEvent_ControlDown 2752
+#define wxKeyEvent_GetKeyCode 2753
+#define wxKeyEvent_GetModifiers 2754
+#define wxKeyEvent_GetPosition 2757
+#define wxKeyEvent_GetRawKeyCode 2758
+#define wxKeyEvent_GetRawKeyFlags 2759
+#define wxKeyEvent_GetUnicodeKey 2760
+#define wxKeyEvent_GetX 2761
+#define wxKeyEvent_GetY 2762
+#define wxKeyEvent_HasModifiers 2763
+#define wxKeyEvent_MetaDown 2764
+#define wxKeyEvent_ShiftDown 2765
+#define wxSizeEvent_GetSize 2766
+#define wxMoveEvent_GetPosition 2767
+#define wxEraseEvent_GetDC 2768
+#define wxFocusEvent_GetWindow 2769
+#define wxChildFocusEvent_GetWindow 2770
+#define wxMenuEvent_GetMenu 2771
+#define wxMenuEvent_GetMenuId 2772
+#define wxMenuEvent_IsPopup 2773
+#define wxCloseEvent_CanVeto 2774
+#define wxCloseEvent_GetLoggingOff 2775
+#define wxCloseEvent_SetCanVeto 2776
+#define wxCloseEvent_SetLoggingOff 2777
+#define wxCloseEvent_Veto 2778
+#define wxShowEvent_SetShow 2779
+#define wxShowEvent_GetShow 2780
+#define wxIconizeEvent_Iconized 2781
+#define wxJoystickEvent_ButtonDown 2782
+#define wxJoystickEvent_ButtonIsDown 2783
+#define wxJoystickEvent_ButtonUp 2784
+#define wxJoystickEvent_GetButtonChange 2785
+#define wxJoystickEvent_GetButtonState 2786
+#define wxJoystickEvent_GetJoystick 2787
+#define wxJoystickEvent_GetPosition 2788
+#define wxJoystickEvent_GetZPosition 2789
+#define wxJoystickEvent_IsButton 2790
+#define wxJoystickEvent_IsMove 2791
+#define wxJoystickEvent_IsZMove 2792
+#define wxUpdateUIEvent_CanUpdate 2793
+#define wxUpdateUIEvent_Check 2794
+#define wxUpdateUIEvent_Enable 2795
+#define wxUpdateUIEvent_Show 2796
+#define wxUpdateUIEvent_GetChecked 2797
+#define wxUpdateUIEvent_GetEnabled 2798
+#define wxUpdateUIEvent_GetShown 2799
+#define wxUpdateUIEvent_GetSetChecked 2800
+#define wxUpdateUIEvent_GetSetEnabled 2801
+#define wxUpdateUIEvent_GetSetShown 2802
+#define wxUpdateUIEvent_GetSetText 2803
+#define wxUpdateUIEvent_GetText 2804
+#define wxUpdateUIEvent_GetMode 2805
+#define wxUpdateUIEvent_GetUpdateInterval 2806
+#define wxUpdateUIEvent_ResetUpdateTime 2807
+#define wxUpdateUIEvent_SetMode 2808
+#define wxUpdateUIEvent_SetText 2809
+#define wxUpdateUIEvent_SetUpdateInterval 2810
+#define wxMouseCaptureChangedEvent_GetCapturedWindow 2811
+#define wxPaletteChangedEvent_SetChangedWindow 2812
+#define wxPaletteChangedEvent_GetChangedWindow 2813
+#define wxQueryNewPaletteEvent_SetPaletteRealized 2814
+#define wxQueryNewPaletteEvent_GetPaletteRealized 2815
+#define wxNavigationKeyEvent_GetDirection 2816
+#define wxNavigationKeyEvent_SetDirection 2817
+#define wxNavigationKeyEvent_IsWindowChange 2818
+#define wxNavigationKeyEvent_SetWindowChange 2819
+#define wxNavigationKeyEvent_IsFromTab 2820
+#define wxNavigationKeyEvent_SetFromTab 2821
+#define wxNavigationKeyEvent_GetCurrentFocus 2822
+#define wxNavigationKeyEvent_SetCurrentFocus 2823
+#define wxHelpEvent_GetOrigin 2824
+#define wxHelpEvent_GetPosition 2825
+#define wxHelpEvent_SetOrigin 2826
+#define wxHelpEvent_SetPosition 2827
+#define wxContextMenuEvent_GetPosition 2828
+#define wxContextMenuEvent_SetPosition 2829
+#define wxIdleEvent_CanSend 2830
+#define wxIdleEvent_GetMode 2831
+#define wxIdleEvent_RequestMore 2832
+#define wxIdleEvent_MoreRequested 2833
+#define wxIdleEvent_SetMode 2834
+#define wxGridEvent_AltDown 2835
+#define wxGridEvent_ControlDown 2836
+#define wxGridEvent_GetCol 2837
+#define wxGridEvent_GetPosition 2838
+#define wxGridEvent_GetRow 2839
+#define wxGridEvent_MetaDown 2840
+#define wxGridEvent_Selecting 2841
+#define wxGridEvent_ShiftDown 2842
+#define wxNotifyEvent_Allow 2843
+#define wxNotifyEvent_IsAllowed 2844
+#define wxNotifyEvent_Veto 2845
+#define wxSashEvent_GetEdge 2846
+#define wxSashEvent_GetDragRect 2847
+#define wxSashEvent_GetDragStatus 2848
+#define wxListEvent_GetCacheFrom 2849
+#define wxListEvent_GetCacheTo 2850
+#define wxListEvent_GetKeyCode 2851
+#define wxListEvent_GetIndex 2852
+#define wxListEvent_GetColumn 2853
+#define wxListEvent_GetPoint 2854
+#define wxListEvent_GetLabel 2855
+#define wxListEvent_GetText 2856
+#define wxListEvent_GetImage 2857
+#define wxListEvent_GetData 2858
+#define wxListEvent_GetMask 2859
+#define wxListEvent_GetItem 2860
+#define wxListEvent_IsEditCancelled 2861
+#define wxDateEvent_GetDate 2862
+#define wxCalendarEvent_GetWeekDay 2863
+#define wxFileDirPickerEvent_GetPath 2864
+#define wxColourPickerEvent_GetColour 2865
+#define wxFontPickerEvent_GetFont 2866
+#define wxStyledTextEvent_GetPosition 2867
+#define wxStyledTextEvent_GetKey 2868
+#define wxStyledTextEvent_GetModifiers 2869
+#define wxStyledTextEvent_GetModificationType 2870
+#define wxStyledTextEvent_GetText 2871
+#define wxStyledTextEvent_GetLength 2872
+#define wxStyledTextEvent_GetLinesAdded 2873
+#define wxStyledTextEvent_GetLine 2874
+#define wxStyledTextEvent_GetFoldLevelNow 2875
+#define wxStyledTextEvent_GetFoldLevelPrev 2876
+#define wxStyledTextEvent_GetMargin 2877
+#define wxStyledTextEvent_GetMessage 2878
+#define wxStyledTextEvent_GetWParam 2879
+#define wxStyledTextEvent_GetLParam 2880
+#define wxStyledTextEvent_GetListType 2881
+#define wxStyledTextEvent_GetX 2882
+#define wxStyledTextEvent_GetY 2883
+#define wxStyledTextEvent_GetDragText 2884
+#define wxStyledTextEvent_GetDragAllowMove 2885
+#define wxStyledTextEvent_GetDragResult 2886
+#define wxStyledTextEvent_GetShift 2887
+#define wxStyledTextEvent_GetControl 2888
+#define wxStyledTextEvent_GetAlt 2889
+#define utils_wxGetKeyState 2890
+#define utils_wxGetMousePosition 2891
+#define utils_wxGetMouseState 2892
+#define utils_wxSetDetectableAutoRepeat 2893
+#define utils_wxBell 2894
+#define utils_wxFindMenuItemId 2895
+#define utils_wxGenericFindWindowAtPoint 2896
+#define utils_wxFindWindowAtPoint 2897
+#define utils_wxBeginBusyCursor 2898
+#define utils_wxEndBusyCursor 2899
+#define utils_wxIsBusy 2900
+#define utils_wxShutdown 2901
+#define utils_wxShell 2902
+#define utils_wxLaunchDefaultBrowser 2903
+#define utils_wxGetEmailAddress 2904
+#define utils_wxGetUserId 2905
+#define utils_wxGetHomeDir 2906
+#define utils_wxNewId 2907
+#define utils_wxRegisterId 2908
+#define utils_wxGetCurrentId 2909
+#define utils_wxGetOsDescription 2910
+#define utils_wxIsPlatformLittleEndian 2911
+#define utils_wxIsPlatform64Bit 2912
+#define wxPrintout_new 2913
+#define wxPrintout_destruct 2914
+#define wxPrintout_GetDC 2915
+#define wxPrintout_GetPageSizeMM 2916
+#define wxPrintout_GetPageSizePixels 2917
+#define wxPrintout_GetPaperRectPixels 2918
+#define wxPrintout_GetPPIPrinter 2919
+#define wxPrintout_GetPPIScreen 2920
+#define wxPrintout_GetTitle 2921
+#define wxPrintout_IsPreview 2922
+#define wxPrintout_FitThisSizeToPaper 2923
+#define wxPrintout_FitThisSizeToPage 2924
+#define wxPrintout_FitThisSizeToPageMargins 2925
+#define wxPrintout_MapScreenSizeToPaper 2926
+#define wxPrintout_MapScreenSizeToPage 2927
+#define wxPrintout_MapScreenSizeToPageMargins 2928
+#define wxPrintout_MapScreenSizeToDevice 2929
+#define wxPrintout_GetLogicalPaperRect 2930
+#define wxPrintout_GetLogicalPageRect 2931
+#define wxPrintout_GetLogicalPageMarginsRect 2932
+#define wxPrintout_SetLogicalOrigin 2933
+#define wxPrintout_OffsetLogicalOrigin 2934
+#define wxStyledTextCtrl_new_2 2935
+#define wxStyledTextCtrl_new_0 2936
+#define wxStyledTextCtrl_destruct 2937
+#define wxStyledTextCtrl_Create 2938
+#define wxStyledTextCtrl_AddText 2939
+#define wxStyledTextCtrl_AddStyledText 2940
+#define wxStyledTextCtrl_InsertText 2941
+#define wxStyledTextCtrl_ClearAll 2942
+#define wxStyledTextCtrl_ClearDocumentStyle 2943
+#define wxStyledTextCtrl_GetLength 2944
+#define wxStyledTextCtrl_GetCharAt 2945
+#define wxStyledTextCtrl_GetCurrentPos 2946
+#define wxStyledTextCtrl_GetAnchor 2947
+#define wxStyledTextCtrl_GetStyleAt 2948
+#define wxStyledTextCtrl_Redo 2949
+#define wxStyledTextCtrl_SetUndoCollection 2950
+#define wxStyledTextCtrl_SelectAll 2951
+#define wxStyledTextCtrl_SetSavePoint 2952
+#define wxStyledTextCtrl_GetStyledText 2953
+#define wxStyledTextCtrl_CanRedo 2954
+#define wxStyledTextCtrl_MarkerLineFromHandle 2955
+#define wxStyledTextCtrl_MarkerDeleteHandle 2956
+#define wxStyledTextCtrl_GetUndoCollection 2957
+#define wxStyledTextCtrl_GetViewWhiteSpace 2958
+#define wxStyledTextCtrl_SetViewWhiteSpace 2959
+#define wxStyledTextCtrl_PositionFromPoint 2960
+#define wxStyledTextCtrl_PositionFromPointClose 2961
+#define wxStyledTextCtrl_GotoLine 2962
+#define wxStyledTextCtrl_GotoPos 2963
+#define wxStyledTextCtrl_SetAnchor 2964
+#define wxStyledTextCtrl_GetCurLine 2965
+#define wxStyledTextCtrl_GetEndStyled 2966
+#define wxStyledTextCtrl_ConvertEOLs 2967
+#define wxStyledTextCtrl_GetEOLMode 2968
+#define wxStyledTextCtrl_SetEOLMode 2969
+#define wxStyledTextCtrl_StartStyling 2970
+#define wxStyledTextCtrl_SetStyling 2971
+#define wxStyledTextCtrl_GetBufferedDraw 2972
+#define wxStyledTextCtrl_SetBufferedDraw 2973
+#define wxStyledTextCtrl_SetTabWidth 2974
+#define wxStyledTextCtrl_GetTabWidth 2975
+#define wxStyledTextCtrl_SetCodePage 2976
+#define wxStyledTextCtrl_MarkerDefine 2977
+#define wxStyledTextCtrl_MarkerSetForeground 2978
+#define wxStyledTextCtrl_MarkerSetBackground 2979
+#define wxStyledTextCtrl_MarkerAdd 2980
+#define wxStyledTextCtrl_MarkerDelete 2981
+#define wxStyledTextCtrl_MarkerDeleteAll 2982
+#define wxStyledTextCtrl_MarkerGet 2983
+#define wxStyledTextCtrl_MarkerNext 2984
+#define wxStyledTextCtrl_MarkerPrevious 2985
+#define wxStyledTextCtrl_MarkerDefineBitmap 2986
+#define wxStyledTextCtrl_MarkerAddSet 2987
+#define wxStyledTextCtrl_MarkerSetAlpha 2988
+#define wxStyledTextCtrl_SetMarginType 2989
+#define wxStyledTextCtrl_GetMarginType 2990
+#define wxStyledTextCtrl_SetMarginWidth 2991
+#define wxStyledTextCtrl_GetMarginWidth 2992
+#define wxStyledTextCtrl_SetMarginMask 2993
+#define wxStyledTextCtrl_GetMarginMask 2994
+#define wxStyledTextCtrl_SetMarginSensitive 2995
+#define wxStyledTextCtrl_GetMarginSensitive 2996
+#define wxStyledTextCtrl_StyleClearAll 2997
+#define wxStyledTextCtrl_StyleSetForeground 2998
+#define wxStyledTextCtrl_StyleSetBackground 2999
+#define wxStyledTextCtrl_StyleSetBold 3000
+#define wxStyledTextCtrl_StyleSetItalic 3001
+#define wxStyledTextCtrl_StyleSetSize 3002
+#define wxStyledTextCtrl_StyleSetFaceName 3003
+#define wxStyledTextCtrl_StyleSetEOLFilled 3004
+#define wxStyledTextCtrl_StyleResetDefault 3005
+#define wxStyledTextCtrl_StyleSetUnderline 3006
+#define wxStyledTextCtrl_StyleSetCase 3007
+#define wxStyledTextCtrl_StyleSetHotSpot 3008
+#define wxStyledTextCtrl_SetSelForeground 3009
+#define wxStyledTextCtrl_SetSelBackground 3010
+#define wxStyledTextCtrl_GetSelAlpha 3011
+#define wxStyledTextCtrl_SetSelAlpha 3012
+#define wxStyledTextCtrl_SetCaretForeground 3013
+#define wxStyledTextCtrl_CmdKeyAssign 3014
+#define wxStyledTextCtrl_CmdKeyClear 3015
+#define wxStyledTextCtrl_CmdKeyClearAll 3016
+#define wxStyledTextCtrl_SetStyleBytes 3017
+#define wxStyledTextCtrl_StyleSetVisible 3018
+#define wxStyledTextCtrl_GetCaretPeriod 3019
+#define wxStyledTextCtrl_SetCaretPeriod 3020
+#define wxStyledTextCtrl_SetWordChars 3021
+#define wxStyledTextCtrl_BeginUndoAction 3022
+#define wxStyledTextCtrl_EndUndoAction 3023
+#define wxStyledTextCtrl_IndicatorSetStyle 3024
+#define wxStyledTextCtrl_IndicatorGetStyle 3025
+#define wxStyledTextCtrl_IndicatorSetForeground 3026
+#define wxStyledTextCtrl_IndicatorGetForeground 3027
+#define wxStyledTextCtrl_SetWhitespaceForeground 3028
+#define wxStyledTextCtrl_SetWhitespaceBackground 3029
+#define wxStyledTextCtrl_GetStyleBits 3030
+#define wxStyledTextCtrl_SetLineState 3031
+#define wxStyledTextCtrl_GetLineState 3032
+#define wxStyledTextCtrl_GetMaxLineState 3033
+#define wxStyledTextCtrl_GetCaretLineVisible 3034
+#define wxStyledTextCtrl_SetCaretLineVisible 3035
+#define wxStyledTextCtrl_GetCaretLineBackground 3036
+#define wxStyledTextCtrl_SetCaretLineBackground 3037
+#define wxStyledTextCtrl_AutoCompShow 3038
+#define wxStyledTextCtrl_AutoCompCancel 3039
+#define wxStyledTextCtrl_AutoCompActive 3040
+#define wxStyledTextCtrl_AutoCompPosStart 3041
+#define wxStyledTextCtrl_AutoCompComplete 3042
+#define wxStyledTextCtrl_AutoCompStops 3043
+#define wxStyledTextCtrl_AutoCompSetSeparator 3044
+#define wxStyledTextCtrl_AutoCompGetSeparator 3045
+#define wxStyledTextCtrl_AutoCompSelect 3046
+#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3047
+#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3048
+#define wxStyledTextCtrl_AutoCompSetFillUps 3049
+#define wxStyledTextCtrl_AutoCompSetChooseSingle 3050
+#define wxStyledTextCtrl_AutoCompGetChooseSingle 3051
+#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3052
+#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3053
+#define wxStyledTextCtrl_UserListShow 3054
+#define wxStyledTextCtrl_AutoCompSetAutoHide 3055
+#define wxStyledTextCtrl_AutoCompGetAutoHide 3056
+#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3057
+#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3058
+#define wxStyledTextCtrl_RegisterImage 3059
+#define wxStyledTextCtrl_ClearRegisteredImages 3060
+#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3061
+#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3062
+#define wxStyledTextCtrl_AutoCompSetMaxWidth 3063
+#define wxStyledTextCtrl_AutoCompGetMaxWidth 3064
+#define wxStyledTextCtrl_AutoCompSetMaxHeight 3065
+#define wxStyledTextCtrl_AutoCompGetMaxHeight 3066
+#define wxStyledTextCtrl_SetIndent 3067
+#define wxStyledTextCtrl_GetIndent 3068
+#define wxStyledTextCtrl_SetUseTabs 3069
+#define wxStyledTextCtrl_GetUseTabs 3070
+#define wxStyledTextCtrl_SetLineIndentation 3071
+#define wxStyledTextCtrl_GetLineIndentation 3072
+#define wxStyledTextCtrl_GetLineIndentPosition 3073
+#define wxStyledTextCtrl_GetColumn 3074
+#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3075
+#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3076
+#define wxStyledTextCtrl_SetIndentationGuides 3077
+#define wxStyledTextCtrl_GetIndentationGuides 3078
+#define wxStyledTextCtrl_SetHighlightGuide 3079
+#define wxStyledTextCtrl_GetHighlightGuide 3080
+#define wxStyledTextCtrl_GetLineEndPosition 3081
+#define wxStyledTextCtrl_GetCodePage 3082
+#define wxStyledTextCtrl_GetCaretForeground 3083
+#define wxStyledTextCtrl_GetReadOnly 3084
+#define wxStyledTextCtrl_SetCurrentPos 3085
+#define wxStyledTextCtrl_SetSelectionStart 3086
+#define wxStyledTextCtrl_GetSelectionStart 3087
+#define wxStyledTextCtrl_SetSelectionEnd 3088
+#define wxStyledTextCtrl_GetSelectionEnd 3089
+#define wxStyledTextCtrl_SetPrintMagnification 3090
+#define wxStyledTextCtrl_GetPrintMagnification 3091
+#define wxStyledTextCtrl_SetPrintColourMode 3092
+#define wxStyledTextCtrl_GetPrintColourMode 3093
+#define wxStyledTextCtrl_FindText 3094
+#define wxStyledTextCtrl_FormatRange 3095
+#define wxStyledTextCtrl_GetFirstVisibleLine 3096
+#define wxStyledTextCtrl_GetLine 3097
+#define wxStyledTextCtrl_GetLineCount 3098
+#define wxStyledTextCtrl_SetMarginLeft 3099
+#define wxStyledTextCtrl_GetMarginLeft 3100
+#define wxStyledTextCtrl_SetMarginRight 3101
+#define wxStyledTextCtrl_GetMarginRight 3102
+#define wxStyledTextCtrl_GetModify 3103
+#define wxStyledTextCtrl_SetSelection 3104
+#define wxStyledTextCtrl_GetSelectedText 3105
+#define wxStyledTextCtrl_GetTextRange 3106
+#define wxStyledTextCtrl_HideSelection 3107
+#define wxStyledTextCtrl_LineFromPosition 3108
+#define wxStyledTextCtrl_PositionFromLine 3109
+#define wxStyledTextCtrl_LineScroll 3110
+#define wxStyledTextCtrl_EnsureCaretVisible 3111
+#define wxStyledTextCtrl_ReplaceSelection 3112
+#define wxStyledTextCtrl_SetReadOnly 3113
+#define wxStyledTextCtrl_CanPaste 3114
+#define wxStyledTextCtrl_CanUndo 3115
+#define wxStyledTextCtrl_EmptyUndoBuffer 3116
+#define wxStyledTextCtrl_Undo 3117
+#define wxStyledTextCtrl_Cut 3118
+#define wxStyledTextCtrl_Copy 3119
+#define wxStyledTextCtrl_Paste 3120
+#define wxStyledTextCtrl_Clear 3121
+#define wxStyledTextCtrl_SetText 3122
+#define wxStyledTextCtrl_GetText 3123
+#define wxStyledTextCtrl_GetTextLength 3124
+#define wxStyledTextCtrl_GetOvertype 3125
+#define wxStyledTextCtrl_SetCaretWidth 3126
+#define wxStyledTextCtrl_GetCaretWidth 3127
+#define wxStyledTextCtrl_SetTargetStart 3128
+#define wxStyledTextCtrl_GetTargetStart 3129
+#define wxStyledTextCtrl_SetTargetEnd 3130
+#define wxStyledTextCtrl_GetTargetEnd 3131
+#define wxStyledTextCtrl_ReplaceTarget 3132
+#define wxStyledTextCtrl_SearchInTarget 3133
+#define wxStyledTextCtrl_SetSearchFlags 3134
+#define wxStyledTextCtrl_GetSearchFlags 3135
+#define wxStyledTextCtrl_CallTipShow 3136
+#define wxStyledTextCtrl_CallTipCancel 3137
+#define wxStyledTextCtrl_CallTipActive 3138
+#define wxStyledTextCtrl_CallTipPosAtStart 3139
+#define wxStyledTextCtrl_CallTipSetHighlight 3140
+#define wxStyledTextCtrl_CallTipSetBackground 3141
+#define wxStyledTextCtrl_CallTipSetForeground 3142
+#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3143
+#define wxStyledTextCtrl_CallTipUseStyle 3144
+#define wxStyledTextCtrl_VisibleFromDocLine 3145
+#define wxStyledTextCtrl_DocLineFromVisible 3146
+#define wxStyledTextCtrl_WrapCount 3147
+#define wxStyledTextCtrl_SetFoldLevel 3148
+#define wxStyledTextCtrl_GetFoldLevel 3149
+#define wxStyledTextCtrl_GetLastChild 3150
+#define wxStyledTextCtrl_GetFoldParent 3151
+#define wxStyledTextCtrl_ShowLines 3152
+#define wxStyledTextCtrl_HideLines 3153
+#define wxStyledTextCtrl_GetLineVisible 3154
+#define wxStyledTextCtrl_SetFoldExpanded 3155
+#define wxStyledTextCtrl_GetFoldExpanded 3156
+#define wxStyledTextCtrl_ToggleFold 3157
+#define wxStyledTextCtrl_EnsureVisible 3158
+#define wxStyledTextCtrl_SetFoldFlags 3159
+#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3160
+#define wxStyledTextCtrl_SetTabIndents 3161
+#define wxStyledTextCtrl_GetTabIndents 3162
+#define wxStyledTextCtrl_SetBackSpaceUnIndents 3163
+#define wxStyledTextCtrl_GetBackSpaceUnIndents 3164
+#define wxStyledTextCtrl_SetMouseDwellTime 3165
+#define wxStyledTextCtrl_GetMouseDwellTime 3166
+#define wxStyledTextCtrl_WordStartPosition 3167
+#define wxStyledTextCtrl_WordEndPosition 3168
+#define wxStyledTextCtrl_SetWrapMode 3169
+#define wxStyledTextCtrl_GetWrapMode 3170
+#define wxStyledTextCtrl_SetWrapVisualFlags 3171
+#define wxStyledTextCtrl_GetWrapVisualFlags 3172
+#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3173
+#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3174
+#define wxStyledTextCtrl_SetWrapStartIndent 3175
+#define wxStyledTextCtrl_GetWrapStartIndent 3176
+#define wxStyledTextCtrl_SetLayoutCache 3177
+#define wxStyledTextCtrl_GetLayoutCache 3178
+#define wxStyledTextCtrl_SetScrollWidth 3179
+#define wxStyledTextCtrl_GetScrollWidth 3180
+#define wxStyledTextCtrl_TextWidth 3181
+#define wxStyledTextCtrl_GetEndAtLastLine 3182
+#define wxStyledTextCtrl_TextHeight 3183
+#define wxStyledTextCtrl_SetUseVerticalScrollBar 3184
+#define wxStyledTextCtrl_GetUseVerticalScrollBar 3185
+#define wxStyledTextCtrl_AppendText 3186
+#define wxStyledTextCtrl_GetTwoPhaseDraw 3187
+#define wxStyledTextCtrl_SetTwoPhaseDraw 3188
+#define wxStyledTextCtrl_TargetFromSelection 3189
+#define wxStyledTextCtrl_LinesJoin 3190
+#define wxStyledTextCtrl_LinesSplit 3191
+#define wxStyledTextCtrl_SetFoldMarginColour 3192
+#define wxStyledTextCtrl_SetFoldMarginHiColour 3193
+#define wxStyledTextCtrl_LineDown 3194
+#define wxStyledTextCtrl_LineDownExtend 3195
+#define wxStyledTextCtrl_LineUp 3196
+#define wxStyledTextCtrl_LineUpExtend 3197
+#define wxStyledTextCtrl_CharLeft 3198
+#define wxStyledTextCtrl_CharLeftExtend 3199
+#define wxStyledTextCtrl_CharRight 3200
+#define wxStyledTextCtrl_CharRightExtend 3201
+#define wxStyledTextCtrl_WordLeft 3202
+#define wxStyledTextCtrl_WordLeftExtend 3203
+#define wxStyledTextCtrl_WordRight 3204
+#define wxStyledTextCtrl_WordRightExtend 3205
+#define wxStyledTextCtrl_Home 3206
+#define wxStyledTextCtrl_HomeExtend 3207
+#define wxStyledTextCtrl_LineEnd 3208
+#define wxStyledTextCtrl_LineEndExtend 3209
+#define wxStyledTextCtrl_DocumentStart 3210
+#define wxStyledTextCtrl_DocumentStartExtend 3211
+#define wxStyledTextCtrl_DocumentEnd 3212
+#define wxStyledTextCtrl_DocumentEndExtend 3213
+#define wxStyledTextCtrl_PageUp 3214
+#define wxStyledTextCtrl_PageUpExtend 3215
+#define wxStyledTextCtrl_PageDown 3216
+#define wxStyledTextCtrl_PageDownExtend 3217
+#define wxStyledTextCtrl_EditToggleOvertype 3218
+#define wxStyledTextCtrl_Cancel 3219
+#define wxStyledTextCtrl_DeleteBack 3220
+#define wxStyledTextCtrl_Tab 3221
+#define wxStyledTextCtrl_BackTab 3222
+#define wxStyledTextCtrl_NewLine 3223
+#define wxStyledTextCtrl_FormFeed 3224
+#define wxStyledTextCtrl_VCHome 3225
+#define wxStyledTextCtrl_VCHomeExtend 3226
+#define wxStyledTextCtrl_ZoomIn 3227
+#define wxStyledTextCtrl_ZoomOut 3228
+#define wxStyledTextCtrl_DelWordLeft 3229
+#define wxStyledTextCtrl_DelWordRight 3230
+#define wxStyledTextCtrl_LineCut 3231
+#define wxStyledTextCtrl_LineDelete 3232
+#define wxStyledTextCtrl_LineTranspose 3233
+#define wxStyledTextCtrl_LineDuplicate 3234
+#define wxStyledTextCtrl_LowerCase 3235
+#define wxStyledTextCtrl_UpperCase 3236
+#define wxStyledTextCtrl_LineScrollDown 3237
+#define wxStyledTextCtrl_LineScrollUp 3238
+#define wxStyledTextCtrl_DeleteBackNotLine 3239
+#define wxStyledTextCtrl_HomeDisplay 3240
+#define wxStyledTextCtrl_HomeDisplayExtend 3241
+#define wxStyledTextCtrl_LineEndDisplay 3242
+#define wxStyledTextCtrl_LineEndDisplayExtend 3243
+#define wxStyledTextCtrl_HomeWrapExtend 3244
+#define wxStyledTextCtrl_LineEndWrap 3245
+#define wxStyledTextCtrl_LineEndWrapExtend 3246
+#define wxStyledTextCtrl_VCHomeWrap 3247
+#define wxStyledTextCtrl_VCHomeWrapExtend 3248
+#define wxStyledTextCtrl_LineCopy 3249
+#define wxStyledTextCtrl_MoveCaretInsideView 3250
+#define wxStyledTextCtrl_LineLength 3251
+#define wxStyledTextCtrl_BraceHighlight 3252
+#define wxStyledTextCtrl_BraceBadLight 3253
+#define wxStyledTextCtrl_BraceMatch 3254
+#define wxStyledTextCtrl_GetViewEOL 3255
+#define wxStyledTextCtrl_SetViewEOL 3256
+#define wxStyledTextCtrl_SetModEventMask 3257
+#define wxStyledTextCtrl_GetEdgeColumn 3258
+#define wxStyledTextCtrl_SetEdgeColumn 3259
+#define wxStyledTextCtrl_GetEdgeMode 3260
+#define wxStyledTextCtrl_GetEdgeColour 3261
+#define wxStyledTextCtrl_SetEdgeColour 3262
+#define wxStyledTextCtrl_SearchAnchor 3263
+#define wxStyledTextCtrl_SearchNext 3264
+#define wxStyledTextCtrl_SearchPrev 3265
+#define wxStyledTextCtrl_LinesOnScreen 3266
+#define wxStyledTextCtrl_UsePopUp 3267
+#define wxStyledTextCtrl_SelectionIsRectangle 3268
+#define wxStyledTextCtrl_SetZoom 3269
+#define wxStyledTextCtrl_GetZoom 3270
+#define wxStyledTextCtrl_GetModEventMask 3271
+#define wxStyledTextCtrl_SetSTCFocus 3272
+#define wxStyledTextCtrl_GetSTCFocus 3273
+#define wxStyledTextCtrl_SetStatus 3274
+#define wxStyledTextCtrl_GetStatus 3275
+#define wxStyledTextCtrl_SetMouseDownCaptures 3276
+#define wxStyledTextCtrl_GetMouseDownCaptures 3277
+#define wxStyledTextCtrl_SetSTCCursor 3278
+#define wxStyledTextCtrl_GetSTCCursor 3279
+#define wxStyledTextCtrl_SetControlCharSymbol 3280
+#define wxStyledTextCtrl_GetControlCharSymbol 3281
+#define wxStyledTextCtrl_WordPartLeft 3282
+#define wxStyledTextCtrl_WordPartLeftExtend 3283
+#define wxStyledTextCtrl_WordPartRight 3284
+#define wxStyledTextCtrl_WordPartRightExtend 3285
+#define wxStyledTextCtrl_SetVisiblePolicy 3286
+#define wxStyledTextCtrl_DelLineLeft 3287
+#define wxStyledTextCtrl_DelLineRight 3288
+#define wxStyledTextCtrl_GetXOffset 3289
+#define wxStyledTextCtrl_ChooseCaretX 3290
+#define wxStyledTextCtrl_SetXCaretPolicy 3291
+#define wxStyledTextCtrl_SetYCaretPolicy 3292
+#define wxStyledTextCtrl_GetPrintWrapMode 3293
+#define wxStyledTextCtrl_SetHotspotActiveForeground 3294
+#define wxStyledTextCtrl_SetHotspotActiveBackground 3295
+#define wxStyledTextCtrl_SetHotspotActiveUnderline 3296
+#define wxStyledTextCtrl_SetHotspotSingleLine 3297
+#define wxStyledTextCtrl_ParaDownExtend 3298
+#define wxStyledTextCtrl_ParaUp 3299
+#define wxStyledTextCtrl_ParaUpExtend 3300
+#define wxStyledTextCtrl_PositionBefore 3301
+#define wxStyledTextCtrl_PositionAfter 3302
+#define wxStyledTextCtrl_CopyRange 3303
+#define wxStyledTextCtrl_CopyText 3304
+#define wxStyledTextCtrl_SetSelectionMode 3305
+#define wxStyledTextCtrl_GetSelectionMode 3306
+#define wxStyledTextCtrl_LineDownRectExtend 3307
+#define wxStyledTextCtrl_LineUpRectExtend 3308
+#define wxStyledTextCtrl_CharLeftRectExtend 3309
+#define wxStyledTextCtrl_CharRightRectExtend 3310
+#define wxStyledTextCtrl_HomeRectExtend 3311
+#define wxStyledTextCtrl_VCHomeRectExtend 3312
+#define wxStyledTextCtrl_LineEndRectExtend 3313
+#define wxStyledTextCtrl_PageUpRectExtend 3314
+#define wxStyledTextCtrl_PageDownRectExtend 3315
+#define wxStyledTextCtrl_StutteredPageUp 3316
+#define wxStyledTextCtrl_StutteredPageUpExtend 3317
+#define wxStyledTextCtrl_StutteredPageDown 3318
+#define wxStyledTextCtrl_StutteredPageDownExtend 3319
+#define wxStyledTextCtrl_WordLeftEnd 3320
+#define wxStyledTextCtrl_WordLeftEndExtend 3321
+#define wxStyledTextCtrl_WordRightEnd 3322
+#define wxStyledTextCtrl_WordRightEndExtend 3323
+#define wxStyledTextCtrl_SetWhitespaceChars 3324
+#define wxStyledTextCtrl_SetCharsDefault 3325
+#define wxStyledTextCtrl_AutoCompGetCurrent 3326
+#define wxStyledTextCtrl_Allocate 3327
+#define wxStyledTextCtrl_FindColumn 3328
+#define wxStyledTextCtrl_GetCaretSticky 3329
+#define wxStyledTextCtrl_SetCaretSticky 3330
+#define wxStyledTextCtrl_ToggleCaretSticky 3331
+#define wxStyledTextCtrl_SetPasteConvertEndings 3332
+#define wxStyledTextCtrl_GetPasteConvertEndings 3333
+#define wxStyledTextCtrl_SelectionDuplicate 3334
+#define wxStyledTextCtrl_SetCaretLineBackAlpha 3335
+#define wxStyledTextCtrl_GetCaretLineBackAlpha 3336
+#define wxStyledTextCtrl_StartRecord 3337
+#define wxStyledTextCtrl_StopRecord 3338
+#define wxStyledTextCtrl_SetLexer 3339
+#define wxStyledTextCtrl_GetLexer 3340
+#define wxStyledTextCtrl_Colourise 3341
+#define wxStyledTextCtrl_SetProperty 3342
+#define wxStyledTextCtrl_SetKeyWords 3343
+#define wxStyledTextCtrl_SetLexerLanguage 3344
+#define wxStyledTextCtrl_GetProperty 3345
+#define wxStyledTextCtrl_GetStyleBitsNeeded 3346
+#define wxStyledTextCtrl_GetCurrentLine 3347
+#define wxStyledTextCtrl_StyleSetSpec 3348
+#define wxStyledTextCtrl_StyleSetFont 3349
+#define wxStyledTextCtrl_StyleSetFontAttr 3350
+#define wxStyledTextCtrl_StyleSetCharacterSet 3351
+#define wxStyledTextCtrl_StyleSetFontEncoding 3352
+#define wxStyledTextCtrl_CmdKeyExecute 3353
+#define wxStyledTextCtrl_SetMargins 3354
+#define wxStyledTextCtrl_GetSelection 3355
+#define wxStyledTextCtrl_PointFromPosition 3356
+#define wxStyledTextCtrl_ScrollToLine 3357
+#define wxStyledTextCtrl_ScrollToColumn 3358
+#define wxStyledTextCtrl_SendMsg 3359
+#define wxStyledTextCtrl_SetVScrollBar 3360
+#define wxStyledTextCtrl_SetHScrollBar 3361
+#define wxStyledTextCtrl_GetLastKeydownProcessed 3362
+#define wxStyledTextCtrl_SetLastKeydownProcessed 3363
+#define wxStyledTextCtrl_SaveFile 3364
+#define wxStyledTextCtrl_LoadFile 3365
+#define wxStyledTextCtrl_DoDragOver 3366
+#define wxStyledTextCtrl_DoDropText 3367
+#define wxStyledTextCtrl_GetUseAntiAliasing 3368
+#define wxStyledTextCtrl_AddTextRaw 3369
+#define wxStyledTextCtrl_InsertTextRaw 3370
+#define wxStyledTextCtrl_GetCurLineRaw 3371
+#define wxStyledTextCtrl_GetLineRaw 3372
+#define wxStyledTextCtrl_GetSelectedTextRaw 3373
+#define wxStyledTextCtrl_GetTextRangeRaw 3374
+#define wxStyledTextCtrl_SetTextRaw 3375
+#define wxStyledTextCtrl_GetTextRaw 3376
+#define wxStyledTextCtrl_AppendTextRaw 3377
+#define wxArtProvider_GetBitmap 3378
+#define wxArtProvider_GetIcon 3379
+#define wxTreeEvent_GetKeyCode 3380
+#define wxTreeEvent_GetItem 3381
+#define wxTreeEvent_GetKeyEvent 3382
+#define wxTreeEvent_GetLabel 3383
+#define wxTreeEvent_GetOldItem 3384
+#define wxTreeEvent_GetPoint 3385
+#define wxTreeEvent_IsEditCancelled 3386
+#define wxTreeEvent_SetToolTip 3387
+#define wxNotebookEvent_GetOldSelection 3388
+#define wxNotebookEvent_GetSelection 3389
+#define wxNotebookEvent_SetOldSelection 3390
+#define wxNotebookEvent_SetSelection 3391
+#define wxFileDataObject_new 3392
+#define wxFileDataObject_AddFile 3393
+#define wxFileDataObject_GetFilenames 3394
+#define wxFileDataObject_destroy 3395
+#define wxTextDataObject_new 3396
+#define wxTextDataObject_GetTextLength 3397
+#define wxTextDataObject_GetText 3398
+#define wxTextDataObject_SetText 3399
+#define wxTextDataObject_destroy 3400
+#define wxBitmapDataObject_new_1_1 3401
+#define wxBitmapDataObject_new_1_0 3402
+#define wxBitmapDataObject_GetBitmap 3403
+#define wxBitmapDataObject_SetBitmap 3404
+#define wxBitmapDataObject_destroy 3405
+#define wxClipboard_new 3407
+#define wxClipboard_destruct 3408
+#define wxClipboard_AddData 3409
+#define wxClipboard_Clear 3410
+#define wxClipboard_Close 3411
+#define wxClipboard_Flush 3412
+#define wxClipboard_GetData 3413
+#define wxClipboard_IsOpened 3414
+#define wxClipboard_Open 3415
+#define wxClipboard_SetData 3416
+#define wxClipboard_UsePrimarySelection 3418
+#define wxClipboard_IsSupported 3419
+#define wxClipboard_Get 3420
+#define wxSpinEvent_GetPosition 3421
+#define wxSpinEvent_SetPosition 3422
+#define wxSplitterWindow_new_0 3423
+#define wxSplitterWindow_new_2 3424
+#define wxSplitterWindow_destruct 3425
+#define wxSplitterWindow_Create 3426
+#define wxSplitterWindow_GetMinimumPaneSize 3427
+#define wxSplitterWindow_GetSashGravity 3428
+#define wxSplitterWindow_GetSashPosition 3429
+#define wxSplitterWindow_GetSplitMode 3430
+#define wxSplitterWindow_GetWindow1 3431
+#define wxSplitterWindow_GetWindow2 3432
+#define wxSplitterWindow_Initialize 3433
+#define wxSplitterWindow_IsSplit 3434
+#define wxSplitterWindow_ReplaceWindow 3435
+#define wxSplitterWindow_SetSashGravity 3436
+#define wxSplitterWindow_SetSashPosition 3437
+#define wxSplitterWindow_SetSashSize 3438
+#define wxSplitterWindow_SetMinimumPaneSize 3439
+#define wxSplitterWindow_SetSplitMode 3440
+#define wxSplitterWindow_SplitHorizontally 3441
+#define wxSplitterWindow_SplitVertically 3442
+#define wxSplitterWindow_Unsplit 3443
+#define wxSplitterWindow_UpdateSize 3444
+#define wxSplitterEvent_GetSashPosition 3445
+#define wxSplitterEvent_GetX 3446
+#define wxSplitterEvent_GetY 3447
+#define wxSplitterEvent_GetWindowBeingRemoved 3448
+#define wxSplitterEvent_SetSashPosition 3449
+#define wxHtmlWindow_new_0 3450
+#define wxHtmlWindow_new_2 3451
+#define wxHtmlWindow_AppendToPage 3452
+#define wxHtmlWindow_GetOpenedAnchor 3453
+#define wxHtmlWindow_GetOpenedPage 3454
+#define wxHtmlWindow_GetOpenedPageTitle 3455
+#define wxHtmlWindow_GetRelatedFrame 3456
+#define wxHtmlWindow_HistoryBack 3457
+#define wxHtmlWindow_HistoryCanBack 3458
+#define wxHtmlWindow_HistoryCanForward 3459
+#define wxHtmlWindow_HistoryClear 3460
+#define wxHtmlWindow_HistoryForward 3461
+#define wxHtmlWindow_LoadFile 3462
+#define wxHtmlWindow_LoadPage 3463
+#define wxHtmlWindow_SelectAll 3464
+#define wxHtmlWindow_SelectionToText 3465
+#define wxHtmlWindow_SelectLine 3466
+#define wxHtmlWindow_SelectWord 3467
+#define wxHtmlWindow_SetBorders 3468
+#define wxHtmlWindow_SetFonts 3469
+#define wxHtmlWindow_SetPage 3470
+#define wxHtmlWindow_SetRelatedFrame 3471
+#define wxHtmlWindow_SetRelatedStatusBar 3472
+#define wxHtmlWindow_ToText 3473
+#define wxHtmlWindow_destroy 3474
+#define wxHtmlLinkEvent_GetLinkInfo 3475
+#define wxSystemSettings_GetColour 3476
+#define wxSystemSettings_GetFont 3477
+#define wxSystemSettings_GetMetric 3478
+#define wxSystemSettings_GetScreenType 3479
+#define wxAuiNotebookEvent_SetSelection 3480
+#define wxAuiNotebookEvent_GetSelection 3481
+#define wxAuiNotebookEvent_SetOldSelection 3482
+#define wxAuiNotebookEvent_GetOldSelection 3483
+#define wxAuiNotebookEvent_SetDragSource 3484
+#define wxAuiNotebookEvent_GetDragSource 3485
+#define wxAuiManagerEvent_SetManager 3486
+#define wxAuiManagerEvent_GetManager 3487
+#define wxAuiManagerEvent_SetPane 3488
+#define wxAuiManagerEvent_GetPane 3489
+#define wxAuiManagerEvent_SetButton 3490
+#define wxAuiManagerEvent_GetButton 3491
+#define wxAuiManagerEvent_SetDC 3492
+#define wxAuiManagerEvent_GetDC 3493
+#define wxAuiManagerEvent_Veto 3494
+#define wxAuiManagerEvent_GetVeto 3495
+#define wxAuiManagerEvent_SetCanVeto 3496
+#define wxAuiManagerEvent_CanVeto 3497
+#define wxLogNull_new 3498
+#define wxLogNull_destroy 3499
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 528a08e654..6d2926ce4e 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -411,7 +411,7 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process)
if(event->caller == process || // Callbacks from CB process only
event->op == WXE_CB_START || // Recursive event callback allow
// Allow connect_cb during CB i.e. msg from wxe_server.
- event->caller == memenv->owner)
+ (memenv && event->caller == memenv->owner))
{
switch(event->op) {
case WXE_BATCH_END:
@@ -669,7 +669,7 @@ void WxeApp::clearPtr(void * ptr) {
send_msg("debug", &msg);
}
- if(refd->pid != -1) {
+ if(((int) refd->pid) != -1) {
// Send terminate pid to owner
wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->memenv->owner, false);
rt.addAtom("_wxe_destroy_");
diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl
index 4fcbb9366e..e3fe4c9612 100644
--- a/lib/wx/src/gen/wxTreeCtrl.erl
+++ b/lib/wx/src/gen/wxTreeCtrl.erl
@@ -35,7 +35,7 @@
-include("wxe.hrl").
-export([addRoot/2,addRoot/3,appendItem/3,appendItem/4,assignImageList/2,assignStateImageList/2,
collapse/2,collapseAndReset/2,create/2,create/3,delete/2,deleteAllItems/1,
- deleteChildren/2,destroy/1,ensureVisible/2,expand/2,getBoundingRect/3,
+ deleteChildren/2,destroy/1,editLabel/2,ensureVisible/2,expand/2,getBoundingRect/3,
getBoundingRect/4,getChildrenCount/2,getChildrenCount/3,getCount/1,
getEditControl/1,getFirstChild/2,getFirstVisibleItem/1,getImageList/1,
getIndent/1,getItemBackgroundColour/2,getItemData/2,getItemFont/2,
@@ -243,6 +243,14 @@ deleteChildren(#wx_ref{type=ThisT,ref=ThisRef},Item)
wxe_util:cast(?wxTreeCtrl_DeleteChildren,
<<ThisRef:32/?UI,0:32,Item:64/?UI>>).
+%% @spec (This::wxTreeCtrl(), Item::integer()) -> wxTextCtrl:wxTextCtrl()
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrleditlabel">external documentation</a>.
+editLabel(#wx_ref{type=ThisT,ref=ThisRef},Item)
+ when is_integer(Item) ->
+ ?CLASS(ThisT,wxTreeCtrl),
+ wxe_util:call(?wxTreeCtrl_EditLabel,
+ <<ThisRef:32/?UI,0:32,Item:64/?UI>>).
+
%% @spec (This::wxTreeCtrl(), Item::integer()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlensurevisible">external documentation</a>.
ensureVisible(#wx_ref{type=ThisT,ref=ThisRef},Item)
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index a3416b75c8..3edfa73599 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -1837,1445 +1837,1450 @@ wxdebug_table() ->
{2007, {wxTreeCtrl, delete, 1}},
{2008, {wxTreeCtrl, deleteAllItems, 0}},
{2009, {wxTreeCtrl, deleteChildren, 1}},
- {2010, {wxTreeCtrl, ensureVisible, 1}},
- {2011, {wxTreeCtrl, expand, 1}},
- {2012, {wxTreeCtrl, getBoundingRect, 3}},
- {2014, {wxTreeCtrl, getChildrenCount, 2}},
- {2015, {wxTreeCtrl, getCount, 0}},
- {2016, {wxTreeCtrl, getEditControl, 0}},
- {2017, {wxTreeCtrl, getFirstChild, 2}},
- {2018, {wxTreeCtrl, getNextChild, 2}},
- {2019, {wxTreeCtrl, getFirstVisibleItem, 0}},
- {2020, {wxTreeCtrl, getImageList, 0}},
- {2021, {wxTreeCtrl, getIndent, 0}},
- {2022, {wxTreeCtrl, getItemBackgroundColour, 1}},
- {2023, {wxTreeCtrl, getItemData, 1}},
- {2024, {wxTreeCtrl, getItemFont, 1}},
- {2025, {wxTreeCtrl, getItemImage_1, 1}},
- {2026, {wxTreeCtrl, getItemImage_2, 2}},
- {2027, {wxTreeCtrl, getItemText, 1}},
- {2028, {wxTreeCtrl, getItemTextColour, 1}},
- {2029, {wxTreeCtrl, getLastChild, 1}},
- {2030, {wxTreeCtrl, getNextSibling, 1}},
- {2031, {wxTreeCtrl, getNextVisible, 1}},
- {2032, {wxTreeCtrl, getItemParent, 1}},
- {2033, {wxTreeCtrl, getPrevSibling, 1}},
- {2034, {wxTreeCtrl, getPrevVisible, 1}},
- {2035, {wxTreeCtrl, getRootItem, 0}},
- {2036, {wxTreeCtrl, getSelection, 0}},
- {2037, {wxTreeCtrl, getSelections, 1}},
- {2038, {wxTreeCtrl, getStateImageList, 0}},
- {2039, {wxTreeCtrl, hitTest, 1}},
- {2041, {wxTreeCtrl, insertItem, 4}},
- {2042, {wxTreeCtrl, isBold, 1}},
- {2043, {wxTreeCtrl, isExpanded, 1}},
- {2044, {wxTreeCtrl, isSelected, 1}},
- {2045, {wxTreeCtrl, isVisible, 1}},
- {2046, {wxTreeCtrl, itemHasChildren, 1}},
- {2047, {wxTreeCtrl, prependItem, 3}},
- {2048, {wxTreeCtrl, scrollTo, 1}},
- {2049, {wxTreeCtrl, selectItem_1, 1}},
- {2050, {wxTreeCtrl, selectItem_2, 2}},
- {2051, {wxTreeCtrl, setIndent, 1}},
- {2052, {wxTreeCtrl, setImageList, 1}},
- {2053, {wxTreeCtrl, setItemBackgroundColour, 2}},
- {2054, {wxTreeCtrl, setItemBold, 2}},
- {2055, {wxTreeCtrl, setItemData, 2}},
- {2056, {wxTreeCtrl, setItemDropHighlight, 2}},
- {2057, {wxTreeCtrl, setItemFont, 2}},
- {2058, {wxTreeCtrl, setItemHasChildren, 2}},
- {2059, {wxTreeCtrl, setItemImage_2, 2}},
- {2060, {wxTreeCtrl, setItemImage_3, 3}},
- {2061, {wxTreeCtrl, setItemText, 2}},
- {2062, {wxTreeCtrl, setItemTextColour, 2}},
- {2063, {wxTreeCtrl, setStateImageList, 1}},
- {2064, {wxTreeCtrl, setWindowStyle, 1}},
- {2065, {wxTreeCtrl, sortChildren, 1}},
- {2066, {wxTreeCtrl, toggle, 1}},
- {2067, {wxTreeCtrl, toggleItemSelection, 1}},
- {2068, {wxTreeCtrl, unselect, 0}},
- {2069, {wxTreeCtrl, unselectAll, 0}},
- {2070, {wxTreeCtrl, unselectItem, 1}},
- {2071, {wxScrollBar, new_0, 0}},
- {2072, {wxScrollBar, new_3, 3}},
- {2073, {wxScrollBar, destruct, 0}},
- {2074, {wxScrollBar, create, 3}},
- {2075, {wxScrollBar, getRange, 0}},
- {2076, {wxScrollBar, getPageSize, 0}},
- {2077, {wxScrollBar, getThumbPosition, 0}},
- {2078, {wxScrollBar, getThumbSize, 0}},
- {2079, {wxScrollBar, setThumbPosition, 1}},
- {2080, {wxScrollBar, setScrollbar, 5}},
- {2082, {wxSpinButton, new_2, 2}},
- {2083, {wxSpinButton, new_0, 0}},
- {2084, {wxSpinButton, create, 2}},
- {2085, {wxSpinButton, getMax, 0}},
- {2086, {wxSpinButton, getMin, 0}},
- {2087, {wxSpinButton, getValue, 0}},
- {2088, {wxSpinButton, setRange, 2}},
- {2089, {wxSpinButton, setValue, 1}},
- {2090, {wxSpinButton, 'Destroy', undefined}},
- {2091, {wxSpinCtrl, new_0, 0}},
- {2092, {wxSpinCtrl, new_2, 2}},
- {2094, {wxSpinCtrl, create, 2}},
- {2097, {wxSpinCtrl, setValue_1_1, 1}},
- {2098, {wxSpinCtrl, setValue_1_0, 1}},
- {2100, {wxSpinCtrl, getValue, 0}},
- {2102, {wxSpinCtrl, setRange, 2}},
- {2103, {wxSpinCtrl, setSelection, 2}},
- {2105, {wxSpinCtrl, getMin, 0}},
- {2107, {wxSpinCtrl, getMax, 0}},
- {2108, {wxSpinCtrl, 'Destroy', undefined}},
- {2109, {wxStaticText, new_0, 0}},
- {2110, {wxStaticText, new_4, 4}},
- {2111, {wxStaticText, create, 4}},
- {2112, {wxStaticText, getLabel, 0}},
- {2113, {wxStaticText, setLabel, 1}},
- {2114, {wxStaticText, wrap, 1}},
- {2115, {wxStaticText, 'Destroy', undefined}},
- {2116, {wxStaticBitmap, new_0, 0}},
- {2117, {wxStaticBitmap, new_4, 4}},
- {2118, {wxStaticBitmap, create, 4}},
- {2119, {wxStaticBitmap, getBitmap, 0}},
- {2120, {wxStaticBitmap, setBitmap, 1}},
- {2121, {wxStaticBitmap, 'Destroy', undefined}},
- {2122, {wxRadioBox, new, 7}},
- {2124, {wxRadioBox, destruct, 0}},
- {2125, {wxRadioBox, create, 7}},
- {2126, {wxRadioBox, enable_2, 2}},
- {2127, {wxRadioBox, enable_1, 1}},
- {2128, {wxRadioBox, getSelection, 0}},
- {2129, {wxRadioBox, getString, 1}},
- {2130, {wxRadioBox, setSelection, 1}},
- {2131, {wxRadioBox, show_2, 2}},
- {2132, {wxRadioBox, show_1, 1}},
- {2133, {wxRadioBox, getColumnCount, 0}},
- {2134, {wxRadioBox, getItemHelpText, 1}},
- {2135, {wxRadioBox, getItemToolTip, 1}},
- {2137, {wxRadioBox, getItemFromPoint, 1}},
- {2138, {wxRadioBox, getRowCount, 0}},
- {2139, {wxRadioBox, isItemEnabled, 1}},
- {2140, {wxRadioBox, isItemShown, 1}},
- {2141, {wxRadioBox, setItemHelpText, 2}},
- {2142, {wxRadioBox, setItemToolTip, 2}},
- {2143, {wxRadioButton, new_0, 0}},
- {2144, {wxRadioButton, new_4, 4}},
- {2145, {wxRadioButton, create, 4}},
- {2146, {wxRadioButton, getValue, 0}},
- {2147, {wxRadioButton, setValue, 1}},
- {2148, {wxRadioButton, 'Destroy', undefined}},
- {2150, {wxSlider, new_6, 6}},
- {2151, {wxSlider, new_0, 0}},
- {2152, {wxSlider, create, 6}},
- {2153, {wxSlider, getLineSize, 0}},
- {2154, {wxSlider, getMax, 0}},
- {2155, {wxSlider, getMin, 0}},
- {2156, {wxSlider, getPageSize, 0}},
- {2157, {wxSlider, getThumbLength, 0}},
- {2158, {wxSlider, getValue, 0}},
- {2159, {wxSlider, setLineSize, 1}},
- {2160, {wxSlider, setPageSize, 1}},
- {2161, {wxSlider, setRange, 2}},
- {2162, {wxSlider, setThumbLength, 1}},
- {2163, {wxSlider, setValue, 1}},
- {2164, {wxSlider, 'Destroy', undefined}},
- {2166, {wxDialog, new_4, 4}},
- {2167, {wxDialog, new_0, 0}},
- {2169, {wxDialog, destruct, 0}},
- {2170, {wxDialog, create, 4}},
- {2171, {wxDialog, createButtonSizer, 1}},
- {2172, {wxDialog, createStdDialogButtonSizer, 1}},
- {2173, {wxDialog, endModal, 1}},
- {2174, {wxDialog, getAffirmativeId, 0}},
- {2175, {wxDialog, getReturnCode, 0}},
- {2176, {wxDialog, isModal, 0}},
- {2177, {wxDialog, setAffirmativeId, 1}},
- {2178, {wxDialog, setReturnCode, 1}},
- {2179, {wxDialog, show, 1}},
- {2180, {wxDialog, showModal, 0}},
- {2181, {wxColourDialog, new_0, 0}},
- {2182, {wxColourDialog, new_2, 2}},
- {2183, {wxColourDialog, destruct, 0}},
- {2184, {wxColourDialog, create, 2}},
- {2185, {wxColourDialog, getColourData, 0}},
- {2186, {wxColourData, new_0, 0}},
- {2187, {wxColourData, new_1, 1}},
- {2188, {wxColourData, destruct, 0}},
- {2189, {wxColourData, getChooseFull, 0}},
- {2190, {wxColourData, getColour, 0}},
- {2192, {wxColourData, getCustomColour, 1}},
- {2193, {wxColourData, setChooseFull, 1}},
- {2194, {wxColourData, setColour, 1}},
- {2195, {wxColourData, setCustomColour, 2}},
- {2196, {wxPalette, new_0, 0}},
- {2197, {wxPalette, new_4, 4}},
- {2199, {wxPalette, destruct, 0}},
- {2200, {wxPalette, create, 4}},
- {2201, {wxPalette, getColoursCount, 0}},
- {2202, {wxPalette, getPixel, 3}},
- {2203, {wxPalette, getRGB, 4}},
- {2204, {wxPalette, isOk, 0}},
- {2208, {wxDirDialog, new, 2}},
- {2209, {wxDirDialog, destruct, 0}},
- {2210, {wxDirDialog, getPath, 0}},
- {2211, {wxDirDialog, getMessage, 0}},
- {2212, {wxDirDialog, setMessage, 1}},
- {2213, {wxDirDialog, setPath, 1}},
- {2217, {wxFileDialog, new, 2}},
- {2218, {wxFileDialog, destruct, 0}},
- {2219, {wxFileDialog, getDirectory, 0}},
- {2220, {wxFileDialog, getFilename, 0}},
- {2221, {wxFileDialog, getFilenames, 1}},
- {2222, {wxFileDialog, getFilterIndex, 0}},
- {2223, {wxFileDialog, getMessage, 0}},
- {2224, {wxFileDialog, getPath, 0}},
- {2225, {wxFileDialog, getPaths, 1}},
- {2226, {wxFileDialog, getWildcard, 0}},
- {2227, {wxFileDialog, setDirectory, 1}},
- {2228, {wxFileDialog, setFilename, 1}},
- {2229, {wxFileDialog, setFilterIndex, 1}},
- {2230, {wxFileDialog, setMessage, 1}},
- {2231, {wxFileDialog, setPath, 1}},
- {2232, {wxFileDialog, setWildcard, 1}},
- {2233, {wxPickerBase, setInternalMargin, 1}},
- {2234, {wxPickerBase, getInternalMargin, 0}},
- {2235, {wxPickerBase, setTextCtrlProportion, 1}},
- {2236, {wxPickerBase, setPickerCtrlProportion, 1}},
- {2237, {wxPickerBase, getTextCtrlProportion, 0}},
- {2238, {wxPickerBase, getPickerCtrlProportion, 0}},
- {2239, {wxPickerBase, hasTextCtrl, 0}},
- {2240, {wxPickerBase, getTextCtrl, 0}},
- {2241, {wxPickerBase, isTextCtrlGrowable, 0}},
- {2242, {wxPickerBase, setPickerCtrlGrowable, 1}},
- {2243, {wxPickerBase, setTextCtrlGrowable, 1}},
- {2244, {wxPickerBase, isPickerCtrlGrowable, 0}},
- {2245, {wxFilePickerCtrl, new_0, 0}},
- {2246, {wxFilePickerCtrl, new_3, 3}},
- {2247, {wxFilePickerCtrl, create, 3}},
- {2248, {wxFilePickerCtrl, getPath, 0}},
- {2249, {wxFilePickerCtrl, setPath, 1}},
- {2250, {wxFilePickerCtrl, 'Destroy', undefined}},
- {2251, {wxDirPickerCtrl, new_0, 0}},
- {2252, {wxDirPickerCtrl, new_3, 3}},
- {2253, {wxDirPickerCtrl, create, 3}},
- {2254, {wxDirPickerCtrl, getPath, 0}},
- {2255, {wxDirPickerCtrl, setPath, 1}},
- {2256, {wxDirPickerCtrl, 'Destroy', undefined}},
- {2257, {wxColourPickerCtrl, new_0, 0}},
- {2258, {wxColourPickerCtrl, new_3, 3}},
- {2259, {wxColourPickerCtrl, create, 3}},
- {2260, {wxColourPickerCtrl, getColour, 0}},
- {2261, {wxColourPickerCtrl, setColour_1_1, 1}},
- {2262, {wxColourPickerCtrl, setColour_1_0, 1}},
- {2263, {wxColourPickerCtrl, 'Destroy', undefined}},
- {2264, {wxDatePickerCtrl, new_0, 0}},
- {2265, {wxDatePickerCtrl, new_3, 3}},
- {2266, {wxDatePickerCtrl, getRange, 2}},
- {2267, {wxDatePickerCtrl, getValue, 0}},
- {2268, {wxDatePickerCtrl, setRange, 2}},
- {2269, {wxDatePickerCtrl, setValue, 1}},
- {2270, {wxDatePickerCtrl, 'Destroy', undefined}},
- {2271, {wxFontPickerCtrl, new_0, 0}},
- {2272, {wxFontPickerCtrl, new_3, 3}},
- {2273, {wxFontPickerCtrl, create, 3}},
- {2274, {wxFontPickerCtrl, getSelectedFont, 0}},
- {2275, {wxFontPickerCtrl, setSelectedFont, 1}},
- {2276, {wxFontPickerCtrl, getMaxPointSize, 0}},
- {2277, {wxFontPickerCtrl, setMaxPointSize, 1}},
- {2278, {wxFontPickerCtrl, 'Destroy', undefined}},
- {2281, {wxFindReplaceDialog, new_0, 0}},
- {2282, {wxFindReplaceDialog, new_4, 4}},
- {2283, {wxFindReplaceDialog, destruct, 0}},
- {2284, {wxFindReplaceDialog, create, 4}},
- {2285, {wxFindReplaceDialog, getData, 0}},
- {2286, {wxFindReplaceData, new_0, 0}},
- {2287, {wxFindReplaceData, new_1, 1}},
- {2288, {wxFindReplaceData, getFindString, 0}},
- {2289, {wxFindReplaceData, getReplaceString, 0}},
- {2290, {wxFindReplaceData, getFlags, 0}},
- {2291, {wxFindReplaceData, setFlags, 1}},
- {2292, {wxFindReplaceData, setFindString, 1}},
- {2293, {wxFindReplaceData, setReplaceString, 1}},
- {2294, {wxFindReplaceData, 'Destroy', undefined}},
- {2295, {wxMultiChoiceDialog, new_0, 0}},
- {2297, {wxMultiChoiceDialog, new_5, 5}},
- {2298, {wxMultiChoiceDialog, getSelections, 0}},
- {2299, {wxMultiChoiceDialog, setSelections, 1}},
- {2300, {wxMultiChoiceDialog, 'Destroy', undefined}},
- {2301, {wxSingleChoiceDialog, new_0, 0}},
- {2303, {wxSingleChoiceDialog, new_5, 5}},
- {2304, {wxSingleChoiceDialog, getSelection, 0}},
- {2305, {wxSingleChoiceDialog, getStringSelection, 0}},
- {2306, {wxSingleChoiceDialog, setSelection, 1}},
- {2307, {wxSingleChoiceDialog, 'Destroy', undefined}},
- {2308, {wxTextEntryDialog, new, 3}},
- {2309, {wxTextEntryDialog, getValue, 0}},
- {2310, {wxTextEntryDialog, setValue, 1}},
- {2311, {wxTextEntryDialog, 'Destroy', undefined}},
- {2312, {wxPasswordEntryDialog, new, 3}},
- {2313, {wxPasswordEntryDialog, 'Destroy', undefined}},
- {2314, {wxFontData, new_0, 0}},
- {2315, {wxFontData, new_1, 1}},
- {2316, {wxFontData, destruct, 0}},
- {2317, {wxFontData, enableEffects, 1}},
- {2318, {wxFontData, getAllowSymbols, 0}},
- {2319, {wxFontData, getColour, 0}},
- {2320, {wxFontData, getChosenFont, 0}},
- {2321, {wxFontData, getEnableEffects, 0}},
- {2322, {wxFontData, getInitialFont, 0}},
- {2323, {wxFontData, getShowHelp, 0}},
- {2324, {wxFontData, setAllowSymbols, 1}},
- {2325, {wxFontData, setChosenFont, 1}},
- {2326, {wxFontData, setColour, 1}},
- {2327, {wxFontData, setInitialFont, 1}},
- {2328, {wxFontData, setRange, 2}},
- {2329, {wxFontData, setShowHelp, 1}},
- {2333, {wxFontDialog, new_0, 0}},
- {2335, {wxFontDialog, new_2, 2}},
- {2337, {wxFontDialog, create, 2}},
- {2338, {wxFontDialog, getFontData, 0}},
- {2340, {wxFontDialog, 'Destroy', undefined}},
- {2341, {wxProgressDialog, new, 3}},
- {2342, {wxProgressDialog, destruct, 0}},
- {2343, {wxProgressDialog, resume, 0}},
- {2344, {wxProgressDialog, update_2, 2}},
- {2345, {wxProgressDialog, update_0, 0}},
- {2346, {wxMessageDialog, new, 3}},
- {2347, {wxMessageDialog, destruct, 0}},
- {2348, {wxPageSetupDialog, new, 2}},
- {2349, {wxPageSetupDialog, destruct, 0}},
- {2350, {wxPageSetupDialog, getPageSetupData, 0}},
- {2351, {wxPageSetupDialog, showModal, 0}},
- {2352, {wxPageSetupDialogData, new_0, 0}},
- {2353, {wxPageSetupDialogData, new_1_0, 1}},
- {2354, {wxPageSetupDialogData, new_1_1, 1}},
- {2355, {wxPageSetupDialogData, destruct, 0}},
- {2356, {wxPageSetupDialogData, enableHelp, 1}},
- {2357, {wxPageSetupDialogData, enableMargins, 1}},
- {2358, {wxPageSetupDialogData, enableOrientation, 1}},
- {2359, {wxPageSetupDialogData, enablePaper, 1}},
- {2360, {wxPageSetupDialogData, enablePrinter, 1}},
- {2361, {wxPageSetupDialogData, getDefaultMinMargins, 0}},
- {2362, {wxPageSetupDialogData, getEnableMargins, 0}},
- {2363, {wxPageSetupDialogData, getEnableOrientation, 0}},
- {2364, {wxPageSetupDialogData, getEnablePaper, 0}},
- {2365, {wxPageSetupDialogData, getEnablePrinter, 0}},
- {2366, {wxPageSetupDialogData, getEnableHelp, 0}},
- {2367, {wxPageSetupDialogData, getDefaultInfo, 0}},
- {2368, {wxPageSetupDialogData, getMarginTopLeft, 0}},
- {2369, {wxPageSetupDialogData, getMarginBottomRight, 0}},
- {2370, {wxPageSetupDialogData, getMinMarginTopLeft, 0}},
- {2371, {wxPageSetupDialogData, getMinMarginBottomRight, 0}},
- {2372, {wxPageSetupDialogData, getPaperId, 0}},
- {2373, {wxPageSetupDialogData, getPaperSize, 0}},
- {2375, {wxPageSetupDialogData, getPrintData, 0}},
- {2376, {wxPageSetupDialogData, isOk, 0}},
- {2377, {wxPageSetupDialogData, setDefaultInfo, 1}},
- {2378, {wxPageSetupDialogData, setDefaultMinMargins, 1}},
- {2379, {wxPageSetupDialogData, setMarginTopLeft, 1}},
- {2380, {wxPageSetupDialogData, setMarginBottomRight, 1}},
- {2381, {wxPageSetupDialogData, setMinMarginTopLeft, 1}},
- {2382, {wxPageSetupDialogData, setMinMarginBottomRight, 1}},
- {2383, {wxPageSetupDialogData, setPaperId, 1}},
- {2384, {wxPageSetupDialogData, setPaperSize_1_1, 1}},
- {2385, {wxPageSetupDialogData, setPaperSize_1_0, 1}},
- {2386, {wxPageSetupDialogData, setPrintData, 1}},
- {2387, {wxPrintDialog, new_2_0, 2}},
- {2388, {wxPrintDialog, new_2_1, 2}},
- {2389, {wxPrintDialog, destruct, 0}},
- {2390, {wxPrintDialog, getPrintDialogData, 0}},
- {2391, {wxPrintDialog, getPrintDC, 0}},
- {2392, {wxPrintDialogData, new_0, 0}},
- {2393, {wxPrintDialogData, new_1_1, 1}},
- {2394, {wxPrintDialogData, new_1_0, 1}},
- {2395, {wxPrintDialogData, destruct, 0}},
- {2396, {wxPrintDialogData, enableHelp, 1}},
- {2397, {wxPrintDialogData, enablePageNumbers, 1}},
- {2398, {wxPrintDialogData, enablePrintToFile, 1}},
- {2399, {wxPrintDialogData, enableSelection, 1}},
- {2400, {wxPrintDialogData, getAllPages, 0}},
- {2401, {wxPrintDialogData, getCollate, 0}},
- {2402, {wxPrintDialogData, getFromPage, 0}},
- {2403, {wxPrintDialogData, getMaxPage, 0}},
- {2404, {wxPrintDialogData, getMinPage, 0}},
- {2405, {wxPrintDialogData, getNoCopies, 0}},
- {2406, {wxPrintDialogData, getPrintData, 0}},
- {2407, {wxPrintDialogData, getPrintToFile, 0}},
- {2408, {wxPrintDialogData, getSelection, 0}},
- {2409, {wxPrintDialogData, getToPage, 0}},
- {2410, {wxPrintDialogData, isOk, 0}},
- {2411, {wxPrintDialogData, setCollate, 1}},
- {2412, {wxPrintDialogData, setFromPage, 1}},
- {2413, {wxPrintDialogData, setMaxPage, 1}},
- {2414, {wxPrintDialogData, setMinPage, 1}},
- {2415, {wxPrintDialogData, setNoCopies, 1}},
- {2416, {wxPrintDialogData, setPrintData, 1}},
- {2417, {wxPrintDialogData, setPrintToFile, 1}},
- {2418, {wxPrintDialogData, setSelection, 1}},
- {2419, {wxPrintDialogData, setToPage, 1}},
- {2420, {wxPrintData, new_0, 0}},
- {2421, {wxPrintData, new_1, 1}},
- {2422, {wxPrintData, destruct, 0}},
- {2423, {wxPrintData, getCollate, 0}},
- {2424, {wxPrintData, getBin, 0}},
- {2425, {wxPrintData, getColour, 0}},
- {2426, {wxPrintData, getDuplex, 0}},
- {2427, {wxPrintData, getNoCopies, 0}},
- {2428, {wxPrintData, getOrientation, 0}},
- {2429, {wxPrintData, getPaperId, 0}},
- {2430, {wxPrintData, getPrinterName, 0}},
- {2431, {wxPrintData, getQuality, 0}},
- {2432, {wxPrintData, isOk, 0}},
- {2433, {wxPrintData, setBin, 1}},
- {2434, {wxPrintData, setCollate, 1}},
- {2435, {wxPrintData, setColour, 1}},
- {2436, {wxPrintData, setDuplex, 1}},
- {2437, {wxPrintData, setNoCopies, 1}},
- {2438, {wxPrintData, setOrientation, 1}},
- {2439, {wxPrintData, setPaperId, 1}},
- {2440, {wxPrintData, setPrinterName, 1}},
- {2441, {wxPrintData, setQuality, 1}},
- {2444, {wxPrintPreview, new_2, 2}},
- {2445, {wxPrintPreview, new_3, 3}},
- {2447, {wxPrintPreview, destruct, 0}},
- {2448, {wxPrintPreview, getCanvas, 0}},
- {2449, {wxPrintPreview, getCurrentPage, 0}},
- {2450, {wxPrintPreview, getFrame, 0}},
- {2451, {wxPrintPreview, getMaxPage, 0}},
- {2452, {wxPrintPreview, getMinPage, 0}},
- {2453, {wxPrintPreview, getPrintout, 0}},
- {2454, {wxPrintPreview, getPrintoutForPrinting, 0}},
- {2455, {wxPrintPreview, isOk, 0}},
- {2456, {wxPrintPreview, paintPage, 2}},
- {2457, {wxPrintPreview, print, 1}},
- {2458, {wxPrintPreview, renderPage, 1}},
- {2459, {wxPrintPreview, setCanvas, 1}},
- {2460, {wxPrintPreview, setCurrentPage, 1}},
- {2461, {wxPrintPreview, setFrame, 1}},
- {2462, {wxPrintPreview, setPrintout, 1}},
- {2463, {wxPrintPreview, setZoom, 1}},
- {2464, {wxPreviewFrame, new, 3}},
- {2465, {wxPreviewFrame, destruct, 0}},
- {2466, {wxPreviewFrame, createControlBar, 0}},
- {2467, {wxPreviewFrame, createCanvas, 0}},
- {2468, {wxPreviewFrame, initialize, 0}},
- {2469, {wxPreviewFrame, onCloseWindow, 1}},
- {2470, {wxPreviewControlBar, new, 4}},
- {2471, {wxPreviewControlBar, destruct, 0}},
- {2472, {wxPreviewControlBar, createButtons, 0}},
- {2473, {wxPreviewControlBar, getPrintPreview, 0}},
- {2474, {wxPreviewControlBar, getZoomControl, 0}},
- {2475, {wxPreviewControlBar, setZoomControl, 1}},
- {2477, {wxPrinter, new, 1}},
- {2478, {wxPrinter, createAbortWindow, 2}},
- {2479, {wxPrinter, getAbort, 0}},
- {2480, {wxPrinter, getLastError, 0}},
- {2481, {wxPrinter, getPrintDialogData, 0}},
- {2482, {wxPrinter, print, 3}},
- {2483, {wxPrinter, printDialog, 1}},
- {2484, {wxPrinter, reportError, 3}},
- {2485, {wxPrinter, setup, 1}},
- {2486, {wxPrinter, 'Destroy', undefined}},
- {2487, {wxXmlResource, new_1, 1}},
- {2488, {wxXmlResource, new_2, 2}},
- {2489, {wxXmlResource, destruct, 0}},
- {2490, {wxXmlResource, attachUnknownControl, 3}},
- {2491, {wxXmlResource, clearHandlers, 0}},
- {2492, {wxXmlResource, compareVersion, 4}},
- {2493, {wxXmlResource, get, 0}},
- {2494, {wxXmlResource, getFlags, 0}},
- {2495, {wxXmlResource, getVersion, 0}},
- {2496, {wxXmlResource, getXRCID, 2}},
- {2497, {wxXmlResource, initAllHandlers, 0}},
- {2498, {wxXmlResource, load, 1}},
- {2499, {wxXmlResource, loadBitmap, 1}},
- {2500, {wxXmlResource, loadDialog_2, 2}},
- {2501, {wxXmlResource, loadDialog_3, 3}},
- {2502, {wxXmlResource, loadFrame_2, 2}},
- {2503, {wxXmlResource, loadFrame_3, 3}},
- {2504, {wxXmlResource, loadIcon, 1}},
- {2505, {wxXmlResource, loadMenu, 1}},
- {2506, {wxXmlResource, loadMenuBar_2, 2}},
- {2507, {wxXmlResource, loadMenuBar_1, 1}},
- {2508, {wxXmlResource, loadPanel_2, 2}},
- {2509, {wxXmlResource, loadPanel_3, 3}},
- {2510, {wxXmlResource, loadToolBar, 2}},
- {2511, {wxXmlResource, set, 1}},
- {2512, {wxXmlResource, setFlags, 1}},
- {2513, {wxXmlResource, unload, 1}},
- {2514, {wxXmlResource, xrcctrl, 3}},
- {2515, {wxHtmlEasyPrinting, new, 1}},
- {2516, {wxHtmlEasyPrinting, destruct, 0}},
- {2517, {wxHtmlEasyPrinting, getPrintData, 0}},
- {2518, {wxHtmlEasyPrinting, getPageSetupData, 0}},
- {2519, {wxHtmlEasyPrinting, previewFile, 1}},
- {2520, {wxHtmlEasyPrinting, previewText, 2}},
- {2521, {wxHtmlEasyPrinting, printFile, 1}},
- {2522, {wxHtmlEasyPrinting, printText, 2}},
- {2523, {wxHtmlEasyPrinting, pageSetup, 0}},
- {2524, {wxHtmlEasyPrinting, setFonts, 3}},
- {2525, {wxHtmlEasyPrinting, setHeader, 2}},
- {2526, {wxHtmlEasyPrinting, setFooter, 2}},
- {2528, {wxGLCanvas, new_2, 2}},
- {2529, {wxGLCanvas, new_3_1, 3}},
- {2530, {wxGLCanvas, new_3_0, 3}},
- {2531, {wxGLCanvas, getContext, 0}},
- {2533, {wxGLCanvas, setCurrent, 0}},
- {2534, {wxGLCanvas, swapBuffers, 0}},
- {2535, {wxGLCanvas, 'Destroy', undefined}},
- {2536, {wxAuiManager, new, 1}},
- {2537, {wxAuiManager, destruct, 0}},
- {2538, {wxAuiManager, addPane_2_1, 2}},
- {2539, {wxAuiManager, addPane_3, 3}},
- {2540, {wxAuiManager, addPane_2_0, 2}},
- {2541, {wxAuiManager, detachPane, 1}},
- {2542, {wxAuiManager, getAllPanes, 0}},
- {2543, {wxAuiManager, getArtProvider, 0}},
- {2544, {wxAuiManager, getDockSizeConstraint, 2}},
- {2545, {wxAuiManager, getFlags, 0}},
- {2546, {wxAuiManager, getManagedWindow, 0}},
- {2547, {wxAuiManager, getManager, 1}},
- {2548, {wxAuiManager, getPane_1_1, 1}},
- {2549, {wxAuiManager, getPane_1_0, 1}},
- {2550, {wxAuiManager, hideHint, 0}},
- {2551, {wxAuiManager, insertPane, 3}},
- {2552, {wxAuiManager, loadPaneInfo, 2}},
- {2553, {wxAuiManager, loadPerspective, 2}},
- {2554, {wxAuiManager, savePaneInfo, 1}},
- {2555, {wxAuiManager, savePerspective, 0}},
- {2556, {wxAuiManager, setArtProvider, 1}},
- {2557, {wxAuiManager, setDockSizeConstraint, 2}},
- {2558, {wxAuiManager, setFlags, 1}},
- {2559, {wxAuiManager, setManagedWindow, 1}},
- {2560, {wxAuiManager, showHint, 1}},
- {2561, {wxAuiManager, unInit, 0}},
- {2562, {wxAuiManager, update, 0}},
- {2563, {wxAuiPaneInfo, new_0, 0}},
- {2564, {wxAuiPaneInfo, new_1, 1}},
- {2565, {wxAuiPaneInfo, destruct, 0}},
- {2566, {wxAuiPaneInfo, bestSize_1, 1}},
- {2567, {wxAuiPaneInfo, bestSize_2, 2}},
- {2568, {wxAuiPaneInfo, bottom, 0}},
- {2569, {wxAuiPaneInfo, bottomDockable, 1}},
- {2570, {wxAuiPaneInfo, caption, 1}},
- {2571, {wxAuiPaneInfo, captionVisible, 1}},
- {2572, {wxAuiPaneInfo, centre, 0}},
- {2573, {wxAuiPaneInfo, centrePane, 0}},
- {2574, {wxAuiPaneInfo, closeButton, 1}},
- {2575, {wxAuiPaneInfo, defaultPane, 0}},
- {2576, {wxAuiPaneInfo, destroyOnClose, 1}},
- {2577, {wxAuiPaneInfo, direction, 1}},
- {2578, {wxAuiPaneInfo, dock, 0}},
- {2579, {wxAuiPaneInfo, dockable, 1}},
- {2580, {wxAuiPaneInfo, fixed, 0}},
- {2581, {wxAuiPaneInfo, float, 0}},
- {2582, {wxAuiPaneInfo, floatable, 1}},
- {2583, {wxAuiPaneInfo, floatingPosition_1, 1}},
- {2584, {wxAuiPaneInfo, floatingPosition_2, 2}},
- {2585, {wxAuiPaneInfo, floatingSize_1, 1}},
- {2586, {wxAuiPaneInfo, floatingSize_2, 2}},
- {2587, {wxAuiPaneInfo, gripper, 1}},
- {2588, {wxAuiPaneInfo, gripperTop, 1}},
- {2589, {wxAuiPaneInfo, hasBorder, 0}},
- {2590, {wxAuiPaneInfo, hasCaption, 0}},
- {2591, {wxAuiPaneInfo, hasCloseButton, 0}},
- {2592, {wxAuiPaneInfo, hasFlag, 1}},
- {2593, {wxAuiPaneInfo, hasGripper, 0}},
- {2594, {wxAuiPaneInfo, hasGripperTop, 0}},
- {2595, {wxAuiPaneInfo, hasMaximizeButton, 0}},
- {2596, {wxAuiPaneInfo, hasMinimizeButton, 0}},
- {2597, {wxAuiPaneInfo, hasPinButton, 0}},
- {2598, {wxAuiPaneInfo, hide, 0}},
- {2599, {wxAuiPaneInfo, isBottomDockable, 0}},
- {2600, {wxAuiPaneInfo, isDocked, 0}},
- {2601, {wxAuiPaneInfo, isFixed, 0}},
- {2602, {wxAuiPaneInfo, isFloatable, 0}},
- {2603, {wxAuiPaneInfo, isFloating, 0}},
- {2604, {wxAuiPaneInfo, isLeftDockable, 0}},
- {2605, {wxAuiPaneInfo, isMovable, 0}},
- {2606, {wxAuiPaneInfo, isOk, 0}},
- {2607, {wxAuiPaneInfo, isResizable, 0}},
- {2608, {wxAuiPaneInfo, isRightDockable, 0}},
- {2609, {wxAuiPaneInfo, isShown, 0}},
- {2610, {wxAuiPaneInfo, isToolbar, 0}},
- {2611, {wxAuiPaneInfo, isTopDockable, 0}},
- {2612, {wxAuiPaneInfo, layer, 1}},
- {2613, {wxAuiPaneInfo, left, 0}},
- {2614, {wxAuiPaneInfo, leftDockable, 1}},
- {2615, {wxAuiPaneInfo, maxSize_1, 1}},
- {2616, {wxAuiPaneInfo, maxSize_2, 2}},
- {2617, {wxAuiPaneInfo, maximizeButton, 1}},
- {2618, {wxAuiPaneInfo, minSize_1, 1}},
- {2619, {wxAuiPaneInfo, minSize_2, 2}},
- {2620, {wxAuiPaneInfo, minimizeButton, 1}},
- {2621, {wxAuiPaneInfo, movable, 1}},
- {2622, {wxAuiPaneInfo, name, 1}},
- {2623, {wxAuiPaneInfo, paneBorder, 1}},
- {2624, {wxAuiPaneInfo, pinButton, 1}},
- {2625, {wxAuiPaneInfo, position, 1}},
- {2626, {wxAuiPaneInfo, resizable, 1}},
- {2627, {wxAuiPaneInfo, right, 0}},
- {2628, {wxAuiPaneInfo, rightDockable, 1}},
- {2629, {wxAuiPaneInfo, row, 1}},
- {2630, {wxAuiPaneInfo, safeSet, 1}},
- {2631, {wxAuiPaneInfo, setFlag, 2}},
- {2632, {wxAuiPaneInfo, show, 1}},
- {2633, {wxAuiPaneInfo, toolbarPane, 0}},
- {2634, {wxAuiPaneInfo, top, 0}},
- {2635, {wxAuiPaneInfo, topDockable, 1}},
- {2636, {wxAuiPaneInfo, window, 1}},
- {2637, {wxAuiNotebook, new_0, 0}},
- {2638, {wxAuiNotebook, new_2, 2}},
- {2639, {wxAuiNotebook, addPage, 3}},
- {2640, {wxAuiNotebook, create, 2}},
- {2641, {wxAuiNotebook, deletePage, 1}},
- {2642, {wxAuiNotebook, getArtProvider, 0}},
- {2643, {wxAuiNotebook, getPage, 1}},
- {2644, {wxAuiNotebook, getPageBitmap, 1}},
- {2645, {wxAuiNotebook, getPageCount, 0}},
- {2646, {wxAuiNotebook, getPageIndex, 1}},
- {2647, {wxAuiNotebook, getPageText, 1}},
- {2648, {wxAuiNotebook, getSelection, 0}},
- {2649, {wxAuiNotebook, insertPage, 4}},
- {2650, {wxAuiNotebook, removePage, 1}},
- {2651, {wxAuiNotebook, setArtProvider, 1}},
- {2652, {wxAuiNotebook, setFont, 1}},
- {2653, {wxAuiNotebook, setPageBitmap, 2}},
- {2654, {wxAuiNotebook, setPageText, 2}},
- {2655, {wxAuiNotebook, setSelection, 1}},
- {2656, {wxAuiNotebook, setTabCtrlHeight, 1}},
- {2657, {wxAuiNotebook, setUniformBitmapSize, 1}},
- {2658, {wxAuiNotebook, 'Destroy', undefined}},
- {2659, {wxMDIParentFrame, new_0, 0}},
- {2660, {wxMDIParentFrame, new_4, 4}},
- {2661, {wxMDIParentFrame, destruct, 0}},
- {2662, {wxMDIParentFrame, activateNext, 0}},
- {2663, {wxMDIParentFrame, activatePrevious, 0}},
- {2664, {wxMDIParentFrame, arrangeIcons, 0}},
- {2665, {wxMDIParentFrame, cascade, 0}},
- {2666, {wxMDIParentFrame, create, 4}},
- {2667, {wxMDIParentFrame, getActiveChild, 0}},
- {2668, {wxMDIParentFrame, getClientWindow, 0}},
- {2669, {wxMDIParentFrame, tile, 1}},
- {2670, {wxMDIChildFrame, new_0, 0}},
- {2671, {wxMDIChildFrame, new_4, 4}},
- {2672, {wxMDIChildFrame, destruct, 0}},
- {2673, {wxMDIChildFrame, activate, 0}},
- {2674, {wxMDIChildFrame, create, 4}},
- {2675, {wxMDIChildFrame, maximize, 1}},
- {2676, {wxMDIChildFrame, restore, 0}},
- {2677, {wxMDIClientWindow, new_0, 0}},
- {2678, {wxMDIClientWindow, new_2, 2}},
- {2679, {wxMDIClientWindow, destruct, 0}},
- {2680, {wxMDIClientWindow, createClient, 2}},
- {2681, {wxLayoutAlgorithm, new, 0}},
- {2682, {wxLayoutAlgorithm, layoutFrame, 2}},
- {2683, {wxLayoutAlgorithm, layoutMDIFrame, 2}},
- {2684, {wxLayoutAlgorithm, layoutWindow, 2}},
- {2685, {wxLayoutAlgorithm, 'Destroy', undefined}},
- {2686, {wxEvent, getId, 0}},
- {2687, {wxEvent, getSkipped, 0}},
- {2688, {wxEvent, getTimestamp, 0}},
- {2689, {wxEvent, isCommandEvent, 0}},
- {2690, {wxEvent, resumePropagation, 1}},
- {2691, {wxEvent, shouldPropagate, 0}},
- {2692, {wxEvent, skip, 1}},
- {2693, {wxEvent, stopPropagation, 0}},
- {2694, {wxCommandEvent, getClientData, 0}},
- {2695, {wxCommandEvent, getExtraLong, 0}},
- {2696, {wxCommandEvent, getInt, 0}},
- {2697, {wxCommandEvent, getSelection, 0}},
- {2698, {wxCommandEvent, getString, 0}},
- {2699, {wxCommandEvent, isChecked, 0}},
- {2700, {wxCommandEvent, isSelection, 0}},
- {2701, {wxCommandEvent, setInt, 1}},
- {2702, {wxCommandEvent, setString, 1}},
- {2703, {wxScrollEvent, getOrientation, 0}},
- {2704, {wxScrollEvent, getPosition, 0}},
- {2705, {wxScrollWinEvent, getOrientation, 0}},
- {2706, {wxScrollWinEvent, getPosition, 0}},
- {2707, {wxMouseEvent, altDown, 0}},
- {2708, {wxMouseEvent, button, 1}},
- {2709, {wxMouseEvent, buttonDClick, 1}},
- {2710, {wxMouseEvent, buttonDown, 1}},
- {2711, {wxMouseEvent, buttonUp, 1}},
- {2712, {wxMouseEvent, cmdDown, 0}},
- {2713, {wxMouseEvent, controlDown, 0}},
- {2714, {wxMouseEvent, dragging, 0}},
- {2715, {wxMouseEvent, entering, 0}},
- {2716, {wxMouseEvent, getButton, 0}},
- {2719, {wxMouseEvent, getPosition, 0}},
- {2720, {wxMouseEvent, getLogicalPosition, 1}},
- {2721, {wxMouseEvent, getLinesPerAction, 0}},
- {2722, {wxMouseEvent, getWheelRotation, 0}},
- {2723, {wxMouseEvent, getWheelDelta, 0}},
- {2724, {wxMouseEvent, getX, 0}},
- {2725, {wxMouseEvent, getY, 0}},
- {2726, {wxMouseEvent, isButton, 0}},
- {2727, {wxMouseEvent, isPageScroll, 0}},
- {2728, {wxMouseEvent, leaving, 0}},
- {2729, {wxMouseEvent, leftDClick, 0}},
- {2730, {wxMouseEvent, leftDown, 0}},
- {2731, {wxMouseEvent, leftIsDown, 0}},
- {2732, {wxMouseEvent, leftUp, 0}},
- {2733, {wxMouseEvent, metaDown, 0}},
- {2734, {wxMouseEvent, middleDClick, 0}},
- {2735, {wxMouseEvent, middleDown, 0}},
- {2736, {wxMouseEvent, middleIsDown, 0}},
- {2737, {wxMouseEvent, middleUp, 0}},
- {2738, {wxMouseEvent, moving, 0}},
- {2739, {wxMouseEvent, rightDClick, 0}},
- {2740, {wxMouseEvent, rightDown, 0}},
- {2741, {wxMouseEvent, rightIsDown, 0}},
- {2742, {wxMouseEvent, rightUp, 0}},
- {2743, {wxMouseEvent, shiftDown, 0}},
- {2744, {wxSetCursorEvent, getCursor, 0}},
- {2745, {wxSetCursorEvent, getX, 0}},
- {2746, {wxSetCursorEvent, getY, 0}},
- {2747, {wxSetCursorEvent, hasCursor, 0}},
- {2748, {wxSetCursorEvent, setCursor, 1}},
- {2749, {wxKeyEvent, altDown, 0}},
- {2750, {wxKeyEvent, cmdDown, 0}},
- {2751, {wxKeyEvent, controlDown, 0}},
- {2752, {wxKeyEvent, getKeyCode, 0}},
- {2753, {wxKeyEvent, getModifiers, 0}},
- {2756, {wxKeyEvent, getPosition, 0}},
- {2757, {wxKeyEvent, getRawKeyCode, 0}},
- {2758, {wxKeyEvent, getRawKeyFlags, 0}},
- {2759, {wxKeyEvent, getUnicodeKey, 0}},
- {2760, {wxKeyEvent, getX, 0}},
- {2761, {wxKeyEvent, getY, 0}},
- {2762, {wxKeyEvent, hasModifiers, 0}},
- {2763, {wxKeyEvent, metaDown, 0}},
- {2764, {wxKeyEvent, shiftDown, 0}},
- {2765, {wxSizeEvent, getSize, 0}},
- {2766, {wxMoveEvent, getPosition, 0}},
- {2767, {wxEraseEvent, getDC, 0}},
- {2768, {wxFocusEvent, getWindow, 0}},
- {2769, {wxChildFocusEvent, getWindow, 0}},
- {2770, {wxMenuEvent, getMenu, 0}},
- {2771, {wxMenuEvent, getMenuId, 0}},
- {2772, {wxMenuEvent, isPopup, 0}},
- {2773, {wxCloseEvent, canVeto, 0}},
- {2774, {wxCloseEvent, getLoggingOff, 0}},
- {2775, {wxCloseEvent, setCanVeto, 1}},
- {2776, {wxCloseEvent, setLoggingOff, 1}},
- {2777, {wxCloseEvent, veto, 1}},
- {2778, {wxShowEvent, setShow, 1}},
- {2779, {wxShowEvent, getShow, 0}},
- {2780, {wxIconizeEvent, iconized, 0}},
- {2781, {wxJoystickEvent, buttonDown, 1}},
- {2782, {wxJoystickEvent, buttonIsDown, 1}},
- {2783, {wxJoystickEvent, buttonUp, 1}},
- {2784, {wxJoystickEvent, getButtonChange, 0}},
- {2785, {wxJoystickEvent, getButtonState, 0}},
- {2786, {wxJoystickEvent, getJoystick, 0}},
- {2787, {wxJoystickEvent, getPosition, 0}},
- {2788, {wxJoystickEvent, getZPosition, 0}},
- {2789, {wxJoystickEvent, isButton, 0}},
- {2790, {wxJoystickEvent, isMove, 0}},
- {2791, {wxJoystickEvent, isZMove, 0}},
- {2792, {wxUpdateUIEvent, canUpdate, 1}},
- {2793, {wxUpdateUIEvent, check, 1}},
- {2794, {wxUpdateUIEvent, enable, 1}},
- {2795, {wxUpdateUIEvent, show, 1}},
- {2796, {wxUpdateUIEvent, getChecked, 0}},
- {2797, {wxUpdateUIEvent, getEnabled, 0}},
- {2798, {wxUpdateUIEvent, getShown, 0}},
- {2799, {wxUpdateUIEvent, getSetChecked, 0}},
- {2800, {wxUpdateUIEvent, getSetEnabled, 0}},
- {2801, {wxUpdateUIEvent, getSetShown, 0}},
- {2802, {wxUpdateUIEvent, getSetText, 0}},
- {2803, {wxUpdateUIEvent, getText, 0}},
- {2804, {wxUpdateUIEvent, getMode, 0}},
- {2805, {wxUpdateUIEvent, getUpdateInterval, 0}},
- {2806, {wxUpdateUIEvent, resetUpdateTime, 0}},
- {2807, {wxUpdateUIEvent, setMode, 1}},
- {2808, {wxUpdateUIEvent, setText, 1}},
- {2809, {wxUpdateUIEvent, setUpdateInterval, 1}},
- {2810, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}},
- {2811, {wxPaletteChangedEvent, setChangedWindow, 1}},
- {2812, {wxPaletteChangedEvent, getChangedWindow, 0}},
- {2813, {wxQueryNewPaletteEvent, setPaletteRealized, 1}},
- {2814, {wxQueryNewPaletteEvent, getPaletteRealized, 0}},
- {2815, {wxNavigationKeyEvent, getDirection, 0}},
- {2816, {wxNavigationKeyEvent, setDirection, 1}},
- {2817, {wxNavigationKeyEvent, isWindowChange, 0}},
- {2818, {wxNavigationKeyEvent, setWindowChange, 1}},
- {2819, {wxNavigationKeyEvent, isFromTab, 0}},
- {2820, {wxNavigationKeyEvent, setFromTab, 1}},
- {2821, {wxNavigationKeyEvent, getCurrentFocus, 0}},
- {2822, {wxNavigationKeyEvent, setCurrentFocus, 1}},
- {2823, {wxHelpEvent, getOrigin, 0}},
- {2824, {wxHelpEvent, getPosition, 0}},
- {2825, {wxHelpEvent, setOrigin, 1}},
- {2826, {wxHelpEvent, setPosition, 1}},
- {2827, {wxContextMenuEvent, getPosition, 0}},
- {2828, {wxContextMenuEvent, setPosition, 1}},
- {2829, {wxIdleEvent, canSend, 1}},
- {2830, {wxIdleEvent, getMode, 0}},
- {2831, {wxIdleEvent, requestMore, 1}},
- {2832, {wxIdleEvent, moreRequested, 0}},
- {2833, {wxIdleEvent, setMode, 1}},
- {2834, {wxGridEvent, altDown, 0}},
- {2835, {wxGridEvent, controlDown, 0}},
- {2836, {wxGridEvent, getCol, 0}},
- {2837, {wxGridEvent, getPosition, 0}},
- {2838, {wxGridEvent, getRow, 0}},
- {2839, {wxGridEvent, metaDown, 0}},
- {2840, {wxGridEvent, selecting, 0}},
- {2841, {wxGridEvent, shiftDown, 0}},
- {2842, {wxNotifyEvent, allow, 0}},
- {2843, {wxNotifyEvent, isAllowed, 0}},
- {2844, {wxNotifyEvent, veto, 0}},
- {2845, {wxSashEvent, getEdge, 0}},
- {2846, {wxSashEvent, getDragRect, 0}},
- {2847, {wxSashEvent, getDragStatus, 0}},
- {2848, {wxListEvent, getCacheFrom, 0}},
- {2849, {wxListEvent, getCacheTo, 0}},
- {2850, {wxListEvent, getKeyCode, 0}},
- {2851, {wxListEvent, getIndex, 0}},
- {2852, {wxListEvent, getColumn, 0}},
- {2853, {wxListEvent, getPoint, 0}},
- {2854, {wxListEvent, getLabel, 0}},
- {2855, {wxListEvent, getText, 0}},
- {2856, {wxListEvent, getImage, 0}},
- {2857, {wxListEvent, getData, 0}},
- {2858, {wxListEvent, getMask, 0}},
- {2859, {wxListEvent, getItem, 0}},
- {2860, {wxListEvent, isEditCancelled, 0}},
- {2861, {wxDateEvent, getDate, 0}},
- {2862, {wxCalendarEvent, getWeekDay, 0}},
- {2863, {wxFileDirPickerEvent, getPath, 0}},
- {2864, {wxColourPickerEvent, getColour, 0}},
- {2865, {wxFontPickerEvent, getFont, 0}},
- {2866, {wxStyledTextEvent, getPosition, 0}},
- {2867, {wxStyledTextEvent, getKey, 0}},
- {2868, {wxStyledTextEvent, getModifiers, 0}},
- {2869, {wxStyledTextEvent, getModificationType, 0}},
- {2870, {wxStyledTextEvent, getText, 0}},
- {2871, {wxStyledTextEvent, getLength, 0}},
- {2872, {wxStyledTextEvent, getLinesAdded, 0}},
- {2873, {wxStyledTextEvent, getLine, 0}},
- {2874, {wxStyledTextEvent, getFoldLevelNow, 0}},
- {2875, {wxStyledTextEvent, getFoldLevelPrev, 0}},
- {2876, {wxStyledTextEvent, getMargin, 0}},
- {2877, {wxStyledTextEvent, getMessage, 0}},
- {2878, {wxStyledTextEvent, getWParam, 0}},
- {2879, {wxStyledTextEvent, getLParam, 0}},
- {2880, {wxStyledTextEvent, getListType, 0}},
- {2881, {wxStyledTextEvent, getX, 0}},
- {2882, {wxStyledTextEvent, getY, 0}},
- {2883, {wxStyledTextEvent, getDragText, 0}},
- {2884, {wxStyledTextEvent, getDragAllowMove, 0}},
- {2885, {wxStyledTextEvent, getDragResult, 0}},
- {2886, {wxStyledTextEvent, getShift, 0}},
- {2887, {wxStyledTextEvent, getControl, 0}},
- {2888, {wxStyledTextEvent, getAlt, 0}},
- {2889, {utils, getKeyState, 1}},
- {2890, {utils, getMousePosition, 2}},
- {2891, {utils, getMouseState, 0}},
- {2892, {utils, setDetectableAutoRepeat, 1}},
- {2893, {utils, bell, 0}},
- {2894, {utils, findMenuItemId, 3}},
- {2895, {utils, genericFindWindowAtPoint, 1}},
- {2896, {utils, findWindowAtPoint, 1}},
- {2897, {utils, beginBusyCursor, 1}},
- {2898, {utils, endBusyCursor, 0}},
- {2899, {utils, isBusy, 0}},
- {2900, {utils, shutdown, 1}},
- {2901, {utils, shell, 1}},
- {2902, {utils, launchDefaultBrowser, 2}},
- {2903, {utils, getEmailAddress, 0}},
- {2904, {utils, getUserId, 0}},
- {2905, {utils, getHomeDir, 0}},
- {2906, {utils, newId, 0}},
- {2907, {utils, registerId, 1}},
- {2908, {utils, getCurrentId, 0}},
- {2909, {utils, getOsDescription, 0}},
- {2910, {utils, isPlatformLittleEndian, 0}},
- {2911, {utils, isPlatform64Bit, 0}},
- {2912, {wxPrintout, new, 1}},
- {2913, {wxPrintout, destruct, 0}},
- {2914, {wxPrintout, getDC, 0}},
- {2915, {wxPrintout, getPageSizeMM, 2}},
- {2916, {wxPrintout, getPageSizePixels, 2}},
- {2917, {wxPrintout, getPaperRectPixels, 0}},
- {2918, {wxPrintout, getPPIPrinter, 2}},
- {2919, {wxPrintout, getPPIScreen, 2}},
- {2920, {wxPrintout, getTitle, 0}},
- {2921, {wxPrintout, isPreview, 0}},
- {2922, {wxPrintout, fitThisSizeToPaper, 1}},
- {2923, {wxPrintout, fitThisSizeToPage, 1}},
- {2924, {wxPrintout, fitThisSizeToPageMargins, 2}},
- {2925, {wxPrintout, mapScreenSizeToPaper, 0}},
- {2926, {wxPrintout, mapScreenSizeToPage, 0}},
- {2927, {wxPrintout, mapScreenSizeToPageMargins, 1}},
- {2928, {wxPrintout, mapScreenSizeToDevice, 0}},
- {2929, {wxPrintout, getLogicalPaperRect, 0}},
- {2930, {wxPrintout, getLogicalPageRect, 0}},
- {2931, {wxPrintout, getLogicalPageMarginsRect, 1}},
- {2932, {wxPrintout, setLogicalOrigin, 2}},
- {2933, {wxPrintout, offsetLogicalOrigin, 2}},
- {2934, {wxStyledTextCtrl, new_2, 2}},
- {2935, {wxStyledTextCtrl, new_0, 0}},
- {2936, {wxStyledTextCtrl, destruct, 0}},
- {2937, {wxStyledTextCtrl, create, 2}},
- {2938, {wxStyledTextCtrl, addText, 1}},
- {2939, {wxStyledTextCtrl, addStyledText, 1}},
- {2940, {wxStyledTextCtrl, insertText, 2}},
- {2941, {wxStyledTextCtrl, clearAll, 0}},
- {2942, {wxStyledTextCtrl, clearDocumentStyle, 0}},
- {2943, {wxStyledTextCtrl, getLength, 0}},
- {2944, {wxStyledTextCtrl, getCharAt, 1}},
- {2945, {wxStyledTextCtrl, getCurrentPos, 0}},
- {2946, {wxStyledTextCtrl, getAnchor, 0}},
- {2947, {wxStyledTextCtrl, getStyleAt, 1}},
- {2948, {wxStyledTextCtrl, redo, 0}},
- {2949, {wxStyledTextCtrl, setUndoCollection, 1}},
- {2950, {wxStyledTextCtrl, selectAll, 0}},
- {2951, {wxStyledTextCtrl, setSavePoint, 0}},
- {2952, {wxStyledTextCtrl, getStyledText, 2}},
- {2953, {wxStyledTextCtrl, canRedo, 0}},
- {2954, {wxStyledTextCtrl, markerLineFromHandle, 1}},
- {2955, {wxStyledTextCtrl, markerDeleteHandle, 1}},
- {2956, {wxStyledTextCtrl, getUndoCollection, 0}},
- {2957, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
- {2958, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
- {2959, {wxStyledTextCtrl, positionFromPoint, 1}},
- {2960, {wxStyledTextCtrl, positionFromPointClose, 2}},
- {2961, {wxStyledTextCtrl, gotoLine, 1}},
- {2962, {wxStyledTextCtrl, gotoPos, 1}},
- {2963, {wxStyledTextCtrl, setAnchor, 1}},
- {2964, {wxStyledTextCtrl, getCurLine, 1}},
- {2965, {wxStyledTextCtrl, getEndStyled, 0}},
- {2966, {wxStyledTextCtrl, convertEOLs, 1}},
- {2967, {wxStyledTextCtrl, getEOLMode, 0}},
- {2968, {wxStyledTextCtrl, setEOLMode, 1}},
- {2969, {wxStyledTextCtrl, startStyling, 2}},
- {2970, {wxStyledTextCtrl, setStyling, 2}},
- {2971, {wxStyledTextCtrl, getBufferedDraw, 0}},
- {2972, {wxStyledTextCtrl, setBufferedDraw, 1}},
- {2973, {wxStyledTextCtrl, setTabWidth, 1}},
- {2974, {wxStyledTextCtrl, getTabWidth, 0}},
- {2975, {wxStyledTextCtrl, setCodePage, 1}},
- {2976, {wxStyledTextCtrl, markerDefine, 3}},
- {2977, {wxStyledTextCtrl, markerSetForeground, 2}},
- {2978, {wxStyledTextCtrl, markerSetBackground, 2}},
- {2979, {wxStyledTextCtrl, markerAdd, 2}},
- {2980, {wxStyledTextCtrl, markerDelete, 2}},
- {2981, {wxStyledTextCtrl, markerDeleteAll, 1}},
- {2982, {wxStyledTextCtrl, markerGet, 1}},
- {2983, {wxStyledTextCtrl, markerNext, 2}},
- {2984, {wxStyledTextCtrl, markerPrevious, 2}},
- {2985, {wxStyledTextCtrl, markerDefineBitmap, 2}},
- {2986, {wxStyledTextCtrl, markerAddSet, 2}},
- {2987, {wxStyledTextCtrl, markerSetAlpha, 2}},
- {2988, {wxStyledTextCtrl, setMarginType, 2}},
- {2989, {wxStyledTextCtrl, getMarginType, 1}},
- {2990, {wxStyledTextCtrl, setMarginWidth, 2}},
- {2991, {wxStyledTextCtrl, getMarginWidth, 1}},
- {2992, {wxStyledTextCtrl, setMarginMask, 2}},
- {2993, {wxStyledTextCtrl, getMarginMask, 1}},
- {2994, {wxStyledTextCtrl, setMarginSensitive, 2}},
- {2995, {wxStyledTextCtrl, getMarginSensitive, 1}},
- {2996, {wxStyledTextCtrl, styleClearAll, 0}},
- {2997, {wxStyledTextCtrl, styleSetForeground, 2}},
- {2998, {wxStyledTextCtrl, styleSetBackground, 2}},
- {2999, {wxStyledTextCtrl, styleSetBold, 2}},
- {3000, {wxStyledTextCtrl, styleSetItalic, 2}},
- {3001, {wxStyledTextCtrl, styleSetSize, 2}},
- {3002, {wxStyledTextCtrl, styleSetFaceName, 2}},
- {3003, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
- {3004, {wxStyledTextCtrl, styleResetDefault, 0}},
- {3005, {wxStyledTextCtrl, styleSetUnderline, 2}},
- {3006, {wxStyledTextCtrl, styleSetCase, 2}},
- {3007, {wxStyledTextCtrl, styleSetHotSpot, 2}},
- {3008, {wxStyledTextCtrl, setSelForeground, 2}},
- {3009, {wxStyledTextCtrl, setSelBackground, 2}},
- {3010, {wxStyledTextCtrl, getSelAlpha, 0}},
- {3011, {wxStyledTextCtrl, setSelAlpha, 1}},
- {3012, {wxStyledTextCtrl, setCaretForeground, 1}},
- {3013, {wxStyledTextCtrl, cmdKeyAssign, 3}},
- {3014, {wxStyledTextCtrl, cmdKeyClear, 2}},
- {3015, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
- {3016, {wxStyledTextCtrl, setStyleBytes, 2}},
- {3017, {wxStyledTextCtrl, styleSetVisible, 2}},
- {3018, {wxStyledTextCtrl, getCaretPeriod, 0}},
- {3019, {wxStyledTextCtrl, setCaretPeriod, 1}},
- {3020, {wxStyledTextCtrl, setWordChars, 1}},
- {3021, {wxStyledTextCtrl, beginUndoAction, 0}},
- {3022, {wxStyledTextCtrl, endUndoAction, 0}},
- {3023, {wxStyledTextCtrl, indicatorSetStyle, 2}},
- {3024, {wxStyledTextCtrl, indicatorGetStyle, 1}},
- {3025, {wxStyledTextCtrl, indicatorSetForeground, 2}},
- {3026, {wxStyledTextCtrl, indicatorGetForeground, 1}},
- {3027, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
- {3028, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
- {3029, {wxStyledTextCtrl, getStyleBits, 0}},
- {3030, {wxStyledTextCtrl, setLineState, 2}},
- {3031, {wxStyledTextCtrl, getLineState, 1}},
- {3032, {wxStyledTextCtrl, getMaxLineState, 0}},
- {3033, {wxStyledTextCtrl, getCaretLineVisible, 0}},
- {3034, {wxStyledTextCtrl, setCaretLineVisible, 1}},
- {3035, {wxStyledTextCtrl, getCaretLineBackground, 0}},
- {3036, {wxStyledTextCtrl, setCaretLineBackground, 1}},
- {3037, {wxStyledTextCtrl, autoCompShow, 2}},
- {3038, {wxStyledTextCtrl, autoCompCancel, 0}},
- {3039, {wxStyledTextCtrl, autoCompActive, 0}},
- {3040, {wxStyledTextCtrl, autoCompPosStart, 0}},
- {3041, {wxStyledTextCtrl, autoCompComplete, 0}},
- {3042, {wxStyledTextCtrl, autoCompStops, 1}},
- {3043, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
- {3044, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
- {3045, {wxStyledTextCtrl, autoCompSelect, 1}},
- {3046, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
- {3047, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
- {3048, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
- {3049, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
- {3050, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
- {3051, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
- {3052, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
- {3053, {wxStyledTextCtrl, userListShow, 2}},
- {3054, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
- {3055, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
- {3056, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
- {3057, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
- {3058, {wxStyledTextCtrl, registerImage, 2}},
- {3059, {wxStyledTextCtrl, clearRegisteredImages, 0}},
- {3060, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
- {3061, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
- {3062, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
- {3063, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
- {3064, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
- {3065, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
- {3066, {wxStyledTextCtrl, setIndent, 1}},
- {3067, {wxStyledTextCtrl, getIndent, 0}},
- {3068, {wxStyledTextCtrl, setUseTabs, 1}},
- {3069, {wxStyledTextCtrl, getUseTabs, 0}},
- {3070, {wxStyledTextCtrl, setLineIndentation, 2}},
- {3071, {wxStyledTextCtrl, getLineIndentation, 1}},
- {3072, {wxStyledTextCtrl, getLineIndentPosition, 1}},
- {3073, {wxStyledTextCtrl, getColumn, 1}},
- {3074, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
- {3075, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
- {3076, {wxStyledTextCtrl, setIndentationGuides, 1}},
- {3077, {wxStyledTextCtrl, getIndentationGuides, 0}},
- {3078, {wxStyledTextCtrl, setHighlightGuide, 1}},
- {3079, {wxStyledTextCtrl, getHighlightGuide, 0}},
- {3080, {wxStyledTextCtrl, getLineEndPosition, 1}},
- {3081, {wxStyledTextCtrl, getCodePage, 0}},
- {3082, {wxStyledTextCtrl, getCaretForeground, 0}},
- {3083, {wxStyledTextCtrl, getReadOnly, 0}},
- {3084, {wxStyledTextCtrl, setCurrentPos, 1}},
- {3085, {wxStyledTextCtrl, setSelectionStart, 1}},
- {3086, {wxStyledTextCtrl, getSelectionStart, 0}},
- {3087, {wxStyledTextCtrl, setSelectionEnd, 1}},
- {3088, {wxStyledTextCtrl, getSelectionEnd, 0}},
- {3089, {wxStyledTextCtrl, setPrintMagnification, 1}},
- {3090, {wxStyledTextCtrl, getPrintMagnification, 0}},
- {3091, {wxStyledTextCtrl, setPrintColourMode, 1}},
- {3092, {wxStyledTextCtrl, getPrintColourMode, 0}},
- {3093, {wxStyledTextCtrl, findText, 4}},
- {3094, {wxStyledTextCtrl, formatRange, 7}},
- {3095, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
- {3096, {wxStyledTextCtrl, getLine, 1}},
- {3097, {wxStyledTextCtrl, getLineCount, 0}},
- {3098, {wxStyledTextCtrl, setMarginLeft, 1}},
- {3099, {wxStyledTextCtrl, getMarginLeft, 0}},
- {3100, {wxStyledTextCtrl, setMarginRight, 1}},
- {3101, {wxStyledTextCtrl, getMarginRight, 0}},
- {3102, {wxStyledTextCtrl, getModify, 0}},
- {3103, {wxStyledTextCtrl, setSelection, 2}},
- {3104, {wxStyledTextCtrl, getSelectedText, 0}},
- {3105, {wxStyledTextCtrl, getTextRange, 2}},
- {3106, {wxStyledTextCtrl, hideSelection, 1}},
- {3107, {wxStyledTextCtrl, lineFromPosition, 1}},
- {3108, {wxStyledTextCtrl, positionFromLine, 1}},
- {3109, {wxStyledTextCtrl, lineScroll, 2}},
- {3110, {wxStyledTextCtrl, ensureCaretVisible, 0}},
- {3111, {wxStyledTextCtrl, replaceSelection, 1}},
- {3112, {wxStyledTextCtrl, setReadOnly, 1}},
- {3113, {wxStyledTextCtrl, canPaste, 0}},
- {3114, {wxStyledTextCtrl, canUndo, 0}},
- {3115, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
- {3116, {wxStyledTextCtrl, undo, 0}},
- {3117, {wxStyledTextCtrl, cut, 0}},
- {3118, {wxStyledTextCtrl, copy, 0}},
- {3119, {wxStyledTextCtrl, paste, 0}},
- {3120, {wxStyledTextCtrl, clear, 0}},
- {3121, {wxStyledTextCtrl, setText, 1}},
- {3122, {wxStyledTextCtrl, getText, 0}},
- {3123, {wxStyledTextCtrl, getTextLength, 0}},
- {3124, {wxStyledTextCtrl, getOvertype, 0}},
- {3125, {wxStyledTextCtrl, setCaretWidth, 1}},
- {3126, {wxStyledTextCtrl, getCaretWidth, 0}},
- {3127, {wxStyledTextCtrl, setTargetStart, 1}},
- {3128, {wxStyledTextCtrl, getTargetStart, 0}},
- {3129, {wxStyledTextCtrl, setTargetEnd, 1}},
- {3130, {wxStyledTextCtrl, getTargetEnd, 0}},
- {3131, {wxStyledTextCtrl, replaceTarget, 1}},
- {3132, {wxStyledTextCtrl, searchInTarget, 1}},
- {3133, {wxStyledTextCtrl, setSearchFlags, 1}},
- {3134, {wxStyledTextCtrl, getSearchFlags, 0}},
- {3135, {wxStyledTextCtrl, callTipShow, 2}},
- {3136, {wxStyledTextCtrl, callTipCancel, 0}},
- {3137, {wxStyledTextCtrl, callTipActive, 0}},
- {3138, {wxStyledTextCtrl, callTipPosAtStart, 0}},
- {3139, {wxStyledTextCtrl, callTipSetHighlight, 2}},
- {3140, {wxStyledTextCtrl, callTipSetBackground, 1}},
- {3141, {wxStyledTextCtrl, callTipSetForeground, 1}},
- {3142, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
- {3143, {wxStyledTextCtrl, callTipUseStyle, 1}},
- {3144, {wxStyledTextCtrl, visibleFromDocLine, 1}},
- {3145, {wxStyledTextCtrl, docLineFromVisible, 1}},
- {3146, {wxStyledTextCtrl, wrapCount, 1}},
- {3147, {wxStyledTextCtrl, setFoldLevel, 2}},
- {3148, {wxStyledTextCtrl, getFoldLevel, 1}},
- {3149, {wxStyledTextCtrl, getLastChild, 2}},
- {3150, {wxStyledTextCtrl, getFoldParent, 1}},
- {3151, {wxStyledTextCtrl, showLines, 2}},
- {3152, {wxStyledTextCtrl, hideLines, 2}},
- {3153, {wxStyledTextCtrl, getLineVisible, 1}},
- {3154, {wxStyledTextCtrl, setFoldExpanded, 2}},
- {3155, {wxStyledTextCtrl, getFoldExpanded, 1}},
- {3156, {wxStyledTextCtrl, toggleFold, 1}},
- {3157, {wxStyledTextCtrl, ensureVisible, 1}},
- {3158, {wxStyledTextCtrl, setFoldFlags, 1}},
- {3159, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
- {3160, {wxStyledTextCtrl, setTabIndents, 1}},
- {3161, {wxStyledTextCtrl, getTabIndents, 0}},
- {3162, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
- {3163, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
- {3164, {wxStyledTextCtrl, setMouseDwellTime, 1}},
- {3165, {wxStyledTextCtrl, getMouseDwellTime, 0}},
- {3166, {wxStyledTextCtrl, wordStartPosition, 2}},
- {3167, {wxStyledTextCtrl, wordEndPosition, 2}},
- {3168, {wxStyledTextCtrl, setWrapMode, 1}},
- {3169, {wxStyledTextCtrl, getWrapMode, 0}},
- {3170, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
- {3171, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
- {3172, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
- {3173, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
- {3174, {wxStyledTextCtrl, setWrapStartIndent, 1}},
- {3175, {wxStyledTextCtrl, getWrapStartIndent, 0}},
- {3176, {wxStyledTextCtrl, setLayoutCache, 1}},
- {3177, {wxStyledTextCtrl, getLayoutCache, 0}},
- {3178, {wxStyledTextCtrl, setScrollWidth, 1}},
- {3179, {wxStyledTextCtrl, getScrollWidth, 0}},
- {3180, {wxStyledTextCtrl, textWidth, 2}},
- {3181, {wxStyledTextCtrl, getEndAtLastLine, 0}},
- {3182, {wxStyledTextCtrl, textHeight, 1}},
- {3183, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
- {3184, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
- {3185, {wxStyledTextCtrl, appendText, 1}},
- {3186, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
- {3187, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
- {3188, {wxStyledTextCtrl, targetFromSelection, 0}},
- {3189, {wxStyledTextCtrl, linesJoin, 0}},
- {3190, {wxStyledTextCtrl, linesSplit, 1}},
- {3191, {wxStyledTextCtrl, setFoldMarginColour, 2}},
- {3192, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
- {3193, {wxStyledTextCtrl, lineDown, 0}},
- {3194, {wxStyledTextCtrl, lineDownExtend, 0}},
- {3195, {wxStyledTextCtrl, lineUp, 0}},
- {3196, {wxStyledTextCtrl, lineUpExtend, 0}},
- {3197, {wxStyledTextCtrl, charLeft, 0}},
- {3198, {wxStyledTextCtrl, charLeftExtend, 0}},
- {3199, {wxStyledTextCtrl, charRight, 0}},
- {3200, {wxStyledTextCtrl, charRightExtend, 0}},
- {3201, {wxStyledTextCtrl, wordLeft, 0}},
- {3202, {wxStyledTextCtrl, wordLeftExtend, 0}},
- {3203, {wxStyledTextCtrl, wordRight, 0}},
- {3204, {wxStyledTextCtrl, wordRightExtend, 0}},
- {3205, {wxStyledTextCtrl, home, 0}},
- {3206, {wxStyledTextCtrl, homeExtend, 0}},
- {3207, {wxStyledTextCtrl, lineEnd, 0}},
- {3208, {wxStyledTextCtrl, lineEndExtend, 0}},
- {3209, {wxStyledTextCtrl, documentStart, 0}},
- {3210, {wxStyledTextCtrl, documentStartExtend, 0}},
- {3211, {wxStyledTextCtrl, documentEnd, 0}},
- {3212, {wxStyledTextCtrl, documentEndExtend, 0}},
- {3213, {wxStyledTextCtrl, pageUp, 0}},
- {3214, {wxStyledTextCtrl, pageUpExtend, 0}},
- {3215, {wxStyledTextCtrl, pageDown, 0}},
- {3216, {wxStyledTextCtrl, pageDownExtend, 0}},
- {3217, {wxStyledTextCtrl, editToggleOvertype, 0}},
- {3218, {wxStyledTextCtrl, cancel, 0}},
- {3219, {wxStyledTextCtrl, deleteBack, 0}},
- {3220, {wxStyledTextCtrl, tab, 0}},
- {3221, {wxStyledTextCtrl, backTab, 0}},
- {3222, {wxStyledTextCtrl, newLine, 0}},
- {3223, {wxStyledTextCtrl, formFeed, 0}},
- {3224, {wxStyledTextCtrl, vCHome, 0}},
- {3225, {wxStyledTextCtrl, vCHomeExtend, 0}},
- {3226, {wxStyledTextCtrl, zoomIn, 0}},
- {3227, {wxStyledTextCtrl, zoomOut, 0}},
- {3228, {wxStyledTextCtrl, delWordLeft, 0}},
- {3229, {wxStyledTextCtrl, delWordRight, 0}},
- {3230, {wxStyledTextCtrl, lineCut, 0}},
- {3231, {wxStyledTextCtrl, lineDelete, 0}},
- {3232, {wxStyledTextCtrl, lineTranspose, 0}},
- {3233, {wxStyledTextCtrl, lineDuplicate, 0}},
- {3234, {wxStyledTextCtrl, lowerCase, 0}},
- {3235, {wxStyledTextCtrl, upperCase, 0}},
- {3236, {wxStyledTextCtrl, lineScrollDown, 0}},
- {3237, {wxStyledTextCtrl, lineScrollUp, 0}},
- {3238, {wxStyledTextCtrl, deleteBackNotLine, 0}},
- {3239, {wxStyledTextCtrl, homeDisplay, 0}},
- {3240, {wxStyledTextCtrl, homeDisplayExtend, 0}},
- {3241, {wxStyledTextCtrl, lineEndDisplay, 0}},
- {3242, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
- {3243, {wxStyledTextCtrl, homeWrapExtend, 0}},
- {3244, {wxStyledTextCtrl, lineEndWrap, 0}},
- {3245, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
- {3246, {wxStyledTextCtrl, vCHomeWrap, 0}},
- {3247, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
- {3248, {wxStyledTextCtrl, lineCopy, 0}},
- {3249, {wxStyledTextCtrl, moveCaretInsideView, 0}},
- {3250, {wxStyledTextCtrl, lineLength, 1}},
- {3251, {wxStyledTextCtrl, braceHighlight, 2}},
- {3252, {wxStyledTextCtrl, braceBadLight, 1}},
- {3253, {wxStyledTextCtrl, braceMatch, 1}},
- {3254, {wxStyledTextCtrl, getViewEOL, 0}},
- {3255, {wxStyledTextCtrl, setViewEOL, 1}},
- {3256, {wxStyledTextCtrl, setModEventMask, 1}},
- {3257, {wxStyledTextCtrl, getEdgeColumn, 0}},
- {3258, {wxStyledTextCtrl, setEdgeColumn, 1}},
- {3259, {wxStyledTextCtrl, getEdgeMode, 0}},
- {3260, {wxStyledTextCtrl, getEdgeColour, 0}},
- {3261, {wxStyledTextCtrl, setEdgeColour, 1}},
- {3262, {wxStyledTextCtrl, searchAnchor, 0}},
- {3263, {wxStyledTextCtrl, searchNext, 2}},
- {3264, {wxStyledTextCtrl, searchPrev, 2}},
- {3265, {wxStyledTextCtrl, linesOnScreen, 0}},
- {3266, {wxStyledTextCtrl, usePopUp, 1}},
- {3267, {wxStyledTextCtrl, selectionIsRectangle, 0}},
- {3268, {wxStyledTextCtrl, setZoom, 1}},
- {3269, {wxStyledTextCtrl, getZoom, 0}},
- {3270, {wxStyledTextCtrl, getModEventMask, 0}},
- {3271, {wxStyledTextCtrl, setSTCFocus, 1}},
- {3272, {wxStyledTextCtrl, getSTCFocus, 0}},
- {3273, {wxStyledTextCtrl, setStatus, 1}},
- {3274, {wxStyledTextCtrl, getStatus, 0}},
- {3275, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
- {3276, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
- {3277, {wxStyledTextCtrl, setSTCCursor, 1}},
- {3278, {wxStyledTextCtrl, getSTCCursor, 0}},
- {3279, {wxStyledTextCtrl, setControlCharSymbol, 1}},
- {3280, {wxStyledTextCtrl, getControlCharSymbol, 0}},
- {3281, {wxStyledTextCtrl, wordPartLeft, 0}},
- {3282, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
- {3283, {wxStyledTextCtrl, wordPartRight, 0}},
- {3284, {wxStyledTextCtrl, wordPartRightExtend, 0}},
- {3285, {wxStyledTextCtrl, setVisiblePolicy, 2}},
- {3286, {wxStyledTextCtrl, delLineLeft, 0}},
- {3287, {wxStyledTextCtrl, delLineRight, 0}},
- {3288, {wxStyledTextCtrl, getXOffset, 0}},
- {3289, {wxStyledTextCtrl, chooseCaretX, 0}},
- {3290, {wxStyledTextCtrl, setXCaretPolicy, 2}},
- {3291, {wxStyledTextCtrl, setYCaretPolicy, 2}},
- {3292, {wxStyledTextCtrl, getPrintWrapMode, 0}},
- {3293, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
- {3294, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
- {3295, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
- {3296, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
- {3297, {wxStyledTextCtrl, paraDownExtend, 0}},
- {3298, {wxStyledTextCtrl, paraUp, 0}},
- {3299, {wxStyledTextCtrl, paraUpExtend, 0}},
- {3300, {wxStyledTextCtrl, positionBefore, 1}},
- {3301, {wxStyledTextCtrl, positionAfter, 1}},
- {3302, {wxStyledTextCtrl, copyRange, 2}},
- {3303, {wxStyledTextCtrl, copyText, 2}},
- {3304, {wxStyledTextCtrl, setSelectionMode, 1}},
- {3305, {wxStyledTextCtrl, getSelectionMode, 0}},
- {3306, {wxStyledTextCtrl, lineDownRectExtend, 0}},
- {3307, {wxStyledTextCtrl, lineUpRectExtend, 0}},
- {3308, {wxStyledTextCtrl, charLeftRectExtend, 0}},
- {3309, {wxStyledTextCtrl, charRightRectExtend, 0}},
- {3310, {wxStyledTextCtrl, homeRectExtend, 0}},
- {3311, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
- {3312, {wxStyledTextCtrl, lineEndRectExtend, 0}},
- {3313, {wxStyledTextCtrl, pageUpRectExtend, 0}},
- {3314, {wxStyledTextCtrl, pageDownRectExtend, 0}},
- {3315, {wxStyledTextCtrl, stutteredPageUp, 0}},
- {3316, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
- {3317, {wxStyledTextCtrl, stutteredPageDown, 0}},
- {3318, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
- {3319, {wxStyledTextCtrl, wordLeftEnd, 0}},
- {3320, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
- {3321, {wxStyledTextCtrl, wordRightEnd, 0}},
- {3322, {wxStyledTextCtrl, wordRightEndExtend, 0}},
- {3323, {wxStyledTextCtrl, setWhitespaceChars, 1}},
- {3324, {wxStyledTextCtrl, setCharsDefault, 0}},
- {3325, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
- {3326, {wxStyledTextCtrl, allocate, 1}},
- {3327, {wxStyledTextCtrl, findColumn, 2}},
- {3328, {wxStyledTextCtrl, getCaretSticky, 0}},
- {3329, {wxStyledTextCtrl, setCaretSticky, 1}},
- {3330, {wxStyledTextCtrl, toggleCaretSticky, 0}},
- {3331, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
- {3332, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
- {3333, {wxStyledTextCtrl, selectionDuplicate, 0}},
- {3334, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
- {3335, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
- {3336, {wxStyledTextCtrl, startRecord, 0}},
- {3337, {wxStyledTextCtrl, stopRecord, 0}},
- {3338, {wxStyledTextCtrl, setLexer, 1}},
- {3339, {wxStyledTextCtrl, getLexer, 0}},
- {3340, {wxStyledTextCtrl, colourise, 2}},
- {3341, {wxStyledTextCtrl, setProperty, 2}},
- {3342, {wxStyledTextCtrl, setKeyWords, 2}},
- {3343, {wxStyledTextCtrl, setLexerLanguage, 1}},
- {3344, {wxStyledTextCtrl, getProperty, 1}},
- {3345, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
- {3346, {wxStyledTextCtrl, getCurrentLine, 0}},
- {3347, {wxStyledTextCtrl, styleSetSpec, 2}},
- {3348, {wxStyledTextCtrl, styleSetFont, 2}},
- {3349, {wxStyledTextCtrl, styleSetFontAttr, 7}},
- {3350, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
- {3351, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
- {3352, {wxStyledTextCtrl, cmdKeyExecute, 1}},
- {3353, {wxStyledTextCtrl, setMargins, 2}},
- {3354, {wxStyledTextCtrl, getSelection, 2}},
- {3355, {wxStyledTextCtrl, pointFromPosition, 1}},
- {3356, {wxStyledTextCtrl, scrollToLine, 1}},
- {3357, {wxStyledTextCtrl, scrollToColumn, 1}},
- {3358, {wxStyledTextCtrl, sendMsg, 2}},
- {3359, {wxStyledTextCtrl, setVScrollBar, 1}},
- {3360, {wxStyledTextCtrl, setHScrollBar, 1}},
- {3361, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
- {3362, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
- {3363, {wxStyledTextCtrl, saveFile, 1}},
- {3364, {wxStyledTextCtrl, loadFile, 1}},
- {3365, {wxStyledTextCtrl, doDragOver, 3}},
- {3366, {wxStyledTextCtrl, doDropText, 3}},
- {3367, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
- {3368, {wxStyledTextCtrl, addTextRaw, 1}},
- {3369, {wxStyledTextCtrl, insertTextRaw, 2}},
- {3370, {wxStyledTextCtrl, getCurLineRaw, 1}},
- {3371, {wxStyledTextCtrl, getLineRaw, 1}},
- {3372, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
- {3373, {wxStyledTextCtrl, getTextRangeRaw, 2}},
- {3374, {wxStyledTextCtrl, setTextRaw, 1}},
- {3375, {wxStyledTextCtrl, getTextRaw, 0}},
- {3376, {wxStyledTextCtrl, appendTextRaw, 1}},
- {3377, {wxArtProvider, getBitmap, 2}},
- {3378, {wxArtProvider, getIcon, 2}},
- {3379, {wxTreeEvent, getKeyCode, 0}},
- {3380, {wxTreeEvent, getItem, 0}},
- {3381, {wxTreeEvent, getKeyEvent, 0}},
- {3382, {wxTreeEvent, getLabel, 0}},
- {3383, {wxTreeEvent, getOldItem, 0}},
- {3384, {wxTreeEvent, getPoint, 0}},
- {3385, {wxTreeEvent, isEditCancelled, 0}},
- {3386, {wxTreeEvent, setToolTip, 1}},
- {3387, {wxNotebookEvent, getOldSelection, 0}},
- {3388, {wxNotebookEvent, getSelection, 0}},
- {3389, {wxNotebookEvent, setOldSelection, 1}},
- {3390, {wxNotebookEvent, setSelection, 1}},
- {3391, {wxFileDataObject, new, 0}},
- {3392, {wxFileDataObject, addFile, 1}},
- {3393, {wxFileDataObject, getFilenames, 0}},
- {3394, {wxFileDataObject, 'Destroy', undefined}},
- {3395, {wxTextDataObject, new, 1}},
- {3396, {wxTextDataObject, getTextLength, 0}},
- {3397, {wxTextDataObject, getText, 0}},
- {3398, {wxTextDataObject, setText, 1}},
- {3399, {wxTextDataObject, 'Destroy', undefined}},
- {3400, {wxBitmapDataObject, new_1_1, 1}},
- {3401, {wxBitmapDataObject, new_1_0, 1}},
- {3402, {wxBitmapDataObject, getBitmap, 0}},
- {3403, {wxBitmapDataObject, setBitmap, 1}},
- {3404, {wxBitmapDataObject, 'Destroy', undefined}},
- {3406, {wxClipboard, new, 0}},
- {3407, {wxClipboard, destruct, 0}},
- {3408, {wxClipboard, addData, 1}},
- {3409, {wxClipboard, clear, 0}},
- {3410, {wxClipboard, close, 0}},
- {3411, {wxClipboard, flush, 0}},
- {3412, {wxClipboard, getData, 1}},
- {3413, {wxClipboard, isOpened, 0}},
- {3414, {wxClipboard, open, 0}},
- {3415, {wxClipboard, setData, 1}},
- {3417, {wxClipboard, usePrimarySelection, 1}},
- {3418, {wxClipboard, isSupported, 1}},
- {3419, {wxClipboard, get, 0}},
- {3420, {wxSpinEvent, getPosition, 0}},
- {3421, {wxSpinEvent, setPosition, 1}},
- {3422, {wxSplitterWindow, new_0, 0}},
- {3423, {wxSplitterWindow, new_2, 2}},
- {3424, {wxSplitterWindow, destruct, 0}},
- {3425, {wxSplitterWindow, create, 2}},
- {3426, {wxSplitterWindow, getMinimumPaneSize, 0}},
- {3427, {wxSplitterWindow, getSashGravity, 0}},
- {3428, {wxSplitterWindow, getSashPosition, 0}},
- {3429, {wxSplitterWindow, getSplitMode, 0}},
- {3430, {wxSplitterWindow, getWindow1, 0}},
- {3431, {wxSplitterWindow, getWindow2, 0}},
- {3432, {wxSplitterWindow, initialize, 1}},
- {3433, {wxSplitterWindow, isSplit, 0}},
- {3434, {wxSplitterWindow, replaceWindow, 2}},
- {3435, {wxSplitterWindow, setSashGravity, 1}},
- {3436, {wxSplitterWindow, setSashPosition, 2}},
- {3437, {wxSplitterWindow, setSashSize, 1}},
- {3438, {wxSplitterWindow, setMinimumPaneSize, 1}},
- {3439, {wxSplitterWindow, setSplitMode, 1}},
- {3440, {wxSplitterWindow, splitHorizontally, 3}},
- {3441, {wxSplitterWindow, splitVertically, 3}},
- {3442, {wxSplitterWindow, unsplit, 1}},
- {3443, {wxSplitterWindow, updateSize, 0}},
- {3444, {wxSplitterEvent, getSashPosition, 0}},
- {3445, {wxSplitterEvent, getX, 0}},
- {3446, {wxSplitterEvent, getY, 0}},
- {3447, {wxSplitterEvent, getWindowBeingRemoved, 0}},
- {3448, {wxSplitterEvent, setSashPosition, 1}},
- {3449, {wxHtmlWindow, new_0, 0}},
- {3450, {wxHtmlWindow, new_2, 2}},
- {3451, {wxHtmlWindow, appendToPage, 1}},
- {3452, {wxHtmlWindow, getOpenedAnchor, 0}},
- {3453, {wxHtmlWindow, getOpenedPage, 0}},
- {3454, {wxHtmlWindow, getOpenedPageTitle, 0}},
- {3455, {wxHtmlWindow, getRelatedFrame, 0}},
- {3456, {wxHtmlWindow, historyBack, 0}},
- {3457, {wxHtmlWindow, historyCanBack, 0}},
- {3458, {wxHtmlWindow, historyCanForward, 0}},
- {3459, {wxHtmlWindow, historyClear, 0}},
- {3460, {wxHtmlWindow, historyForward, 0}},
- {3461, {wxHtmlWindow, loadFile, 1}},
- {3462, {wxHtmlWindow, loadPage, 1}},
- {3463, {wxHtmlWindow, selectAll, 0}},
- {3464, {wxHtmlWindow, selectionToText, 0}},
- {3465, {wxHtmlWindow, selectLine, 1}},
- {3466, {wxHtmlWindow, selectWord, 1}},
- {3467, {wxHtmlWindow, setBorders, 1}},
- {3468, {wxHtmlWindow, setFonts, 3}},
- {3469, {wxHtmlWindow, setPage, 1}},
- {3470, {wxHtmlWindow, setRelatedFrame, 2}},
- {3471, {wxHtmlWindow, setRelatedStatusBar, 1}},
- {3472, {wxHtmlWindow, toText, 0}},
- {3473, {wxHtmlWindow, 'Destroy', undefined}},
- {3474, {wxHtmlLinkEvent, getLinkInfo, 0}},
- {3475, {wxAuiNotebookEvent, setSelection, 1}},
- {3476, {wxAuiNotebookEvent, getSelection, 0}},
- {3477, {wxAuiNotebookEvent, setOldSelection, 1}},
- {3478, {wxAuiNotebookEvent, getOldSelection, 0}},
- {3479, {wxAuiNotebookEvent, setDragSource, 1}},
- {3480, {wxAuiNotebookEvent, getDragSource, 0}},
- {3481, {wxAuiManagerEvent, setManager, 1}},
- {3482, {wxAuiManagerEvent, getManager, 0}},
- {3483, {wxAuiManagerEvent, setPane, 1}},
- {3484, {wxAuiManagerEvent, getPane, 0}},
- {3485, {wxAuiManagerEvent, setButton, 1}},
- {3486, {wxAuiManagerEvent, getButton, 0}},
- {3487, {wxAuiManagerEvent, setDC, 1}},
- {3488, {wxAuiManagerEvent, getDC, 0}},
- {3489, {wxAuiManagerEvent, veto, 1}},
- {3490, {wxAuiManagerEvent, getVeto, 0}},
- {3491, {wxAuiManagerEvent, setCanVeto, 1}},
- {3492, {wxAuiManagerEvent, canVeto, 0}},
- {3493, {wxLogNull, new, 0}},
- {3494, {wxLogNull, 'Destroy', undefined}},
+ {2010, {wxTreeCtrl, editLabel, 1}},
+ {2011, {wxTreeCtrl, ensureVisible, 1}},
+ {2012, {wxTreeCtrl, expand, 1}},
+ {2013, {wxTreeCtrl, getBoundingRect, 3}},
+ {2015, {wxTreeCtrl, getChildrenCount, 2}},
+ {2016, {wxTreeCtrl, getCount, 0}},
+ {2017, {wxTreeCtrl, getEditControl, 0}},
+ {2018, {wxTreeCtrl, getFirstChild, 2}},
+ {2019, {wxTreeCtrl, getNextChild, 2}},
+ {2020, {wxTreeCtrl, getFirstVisibleItem, 0}},
+ {2021, {wxTreeCtrl, getImageList, 0}},
+ {2022, {wxTreeCtrl, getIndent, 0}},
+ {2023, {wxTreeCtrl, getItemBackgroundColour, 1}},
+ {2024, {wxTreeCtrl, getItemData, 1}},
+ {2025, {wxTreeCtrl, getItemFont, 1}},
+ {2026, {wxTreeCtrl, getItemImage_1, 1}},
+ {2027, {wxTreeCtrl, getItemImage_2, 2}},
+ {2028, {wxTreeCtrl, getItemText, 1}},
+ {2029, {wxTreeCtrl, getItemTextColour, 1}},
+ {2030, {wxTreeCtrl, getLastChild, 1}},
+ {2031, {wxTreeCtrl, getNextSibling, 1}},
+ {2032, {wxTreeCtrl, getNextVisible, 1}},
+ {2033, {wxTreeCtrl, getItemParent, 1}},
+ {2034, {wxTreeCtrl, getPrevSibling, 1}},
+ {2035, {wxTreeCtrl, getPrevVisible, 1}},
+ {2036, {wxTreeCtrl, getRootItem, 0}},
+ {2037, {wxTreeCtrl, getSelection, 0}},
+ {2038, {wxTreeCtrl, getSelections, 1}},
+ {2039, {wxTreeCtrl, getStateImageList, 0}},
+ {2040, {wxTreeCtrl, hitTest, 1}},
+ {2042, {wxTreeCtrl, insertItem, 4}},
+ {2043, {wxTreeCtrl, isBold, 1}},
+ {2044, {wxTreeCtrl, isExpanded, 1}},
+ {2045, {wxTreeCtrl, isSelected, 1}},
+ {2046, {wxTreeCtrl, isVisible, 1}},
+ {2047, {wxTreeCtrl, itemHasChildren, 1}},
+ {2048, {wxTreeCtrl, prependItem, 3}},
+ {2049, {wxTreeCtrl, scrollTo, 1}},
+ {2050, {wxTreeCtrl, selectItem_1, 1}},
+ {2051, {wxTreeCtrl, selectItem_2, 2}},
+ {2052, {wxTreeCtrl, setIndent, 1}},
+ {2053, {wxTreeCtrl, setImageList, 1}},
+ {2054, {wxTreeCtrl, setItemBackgroundColour, 2}},
+ {2055, {wxTreeCtrl, setItemBold, 2}},
+ {2056, {wxTreeCtrl, setItemData, 2}},
+ {2057, {wxTreeCtrl, setItemDropHighlight, 2}},
+ {2058, {wxTreeCtrl, setItemFont, 2}},
+ {2059, {wxTreeCtrl, setItemHasChildren, 2}},
+ {2060, {wxTreeCtrl, setItemImage_2, 2}},
+ {2061, {wxTreeCtrl, setItemImage_3, 3}},
+ {2062, {wxTreeCtrl, setItemText, 2}},
+ {2063, {wxTreeCtrl, setItemTextColour, 2}},
+ {2064, {wxTreeCtrl, setStateImageList, 1}},
+ {2065, {wxTreeCtrl, setWindowStyle, 1}},
+ {2066, {wxTreeCtrl, sortChildren, 1}},
+ {2067, {wxTreeCtrl, toggle, 1}},
+ {2068, {wxTreeCtrl, toggleItemSelection, 1}},
+ {2069, {wxTreeCtrl, unselect, 0}},
+ {2070, {wxTreeCtrl, unselectAll, 0}},
+ {2071, {wxTreeCtrl, unselectItem, 1}},
+ {2072, {wxScrollBar, new_0, 0}},
+ {2073, {wxScrollBar, new_3, 3}},
+ {2074, {wxScrollBar, destruct, 0}},
+ {2075, {wxScrollBar, create, 3}},
+ {2076, {wxScrollBar, getRange, 0}},
+ {2077, {wxScrollBar, getPageSize, 0}},
+ {2078, {wxScrollBar, getThumbPosition, 0}},
+ {2079, {wxScrollBar, getThumbSize, 0}},
+ {2080, {wxScrollBar, setThumbPosition, 1}},
+ {2081, {wxScrollBar, setScrollbar, 5}},
+ {2083, {wxSpinButton, new_2, 2}},
+ {2084, {wxSpinButton, new_0, 0}},
+ {2085, {wxSpinButton, create, 2}},
+ {2086, {wxSpinButton, getMax, 0}},
+ {2087, {wxSpinButton, getMin, 0}},
+ {2088, {wxSpinButton, getValue, 0}},
+ {2089, {wxSpinButton, setRange, 2}},
+ {2090, {wxSpinButton, setValue, 1}},
+ {2091, {wxSpinButton, 'Destroy', undefined}},
+ {2092, {wxSpinCtrl, new_0, 0}},
+ {2093, {wxSpinCtrl, new_2, 2}},
+ {2095, {wxSpinCtrl, create, 2}},
+ {2098, {wxSpinCtrl, setValue_1_1, 1}},
+ {2099, {wxSpinCtrl, setValue_1_0, 1}},
+ {2101, {wxSpinCtrl, getValue, 0}},
+ {2103, {wxSpinCtrl, setRange, 2}},
+ {2104, {wxSpinCtrl, setSelection, 2}},
+ {2106, {wxSpinCtrl, getMin, 0}},
+ {2108, {wxSpinCtrl, getMax, 0}},
+ {2109, {wxSpinCtrl, 'Destroy', undefined}},
+ {2110, {wxStaticText, new_0, 0}},
+ {2111, {wxStaticText, new_4, 4}},
+ {2112, {wxStaticText, create, 4}},
+ {2113, {wxStaticText, getLabel, 0}},
+ {2114, {wxStaticText, setLabel, 1}},
+ {2115, {wxStaticText, wrap, 1}},
+ {2116, {wxStaticText, 'Destroy', undefined}},
+ {2117, {wxStaticBitmap, new_0, 0}},
+ {2118, {wxStaticBitmap, new_4, 4}},
+ {2119, {wxStaticBitmap, create, 4}},
+ {2120, {wxStaticBitmap, getBitmap, 0}},
+ {2121, {wxStaticBitmap, setBitmap, 1}},
+ {2122, {wxStaticBitmap, 'Destroy', undefined}},
+ {2123, {wxRadioBox, new, 7}},
+ {2125, {wxRadioBox, destruct, 0}},
+ {2126, {wxRadioBox, create, 7}},
+ {2127, {wxRadioBox, enable_2, 2}},
+ {2128, {wxRadioBox, enable_1, 1}},
+ {2129, {wxRadioBox, getSelection, 0}},
+ {2130, {wxRadioBox, getString, 1}},
+ {2131, {wxRadioBox, setSelection, 1}},
+ {2132, {wxRadioBox, show_2, 2}},
+ {2133, {wxRadioBox, show_1, 1}},
+ {2134, {wxRadioBox, getColumnCount, 0}},
+ {2135, {wxRadioBox, getItemHelpText, 1}},
+ {2136, {wxRadioBox, getItemToolTip, 1}},
+ {2138, {wxRadioBox, getItemFromPoint, 1}},
+ {2139, {wxRadioBox, getRowCount, 0}},
+ {2140, {wxRadioBox, isItemEnabled, 1}},
+ {2141, {wxRadioBox, isItemShown, 1}},
+ {2142, {wxRadioBox, setItemHelpText, 2}},
+ {2143, {wxRadioBox, setItemToolTip, 2}},
+ {2144, {wxRadioButton, new_0, 0}},
+ {2145, {wxRadioButton, new_4, 4}},
+ {2146, {wxRadioButton, create, 4}},
+ {2147, {wxRadioButton, getValue, 0}},
+ {2148, {wxRadioButton, setValue, 1}},
+ {2149, {wxRadioButton, 'Destroy', undefined}},
+ {2151, {wxSlider, new_6, 6}},
+ {2152, {wxSlider, new_0, 0}},
+ {2153, {wxSlider, create, 6}},
+ {2154, {wxSlider, getLineSize, 0}},
+ {2155, {wxSlider, getMax, 0}},
+ {2156, {wxSlider, getMin, 0}},
+ {2157, {wxSlider, getPageSize, 0}},
+ {2158, {wxSlider, getThumbLength, 0}},
+ {2159, {wxSlider, getValue, 0}},
+ {2160, {wxSlider, setLineSize, 1}},
+ {2161, {wxSlider, setPageSize, 1}},
+ {2162, {wxSlider, setRange, 2}},
+ {2163, {wxSlider, setThumbLength, 1}},
+ {2164, {wxSlider, setValue, 1}},
+ {2165, {wxSlider, 'Destroy', undefined}},
+ {2167, {wxDialog, new_4, 4}},
+ {2168, {wxDialog, new_0, 0}},
+ {2170, {wxDialog, destruct, 0}},
+ {2171, {wxDialog, create, 4}},
+ {2172, {wxDialog, createButtonSizer, 1}},
+ {2173, {wxDialog, createStdDialogButtonSizer, 1}},
+ {2174, {wxDialog, endModal, 1}},
+ {2175, {wxDialog, getAffirmativeId, 0}},
+ {2176, {wxDialog, getReturnCode, 0}},
+ {2177, {wxDialog, isModal, 0}},
+ {2178, {wxDialog, setAffirmativeId, 1}},
+ {2179, {wxDialog, setReturnCode, 1}},
+ {2180, {wxDialog, show, 1}},
+ {2181, {wxDialog, showModal, 0}},
+ {2182, {wxColourDialog, new_0, 0}},
+ {2183, {wxColourDialog, new_2, 2}},
+ {2184, {wxColourDialog, destruct, 0}},
+ {2185, {wxColourDialog, create, 2}},
+ {2186, {wxColourDialog, getColourData, 0}},
+ {2187, {wxColourData, new_0, 0}},
+ {2188, {wxColourData, new_1, 1}},
+ {2189, {wxColourData, destruct, 0}},
+ {2190, {wxColourData, getChooseFull, 0}},
+ {2191, {wxColourData, getColour, 0}},
+ {2193, {wxColourData, getCustomColour, 1}},
+ {2194, {wxColourData, setChooseFull, 1}},
+ {2195, {wxColourData, setColour, 1}},
+ {2196, {wxColourData, setCustomColour, 2}},
+ {2197, {wxPalette, new_0, 0}},
+ {2198, {wxPalette, new_4, 4}},
+ {2200, {wxPalette, destruct, 0}},
+ {2201, {wxPalette, create, 4}},
+ {2202, {wxPalette, getColoursCount, 0}},
+ {2203, {wxPalette, getPixel, 3}},
+ {2204, {wxPalette, getRGB, 4}},
+ {2205, {wxPalette, isOk, 0}},
+ {2209, {wxDirDialog, new, 2}},
+ {2210, {wxDirDialog, destruct, 0}},
+ {2211, {wxDirDialog, getPath, 0}},
+ {2212, {wxDirDialog, getMessage, 0}},
+ {2213, {wxDirDialog, setMessage, 1}},
+ {2214, {wxDirDialog, setPath, 1}},
+ {2218, {wxFileDialog, new, 2}},
+ {2219, {wxFileDialog, destruct, 0}},
+ {2220, {wxFileDialog, getDirectory, 0}},
+ {2221, {wxFileDialog, getFilename, 0}},
+ {2222, {wxFileDialog, getFilenames, 1}},
+ {2223, {wxFileDialog, getFilterIndex, 0}},
+ {2224, {wxFileDialog, getMessage, 0}},
+ {2225, {wxFileDialog, getPath, 0}},
+ {2226, {wxFileDialog, getPaths, 1}},
+ {2227, {wxFileDialog, getWildcard, 0}},
+ {2228, {wxFileDialog, setDirectory, 1}},
+ {2229, {wxFileDialog, setFilename, 1}},
+ {2230, {wxFileDialog, setFilterIndex, 1}},
+ {2231, {wxFileDialog, setMessage, 1}},
+ {2232, {wxFileDialog, setPath, 1}},
+ {2233, {wxFileDialog, setWildcard, 1}},
+ {2234, {wxPickerBase, setInternalMargin, 1}},
+ {2235, {wxPickerBase, getInternalMargin, 0}},
+ {2236, {wxPickerBase, setTextCtrlProportion, 1}},
+ {2237, {wxPickerBase, setPickerCtrlProportion, 1}},
+ {2238, {wxPickerBase, getTextCtrlProportion, 0}},
+ {2239, {wxPickerBase, getPickerCtrlProportion, 0}},
+ {2240, {wxPickerBase, hasTextCtrl, 0}},
+ {2241, {wxPickerBase, getTextCtrl, 0}},
+ {2242, {wxPickerBase, isTextCtrlGrowable, 0}},
+ {2243, {wxPickerBase, setPickerCtrlGrowable, 1}},
+ {2244, {wxPickerBase, setTextCtrlGrowable, 1}},
+ {2245, {wxPickerBase, isPickerCtrlGrowable, 0}},
+ {2246, {wxFilePickerCtrl, new_0, 0}},
+ {2247, {wxFilePickerCtrl, new_3, 3}},
+ {2248, {wxFilePickerCtrl, create, 3}},
+ {2249, {wxFilePickerCtrl, getPath, 0}},
+ {2250, {wxFilePickerCtrl, setPath, 1}},
+ {2251, {wxFilePickerCtrl, 'Destroy', undefined}},
+ {2252, {wxDirPickerCtrl, new_0, 0}},
+ {2253, {wxDirPickerCtrl, new_3, 3}},
+ {2254, {wxDirPickerCtrl, create, 3}},
+ {2255, {wxDirPickerCtrl, getPath, 0}},
+ {2256, {wxDirPickerCtrl, setPath, 1}},
+ {2257, {wxDirPickerCtrl, 'Destroy', undefined}},
+ {2258, {wxColourPickerCtrl, new_0, 0}},
+ {2259, {wxColourPickerCtrl, new_3, 3}},
+ {2260, {wxColourPickerCtrl, create, 3}},
+ {2261, {wxColourPickerCtrl, getColour, 0}},
+ {2262, {wxColourPickerCtrl, setColour_1_1, 1}},
+ {2263, {wxColourPickerCtrl, setColour_1_0, 1}},
+ {2264, {wxColourPickerCtrl, 'Destroy', undefined}},
+ {2265, {wxDatePickerCtrl, new_0, 0}},
+ {2266, {wxDatePickerCtrl, new_3, 3}},
+ {2267, {wxDatePickerCtrl, getRange, 2}},
+ {2268, {wxDatePickerCtrl, getValue, 0}},
+ {2269, {wxDatePickerCtrl, setRange, 2}},
+ {2270, {wxDatePickerCtrl, setValue, 1}},
+ {2271, {wxDatePickerCtrl, 'Destroy', undefined}},
+ {2272, {wxFontPickerCtrl, new_0, 0}},
+ {2273, {wxFontPickerCtrl, new_3, 3}},
+ {2274, {wxFontPickerCtrl, create, 3}},
+ {2275, {wxFontPickerCtrl, getSelectedFont, 0}},
+ {2276, {wxFontPickerCtrl, setSelectedFont, 1}},
+ {2277, {wxFontPickerCtrl, getMaxPointSize, 0}},
+ {2278, {wxFontPickerCtrl, setMaxPointSize, 1}},
+ {2279, {wxFontPickerCtrl, 'Destroy', undefined}},
+ {2282, {wxFindReplaceDialog, new_0, 0}},
+ {2283, {wxFindReplaceDialog, new_4, 4}},
+ {2284, {wxFindReplaceDialog, destruct, 0}},
+ {2285, {wxFindReplaceDialog, create, 4}},
+ {2286, {wxFindReplaceDialog, getData, 0}},
+ {2287, {wxFindReplaceData, new_0, 0}},
+ {2288, {wxFindReplaceData, new_1, 1}},
+ {2289, {wxFindReplaceData, getFindString, 0}},
+ {2290, {wxFindReplaceData, getReplaceString, 0}},
+ {2291, {wxFindReplaceData, getFlags, 0}},
+ {2292, {wxFindReplaceData, setFlags, 1}},
+ {2293, {wxFindReplaceData, setFindString, 1}},
+ {2294, {wxFindReplaceData, setReplaceString, 1}},
+ {2295, {wxFindReplaceData, 'Destroy', undefined}},
+ {2296, {wxMultiChoiceDialog, new_0, 0}},
+ {2298, {wxMultiChoiceDialog, new_5, 5}},
+ {2299, {wxMultiChoiceDialog, getSelections, 0}},
+ {2300, {wxMultiChoiceDialog, setSelections, 1}},
+ {2301, {wxMultiChoiceDialog, 'Destroy', undefined}},
+ {2302, {wxSingleChoiceDialog, new_0, 0}},
+ {2304, {wxSingleChoiceDialog, new_5, 5}},
+ {2305, {wxSingleChoiceDialog, getSelection, 0}},
+ {2306, {wxSingleChoiceDialog, getStringSelection, 0}},
+ {2307, {wxSingleChoiceDialog, setSelection, 1}},
+ {2308, {wxSingleChoiceDialog, 'Destroy', undefined}},
+ {2309, {wxTextEntryDialog, new, 3}},
+ {2310, {wxTextEntryDialog, getValue, 0}},
+ {2311, {wxTextEntryDialog, setValue, 1}},
+ {2312, {wxTextEntryDialog, 'Destroy', undefined}},
+ {2313, {wxPasswordEntryDialog, new, 3}},
+ {2314, {wxPasswordEntryDialog, 'Destroy', undefined}},
+ {2315, {wxFontData, new_0, 0}},
+ {2316, {wxFontData, new_1, 1}},
+ {2317, {wxFontData, destruct, 0}},
+ {2318, {wxFontData, enableEffects, 1}},
+ {2319, {wxFontData, getAllowSymbols, 0}},
+ {2320, {wxFontData, getColour, 0}},
+ {2321, {wxFontData, getChosenFont, 0}},
+ {2322, {wxFontData, getEnableEffects, 0}},
+ {2323, {wxFontData, getInitialFont, 0}},
+ {2324, {wxFontData, getShowHelp, 0}},
+ {2325, {wxFontData, setAllowSymbols, 1}},
+ {2326, {wxFontData, setChosenFont, 1}},
+ {2327, {wxFontData, setColour, 1}},
+ {2328, {wxFontData, setInitialFont, 1}},
+ {2329, {wxFontData, setRange, 2}},
+ {2330, {wxFontData, setShowHelp, 1}},
+ {2334, {wxFontDialog, new_0, 0}},
+ {2336, {wxFontDialog, new_2, 2}},
+ {2338, {wxFontDialog, create, 2}},
+ {2339, {wxFontDialog, getFontData, 0}},
+ {2341, {wxFontDialog, 'Destroy', undefined}},
+ {2342, {wxProgressDialog, new, 3}},
+ {2343, {wxProgressDialog, destruct, 0}},
+ {2344, {wxProgressDialog, resume, 0}},
+ {2345, {wxProgressDialog, update_2, 2}},
+ {2346, {wxProgressDialog, update_0, 0}},
+ {2347, {wxMessageDialog, new, 3}},
+ {2348, {wxMessageDialog, destruct, 0}},
+ {2349, {wxPageSetupDialog, new, 2}},
+ {2350, {wxPageSetupDialog, destruct, 0}},
+ {2351, {wxPageSetupDialog, getPageSetupData, 0}},
+ {2352, {wxPageSetupDialog, showModal, 0}},
+ {2353, {wxPageSetupDialogData, new_0, 0}},
+ {2354, {wxPageSetupDialogData, new_1_0, 1}},
+ {2355, {wxPageSetupDialogData, new_1_1, 1}},
+ {2356, {wxPageSetupDialogData, destruct, 0}},
+ {2357, {wxPageSetupDialogData, enableHelp, 1}},
+ {2358, {wxPageSetupDialogData, enableMargins, 1}},
+ {2359, {wxPageSetupDialogData, enableOrientation, 1}},
+ {2360, {wxPageSetupDialogData, enablePaper, 1}},
+ {2361, {wxPageSetupDialogData, enablePrinter, 1}},
+ {2362, {wxPageSetupDialogData, getDefaultMinMargins, 0}},
+ {2363, {wxPageSetupDialogData, getEnableMargins, 0}},
+ {2364, {wxPageSetupDialogData, getEnableOrientation, 0}},
+ {2365, {wxPageSetupDialogData, getEnablePaper, 0}},
+ {2366, {wxPageSetupDialogData, getEnablePrinter, 0}},
+ {2367, {wxPageSetupDialogData, getEnableHelp, 0}},
+ {2368, {wxPageSetupDialogData, getDefaultInfo, 0}},
+ {2369, {wxPageSetupDialogData, getMarginTopLeft, 0}},
+ {2370, {wxPageSetupDialogData, getMarginBottomRight, 0}},
+ {2371, {wxPageSetupDialogData, getMinMarginTopLeft, 0}},
+ {2372, {wxPageSetupDialogData, getMinMarginBottomRight, 0}},
+ {2373, {wxPageSetupDialogData, getPaperId, 0}},
+ {2374, {wxPageSetupDialogData, getPaperSize, 0}},
+ {2376, {wxPageSetupDialogData, getPrintData, 0}},
+ {2377, {wxPageSetupDialogData, isOk, 0}},
+ {2378, {wxPageSetupDialogData, setDefaultInfo, 1}},
+ {2379, {wxPageSetupDialogData, setDefaultMinMargins, 1}},
+ {2380, {wxPageSetupDialogData, setMarginTopLeft, 1}},
+ {2381, {wxPageSetupDialogData, setMarginBottomRight, 1}},
+ {2382, {wxPageSetupDialogData, setMinMarginTopLeft, 1}},
+ {2383, {wxPageSetupDialogData, setMinMarginBottomRight, 1}},
+ {2384, {wxPageSetupDialogData, setPaperId, 1}},
+ {2385, {wxPageSetupDialogData, setPaperSize_1_1, 1}},
+ {2386, {wxPageSetupDialogData, setPaperSize_1_0, 1}},
+ {2387, {wxPageSetupDialogData, setPrintData, 1}},
+ {2388, {wxPrintDialog, new_2_0, 2}},
+ {2389, {wxPrintDialog, new_2_1, 2}},
+ {2390, {wxPrintDialog, destruct, 0}},
+ {2391, {wxPrintDialog, getPrintDialogData, 0}},
+ {2392, {wxPrintDialog, getPrintDC, 0}},
+ {2393, {wxPrintDialogData, new_0, 0}},
+ {2394, {wxPrintDialogData, new_1_1, 1}},
+ {2395, {wxPrintDialogData, new_1_0, 1}},
+ {2396, {wxPrintDialogData, destruct, 0}},
+ {2397, {wxPrintDialogData, enableHelp, 1}},
+ {2398, {wxPrintDialogData, enablePageNumbers, 1}},
+ {2399, {wxPrintDialogData, enablePrintToFile, 1}},
+ {2400, {wxPrintDialogData, enableSelection, 1}},
+ {2401, {wxPrintDialogData, getAllPages, 0}},
+ {2402, {wxPrintDialogData, getCollate, 0}},
+ {2403, {wxPrintDialogData, getFromPage, 0}},
+ {2404, {wxPrintDialogData, getMaxPage, 0}},
+ {2405, {wxPrintDialogData, getMinPage, 0}},
+ {2406, {wxPrintDialogData, getNoCopies, 0}},
+ {2407, {wxPrintDialogData, getPrintData, 0}},
+ {2408, {wxPrintDialogData, getPrintToFile, 0}},
+ {2409, {wxPrintDialogData, getSelection, 0}},
+ {2410, {wxPrintDialogData, getToPage, 0}},
+ {2411, {wxPrintDialogData, isOk, 0}},
+ {2412, {wxPrintDialogData, setCollate, 1}},
+ {2413, {wxPrintDialogData, setFromPage, 1}},
+ {2414, {wxPrintDialogData, setMaxPage, 1}},
+ {2415, {wxPrintDialogData, setMinPage, 1}},
+ {2416, {wxPrintDialogData, setNoCopies, 1}},
+ {2417, {wxPrintDialogData, setPrintData, 1}},
+ {2418, {wxPrintDialogData, setPrintToFile, 1}},
+ {2419, {wxPrintDialogData, setSelection, 1}},
+ {2420, {wxPrintDialogData, setToPage, 1}},
+ {2421, {wxPrintData, new_0, 0}},
+ {2422, {wxPrintData, new_1, 1}},
+ {2423, {wxPrintData, destruct, 0}},
+ {2424, {wxPrintData, getCollate, 0}},
+ {2425, {wxPrintData, getBin, 0}},
+ {2426, {wxPrintData, getColour, 0}},
+ {2427, {wxPrintData, getDuplex, 0}},
+ {2428, {wxPrintData, getNoCopies, 0}},
+ {2429, {wxPrintData, getOrientation, 0}},
+ {2430, {wxPrintData, getPaperId, 0}},
+ {2431, {wxPrintData, getPrinterName, 0}},
+ {2432, {wxPrintData, getQuality, 0}},
+ {2433, {wxPrintData, isOk, 0}},
+ {2434, {wxPrintData, setBin, 1}},
+ {2435, {wxPrintData, setCollate, 1}},
+ {2436, {wxPrintData, setColour, 1}},
+ {2437, {wxPrintData, setDuplex, 1}},
+ {2438, {wxPrintData, setNoCopies, 1}},
+ {2439, {wxPrintData, setOrientation, 1}},
+ {2440, {wxPrintData, setPaperId, 1}},
+ {2441, {wxPrintData, setPrinterName, 1}},
+ {2442, {wxPrintData, setQuality, 1}},
+ {2445, {wxPrintPreview, new_2, 2}},
+ {2446, {wxPrintPreview, new_3, 3}},
+ {2448, {wxPrintPreview, destruct, 0}},
+ {2449, {wxPrintPreview, getCanvas, 0}},
+ {2450, {wxPrintPreview, getCurrentPage, 0}},
+ {2451, {wxPrintPreview, getFrame, 0}},
+ {2452, {wxPrintPreview, getMaxPage, 0}},
+ {2453, {wxPrintPreview, getMinPage, 0}},
+ {2454, {wxPrintPreview, getPrintout, 0}},
+ {2455, {wxPrintPreview, getPrintoutForPrinting, 0}},
+ {2456, {wxPrintPreview, isOk, 0}},
+ {2457, {wxPrintPreview, paintPage, 2}},
+ {2458, {wxPrintPreview, print, 1}},
+ {2459, {wxPrintPreview, renderPage, 1}},
+ {2460, {wxPrintPreview, setCanvas, 1}},
+ {2461, {wxPrintPreview, setCurrentPage, 1}},
+ {2462, {wxPrintPreview, setFrame, 1}},
+ {2463, {wxPrintPreview, setPrintout, 1}},
+ {2464, {wxPrintPreview, setZoom, 1}},
+ {2465, {wxPreviewFrame, new, 3}},
+ {2466, {wxPreviewFrame, destruct, 0}},
+ {2467, {wxPreviewFrame, createControlBar, 0}},
+ {2468, {wxPreviewFrame, createCanvas, 0}},
+ {2469, {wxPreviewFrame, initialize, 0}},
+ {2470, {wxPreviewFrame, onCloseWindow, 1}},
+ {2471, {wxPreviewControlBar, new, 4}},
+ {2472, {wxPreviewControlBar, destruct, 0}},
+ {2473, {wxPreviewControlBar, createButtons, 0}},
+ {2474, {wxPreviewControlBar, getPrintPreview, 0}},
+ {2475, {wxPreviewControlBar, getZoomControl, 0}},
+ {2476, {wxPreviewControlBar, setZoomControl, 1}},
+ {2478, {wxPrinter, new, 1}},
+ {2479, {wxPrinter, createAbortWindow, 2}},
+ {2480, {wxPrinter, getAbort, 0}},
+ {2481, {wxPrinter, getLastError, 0}},
+ {2482, {wxPrinter, getPrintDialogData, 0}},
+ {2483, {wxPrinter, print, 3}},
+ {2484, {wxPrinter, printDialog, 1}},
+ {2485, {wxPrinter, reportError, 3}},
+ {2486, {wxPrinter, setup, 1}},
+ {2487, {wxPrinter, 'Destroy', undefined}},
+ {2488, {wxXmlResource, new_1, 1}},
+ {2489, {wxXmlResource, new_2, 2}},
+ {2490, {wxXmlResource, destruct, 0}},
+ {2491, {wxXmlResource, attachUnknownControl, 3}},
+ {2492, {wxXmlResource, clearHandlers, 0}},
+ {2493, {wxXmlResource, compareVersion, 4}},
+ {2494, {wxXmlResource, get, 0}},
+ {2495, {wxXmlResource, getFlags, 0}},
+ {2496, {wxXmlResource, getVersion, 0}},
+ {2497, {wxXmlResource, getXRCID, 2}},
+ {2498, {wxXmlResource, initAllHandlers, 0}},
+ {2499, {wxXmlResource, load, 1}},
+ {2500, {wxXmlResource, loadBitmap, 1}},
+ {2501, {wxXmlResource, loadDialog_2, 2}},
+ {2502, {wxXmlResource, loadDialog_3, 3}},
+ {2503, {wxXmlResource, loadFrame_2, 2}},
+ {2504, {wxXmlResource, loadFrame_3, 3}},
+ {2505, {wxXmlResource, loadIcon, 1}},
+ {2506, {wxXmlResource, loadMenu, 1}},
+ {2507, {wxXmlResource, loadMenuBar_2, 2}},
+ {2508, {wxXmlResource, loadMenuBar_1, 1}},
+ {2509, {wxXmlResource, loadPanel_2, 2}},
+ {2510, {wxXmlResource, loadPanel_3, 3}},
+ {2511, {wxXmlResource, loadToolBar, 2}},
+ {2512, {wxXmlResource, set, 1}},
+ {2513, {wxXmlResource, setFlags, 1}},
+ {2514, {wxXmlResource, unload, 1}},
+ {2515, {wxXmlResource, xrcctrl, 3}},
+ {2516, {wxHtmlEasyPrinting, new, 1}},
+ {2517, {wxHtmlEasyPrinting, destruct, 0}},
+ {2518, {wxHtmlEasyPrinting, getPrintData, 0}},
+ {2519, {wxHtmlEasyPrinting, getPageSetupData, 0}},
+ {2520, {wxHtmlEasyPrinting, previewFile, 1}},
+ {2521, {wxHtmlEasyPrinting, previewText, 2}},
+ {2522, {wxHtmlEasyPrinting, printFile, 1}},
+ {2523, {wxHtmlEasyPrinting, printText, 2}},
+ {2524, {wxHtmlEasyPrinting, pageSetup, 0}},
+ {2525, {wxHtmlEasyPrinting, setFonts, 3}},
+ {2526, {wxHtmlEasyPrinting, setHeader, 2}},
+ {2527, {wxHtmlEasyPrinting, setFooter, 2}},
+ {2529, {wxGLCanvas, new_2, 2}},
+ {2530, {wxGLCanvas, new_3_1, 3}},
+ {2531, {wxGLCanvas, new_3_0, 3}},
+ {2532, {wxGLCanvas, getContext, 0}},
+ {2534, {wxGLCanvas, setCurrent, 0}},
+ {2535, {wxGLCanvas, swapBuffers, 0}},
+ {2536, {wxGLCanvas, 'Destroy', undefined}},
+ {2537, {wxAuiManager, new, 1}},
+ {2538, {wxAuiManager, destruct, 0}},
+ {2539, {wxAuiManager, addPane_2_1, 2}},
+ {2540, {wxAuiManager, addPane_3, 3}},
+ {2541, {wxAuiManager, addPane_2_0, 2}},
+ {2542, {wxAuiManager, detachPane, 1}},
+ {2543, {wxAuiManager, getAllPanes, 0}},
+ {2544, {wxAuiManager, getArtProvider, 0}},
+ {2545, {wxAuiManager, getDockSizeConstraint, 2}},
+ {2546, {wxAuiManager, getFlags, 0}},
+ {2547, {wxAuiManager, getManagedWindow, 0}},
+ {2548, {wxAuiManager, getManager, 1}},
+ {2549, {wxAuiManager, getPane_1_1, 1}},
+ {2550, {wxAuiManager, getPane_1_0, 1}},
+ {2551, {wxAuiManager, hideHint, 0}},
+ {2552, {wxAuiManager, insertPane, 3}},
+ {2553, {wxAuiManager, loadPaneInfo, 2}},
+ {2554, {wxAuiManager, loadPerspective, 2}},
+ {2555, {wxAuiManager, savePaneInfo, 1}},
+ {2556, {wxAuiManager, savePerspective, 0}},
+ {2557, {wxAuiManager, setArtProvider, 1}},
+ {2558, {wxAuiManager, setDockSizeConstraint, 2}},
+ {2559, {wxAuiManager, setFlags, 1}},
+ {2560, {wxAuiManager, setManagedWindow, 1}},
+ {2561, {wxAuiManager, showHint, 1}},
+ {2562, {wxAuiManager, unInit, 0}},
+ {2563, {wxAuiManager, update, 0}},
+ {2564, {wxAuiPaneInfo, new_0, 0}},
+ {2565, {wxAuiPaneInfo, new_1, 1}},
+ {2566, {wxAuiPaneInfo, destruct, 0}},
+ {2567, {wxAuiPaneInfo, bestSize_1, 1}},
+ {2568, {wxAuiPaneInfo, bestSize_2, 2}},
+ {2569, {wxAuiPaneInfo, bottom, 0}},
+ {2570, {wxAuiPaneInfo, bottomDockable, 1}},
+ {2571, {wxAuiPaneInfo, caption, 1}},
+ {2572, {wxAuiPaneInfo, captionVisible, 1}},
+ {2573, {wxAuiPaneInfo, centre, 0}},
+ {2574, {wxAuiPaneInfo, centrePane, 0}},
+ {2575, {wxAuiPaneInfo, closeButton, 1}},
+ {2576, {wxAuiPaneInfo, defaultPane, 0}},
+ {2577, {wxAuiPaneInfo, destroyOnClose, 1}},
+ {2578, {wxAuiPaneInfo, direction, 1}},
+ {2579, {wxAuiPaneInfo, dock, 0}},
+ {2580, {wxAuiPaneInfo, dockable, 1}},
+ {2581, {wxAuiPaneInfo, fixed, 0}},
+ {2582, {wxAuiPaneInfo, float, 0}},
+ {2583, {wxAuiPaneInfo, floatable, 1}},
+ {2584, {wxAuiPaneInfo, floatingPosition_1, 1}},
+ {2585, {wxAuiPaneInfo, floatingPosition_2, 2}},
+ {2586, {wxAuiPaneInfo, floatingSize_1, 1}},
+ {2587, {wxAuiPaneInfo, floatingSize_2, 2}},
+ {2588, {wxAuiPaneInfo, gripper, 1}},
+ {2589, {wxAuiPaneInfo, gripperTop, 1}},
+ {2590, {wxAuiPaneInfo, hasBorder, 0}},
+ {2591, {wxAuiPaneInfo, hasCaption, 0}},
+ {2592, {wxAuiPaneInfo, hasCloseButton, 0}},
+ {2593, {wxAuiPaneInfo, hasFlag, 1}},
+ {2594, {wxAuiPaneInfo, hasGripper, 0}},
+ {2595, {wxAuiPaneInfo, hasGripperTop, 0}},
+ {2596, {wxAuiPaneInfo, hasMaximizeButton, 0}},
+ {2597, {wxAuiPaneInfo, hasMinimizeButton, 0}},
+ {2598, {wxAuiPaneInfo, hasPinButton, 0}},
+ {2599, {wxAuiPaneInfo, hide, 0}},
+ {2600, {wxAuiPaneInfo, isBottomDockable, 0}},
+ {2601, {wxAuiPaneInfo, isDocked, 0}},
+ {2602, {wxAuiPaneInfo, isFixed, 0}},
+ {2603, {wxAuiPaneInfo, isFloatable, 0}},
+ {2604, {wxAuiPaneInfo, isFloating, 0}},
+ {2605, {wxAuiPaneInfo, isLeftDockable, 0}},
+ {2606, {wxAuiPaneInfo, isMovable, 0}},
+ {2607, {wxAuiPaneInfo, isOk, 0}},
+ {2608, {wxAuiPaneInfo, isResizable, 0}},
+ {2609, {wxAuiPaneInfo, isRightDockable, 0}},
+ {2610, {wxAuiPaneInfo, isShown, 0}},
+ {2611, {wxAuiPaneInfo, isToolbar, 0}},
+ {2612, {wxAuiPaneInfo, isTopDockable, 0}},
+ {2613, {wxAuiPaneInfo, layer, 1}},
+ {2614, {wxAuiPaneInfo, left, 0}},
+ {2615, {wxAuiPaneInfo, leftDockable, 1}},
+ {2616, {wxAuiPaneInfo, maxSize_1, 1}},
+ {2617, {wxAuiPaneInfo, maxSize_2, 2}},
+ {2618, {wxAuiPaneInfo, maximizeButton, 1}},
+ {2619, {wxAuiPaneInfo, minSize_1, 1}},
+ {2620, {wxAuiPaneInfo, minSize_2, 2}},
+ {2621, {wxAuiPaneInfo, minimizeButton, 1}},
+ {2622, {wxAuiPaneInfo, movable, 1}},
+ {2623, {wxAuiPaneInfo, name, 1}},
+ {2624, {wxAuiPaneInfo, paneBorder, 1}},
+ {2625, {wxAuiPaneInfo, pinButton, 1}},
+ {2626, {wxAuiPaneInfo, position, 1}},
+ {2627, {wxAuiPaneInfo, resizable, 1}},
+ {2628, {wxAuiPaneInfo, right, 0}},
+ {2629, {wxAuiPaneInfo, rightDockable, 1}},
+ {2630, {wxAuiPaneInfo, row, 1}},
+ {2631, {wxAuiPaneInfo, safeSet, 1}},
+ {2632, {wxAuiPaneInfo, setFlag, 2}},
+ {2633, {wxAuiPaneInfo, show, 1}},
+ {2634, {wxAuiPaneInfo, toolbarPane, 0}},
+ {2635, {wxAuiPaneInfo, top, 0}},
+ {2636, {wxAuiPaneInfo, topDockable, 1}},
+ {2637, {wxAuiPaneInfo, window, 1}},
+ {2638, {wxAuiNotebook, new_0, 0}},
+ {2639, {wxAuiNotebook, new_2, 2}},
+ {2640, {wxAuiNotebook, addPage, 3}},
+ {2641, {wxAuiNotebook, create, 2}},
+ {2642, {wxAuiNotebook, deletePage, 1}},
+ {2643, {wxAuiNotebook, getArtProvider, 0}},
+ {2644, {wxAuiNotebook, getPage, 1}},
+ {2645, {wxAuiNotebook, getPageBitmap, 1}},
+ {2646, {wxAuiNotebook, getPageCount, 0}},
+ {2647, {wxAuiNotebook, getPageIndex, 1}},
+ {2648, {wxAuiNotebook, getPageText, 1}},
+ {2649, {wxAuiNotebook, getSelection, 0}},
+ {2650, {wxAuiNotebook, insertPage, 4}},
+ {2651, {wxAuiNotebook, removePage, 1}},
+ {2652, {wxAuiNotebook, setArtProvider, 1}},
+ {2653, {wxAuiNotebook, setFont, 1}},
+ {2654, {wxAuiNotebook, setPageBitmap, 2}},
+ {2655, {wxAuiNotebook, setPageText, 2}},
+ {2656, {wxAuiNotebook, setSelection, 1}},
+ {2657, {wxAuiNotebook, setTabCtrlHeight, 1}},
+ {2658, {wxAuiNotebook, setUniformBitmapSize, 1}},
+ {2659, {wxAuiNotebook, 'Destroy', undefined}},
+ {2660, {wxMDIParentFrame, new_0, 0}},
+ {2661, {wxMDIParentFrame, new_4, 4}},
+ {2662, {wxMDIParentFrame, destruct, 0}},
+ {2663, {wxMDIParentFrame, activateNext, 0}},
+ {2664, {wxMDIParentFrame, activatePrevious, 0}},
+ {2665, {wxMDIParentFrame, arrangeIcons, 0}},
+ {2666, {wxMDIParentFrame, cascade, 0}},
+ {2667, {wxMDIParentFrame, create, 4}},
+ {2668, {wxMDIParentFrame, getActiveChild, 0}},
+ {2669, {wxMDIParentFrame, getClientWindow, 0}},
+ {2670, {wxMDIParentFrame, tile, 1}},
+ {2671, {wxMDIChildFrame, new_0, 0}},
+ {2672, {wxMDIChildFrame, new_4, 4}},
+ {2673, {wxMDIChildFrame, destruct, 0}},
+ {2674, {wxMDIChildFrame, activate, 0}},
+ {2675, {wxMDIChildFrame, create, 4}},
+ {2676, {wxMDIChildFrame, maximize, 1}},
+ {2677, {wxMDIChildFrame, restore, 0}},
+ {2678, {wxMDIClientWindow, new_0, 0}},
+ {2679, {wxMDIClientWindow, new_2, 2}},
+ {2680, {wxMDIClientWindow, destruct, 0}},
+ {2681, {wxMDIClientWindow, createClient, 2}},
+ {2682, {wxLayoutAlgorithm, new, 0}},
+ {2683, {wxLayoutAlgorithm, layoutFrame, 2}},
+ {2684, {wxLayoutAlgorithm, layoutMDIFrame, 2}},
+ {2685, {wxLayoutAlgorithm, layoutWindow, 2}},
+ {2686, {wxLayoutAlgorithm, 'Destroy', undefined}},
+ {2687, {wxEvent, getId, 0}},
+ {2688, {wxEvent, getSkipped, 0}},
+ {2689, {wxEvent, getTimestamp, 0}},
+ {2690, {wxEvent, isCommandEvent, 0}},
+ {2691, {wxEvent, resumePropagation, 1}},
+ {2692, {wxEvent, shouldPropagate, 0}},
+ {2693, {wxEvent, skip, 1}},
+ {2694, {wxEvent, stopPropagation, 0}},
+ {2695, {wxCommandEvent, getClientData, 0}},
+ {2696, {wxCommandEvent, getExtraLong, 0}},
+ {2697, {wxCommandEvent, getInt, 0}},
+ {2698, {wxCommandEvent, getSelection, 0}},
+ {2699, {wxCommandEvent, getString, 0}},
+ {2700, {wxCommandEvent, isChecked, 0}},
+ {2701, {wxCommandEvent, isSelection, 0}},
+ {2702, {wxCommandEvent, setInt, 1}},
+ {2703, {wxCommandEvent, setString, 1}},
+ {2704, {wxScrollEvent, getOrientation, 0}},
+ {2705, {wxScrollEvent, getPosition, 0}},
+ {2706, {wxScrollWinEvent, getOrientation, 0}},
+ {2707, {wxScrollWinEvent, getPosition, 0}},
+ {2708, {wxMouseEvent, altDown, 0}},
+ {2709, {wxMouseEvent, button, 1}},
+ {2710, {wxMouseEvent, buttonDClick, 1}},
+ {2711, {wxMouseEvent, buttonDown, 1}},
+ {2712, {wxMouseEvent, buttonUp, 1}},
+ {2713, {wxMouseEvent, cmdDown, 0}},
+ {2714, {wxMouseEvent, controlDown, 0}},
+ {2715, {wxMouseEvent, dragging, 0}},
+ {2716, {wxMouseEvent, entering, 0}},
+ {2717, {wxMouseEvent, getButton, 0}},
+ {2720, {wxMouseEvent, getPosition, 0}},
+ {2721, {wxMouseEvent, getLogicalPosition, 1}},
+ {2722, {wxMouseEvent, getLinesPerAction, 0}},
+ {2723, {wxMouseEvent, getWheelRotation, 0}},
+ {2724, {wxMouseEvent, getWheelDelta, 0}},
+ {2725, {wxMouseEvent, getX, 0}},
+ {2726, {wxMouseEvent, getY, 0}},
+ {2727, {wxMouseEvent, isButton, 0}},
+ {2728, {wxMouseEvent, isPageScroll, 0}},
+ {2729, {wxMouseEvent, leaving, 0}},
+ {2730, {wxMouseEvent, leftDClick, 0}},
+ {2731, {wxMouseEvent, leftDown, 0}},
+ {2732, {wxMouseEvent, leftIsDown, 0}},
+ {2733, {wxMouseEvent, leftUp, 0}},
+ {2734, {wxMouseEvent, metaDown, 0}},
+ {2735, {wxMouseEvent, middleDClick, 0}},
+ {2736, {wxMouseEvent, middleDown, 0}},
+ {2737, {wxMouseEvent, middleIsDown, 0}},
+ {2738, {wxMouseEvent, middleUp, 0}},
+ {2739, {wxMouseEvent, moving, 0}},
+ {2740, {wxMouseEvent, rightDClick, 0}},
+ {2741, {wxMouseEvent, rightDown, 0}},
+ {2742, {wxMouseEvent, rightIsDown, 0}},
+ {2743, {wxMouseEvent, rightUp, 0}},
+ {2744, {wxMouseEvent, shiftDown, 0}},
+ {2745, {wxSetCursorEvent, getCursor, 0}},
+ {2746, {wxSetCursorEvent, getX, 0}},
+ {2747, {wxSetCursorEvent, getY, 0}},
+ {2748, {wxSetCursorEvent, hasCursor, 0}},
+ {2749, {wxSetCursorEvent, setCursor, 1}},
+ {2750, {wxKeyEvent, altDown, 0}},
+ {2751, {wxKeyEvent, cmdDown, 0}},
+ {2752, {wxKeyEvent, controlDown, 0}},
+ {2753, {wxKeyEvent, getKeyCode, 0}},
+ {2754, {wxKeyEvent, getModifiers, 0}},
+ {2757, {wxKeyEvent, getPosition, 0}},
+ {2758, {wxKeyEvent, getRawKeyCode, 0}},
+ {2759, {wxKeyEvent, getRawKeyFlags, 0}},
+ {2760, {wxKeyEvent, getUnicodeKey, 0}},
+ {2761, {wxKeyEvent, getX, 0}},
+ {2762, {wxKeyEvent, getY, 0}},
+ {2763, {wxKeyEvent, hasModifiers, 0}},
+ {2764, {wxKeyEvent, metaDown, 0}},
+ {2765, {wxKeyEvent, shiftDown, 0}},
+ {2766, {wxSizeEvent, getSize, 0}},
+ {2767, {wxMoveEvent, getPosition, 0}},
+ {2768, {wxEraseEvent, getDC, 0}},
+ {2769, {wxFocusEvent, getWindow, 0}},
+ {2770, {wxChildFocusEvent, getWindow, 0}},
+ {2771, {wxMenuEvent, getMenu, 0}},
+ {2772, {wxMenuEvent, getMenuId, 0}},
+ {2773, {wxMenuEvent, isPopup, 0}},
+ {2774, {wxCloseEvent, canVeto, 0}},
+ {2775, {wxCloseEvent, getLoggingOff, 0}},
+ {2776, {wxCloseEvent, setCanVeto, 1}},
+ {2777, {wxCloseEvent, setLoggingOff, 1}},
+ {2778, {wxCloseEvent, veto, 1}},
+ {2779, {wxShowEvent, setShow, 1}},
+ {2780, {wxShowEvent, getShow, 0}},
+ {2781, {wxIconizeEvent, iconized, 0}},
+ {2782, {wxJoystickEvent, buttonDown, 1}},
+ {2783, {wxJoystickEvent, buttonIsDown, 1}},
+ {2784, {wxJoystickEvent, buttonUp, 1}},
+ {2785, {wxJoystickEvent, getButtonChange, 0}},
+ {2786, {wxJoystickEvent, getButtonState, 0}},
+ {2787, {wxJoystickEvent, getJoystick, 0}},
+ {2788, {wxJoystickEvent, getPosition, 0}},
+ {2789, {wxJoystickEvent, getZPosition, 0}},
+ {2790, {wxJoystickEvent, isButton, 0}},
+ {2791, {wxJoystickEvent, isMove, 0}},
+ {2792, {wxJoystickEvent, isZMove, 0}},
+ {2793, {wxUpdateUIEvent, canUpdate, 1}},
+ {2794, {wxUpdateUIEvent, check, 1}},
+ {2795, {wxUpdateUIEvent, enable, 1}},
+ {2796, {wxUpdateUIEvent, show, 1}},
+ {2797, {wxUpdateUIEvent, getChecked, 0}},
+ {2798, {wxUpdateUIEvent, getEnabled, 0}},
+ {2799, {wxUpdateUIEvent, getShown, 0}},
+ {2800, {wxUpdateUIEvent, getSetChecked, 0}},
+ {2801, {wxUpdateUIEvent, getSetEnabled, 0}},
+ {2802, {wxUpdateUIEvent, getSetShown, 0}},
+ {2803, {wxUpdateUIEvent, getSetText, 0}},
+ {2804, {wxUpdateUIEvent, getText, 0}},
+ {2805, {wxUpdateUIEvent, getMode, 0}},
+ {2806, {wxUpdateUIEvent, getUpdateInterval, 0}},
+ {2807, {wxUpdateUIEvent, resetUpdateTime, 0}},
+ {2808, {wxUpdateUIEvent, setMode, 1}},
+ {2809, {wxUpdateUIEvent, setText, 1}},
+ {2810, {wxUpdateUIEvent, setUpdateInterval, 1}},
+ {2811, {wxMouseCaptureChangedEvent, getCapturedWindow, 0}},
+ {2812, {wxPaletteChangedEvent, setChangedWindow, 1}},
+ {2813, {wxPaletteChangedEvent, getChangedWindow, 0}},
+ {2814, {wxQueryNewPaletteEvent, setPaletteRealized, 1}},
+ {2815, {wxQueryNewPaletteEvent, getPaletteRealized, 0}},
+ {2816, {wxNavigationKeyEvent, getDirection, 0}},
+ {2817, {wxNavigationKeyEvent, setDirection, 1}},
+ {2818, {wxNavigationKeyEvent, isWindowChange, 0}},
+ {2819, {wxNavigationKeyEvent, setWindowChange, 1}},
+ {2820, {wxNavigationKeyEvent, isFromTab, 0}},
+ {2821, {wxNavigationKeyEvent, setFromTab, 1}},
+ {2822, {wxNavigationKeyEvent, getCurrentFocus, 0}},
+ {2823, {wxNavigationKeyEvent, setCurrentFocus, 1}},
+ {2824, {wxHelpEvent, getOrigin, 0}},
+ {2825, {wxHelpEvent, getPosition, 0}},
+ {2826, {wxHelpEvent, setOrigin, 1}},
+ {2827, {wxHelpEvent, setPosition, 1}},
+ {2828, {wxContextMenuEvent, getPosition, 0}},
+ {2829, {wxContextMenuEvent, setPosition, 1}},
+ {2830, {wxIdleEvent, canSend, 1}},
+ {2831, {wxIdleEvent, getMode, 0}},
+ {2832, {wxIdleEvent, requestMore, 1}},
+ {2833, {wxIdleEvent, moreRequested, 0}},
+ {2834, {wxIdleEvent, setMode, 1}},
+ {2835, {wxGridEvent, altDown, 0}},
+ {2836, {wxGridEvent, controlDown, 0}},
+ {2837, {wxGridEvent, getCol, 0}},
+ {2838, {wxGridEvent, getPosition, 0}},
+ {2839, {wxGridEvent, getRow, 0}},
+ {2840, {wxGridEvent, metaDown, 0}},
+ {2841, {wxGridEvent, selecting, 0}},
+ {2842, {wxGridEvent, shiftDown, 0}},
+ {2843, {wxNotifyEvent, allow, 0}},
+ {2844, {wxNotifyEvent, isAllowed, 0}},
+ {2845, {wxNotifyEvent, veto, 0}},
+ {2846, {wxSashEvent, getEdge, 0}},
+ {2847, {wxSashEvent, getDragRect, 0}},
+ {2848, {wxSashEvent, getDragStatus, 0}},
+ {2849, {wxListEvent, getCacheFrom, 0}},
+ {2850, {wxListEvent, getCacheTo, 0}},
+ {2851, {wxListEvent, getKeyCode, 0}},
+ {2852, {wxListEvent, getIndex, 0}},
+ {2853, {wxListEvent, getColumn, 0}},
+ {2854, {wxListEvent, getPoint, 0}},
+ {2855, {wxListEvent, getLabel, 0}},
+ {2856, {wxListEvent, getText, 0}},
+ {2857, {wxListEvent, getImage, 0}},
+ {2858, {wxListEvent, getData, 0}},
+ {2859, {wxListEvent, getMask, 0}},
+ {2860, {wxListEvent, getItem, 0}},
+ {2861, {wxListEvent, isEditCancelled, 0}},
+ {2862, {wxDateEvent, getDate, 0}},
+ {2863, {wxCalendarEvent, getWeekDay, 0}},
+ {2864, {wxFileDirPickerEvent, getPath, 0}},
+ {2865, {wxColourPickerEvent, getColour, 0}},
+ {2866, {wxFontPickerEvent, getFont, 0}},
+ {2867, {wxStyledTextEvent, getPosition, 0}},
+ {2868, {wxStyledTextEvent, getKey, 0}},
+ {2869, {wxStyledTextEvent, getModifiers, 0}},
+ {2870, {wxStyledTextEvent, getModificationType, 0}},
+ {2871, {wxStyledTextEvent, getText, 0}},
+ {2872, {wxStyledTextEvent, getLength, 0}},
+ {2873, {wxStyledTextEvent, getLinesAdded, 0}},
+ {2874, {wxStyledTextEvent, getLine, 0}},
+ {2875, {wxStyledTextEvent, getFoldLevelNow, 0}},
+ {2876, {wxStyledTextEvent, getFoldLevelPrev, 0}},
+ {2877, {wxStyledTextEvent, getMargin, 0}},
+ {2878, {wxStyledTextEvent, getMessage, 0}},
+ {2879, {wxStyledTextEvent, getWParam, 0}},
+ {2880, {wxStyledTextEvent, getLParam, 0}},
+ {2881, {wxStyledTextEvent, getListType, 0}},
+ {2882, {wxStyledTextEvent, getX, 0}},
+ {2883, {wxStyledTextEvent, getY, 0}},
+ {2884, {wxStyledTextEvent, getDragText, 0}},
+ {2885, {wxStyledTextEvent, getDragAllowMove, 0}},
+ {2886, {wxStyledTextEvent, getDragResult, 0}},
+ {2887, {wxStyledTextEvent, getShift, 0}},
+ {2888, {wxStyledTextEvent, getControl, 0}},
+ {2889, {wxStyledTextEvent, getAlt, 0}},
+ {2890, {utils, getKeyState, 1}},
+ {2891, {utils, getMousePosition, 2}},
+ {2892, {utils, getMouseState, 0}},
+ {2893, {utils, setDetectableAutoRepeat, 1}},
+ {2894, {utils, bell, 0}},
+ {2895, {utils, findMenuItemId, 3}},
+ {2896, {utils, genericFindWindowAtPoint, 1}},
+ {2897, {utils, findWindowAtPoint, 1}},
+ {2898, {utils, beginBusyCursor, 1}},
+ {2899, {utils, endBusyCursor, 0}},
+ {2900, {utils, isBusy, 0}},
+ {2901, {utils, shutdown, 1}},
+ {2902, {utils, shell, 1}},
+ {2903, {utils, launchDefaultBrowser, 2}},
+ {2904, {utils, getEmailAddress, 0}},
+ {2905, {utils, getUserId, 0}},
+ {2906, {utils, getHomeDir, 0}},
+ {2907, {utils, newId, 0}},
+ {2908, {utils, registerId, 1}},
+ {2909, {utils, getCurrentId, 0}},
+ {2910, {utils, getOsDescription, 0}},
+ {2911, {utils, isPlatformLittleEndian, 0}},
+ {2912, {utils, isPlatform64Bit, 0}},
+ {2913, {wxPrintout, new, 1}},
+ {2914, {wxPrintout, destruct, 0}},
+ {2915, {wxPrintout, getDC, 0}},
+ {2916, {wxPrintout, getPageSizeMM, 2}},
+ {2917, {wxPrintout, getPageSizePixels, 2}},
+ {2918, {wxPrintout, getPaperRectPixels, 0}},
+ {2919, {wxPrintout, getPPIPrinter, 2}},
+ {2920, {wxPrintout, getPPIScreen, 2}},
+ {2921, {wxPrintout, getTitle, 0}},
+ {2922, {wxPrintout, isPreview, 0}},
+ {2923, {wxPrintout, fitThisSizeToPaper, 1}},
+ {2924, {wxPrintout, fitThisSizeToPage, 1}},
+ {2925, {wxPrintout, fitThisSizeToPageMargins, 2}},
+ {2926, {wxPrintout, mapScreenSizeToPaper, 0}},
+ {2927, {wxPrintout, mapScreenSizeToPage, 0}},
+ {2928, {wxPrintout, mapScreenSizeToPageMargins, 1}},
+ {2929, {wxPrintout, mapScreenSizeToDevice, 0}},
+ {2930, {wxPrintout, getLogicalPaperRect, 0}},
+ {2931, {wxPrintout, getLogicalPageRect, 0}},
+ {2932, {wxPrintout, getLogicalPageMarginsRect, 1}},
+ {2933, {wxPrintout, setLogicalOrigin, 2}},
+ {2934, {wxPrintout, offsetLogicalOrigin, 2}},
+ {2935, {wxStyledTextCtrl, new_2, 2}},
+ {2936, {wxStyledTextCtrl, new_0, 0}},
+ {2937, {wxStyledTextCtrl, destruct, 0}},
+ {2938, {wxStyledTextCtrl, create, 2}},
+ {2939, {wxStyledTextCtrl, addText, 1}},
+ {2940, {wxStyledTextCtrl, addStyledText, 1}},
+ {2941, {wxStyledTextCtrl, insertText, 2}},
+ {2942, {wxStyledTextCtrl, clearAll, 0}},
+ {2943, {wxStyledTextCtrl, clearDocumentStyle, 0}},
+ {2944, {wxStyledTextCtrl, getLength, 0}},
+ {2945, {wxStyledTextCtrl, getCharAt, 1}},
+ {2946, {wxStyledTextCtrl, getCurrentPos, 0}},
+ {2947, {wxStyledTextCtrl, getAnchor, 0}},
+ {2948, {wxStyledTextCtrl, getStyleAt, 1}},
+ {2949, {wxStyledTextCtrl, redo, 0}},
+ {2950, {wxStyledTextCtrl, setUndoCollection, 1}},
+ {2951, {wxStyledTextCtrl, selectAll, 0}},
+ {2952, {wxStyledTextCtrl, setSavePoint, 0}},
+ {2953, {wxStyledTextCtrl, getStyledText, 2}},
+ {2954, {wxStyledTextCtrl, canRedo, 0}},
+ {2955, {wxStyledTextCtrl, markerLineFromHandle, 1}},
+ {2956, {wxStyledTextCtrl, markerDeleteHandle, 1}},
+ {2957, {wxStyledTextCtrl, getUndoCollection, 0}},
+ {2958, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
+ {2959, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
+ {2960, {wxStyledTextCtrl, positionFromPoint, 1}},
+ {2961, {wxStyledTextCtrl, positionFromPointClose, 2}},
+ {2962, {wxStyledTextCtrl, gotoLine, 1}},
+ {2963, {wxStyledTextCtrl, gotoPos, 1}},
+ {2964, {wxStyledTextCtrl, setAnchor, 1}},
+ {2965, {wxStyledTextCtrl, getCurLine, 1}},
+ {2966, {wxStyledTextCtrl, getEndStyled, 0}},
+ {2967, {wxStyledTextCtrl, convertEOLs, 1}},
+ {2968, {wxStyledTextCtrl, getEOLMode, 0}},
+ {2969, {wxStyledTextCtrl, setEOLMode, 1}},
+ {2970, {wxStyledTextCtrl, startStyling, 2}},
+ {2971, {wxStyledTextCtrl, setStyling, 2}},
+ {2972, {wxStyledTextCtrl, getBufferedDraw, 0}},
+ {2973, {wxStyledTextCtrl, setBufferedDraw, 1}},
+ {2974, {wxStyledTextCtrl, setTabWidth, 1}},
+ {2975, {wxStyledTextCtrl, getTabWidth, 0}},
+ {2976, {wxStyledTextCtrl, setCodePage, 1}},
+ {2977, {wxStyledTextCtrl, markerDefine, 3}},
+ {2978, {wxStyledTextCtrl, markerSetForeground, 2}},
+ {2979, {wxStyledTextCtrl, markerSetBackground, 2}},
+ {2980, {wxStyledTextCtrl, markerAdd, 2}},
+ {2981, {wxStyledTextCtrl, markerDelete, 2}},
+ {2982, {wxStyledTextCtrl, markerDeleteAll, 1}},
+ {2983, {wxStyledTextCtrl, markerGet, 1}},
+ {2984, {wxStyledTextCtrl, markerNext, 2}},
+ {2985, {wxStyledTextCtrl, markerPrevious, 2}},
+ {2986, {wxStyledTextCtrl, markerDefineBitmap, 2}},
+ {2987, {wxStyledTextCtrl, markerAddSet, 2}},
+ {2988, {wxStyledTextCtrl, markerSetAlpha, 2}},
+ {2989, {wxStyledTextCtrl, setMarginType, 2}},
+ {2990, {wxStyledTextCtrl, getMarginType, 1}},
+ {2991, {wxStyledTextCtrl, setMarginWidth, 2}},
+ {2992, {wxStyledTextCtrl, getMarginWidth, 1}},
+ {2993, {wxStyledTextCtrl, setMarginMask, 2}},
+ {2994, {wxStyledTextCtrl, getMarginMask, 1}},
+ {2995, {wxStyledTextCtrl, setMarginSensitive, 2}},
+ {2996, {wxStyledTextCtrl, getMarginSensitive, 1}},
+ {2997, {wxStyledTextCtrl, styleClearAll, 0}},
+ {2998, {wxStyledTextCtrl, styleSetForeground, 2}},
+ {2999, {wxStyledTextCtrl, styleSetBackground, 2}},
+ {3000, {wxStyledTextCtrl, styleSetBold, 2}},
+ {3001, {wxStyledTextCtrl, styleSetItalic, 2}},
+ {3002, {wxStyledTextCtrl, styleSetSize, 2}},
+ {3003, {wxStyledTextCtrl, styleSetFaceName, 2}},
+ {3004, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
+ {3005, {wxStyledTextCtrl, styleResetDefault, 0}},
+ {3006, {wxStyledTextCtrl, styleSetUnderline, 2}},
+ {3007, {wxStyledTextCtrl, styleSetCase, 2}},
+ {3008, {wxStyledTextCtrl, styleSetHotSpot, 2}},
+ {3009, {wxStyledTextCtrl, setSelForeground, 2}},
+ {3010, {wxStyledTextCtrl, setSelBackground, 2}},
+ {3011, {wxStyledTextCtrl, getSelAlpha, 0}},
+ {3012, {wxStyledTextCtrl, setSelAlpha, 1}},
+ {3013, {wxStyledTextCtrl, setCaretForeground, 1}},
+ {3014, {wxStyledTextCtrl, cmdKeyAssign, 3}},
+ {3015, {wxStyledTextCtrl, cmdKeyClear, 2}},
+ {3016, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
+ {3017, {wxStyledTextCtrl, setStyleBytes, 2}},
+ {3018, {wxStyledTextCtrl, styleSetVisible, 2}},
+ {3019, {wxStyledTextCtrl, getCaretPeriod, 0}},
+ {3020, {wxStyledTextCtrl, setCaretPeriod, 1}},
+ {3021, {wxStyledTextCtrl, setWordChars, 1}},
+ {3022, {wxStyledTextCtrl, beginUndoAction, 0}},
+ {3023, {wxStyledTextCtrl, endUndoAction, 0}},
+ {3024, {wxStyledTextCtrl, indicatorSetStyle, 2}},
+ {3025, {wxStyledTextCtrl, indicatorGetStyle, 1}},
+ {3026, {wxStyledTextCtrl, indicatorSetForeground, 2}},
+ {3027, {wxStyledTextCtrl, indicatorGetForeground, 1}},
+ {3028, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
+ {3029, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
+ {3030, {wxStyledTextCtrl, getStyleBits, 0}},
+ {3031, {wxStyledTextCtrl, setLineState, 2}},
+ {3032, {wxStyledTextCtrl, getLineState, 1}},
+ {3033, {wxStyledTextCtrl, getMaxLineState, 0}},
+ {3034, {wxStyledTextCtrl, getCaretLineVisible, 0}},
+ {3035, {wxStyledTextCtrl, setCaretLineVisible, 1}},
+ {3036, {wxStyledTextCtrl, getCaretLineBackground, 0}},
+ {3037, {wxStyledTextCtrl, setCaretLineBackground, 1}},
+ {3038, {wxStyledTextCtrl, autoCompShow, 2}},
+ {3039, {wxStyledTextCtrl, autoCompCancel, 0}},
+ {3040, {wxStyledTextCtrl, autoCompActive, 0}},
+ {3041, {wxStyledTextCtrl, autoCompPosStart, 0}},
+ {3042, {wxStyledTextCtrl, autoCompComplete, 0}},
+ {3043, {wxStyledTextCtrl, autoCompStops, 1}},
+ {3044, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
+ {3045, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
+ {3046, {wxStyledTextCtrl, autoCompSelect, 1}},
+ {3047, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
+ {3048, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
+ {3049, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
+ {3050, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
+ {3051, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
+ {3052, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
+ {3053, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
+ {3054, {wxStyledTextCtrl, userListShow, 2}},
+ {3055, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
+ {3056, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
+ {3057, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
+ {3058, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
+ {3059, {wxStyledTextCtrl, registerImage, 2}},
+ {3060, {wxStyledTextCtrl, clearRegisteredImages, 0}},
+ {3061, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
+ {3062, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
+ {3063, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
+ {3064, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
+ {3065, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
+ {3066, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
+ {3067, {wxStyledTextCtrl, setIndent, 1}},
+ {3068, {wxStyledTextCtrl, getIndent, 0}},
+ {3069, {wxStyledTextCtrl, setUseTabs, 1}},
+ {3070, {wxStyledTextCtrl, getUseTabs, 0}},
+ {3071, {wxStyledTextCtrl, setLineIndentation, 2}},
+ {3072, {wxStyledTextCtrl, getLineIndentation, 1}},
+ {3073, {wxStyledTextCtrl, getLineIndentPosition, 1}},
+ {3074, {wxStyledTextCtrl, getColumn, 1}},
+ {3075, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
+ {3076, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
+ {3077, {wxStyledTextCtrl, setIndentationGuides, 1}},
+ {3078, {wxStyledTextCtrl, getIndentationGuides, 0}},
+ {3079, {wxStyledTextCtrl, setHighlightGuide, 1}},
+ {3080, {wxStyledTextCtrl, getHighlightGuide, 0}},
+ {3081, {wxStyledTextCtrl, getLineEndPosition, 1}},
+ {3082, {wxStyledTextCtrl, getCodePage, 0}},
+ {3083, {wxStyledTextCtrl, getCaretForeground, 0}},
+ {3084, {wxStyledTextCtrl, getReadOnly, 0}},
+ {3085, {wxStyledTextCtrl, setCurrentPos, 1}},
+ {3086, {wxStyledTextCtrl, setSelectionStart, 1}},
+ {3087, {wxStyledTextCtrl, getSelectionStart, 0}},
+ {3088, {wxStyledTextCtrl, setSelectionEnd, 1}},
+ {3089, {wxStyledTextCtrl, getSelectionEnd, 0}},
+ {3090, {wxStyledTextCtrl, setPrintMagnification, 1}},
+ {3091, {wxStyledTextCtrl, getPrintMagnification, 0}},
+ {3092, {wxStyledTextCtrl, setPrintColourMode, 1}},
+ {3093, {wxStyledTextCtrl, getPrintColourMode, 0}},
+ {3094, {wxStyledTextCtrl, findText, 4}},
+ {3095, {wxStyledTextCtrl, formatRange, 7}},
+ {3096, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
+ {3097, {wxStyledTextCtrl, getLine, 1}},
+ {3098, {wxStyledTextCtrl, getLineCount, 0}},
+ {3099, {wxStyledTextCtrl, setMarginLeft, 1}},
+ {3100, {wxStyledTextCtrl, getMarginLeft, 0}},
+ {3101, {wxStyledTextCtrl, setMarginRight, 1}},
+ {3102, {wxStyledTextCtrl, getMarginRight, 0}},
+ {3103, {wxStyledTextCtrl, getModify, 0}},
+ {3104, {wxStyledTextCtrl, setSelection, 2}},
+ {3105, {wxStyledTextCtrl, getSelectedText, 0}},
+ {3106, {wxStyledTextCtrl, getTextRange, 2}},
+ {3107, {wxStyledTextCtrl, hideSelection, 1}},
+ {3108, {wxStyledTextCtrl, lineFromPosition, 1}},
+ {3109, {wxStyledTextCtrl, positionFromLine, 1}},
+ {3110, {wxStyledTextCtrl, lineScroll, 2}},
+ {3111, {wxStyledTextCtrl, ensureCaretVisible, 0}},
+ {3112, {wxStyledTextCtrl, replaceSelection, 1}},
+ {3113, {wxStyledTextCtrl, setReadOnly, 1}},
+ {3114, {wxStyledTextCtrl, canPaste, 0}},
+ {3115, {wxStyledTextCtrl, canUndo, 0}},
+ {3116, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
+ {3117, {wxStyledTextCtrl, undo, 0}},
+ {3118, {wxStyledTextCtrl, cut, 0}},
+ {3119, {wxStyledTextCtrl, copy, 0}},
+ {3120, {wxStyledTextCtrl, paste, 0}},
+ {3121, {wxStyledTextCtrl, clear, 0}},
+ {3122, {wxStyledTextCtrl, setText, 1}},
+ {3123, {wxStyledTextCtrl, getText, 0}},
+ {3124, {wxStyledTextCtrl, getTextLength, 0}},
+ {3125, {wxStyledTextCtrl, getOvertype, 0}},
+ {3126, {wxStyledTextCtrl, setCaretWidth, 1}},
+ {3127, {wxStyledTextCtrl, getCaretWidth, 0}},
+ {3128, {wxStyledTextCtrl, setTargetStart, 1}},
+ {3129, {wxStyledTextCtrl, getTargetStart, 0}},
+ {3130, {wxStyledTextCtrl, setTargetEnd, 1}},
+ {3131, {wxStyledTextCtrl, getTargetEnd, 0}},
+ {3132, {wxStyledTextCtrl, replaceTarget, 1}},
+ {3133, {wxStyledTextCtrl, searchInTarget, 1}},
+ {3134, {wxStyledTextCtrl, setSearchFlags, 1}},
+ {3135, {wxStyledTextCtrl, getSearchFlags, 0}},
+ {3136, {wxStyledTextCtrl, callTipShow, 2}},
+ {3137, {wxStyledTextCtrl, callTipCancel, 0}},
+ {3138, {wxStyledTextCtrl, callTipActive, 0}},
+ {3139, {wxStyledTextCtrl, callTipPosAtStart, 0}},
+ {3140, {wxStyledTextCtrl, callTipSetHighlight, 2}},
+ {3141, {wxStyledTextCtrl, callTipSetBackground, 1}},
+ {3142, {wxStyledTextCtrl, callTipSetForeground, 1}},
+ {3143, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
+ {3144, {wxStyledTextCtrl, callTipUseStyle, 1}},
+ {3145, {wxStyledTextCtrl, visibleFromDocLine, 1}},
+ {3146, {wxStyledTextCtrl, docLineFromVisible, 1}},
+ {3147, {wxStyledTextCtrl, wrapCount, 1}},
+ {3148, {wxStyledTextCtrl, setFoldLevel, 2}},
+ {3149, {wxStyledTextCtrl, getFoldLevel, 1}},
+ {3150, {wxStyledTextCtrl, getLastChild, 2}},
+ {3151, {wxStyledTextCtrl, getFoldParent, 1}},
+ {3152, {wxStyledTextCtrl, showLines, 2}},
+ {3153, {wxStyledTextCtrl, hideLines, 2}},
+ {3154, {wxStyledTextCtrl, getLineVisible, 1}},
+ {3155, {wxStyledTextCtrl, setFoldExpanded, 2}},
+ {3156, {wxStyledTextCtrl, getFoldExpanded, 1}},
+ {3157, {wxStyledTextCtrl, toggleFold, 1}},
+ {3158, {wxStyledTextCtrl, ensureVisible, 1}},
+ {3159, {wxStyledTextCtrl, setFoldFlags, 1}},
+ {3160, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
+ {3161, {wxStyledTextCtrl, setTabIndents, 1}},
+ {3162, {wxStyledTextCtrl, getTabIndents, 0}},
+ {3163, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
+ {3164, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
+ {3165, {wxStyledTextCtrl, setMouseDwellTime, 1}},
+ {3166, {wxStyledTextCtrl, getMouseDwellTime, 0}},
+ {3167, {wxStyledTextCtrl, wordStartPosition, 2}},
+ {3168, {wxStyledTextCtrl, wordEndPosition, 2}},
+ {3169, {wxStyledTextCtrl, setWrapMode, 1}},
+ {3170, {wxStyledTextCtrl, getWrapMode, 0}},
+ {3171, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
+ {3172, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
+ {3173, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
+ {3174, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
+ {3175, {wxStyledTextCtrl, setWrapStartIndent, 1}},
+ {3176, {wxStyledTextCtrl, getWrapStartIndent, 0}},
+ {3177, {wxStyledTextCtrl, setLayoutCache, 1}},
+ {3178, {wxStyledTextCtrl, getLayoutCache, 0}},
+ {3179, {wxStyledTextCtrl, setScrollWidth, 1}},
+ {3180, {wxStyledTextCtrl, getScrollWidth, 0}},
+ {3181, {wxStyledTextCtrl, textWidth, 2}},
+ {3182, {wxStyledTextCtrl, getEndAtLastLine, 0}},
+ {3183, {wxStyledTextCtrl, textHeight, 1}},
+ {3184, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
+ {3185, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
+ {3186, {wxStyledTextCtrl, appendText, 1}},
+ {3187, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
+ {3188, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
+ {3189, {wxStyledTextCtrl, targetFromSelection, 0}},
+ {3190, {wxStyledTextCtrl, linesJoin, 0}},
+ {3191, {wxStyledTextCtrl, linesSplit, 1}},
+ {3192, {wxStyledTextCtrl, setFoldMarginColour, 2}},
+ {3193, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
+ {3194, {wxStyledTextCtrl, lineDown, 0}},
+ {3195, {wxStyledTextCtrl, lineDownExtend, 0}},
+ {3196, {wxStyledTextCtrl, lineUp, 0}},
+ {3197, {wxStyledTextCtrl, lineUpExtend, 0}},
+ {3198, {wxStyledTextCtrl, charLeft, 0}},
+ {3199, {wxStyledTextCtrl, charLeftExtend, 0}},
+ {3200, {wxStyledTextCtrl, charRight, 0}},
+ {3201, {wxStyledTextCtrl, charRightExtend, 0}},
+ {3202, {wxStyledTextCtrl, wordLeft, 0}},
+ {3203, {wxStyledTextCtrl, wordLeftExtend, 0}},
+ {3204, {wxStyledTextCtrl, wordRight, 0}},
+ {3205, {wxStyledTextCtrl, wordRightExtend, 0}},
+ {3206, {wxStyledTextCtrl, home, 0}},
+ {3207, {wxStyledTextCtrl, homeExtend, 0}},
+ {3208, {wxStyledTextCtrl, lineEnd, 0}},
+ {3209, {wxStyledTextCtrl, lineEndExtend, 0}},
+ {3210, {wxStyledTextCtrl, documentStart, 0}},
+ {3211, {wxStyledTextCtrl, documentStartExtend, 0}},
+ {3212, {wxStyledTextCtrl, documentEnd, 0}},
+ {3213, {wxStyledTextCtrl, documentEndExtend, 0}},
+ {3214, {wxStyledTextCtrl, pageUp, 0}},
+ {3215, {wxStyledTextCtrl, pageUpExtend, 0}},
+ {3216, {wxStyledTextCtrl, pageDown, 0}},
+ {3217, {wxStyledTextCtrl, pageDownExtend, 0}},
+ {3218, {wxStyledTextCtrl, editToggleOvertype, 0}},
+ {3219, {wxStyledTextCtrl, cancel, 0}},
+ {3220, {wxStyledTextCtrl, deleteBack, 0}},
+ {3221, {wxStyledTextCtrl, tab, 0}},
+ {3222, {wxStyledTextCtrl, backTab, 0}},
+ {3223, {wxStyledTextCtrl, newLine, 0}},
+ {3224, {wxStyledTextCtrl, formFeed, 0}},
+ {3225, {wxStyledTextCtrl, vCHome, 0}},
+ {3226, {wxStyledTextCtrl, vCHomeExtend, 0}},
+ {3227, {wxStyledTextCtrl, zoomIn, 0}},
+ {3228, {wxStyledTextCtrl, zoomOut, 0}},
+ {3229, {wxStyledTextCtrl, delWordLeft, 0}},
+ {3230, {wxStyledTextCtrl, delWordRight, 0}},
+ {3231, {wxStyledTextCtrl, lineCut, 0}},
+ {3232, {wxStyledTextCtrl, lineDelete, 0}},
+ {3233, {wxStyledTextCtrl, lineTranspose, 0}},
+ {3234, {wxStyledTextCtrl, lineDuplicate, 0}},
+ {3235, {wxStyledTextCtrl, lowerCase, 0}},
+ {3236, {wxStyledTextCtrl, upperCase, 0}},
+ {3237, {wxStyledTextCtrl, lineScrollDown, 0}},
+ {3238, {wxStyledTextCtrl, lineScrollUp, 0}},
+ {3239, {wxStyledTextCtrl, deleteBackNotLine, 0}},
+ {3240, {wxStyledTextCtrl, homeDisplay, 0}},
+ {3241, {wxStyledTextCtrl, homeDisplayExtend, 0}},
+ {3242, {wxStyledTextCtrl, lineEndDisplay, 0}},
+ {3243, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
+ {3244, {wxStyledTextCtrl, homeWrapExtend, 0}},
+ {3245, {wxStyledTextCtrl, lineEndWrap, 0}},
+ {3246, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
+ {3247, {wxStyledTextCtrl, vCHomeWrap, 0}},
+ {3248, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
+ {3249, {wxStyledTextCtrl, lineCopy, 0}},
+ {3250, {wxStyledTextCtrl, moveCaretInsideView, 0}},
+ {3251, {wxStyledTextCtrl, lineLength, 1}},
+ {3252, {wxStyledTextCtrl, braceHighlight, 2}},
+ {3253, {wxStyledTextCtrl, braceBadLight, 1}},
+ {3254, {wxStyledTextCtrl, braceMatch, 1}},
+ {3255, {wxStyledTextCtrl, getViewEOL, 0}},
+ {3256, {wxStyledTextCtrl, setViewEOL, 1}},
+ {3257, {wxStyledTextCtrl, setModEventMask, 1}},
+ {3258, {wxStyledTextCtrl, getEdgeColumn, 0}},
+ {3259, {wxStyledTextCtrl, setEdgeColumn, 1}},
+ {3260, {wxStyledTextCtrl, getEdgeMode, 0}},
+ {3261, {wxStyledTextCtrl, getEdgeColour, 0}},
+ {3262, {wxStyledTextCtrl, setEdgeColour, 1}},
+ {3263, {wxStyledTextCtrl, searchAnchor, 0}},
+ {3264, {wxStyledTextCtrl, searchNext, 2}},
+ {3265, {wxStyledTextCtrl, searchPrev, 2}},
+ {3266, {wxStyledTextCtrl, linesOnScreen, 0}},
+ {3267, {wxStyledTextCtrl, usePopUp, 1}},
+ {3268, {wxStyledTextCtrl, selectionIsRectangle, 0}},
+ {3269, {wxStyledTextCtrl, setZoom, 1}},
+ {3270, {wxStyledTextCtrl, getZoom, 0}},
+ {3271, {wxStyledTextCtrl, getModEventMask, 0}},
+ {3272, {wxStyledTextCtrl, setSTCFocus, 1}},
+ {3273, {wxStyledTextCtrl, getSTCFocus, 0}},
+ {3274, {wxStyledTextCtrl, setStatus, 1}},
+ {3275, {wxStyledTextCtrl, getStatus, 0}},
+ {3276, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
+ {3277, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
+ {3278, {wxStyledTextCtrl, setSTCCursor, 1}},
+ {3279, {wxStyledTextCtrl, getSTCCursor, 0}},
+ {3280, {wxStyledTextCtrl, setControlCharSymbol, 1}},
+ {3281, {wxStyledTextCtrl, getControlCharSymbol, 0}},
+ {3282, {wxStyledTextCtrl, wordPartLeft, 0}},
+ {3283, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
+ {3284, {wxStyledTextCtrl, wordPartRight, 0}},
+ {3285, {wxStyledTextCtrl, wordPartRightExtend, 0}},
+ {3286, {wxStyledTextCtrl, setVisiblePolicy, 2}},
+ {3287, {wxStyledTextCtrl, delLineLeft, 0}},
+ {3288, {wxStyledTextCtrl, delLineRight, 0}},
+ {3289, {wxStyledTextCtrl, getXOffset, 0}},
+ {3290, {wxStyledTextCtrl, chooseCaretX, 0}},
+ {3291, {wxStyledTextCtrl, setXCaretPolicy, 2}},
+ {3292, {wxStyledTextCtrl, setYCaretPolicy, 2}},
+ {3293, {wxStyledTextCtrl, getPrintWrapMode, 0}},
+ {3294, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
+ {3295, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
+ {3296, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
+ {3297, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
+ {3298, {wxStyledTextCtrl, paraDownExtend, 0}},
+ {3299, {wxStyledTextCtrl, paraUp, 0}},
+ {3300, {wxStyledTextCtrl, paraUpExtend, 0}},
+ {3301, {wxStyledTextCtrl, positionBefore, 1}},
+ {3302, {wxStyledTextCtrl, positionAfter, 1}},
+ {3303, {wxStyledTextCtrl, copyRange, 2}},
+ {3304, {wxStyledTextCtrl, copyText, 2}},
+ {3305, {wxStyledTextCtrl, setSelectionMode, 1}},
+ {3306, {wxStyledTextCtrl, getSelectionMode, 0}},
+ {3307, {wxStyledTextCtrl, lineDownRectExtend, 0}},
+ {3308, {wxStyledTextCtrl, lineUpRectExtend, 0}},
+ {3309, {wxStyledTextCtrl, charLeftRectExtend, 0}},
+ {3310, {wxStyledTextCtrl, charRightRectExtend, 0}},
+ {3311, {wxStyledTextCtrl, homeRectExtend, 0}},
+ {3312, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
+ {3313, {wxStyledTextCtrl, lineEndRectExtend, 0}},
+ {3314, {wxStyledTextCtrl, pageUpRectExtend, 0}},
+ {3315, {wxStyledTextCtrl, pageDownRectExtend, 0}},
+ {3316, {wxStyledTextCtrl, stutteredPageUp, 0}},
+ {3317, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
+ {3318, {wxStyledTextCtrl, stutteredPageDown, 0}},
+ {3319, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
+ {3320, {wxStyledTextCtrl, wordLeftEnd, 0}},
+ {3321, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
+ {3322, {wxStyledTextCtrl, wordRightEnd, 0}},
+ {3323, {wxStyledTextCtrl, wordRightEndExtend, 0}},
+ {3324, {wxStyledTextCtrl, setWhitespaceChars, 1}},
+ {3325, {wxStyledTextCtrl, setCharsDefault, 0}},
+ {3326, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
+ {3327, {wxStyledTextCtrl, allocate, 1}},
+ {3328, {wxStyledTextCtrl, findColumn, 2}},
+ {3329, {wxStyledTextCtrl, getCaretSticky, 0}},
+ {3330, {wxStyledTextCtrl, setCaretSticky, 1}},
+ {3331, {wxStyledTextCtrl, toggleCaretSticky, 0}},
+ {3332, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
+ {3333, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
+ {3334, {wxStyledTextCtrl, selectionDuplicate, 0}},
+ {3335, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
+ {3336, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
+ {3337, {wxStyledTextCtrl, startRecord, 0}},
+ {3338, {wxStyledTextCtrl, stopRecord, 0}},
+ {3339, {wxStyledTextCtrl, setLexer, 1}},
+ {3340, {wxStyledTextCtrl, getLexer, 0}},
+ {3341, {wxStyledTextCtrl, colourise, 2}},
+ {3342, {wxStyledTextCtrl, setProperty, 2}},
+ {3343, {wxStyledTextCtrl, setKeyWords, 2}},
+ {3344, {wxStyledTextCtrl, setLexerLanguage, 1}},
+ {3345, {wxStyledTextCtrl, getProperty, 1}},
+ {3346, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
+ {3347, {wxStyledTextCtrl, getCurrentLine, 0}},
+ {3348, {wxStyledTextCtrl, styleSetSpec, 2}},
+ {3349, {wxStyledTextCtrl, styleSetFont, 2}},
+ {3350, {wxStyledTextCtrl, styleSetFontAttr, 7}},
+ {3351, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
+ {3352, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
+ {3353, {wxStyledTextCtrl, cmdKeyExecute, 1}},
+ {3354, {wxStyledTextCtrl, setMargins, 2}},
+ {3355, {wxStyledTextCtrl, getSelection, 2}},
+ {3356, {wxStyledTextCtrl, pointFromPosition, 1}},
+ {3357, {wxStyledTextCtrl, scrollToLine, 1}},
+ {3358, {wxStyledTextCtrl, scrollToColumn, 1}},
+ {3359, {wxStyledTextCtrl, sendMsg, 2}},
+ {3360, {wxStyledTextCtrl, setVScrollBar, 1}},
+ {3361, {wxStyledTextCtrl, setHScrollBar, 1}},
+ {3362, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
+ {3363, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
+ {3364, {wxStyledTextCtrl, saveFile, 1}},
+ {3365, {wxStyledTextCtrl, loadFile, 1}},
+ {3366, {wxStyledTextCtrl, doDragOver, 3}},
+ {3367, {wxStyledTextCtrl, doDropText, 3}},
+ {3368, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
+ {3369, {wxStyledTextCtrl, addTextRaw, 1}},
+ {3370, {wxStyledTextCtrl, insertTextRaw, 2}},
+ {3371, {wxStyledTextCtrl, getCurLineRaw, 1}},
+ {3372, {wxStyledTextCtrl, getLineRaw, 1}},
+ {3373, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
+ {3374, {wxStyledTextCtrl, getTextRangeRaw, 2}},
+ {3375, {wxStyledTextCtrl, setTextRaw, 1}},
+ {3376, {wxStyledTextCtrl, getTextRaw, 0}},
+ {3377, {wxStyledTextCtrl, appendTextRaw, 1}},
+ {3378, {wxArtProvider, getBitmap, 2}},
+ {3379, {wxArtProvider, getIcon, 2}},
+ {3380, {wxTreeEvent, getKeyCode, 0}},
+ {3381, {wxTreeEvent, getItem, 0}},
+ {3382, {wxTreeEvent, getKeyEvent, 0}},
+ {3383, {wxTreeEvent, getLabel, 0}},
+ {3384, {wxTreeEvent, getOldItem, 0}},
+ {3385, {wxTreeEvent, getPoint, 0}},
+ {3386, {wxTreeEvent, isEditCancelled, 0}},
+ {3387, {wxTreeEvent, setToolTip, 1}},
+ {3388, {wxNotebookEvent, getOldSelection, 0}},
+ {3389, {wxNotebookEvent, getSelection, 0}},
+ {3390, {wxNotebookEvent, setOldSelection, 1}},
+ {3391, {wxNotebookEvent, setSelection, 1}},
+ {3392, {wxFileDataObject, new, 0}},
+ {3393, {wxFileDataObject, addFile, 1}},
+ {3394, {wxFileDataObject, getFilenames, 0}},
+ {3395, {wxFileDataObject, 'Destroy', undefined}},
+ {3396, {wxTextDataObject, new, 1}},
+ {3397, {wxTextDataObject, getTextLength, 0}},
+ {3398, {wxTextDataObject, getText, 0}},
+ {3399, {wxTextDataObject, setText, 1}},
+ {3400, {wxTextDataObject, 'Destroy', undefined}},
+ {3401, {wxBitmapDataObject, new_1_1, 1}},
+ {3402, {wxBitmapDataObject, new_1_0, 1}},
+ {3403, {wxBitmapDataObject, getBitmap, 0}},
+ {3404, {wxBitmapDataObject, setBitmap, 1}},
+ {3405, {wxBitmapDataObject, 'Destroy', undefined}},
+ {3407, {wxClipboard, new, 0}},
+ {3408, {wxClipboard, destruct, 0}},
+ {3409, {wxClipboard, addData, 1}},
+ {3410, {wxClipboard, clear, 0}},
+ {3411, {wxClipboard, close, 0}},
+ {3412, {wxClipboard, flush, 0}},
+ {3413, {wxClipboard, getData, 1}},
+ {3414, {wxClipboard, isOpened, 0}},
+ {3415, {wxClipboard, open, 0}},
+ {3416, {wxClipboard, setData, 1}},
+ {3418, {wxClipboard, usePrimarySelection, 1}},
+ {3419, {wxClipboard, isSupported, 1}},
+ {3420, {wxClipboard, get, 0}},
+ {3421, {wxSpinEvent, getPosition, 0}},
+ {3422, {wxSpinEvent, setPosition, 1}},
+ {3423, {wxSplitterWindow, new_0, 0}},
+ {3424, {wxSplitterWindow, new_2, 2}},
+ {3425, {wxSplitterWindow, destruct, 0}},
+ {3426, {wxSplitterWindow, create, 2}},
+ {3427, {wxSplitterWindow, getMinimumPaneSize, 0}},
+ {3428, {wxSplitterWindow, getSashGravity, 0}},
+ {3429, {wxSplitterWindow, getSashPosition, 0}},
+ {3430, {wxSplitterWindow, getSplitMode, 0}},
+ {3431, {wxSplitterWindow, getWindow1, 0}},
+ {3432, {wxSplitterWindow, getWindow2, 0}},
+ {3433, {wxSplitterWindow, initialize, 1}},
+ {3434, {wxSplitterWindow, isSplit, 0}},
+ {3435, {wxSplitterWindow, replaceWindow, 2}},
+ {3436, {wxSplitterWindow, setSashGravity, 1}},
+ {3437, {wxSplitterWindow, setSashPosition, 2}},
+ {3438, {wxSplitterWindow, setSashSize, 1}},
+ {3439, {wxSplitterWindow, setMinimumPaneSize, 1}},
+ {3440, {wxSplitterWindow, setSplitMode, 1}},
+ {3441, {wxSplitterWindow, splitHorizontally, 3}},
+ {3442, {wxSplitterWindow, splitVertically, 3}},
+ {3443, {wxSplitterWindow, unsplit, 1}},
+ {3444, {wxSplitterWindow, updateSize, 0}},
+ {3445, {wxSplitterEvent, getSashPosition, 0}},
+ {3446, {wxSplitterEvent, getX, 0}},
+ {3447, {wxSplitterEvent, getY, 0}},
+ {3448, {wxSplitterEvent, getWindowBeingRemoved, 0}},
+ {3449, {wxSplitterEvent, setSashPosition, 1}},
+ {3450, {wxHtmlWindow, new_0, 0}},
+ {3451, {wxHtmlWindow, new_2, 2}},
+ {3452, {wxHtmlWindow, appendToPage, 1}},
+ {3453, {wxHtmlWindow, getOpenedAnchor, 0}},
+ {3454, {wxHtmlWindow, getOpenedPage, 0}},
+ {3455, {wxHtmlWindow, getOpenedPageTitle, 0}},
+ {3456, {wxHtmlWindow, getRelatedFrame, 0}},
+ {3457, {wxHtmlWindow, historyBack, 0}},
+ {3458, {wxHtmlWindow, historyCanBack, 0}},
+ {3459, {wxHtmlWindow, historyCanForward, 0}},
+ {3460, {wxHtmlWindow, historyClear, 0}},
+ {3461, {wxHtmlWindow, historyForward, 0}},
+ {3462, {wxHtmlWindow, loadFile, 1}},
+ {3463, {wxHtmlWindow, loadPage, 1}},
+ {3464, {wxHtmlWindow, selectAll, 0}},
+ {3465, {wxHtmlWindow, selectionToText, 0}},
+ {3466, {wxHtmlWindow, selectLine, 1}},
+ {3467, {wxHtmlWindow, selectWord, 1}},
+ {3468, {wxHtmlWindow, setBorders, 1}},
+ {3469, {wxHtmlWindow, setFonts, 3}},
+ {3470, {wxHtmlWindow, setPage, 1}},
+ {3471, {wxHtmlWindow, setRelatedFrame, 2}},
+ {3472, {wxHtmlWindow, setRelatedStatusBar, 1}},
+ {3473, {wxHtmlWindow, toText, 0}},
+ {3474, {wxHtmlWindow, 'Destroy', undefined}},
+ {3475, {wxHtmlLinkEvent, getLinkInfo, 0}},
+ {3476, {wxSystemSettings, getColour, 1}},
+ {3477, {wxSystemSettings, getFont, 1}},
+ {3478, {wxSystemSettings, getMetric, 2}},
+ {3479, {wxSystemSettings, getScreenType, 0}},
+ {3480, {wxAuiNotebookEvent, setSelection, 1}},
+ {3481, {wxAuiNotebookEvent, getSelection, 0}},
+ {3482, {wxAuiNotebookEvent, setOldSelection, 1}},
+ {3483, {wxAuiNotebookEvent, getOldSelection, 0}},
+ {3484, {wxAuiNotebookEvent, setDragSource, 1}},
+ {3485, {wxAuiNotebookEvent, getDragSource, 0}},
+ {3486, {wxAuiManagerEvent, setManager, 1}},
+ {3487, {wxAuiManagerEvent, getManager, 0}},
+ {3488, {wxAuiManagerEvent, setPane, 1}},
+ {3489, {wxAuiManagerEvent, getPane, 0}},
+ {3490, {wxAuiManagerEvent, setButton, 1}},
+ {3491, {wxAuiManagerEvent, getButton, 0}},
+ {3492, {wxAuiManagerEvent, setDC, 1}},
+ {3493, {wxAuiManagerEvent, getDC, 0}},
+ {3494, {wxAuiManagerEvent, veto, 1}},
+ {3495, {wxAuiManagerEvent, getVeto, 0}},
+ {3496, {wxAuiManagerEvent, setCanVeto, 1}},
+ {3497, {wxAuiManagerEvent, canVeto, 0}},
+ {3498, {wxLogNull, new, 0}},
+ {3499, {wxLogNull, 'Destroy', undefined}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index 7b5ca229c8..cf672644c6 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -1834,1442 +1834,1447 @@
-define(wxTreeCtrl_Delete, 2007).
-define(wxTreeCtrl_DeleteAllItems, 2008).
-define(wxTreeCtrl_DeleteChildren, 2009).
--define(wxTreeCtrl_EnsureVisible, 2010).
--define(wxTreeCtrl_Expand, 2011).
--define(wxTreeCtrl_GetBoundingRect, 2012).
--define(wxTreeCtrl_GetChildrenCount, 2014).
--define(wxTreeCtrl_GetCount, 2015).
--define(wxTreeCtrl_GetEditControl, 2016).
--define(wxTreeCtrl_GetFirstChild, 2017).
--define(wxTreeCtrl_GetNextChild, 2018).
--define(wxTreeCtrl_GetFirstVisibleItem, 2019).
--define(wxTreeCtrl_GetImageList, 2020).
--define(wxTreeCtrl_GetIndent, 2021).
--define(wxTreeCtrl_GetItemBackgroundColour, 2022).
--define(wxTreeCtrl_GetItemData, 2023).
--define(wxTreeCtrl_GetItemFont, 2024).
--define(wxTreeCtrl_GetItemImage_1, 2025).
--define(wxTreeCtrl_GetItemImage_2, 2026).
--define(wxTreeCtrl_GetItemText, 2027).
--define(wxTreeCtrl_GetItemTextColour, 2028).
--define(wxTreeCtrl_GetLastChild, 2029).
--define(wxTreeCtrl_GetNextSibling, 2030).
--define(wxTreeCtrl_GetNextVisible, 2031).
--define(wxTreeCtrl_GetItemParent, 2032).
--define(wxTreeCtrl_GetPrevSibling, 2033).
--define(wxTreeCtrl_GetPrevVisible, 2034).
--define(wxTreeCtrl_GetRootItem, 2035).
--define(wxTreeCtrl_GetSelection, 2036).
--define(wxTreeCtrl_GetSelections, 2037).
--define(wxTreeCtrl_GetStateImageList, 2038).
--define(wxTreeCtrl_HitTest, 2039).
--define(wxTreeCtrl_InsertItem, 2041).
--define(wxTreeCtrl_IsBold, 2042).
--define(wxTreeCtrl_IsExpanded, 2043).
--define(wxTreeCtrl_IsSelected, 2044).
--define(wxTreeCtrl_IsVisible, 2045).
--define(wxTreeCtrl_ItemHasChildren, 2046).
--define(wxTreeCtrl_PrependItem, 2047).
--define(wxTreeCtrl_ScrollTo, 2048).
--define(wxTreeCtrl_SelectItem_1, 2049).
--define(wxTreeCtrl_SelectItem_2, 2050).
--define(wxTreeCtrl_SetIndent, 2051).
--define(wxTreeCtrl_SetImageList, 2052).
--define(wxTreeCtrl_SetItemBackgroundColour, 2053).
--define(wxTreeCtrl_SetItemBold, 2054).
--define(wxTreeCtrl_SetItemData, 2055).
--define(wxTreeCtrl_SetItemDropHighlight, 2056).
--define(wxTreeCtrl_SetItemFont, 2057).
--define(wxTreeCtrl_SetItemHasChildren, 2058).
--define(wxTreeCtrl_SetItemImage_2, 2059).
--define(wxTreeCtrl_SetItemImage_3, 2060).
--define(wxTreeCtrl_SetItemText, 2061).
--define(wxTreeCtrl_SetItemTextColour, 2062).
--define(wxTreeCtrl_SetStateImageList, 2063).
--define(wxTreeCtrl_SetWindowStyle, 2064).
--define(wxTreeCtrl_SortChildren, 2065).
--define(wxTreeCtrl_Toggle, 2066).
--define(wxTreeCtrl_ToggleItemSelection, 2067).
--define(wxTreeCtrl_Unselect, 2068).
--define(wxTreeCtrl_UnselectAll, 2069).
--define(wxTreeCtrl_UnselectItem, 2070).
--define(wxScrollBar_new_0, 2071).
--define(wxScrollBar_new_3, 2072).
--define(wxScrollBar_destruct, 2073).
--define(wxScrollBar_Create, 2074).
--define(wxScrollBar_GetRange, 2075).
--define(wxScrollBar_GetPageSize, 2076).
--define(wxScrollBar_GetThumbPosition, 2077).
--define(wxScrollBar_GetThumbSize, 2078).
--define(wxScrollBar_SetThumbPosition, 2079).
--define(wxScrollBar_SetScrollbar, 2080).
--define(wxSpinButton_new_2, 2082).
--define(wxSpinButton_new_0, 2083).
--define(wxSpinButton_Create, 2084).
--define(wxSpinButton_GetMax, 2085).
--define(wxSpinButton_GetMin, 2086).
--define(wxSpinButton_GetValue, 2087).
--define(wxSpinButton_SetRange, 2088).
--define(wxSpinButton_SetValue, 2089).
--define(wxSpinButton_destroy, 2090).
--define(wxSpinCtrl_new_0, 2091).
--define(wxSpinCtrl_new_2, 2092).
--define(wxSpinCtrl_Create, 2094).
--define(wxSpinCtrl_SetValue_1_1, 2097).
--define(wxSpinCtrl_SetValue_1_0, 2098).
--define(wxSpinCtrl_GetValue, 2100).
--define(wxSpinCtrl_SetRange, 2102).
--define(wxSpinCtrl_SetSelection, 2103).
--define(wxSpinCtrl_GetMin, 2105).
--define(wxSpinCtrl_GetMax, 2107).
--define(wxSpinCtrl_destroy, 2108).
--define(wxStaticText_new_0, 2109).
--define(wxStaticText_new_4, 2110).
--define(wxStaticText_Create, 2111).
--define(wxStaticText_GetLabel, 2112).
--define(wxStaticText_SetLabel, 2113).
--define(wxStaticText_Wrap, 2114).
--define(wxStaticText_destroy, 2115).
--define(wxStaticBitmap_new_0, 2116).
--define(wxStaticBitmap_new_4, 2117).
--define(wxStaticBitmap_Create, 2118).
--define(wxStaticBitmap_GetBitmap, 2119).
--define(wxStaticBitmap_SetBitmap, 2120).
--define(wxStaticBitmap_destroy, 2121).
--define(wxRadioBox_new, 2122).
--define(wxRadioBox_destruct, 2124).
--define(wxRadioBox_Create, 2125).
--define(wxRadioBox_Enable_2, 2126).
--define(wxRadioBox_Enable_1, 2127).
--define(wxRadioBox_GetSelection, 2128).
--define(wxRadioBox_GetString, 2129).
--define(wxRadioBox_SetSelection, 2130).
--define(wxRadioBox_Show_2, 2131).
--define(wxRadioBox_Show_1, 2132).
--define(wxRadioBox_GetColumnCount, 2133).
--define(wxRadioBox_GetItemHelpText, 2134).
--define(wxRadioBox_GetItemToolTip, 2135).
--define(wxRadioBox_GetItemFromPoint, 2137).
--define(wxRadioBox_GetRowCount, 2138).
--define(wxRadioBox_IsItemEnabled, 2139).
--define(wxRadioBox_IsItemShown, 2140).
--define(wxRadioBox_SetItemHelpText, 2141).
--define(wxRadioBox_SetItemToolTip, 2142).
--define(wxRadioButton_new_0, 2143).
--define(wxRadioButton_new_4, 2144).
--define(wxRadioButton_Create, 2145).
--define(wxRadioButton_GetValue, 2146).
--define(wxRadioButton_SetValue, 2147).
--define(wxRadioButton_destroy, 2148).
--define(wxSlider_new_6, 2150).
--define(wxSlider_new_0, 2151).
--define(wxSlider_Create, 2152).
--define(wxSlider_GetLineSize, 2153).
--define(wxSlider_GetMax, 2154).
--define(wxSlider_GetMin, 2155).
--define(wxSlider_GetPageSize, 2156).
--define(wxSlider_GetThumbLength, 2157).
--define(wxSlider_GetValue, 2158).
--define(wxSlider_SetLineSize, 2159).
--define(wxSlider_SetPageSize, 2160).
--define(wxSlider_SetRange, 2161).
--define(wxSlider_SetThumbLength, 2162).
--define(wxSlider_SetValue, 2163).
--define(wxSlider_destroy, 2164).
--define(wxDialog_new_4, 2166).
--define(wxDialog_new_0, 2167).
--define(wxDialog_destruct, 2169).
--define(wxDialog_Create, 2170).
--define(wxDialog_CreateButtonSizer, 2171).
--define(wxDialog_CreateStdDialogButtonSizer, 2172).
--define(wxDialog_EndModal, 2173).
--define(wxDialog_GetAffirmativeId, 2174).
--define(wxDialog_GetReturnCode, 2175).
--define(wxDialog_IsModal, 2176).
--define(wxDialog_SetAffirmativeId, 2177).
--define(wxDialog_SetReturnCode, 2178).
--define(wxDialog_Show, 2179).
--define(wxDialog_ShowModal, 2180).
--define(wxColourDialog_new_0, 2181).
--define(wxColourDialog_new_2, 2182).
--define(wxColourDialog_destruct, 2183).
--define(wxColourDialog_Create, 2184).
--define(wxColourDialog_GetColourData, 2185).
--define(wxColourData_new_0, 2186).
--define(wxColourData_new_1, 2187).
--define(wxColourData_destruct, 2188).
--define(wxColourData_GetChooseFull, 2189).
--define(wxColourData_GetColour, 2190).
--define(wxColourData_GetCustomColour, 2192).
--define(wxColourData_SetChooseFull, 2193).
--define(wxColourData_SetColour, 2194).
--define(wxColourData_SetCustomColour, 2195).
--define(wxPalette_new_0, 2196).
--define(wxPalette_new_4, 2197).
--define(wxPalette_destruct, 2199).
--define(wxPalette_Create, 2200).
--define(wxPalette_GetColoursCount, 2201).
--define(wxPalette_GetPixel, 2202).
--define(wxPalette_GetRGB, 2203).
--define(wxPalette_IsOk, 2204).
--define(wxDirDialog_new, 2208).
--define(wxDirDialog_destruct, 2209).
--define(wxDirDialog_GetPath, 2210).
--define(wxDirDialog_GetMessage, 2211).
--define(wxDirDialog_SetMessage, 2212).
--define(wxDirDialog_SetPath, 2213).
--define(wxFileDialog_new, 2217).
--define(wxFileDialog_destruct, 2218).
--define(wxFileDialog_GetDirectory, 2219).
--define(wxFileDialog_GetFilename, 2220).
--define(wxFileDialog_GetFilenames, 2221).
--define(wxFileDialog_GetFilterIndex, 2222).
--define(wxFileDialog_GetMessage, 2223).
--define(wxFileDialog_GetPath, 2224).
--define(wxFileDialog_GetPaths, 2225).
--define(wxFileDialog_GetWildcard, 2226).
--define(wxFileDialog_SetDirectory, 2227).
--define(wxFileDialog_SetFilename, 2228).
--define(wxFileDialog_SetFilterIndex, 2229).
--define(wxFileDialog_SetMessage, 2230).
--define(wxFileDialog_SetPath, 2231).
--define(wxFileDialog_SetWildcard, 2232).
--define(wxPickerBase_SetInternalMargin, 2233).
--define(wxPickerBase_GetInternalMargin, 2234).
--define(wxPickerBase_SetTextCtrlProportion, 2235).
--define(wxPickerBase_SetPickerCtrlProportion, 2236).
--define(wxPickerBase_GetTextCtrlProportion, 2237).
--define(wxPickerBase_GetPickerCtrlProportion, 2238).
--define(wxPickerBase_HasTextCtrl, 2239).
--define(wxPickerBase_GetTextCtrl, 2240).
--define(wxPickerBase_IsTextCtrlGrowable, 2241).
--define(wxPickerBase_SetPickerCtrlGrowable, 2242).
--define(wxPickerBase_SetTextCtrlGrowable, 2243).
--define(wxPickerBase_IsPickerCtrlGrowable, 2244).
--define(wxFilePickerCtrl_new_0, 2245).
--define(wxFilePickerCtrl_new_3, 2246).
--define(wxFilePickerCtrl_Create, 2247).
--define(wxFilePickerCtrl_GetPath, 2248).
--define(wxFilePickerCtrl_SetPath, 2249).
--define(wxFilePickerCtrl_destroy, 2250).
--define(wxDirPickerCtrl_new_0, 2251).
--define(wxDirPickerCtrl_new_3, 2252).
--define(wxDirPickerCtrl_Create, 2253).
--define(wxDirPickerCtrl_GetPath, 2254).
--define(wxDirPickerCtrl_SetPath, 2255).
--define(wxDirPickerCtrl_destroy, 2256).
--define(wxColourPickerCtrl_new_0, 2257).
--define(wxColourPickerCtrl_new_3, 2258).
--define(wxColourPickerCtrl_Create, 2259).
--define(wxColourPickerCtrl_GetColour, 2260).
--define(wxColourPickerCtrl_SetColour_1_1, 2261).
--define(wxColourPickerCtrl_SetColour_1_0, 2262).
--define(wxColourPickerCtrl_destroy, 2263).
--define(wxDatePickerCtrl_new_0, 2264).
--define(wxDatePickerCtrl_new_3, 2265).
--define(wxDatePickerCtrl_GetRange, 2266).
--define(wxDatePickerCtrl_GetValue, 2267).
--define(wxDatePickerCtrl_SetRange, 2268).
--define(wxDatePickerCtrl_SetValue, 2269).
--define(wxDatePickerCtrl_destroy, 2270).
--define(wxFontPickerCtrl_new_0, 2271).
--define(wxFontPickerCtrl_new_3, 2272).
--define(wxFontPickerCtrl_Create, 2273).
--define(wxFontPickerCtrl_GetSelectedFont, 2274).
--define(wxFontPickerCtrl_SetSelectedFont, 2275).
--define(wxFontPickerCtrl_GetMaxPointSize, 2276).
--define(wxFontPickerCtrl_SetMaxPointSize, 2277).
--define(wxFontPickerCtrl_destroy, 2278).
--define(wxFindReplaceDialog_new_0, 2281).
--define(wxFindReplaceDialog_new_4, 2282).
--define(wxFindReplaceDialog_destruct, 2283).
--define(wxFindReplaceDialog_Create, 2284).
--define(wxFindReplaceDialog_GetData, 2285).
--define(wxFindReplaceData_new_0, 2286).
--define(wxFindReplaceData_new_1, 2287).
--define(wxFindReplaceData_GetFindString, 2288).
--define(wxFindReplaceData_GetReplaceString, 2289).
--define(wxFindReplaceData_GetFlags, 2290).
--define(wxFindReplaceData_SetFlags, 2291).
--define(wxFindReplaceData_SetFindString, 2292).
--define(wxFindReplaceData_SetReplaceString, 2293).
--define(wxFindReplaceData_destroy, 2294).
--define(wxMultiChoiceDialog_new_0, 2295).
--define(wxMultiChoiceDialog_new_5, 2297).
--define(wxMultiChoiceDialog_GetSelections, 2298).
--define(wxMultiChoiceDialog_SetSelections, 2299).
--define(wxMultiChoiceDialog_destroy, 2300).
--define(wxSingleChoiceDialog_new_0, 2301).
--define(wxSingleChoiceDialog_new_5, 2303).
--define(wxSingleChoiceDialog_GetSelection, 2304).
--define(wxSingleChoiceDialog_GetStringSelection, 2305).
--define(wxSingleChoiceDialog_SetSelection, 2306).
--define(wxSingleChoiceDialog_destroy, 2307).
--define(wxTextEntryDialog_new, 2308).
--define(wxTextEntryDialog_GetValue, 2309).
--define(wxTextEntryDialog_SetValue, 2310).
--define(wxTextEntryDialog_destroy, 2311).
--define(wxPasswordEntryDialog_new, 2312).
--define(wxPasswordEntryDialog_destroy, 2313).
--define(wxFontData_new_0, 2314).
--define(wxFontData_new_1, 2315).
--define(wxFontData_destruct, 2316).
--define(wxFontData_EnableEffects, 2317).
--define(wxFontData_GetAllowSymbols, 2318).
--define(wxFontData_GetColour, 2319).
--define(wxFontData_GetChosenFont, 2320).
--define(wxFontData_GetEnableEffects, 2321).
--define(wxFontData_GetInitialFont, 2322).
--define(wxFontData_GetShowHelp, 2323).
--define(wxFontData_SetAllowSymbols, 2324).
--define(wxFontData_SetChosenFont, 2325).
--define(wxFontData_SetColour, 2326).
--define(wxFontData_SetInitialFont, 2327).
--define(wxFontData_SetRange, 2328).
--define(wxFontData_SetShowHelp, 2329).
--define(wxFontDialog_new_0, 2333).
--define(wxFontDialog_new_2, 2335).
--define(wxFontDialog_Create, 2337).
--define(wxFontDialog_GetFontData, 2338).
--define(wxFontDialog_destroy, 2340).
--define(wxProgressDialog_new, 2341).
--define(wxProgressDialog_destruct, 2342).
--define(wxProgressDialog_Resume, 2343).
--define(wxProgressDialog_Update_2, 2344).
--define(wxProgressDialog_Update_0, 2345).
--define(wxMessageDialog_new, 2346).
--define(wxMessageDialog_destruct, 2347).
--define(wxPageSetupDialog_new, 2348).
--define(wxPageSetupDialog_destruct, 2349).
--define(wxPageSetupDialog_GetPageSetupData, 2350).
--define(wxPageSetupDialog_ShowModal, 2351).
--define(wxPageSetupDialogData_new_0, 2352).
--define(wxPageSetupDialogData_new_1_0, 2353).
--define(wxPageSetupDialogData_new_1_1, 2354).
--define(wxPageSetupDialogData_destruct, 2355).
--define(wxPageSetupDialogData_EnableHelp, 2356).
--define(wxPageSetupDialogData_EnableMargins, 2357).
--define(wxPageSetupDialogData_EnableOrientation, 2358).
--define(wxPageSetupDialogData_EnablePaper, 2359).
--define(wxPageSetupDialogData_EnablePrinter, 2360).
--define(wxPageSetupDialogData_GetDefaultMinMargins, 2361).
--define(wxPageSetupDialogData_GetEnableMargins, 2362).
--define(wxPageSetupDialogData_GetEnableOrientation, 2363).
--define(wxPageSetupDialogData_GetEnablePaper, 2364).
--define(wxPageSetupDialogData_GetEnablePrinter, 2365).
--define(wxPageSetupDialogData_GetEnableHelp, 2366).
--define(wxPageSetupDialogData_GetDefaultInfo, 2367).
--define(wxPageSetupDialogData_GetMarginTopLeft, 2368).
--define(wxPageSetupDialogData_GetMarginBottomRight, 2369).
--define(wxPageSetupDialogData_GetMinMarginTopLeft, 2370).
--define(wxPageSetupDialogData_GetMinMarginBottomRight, 2371).
--define(wxPageSetupDialogData_GetPaperId, 2372).
--define(wxPageSetupDialogData_GetPaperSize, 2373).
--define(wxPageSetupDialogData_GetPrintData, 2375).
--define(wxPageSetupDialogData_IsOk, 2376).
--define(wxPageSetupDialogData_SetDefaultInfo, 2377).
--define(wxPageSetupDialogData_SetDefaultMinMargins, 2378).
--define(wxPageSetupDialogData_SetMarginTopLeft, 2379).
--define(wxPageSetupDialogData_SetMarginBottomRight, 2380).
--define(wxPageSetupDialogData_SetMinMarginTopLeft, 2381).
--define(wxPageSetupDialogData_SetMinMarginBottomRight, 2382).
--define(wxPageSetupDialogData_SetPaperId, 2383).
--define(wxPageSetupDialogData_SetPaperSize_1_1, 2384).
--define(wxPageSetupDialogData_SetPaperSize_1_0, 2385).
--define(wxPageSetupDialogData_SetPrintData, 2386).
--define(wxPrintDialog_new_2_0, 2387).
--define(wxPrintDialog_new_2_1, 2388).
--define(wxPrintDialog_destruct, 2389).
--define(wxPrintDialog_GetPrintDialogData, 2390).
--define(wxPrintDialog_GetPrintDC, 2391).
--define(wxPrintDialogData_new_0, 2392).
--define(wxPrintDialogData_new_1_1, 2393).
--define(wxPrintDialogData_new_1_0, 2394).
--define(wxPrintDialogData_destruct, 2395).
--define(wxPrintDialogData_EnableHelp, 2396).
--define(wxPrintDialogData_EnablePageNumbers, 2397).
--define(wxPrintDialogData_EnablePrintToFile, 2398).
--define(wxPrintDialogData_EnableSelection, 2399).
--define(wxPrintDialogData_GetAllPages, 2400).
--define(wxPrintDialogData_GetCollate, 2401).
--define(wxPrintDialogData_GetFromPage, 2402).
--define(wxPrintDialogData_GetMaxPage, 2403).
--define(wxPrintDialogData_GetMinPage, 2404).
--define(wxPrintDialogData_GetNoCopies, 2405).
--define(wxPrintDialogData_GetPrintData, 2406).
--define(wxPrintDialogData_GetPrintToFile, 2407).
--define(wxPrintDialogData_GetSelection, 2408).
--define(wxPrintDialogData_GetToPage, 2409).
--define(wxPrintDialogData_IsOk, 2410).
--define(wxPrintDialogData_SetCollate, 2411).
--define(wxPrintDialogData_SetFromPage, 2412).
--define(wxPrintDialogData_SetMaxPage, 2413).
--define(wxPrintDialogData_SetMinPage, 2414).
--define(wxPrintDialogData_SetNoCopies, 2415).
--define(wxPrintDialogData_SetPrintData, 2416).
--define(wxPrintDialogData_SetPrintToFile, 2417).
--define(wxPrintDialogData_SetSelection, 2418).
--define(wxPrintDialogData_SetToPage, 2419).
--define(wxPrintData_new_0, 2420).
--define(wxPrintData_new_1, 2421).
--define(wxPrintData_destruct, 2422).
--define(wxPrintData_GetCollate, 2423).
--define(wxPrintData_GetBin, 2424).
--define(wxPrintData_GetColour, 2425).
--define(wxPrintData_GetDuplex, 2426).
--define(wxPrintData_GetNoCopies, 2427).
--define(wxPrintData_GetOrientation, 2428).
--define(wxPrintData_GetPaperId, 2429).
--define(wxPrintData_GetPrinterName, 2430).
--define(wxPrintData_GetQuality, 2431).
--define(wxPrintData_IsOk, 2432).
--define(wxPrintData_SetBin, 2433).
--define(wxPrintData_SetCollate, 2434).
--define(wxPrintData_SetColour, 2435).
--define(wxPrintData_SetDuplex, 2436).
--define(wxPrintData_SetNoCopies, 2437).
--define(wxPrintData_SetOrientation, 2438).
--define(wxPrintData_SetPaperId, 2439).
--define(wxPrintData_SetPrinterName, 2440).
--define(wxPrintData_SetQuality, 2441).
--define(wxPrintPreview_new_2, 2444).
--define(wxPrintPreview_new_3, 2445).
--define(wxPrintPreview_destruct, 2447).
--define(wxPrintPreview_GetCanvas, 2448).
--define(wxPrintPreview_GetCurrentPage, 2449).
--define(wxPrintPreview_GetFrame, 2450).
--define(wxPrintPreview_GetMaxPage, 2451).
--define(wxPrintPreview_GetMinPage, 2452).
--define(wxPrintPreview_GetPrintout, 2453).
--define(wxPrintPreview_GetPrintoutForPrinting, 2454).
--define(wxPrintPreview_IsOk, 2455).
--define(wxPrintPreview_PaintPage, 2456).
--define(wxPrintPreview_Print, 2457).
--define(wxPrintPreview_RenderPage, 2458).
--define(wxPrintPreview_SetCanvas, 2459).
--define(wxPrintPreview_SetCurrentPage, 2460).
--define(wxPrintPreview_SetFrame, 2461).
--define(wxPrintPreview_SetPrintout, 2462).
--define(wxPrintPreview_SetZoom, 2463).
--define(wxPreviewFrame_new, 2464).
--define(wxPreviewFrame_destruct, 2465).
--define(wxPreviewFrame_CreateControlBar, 2466).
--define(wxPreviewFrame_CreateCanvas, 2467).
--define(wxPreviewFrame_Initialize, 2468).
--define(wxPreviewFrame_OnCloseWindow, 2469).
--define(wxPreviewControlBar_new, 2470).
--define(wxPreviewControlBar_destruct, 2471).
--define(wxPreviewControlBar_CreateButtons, 2472).
--define(wxPreviewControlBar_GetPrintPreview, 2473).
--define(wxPreviewControlBar_GetZoomControl, 2474).
--define(wxPreviewControlBar_SetZoomControl, 2475).
--define(wxPrinter_new, 2477).
--define(wxPrinter_CreateAbortWindow, 2478).
--define(wxPrinter_GetAbort, 2479).
--define(wxPrinter_GetLastError, 2480).
--define(wxPrinter_GetPrintDialogData, 2481).
--define(wxPrinter_Print, 2482).
--define(wxPrinter_PrintDialog, 2483).
--define(wxPrinter_ReportError, 2484).
--define(wxPrinter_Setup, 2485).
--define(wxPrinter_destroy, 2486).
--define(wxXmlResource_new_1, 2487).
--define(wxXmlResource_new_2, 2488).
--define(wxXmlResource_destruct, 2489).
--define(wxXmlResource_AttachUnknownControl, 2490).
--define(wxXmlResource_ClearHandlers, 2491).
--define(wxXmlResource_CompareVersion, 2492).
--define(wxXmlResource_Get, 2493).
--define(wxXmlResource_GetFlags, 2494).
--define(wxXmlResource_GetVersion, 2495).
--define(wxXmlResource_GetXRCID, 2496).
--define(wxXmlResource_InitAllHandlers, 2497).
--define(wxXmlResource_Load, 2498).
--define(wxXmlResource_LoadBitmap, 2499).
--define(wxXmlResource_LoadDialog_2, 2500).
--define(wxXmlResource_LoadDialog_3, 2501).
--define(wxXmlResource_LoadFrame_2, 2502).
--define(wxXmlResource_LoadFrame_3, 2503).
--define(wxXmlResource_LoadIcon, 2504).
--define(wxXmlResource_LoadMenu, 2505).
--define(wxXmlResource_LoadMenuBar_2, 2506).
--define(wxXmlResource_LoadMenuBar_1, 2507).
--define(wxXmlResource_LoadPanel_2, 2508).
--define(wxXmlResource_LoadPanel_3, 2509).
--define(wxXmlResource_LoadToolBar, 2510).
--define(wxXmlResource_Set, 2511).
--define(wxXmlResource_SetFlags, 2512).
--define(wxXmlResource_Unload, 2513).
--define(wxXmlResource_xrcctrl, 2514).
--define(wxHtmlEasyPrinting_new, 2515).
--define(wxHtmlEasyPrinting_destruct, 2516).
--define(wxHtmlEasyPrinting_GetPrintData, 2517).
--define(wxHtmlEasyPrinting_GetPageSetupData, 2518).
--define(wxHtmlEasyPrinting_PreviewFile, 2519).
--define(wxHtmlEasyPrinting_PreviewText, 2520).
--define(wxHtmlEasyPrinting_PrintFile, 2521).
--define(wxHtmlEasyPrinting_PrintText, 2522).
--define(wxHtmlEasyPrinting_PageSetup, 2523).
--define(wxHtmlEasyPrinting_SetFonts, 2524).
--define(wxHtmlEasyPrinting_SetHeader, 2525).
--define(wxHtmlEasyPrinting_SetFooter, 2526).
--define(wxGLCanvas_new_2, 2528).
--define(wxGLCanvas_new_3_1, 2529).
--define(wxGLCanvas_new_3_0, 2530).
--define(wxGLCanvas_GetContext, 2531).
--define(wxGLCanvas_SetCurrent, 2533).
--define(wxGLCanvas_SwapBuffers, 2534).
--define(wxGLCanvas_destroy, 2535).
--define(wxAuiManager_new, 2536).
--define(wxAuiManager_destruct, 2537).
--define(wxAuiManager_AddPane_2_1, 2538).
--define(wxAuiManager_AddPane_3, 2539).
--define(wxAuiManager_AddPane_2_0, 2540).
--define(wxAuiManager_DetachPane, 2541).
--define(wxAuiManager_GetAllPanes, 2542).
--define(wxAuiManager_GetArtProvider, 2543).
--define(wxAuiManager_GetDockSizeConstraint, 2544).
--define(wxAuiManager_GetFlags, 2545).
--define(wxAuiManager_GetManagedWindow, 2546).
--define(wxAuiManager_GetManager, 2547).
--define(wxAuiManager_GetPane_1_1, 2548).
--define(wxAuiManager_GetPane_1_0, 2549).
--define(wxAuiManager_HideHint, 2550).
--define(wxAuiManager_InsertPane, 2551).
--define(wxAuiManager_LoadPaneInfo, 2552).
--define(wxAuiManager_LoadPerspective, 2553).
--define(wxAuiManager_SavePaneInfo, 2554).
--define(wxAuiManager_SavePerspective, 2555).
--define(wxAuiManager_SetArtProvider, 2556).
--define(wxAuiManager_SetDockSizeConstraint, 2557).
--define(wxAuiManager_SetFlags, 2558).
--define(wxAuiManager_SetManagedWindow, 2559).
--define(wxAuiManager_ShowHint, 2560).
--define(wxAuiManager_UnInit, 2561).
--define(wxAuiManager_Update, 2562).
--define(wxAuiPaneInfo_new_0, 2563).
--define(wxAuiPaneInfo_new_1, 2564).
--define(wxAuiPaneInfo_destruct, 2565).
--define(wxAuiPaneInfo_BestSize_1, 2566).
--define(wxAuiPaneInfo_BestSize_2, 2567).
--define(wxAuiPaneInfo_Bottom, 2568).
--define(wxAuiPaneInfo_BottomDockable, 2569).
--define(wxAuiPaneInfo_Caption, 2570).
--define(wxAuiPaneInfo_CaptionVisible, 2571).
--define(wxAuiPaneInfo_Centre, 2572).
--define(wxAuiPaneInfo_CentrePane, 2573).
--define(wxAuiPaneInfo_CloseButton, 2574).
--define(wxAuiPaneInfo_DefaultPane, 2575).
--define(wxAuiPaneInfo_DestroyOnClose, 2576).
--define(wxAuiPaneInfo_Direction, 2577).
--define(wxAuiPaneInfo_Dock, 2578).
--define(wxAuiPaneInfo_Dockable, 2579).
--define(wxAuiPaneInfo_Fixed, 2580).
--define(wxAuiPaneInfo_Float, 2581).
--define(wxAuiPaneInfo_Floatable, 2582).
--define(wxAuiPaneInfo_FloatingPosition_1, 2583).
--define(wxAuiPaneInfo_FloatingPosition_2, 2584).
--define(wxAuiPaneInfo_FloatingSize_1, 2585).
--define(wxAuiPaneInfo_FloatingSize_2, 2586).
--define(wxAuiPaneInfo_Gripper, 2587).
--define(wxAuiPaneInfo_GripperTop, 2588).
--define(wxAuiPaneInfo_HasBorder, 2589).
--define(wxAuiPaneInfo_HasCaption, 2590).
--define(wxAuiPaneInfo_HasCloseButton, 2591).
--define(wxAuiPaneInfo_HasFlag, 2592).
--define(wxAuiPaneInfo_HasGripper, 2593).
--define(wxAuiPaneInfo_HasGripperTop, 2594).
--define(wxAuiPaneInfo_HasMaximizeButton, 2595).
--define(wxAuiPaneInfo_HasMinimizeButton, 2596).
--define(wxAuiPaneInfo_HasPinButton, 2597).
--define(wxAuiPaneInfo_Hide, 2598).
--define(wxAuiPaneInfo_IsBottomDockable, 2599).
--define(wxAuiPaneInfo_IsDocked, 2600).
--define(wxAuiPaneInfo_IsFixed, 2601).
--define(wxAuiPaneInfo_IsFloatable, 2602).
--define(wxAuiPaneInfo_IsFloating, 2603).
--define(wxAuiPaneInfo_IsLeftDockable, 2604).
--define(wxAuiPaneInfo_IsMovable, 2605).
--define(wxAuiPaneInfo_IsOk, 2606).
--define(wxAuiPaneInfo_IsResizable, 2607).
--define(wxAuiPaneInfo_IsRightDockable, 2608).
--define(wxAuiPaneInfo_IsShown, 2609).
--define(wxAuiPaneInfo_IsToolbar, 2610).
--define(wxAuiPaneInfo_IsTopDockable, 2611).
--define(wxAuiPaneInfo_Layer, 2612).
--define(wxAuiPaneInfo_Left, 2613).
--define(wxAuiPaneInfo_LeftDockable, 2614).
--define(wxAuiPaneInfo_MaxSize_1, 2615).
--define(wxAuiPaneInfo_MaxSize_2, 2616).
--define(wxAuiPaneInfo_MaximizeButton, 2617).
--define(wxAuiPaneInfo_MinSize_1, 2618).
--define(wxAuiPaneInfo_MinSize_2, 2619).
--define(wxAuiPaneInfo_MinimizeButton, 2620).
--define(wxAuiPaneInfo_Movable, 2621).
--define(wxAuiPaneInfo_Name, 2622).
--define(wxAuiPaneInfo_PaneBorder, 2623).
--define(wxAuiPaneInfo_PinButton, 2624).
--define(wxAuiPaneInfo_Position, 2625).
--define(wxAuiPaneInfo_Resizable, 2626).
--define(wxAuiPaneInfo_Right, 2627).
--define(wxAuiPaneInfo_RightDockable, 2628).
--define(wxAuiPaneInfo_Row, 2629).
--define(wxAuiPaneInfo_SafeSet, 2630).
--define(wxAuiPaneInfo_SetFlag, 2631).
--define(wxAuiPaneInfo_Show, 2632).
--define(wxAuiPaneInfo_ToolbarPane, 2633).
--define(wxAuiPaneInfo_Top, 2634).
--define(wxAuiPaneInfo_TopDockable, 2635).
--define(wxAuiPaneInfo_Window, 2636).
--define(wxAuiNotebook_new_0, 2637).
--define(wxAuiNotebook_new_2, 2638).
--define(wxAuiNotebook_AddPage, 2639).
--define(wxAuiNotebook_Create, 2640).
--define(wxAuiNotebook_DeletePage, 2641).
--define(wxAuiNotebook_GetArtProvider, 2642).
--define(wxAuiNotebook_GetPage, 2643).
--define(wxAuiNotebook_GetPageBitmap, 2644).
--define(wxAuiNotebook_GetPageCount, 2645).
--define(wxAuiNotebook_GetPageIndex, 2646).
--define(wxAuiNotebook_GetPageText, 2647).
--define(wxAuiNotebook_GetSelection, 2648).
--define(wxAuiNotebook_InsertPage, 2649).
--define(wxAuiNotebook_RemovePage, 2650).
--define(wxAuiNotebook_SetArtProvider, 2651).
--define(wxAuiNotebook_SetFont, 2652).
--define(wxAuiNotebook_SetPageBitmap, 2653).
--define(wxAuiNotebook_SetPageText, 2654).
--define(wxAuiNotebook_SetSelection, 2655).
--define(wxAuiNotebook_SetTabCtrlHeight, 2656).
--define(wxAuiNotebook_SetUniformBitmapSize, 2657).
--define(wxAuiNotebook_destroy, 2658).
--define(wxMDIParentFrame_new_0, 2659).
--define(wxMDIParentFrame_new_4, 2660).
--define(wxMDIParentFrame_destruct, 2661).
--define(wxMDIParentFrame_ActivateNext, 2662).
--define(wxMDIParentFrame_ActivatePrevious, 2663).
--define(wxMDIParentFrame_ArrangeIcons, 2664).
--define(wxMDIParentFrame_Cascade, 2665).
--define(wxMDIParentFrame_Create, 2666).
--define(wxMDIParentFrame_GetActiveChild, 2667).
--define(wxMDIParentFrame_GetClientWindow, 2668).
--define(wxMDIParentFrame_Tile, 2669).
--define(wxMDIChildFrame_new_0, 2670).
--define(wxMDIChildFrame_new_4, 2671).
--define(wxMDIChildFrame_destruct, 2672).
--define(wxMDIChildFrame_Activate, 2673).
--define(wxMDIChildFrame_Create, 2674).
--define(wxMDIChildFrame_Maximize, 2675).
--define(wxMDIChildFrame_Restore, 2676).
--define(wxMDIClientWindow_new_0, 2677).
--define(wxMDIClientWindow_new_2, 2678).
--define(wxMDIClientWindow_destruct, 2679).
--define(wxMDIClientWindow_CreateClient, 2680).
--define(wxLayoutAlgorithm_new, 2681).
--define(wxLayoutAlgorithm_LayoutFrame, 2682).
--define(wxLayoutAlgorithm_LayoutMDIFrame, 2683).
--define(wxLayoutAlgorithm_LayoutWindow, 2684).
--define(wxLayoutAlgorithm_destroy, 2685).
--define(wxEvent_GetId, 2686).
--define(wxEvent_GetSkipped, 2687).
--define(wxEvent_GetTimestamp, 2688).
--define(wxEvent_IsCommandEvent, 2689).
--define(wxEvent_ResumePropagation, 2690).
--define(wxEvent_ShouldPropagate, 2691).
--define(wxEvent_Skip, 2692).
--define(wxEvent_StopPropagation, 2693).
--define(wxCommandEvent_getClientData, 2694).
--define(wxCommandEvent_GetExtraLong, 2695).
--define(wxCommandEvent_GetInt, 2696).
--define(wxCommandEvent_GetSelection, 2697).
--define(wxCommandEvent_GetString, 2698).
--define(wxCommandEvent_IsChecked, 2699).
--define(wxCommandEvent_IsSelection, 2700).
--define(wxCommandEvent_SetInt, 2701).
--define(wxCommandEvent_SetString, 2702).
--define(wxScrollEvent_GetOrientation, 2703).
--define(wxScrollEvent_GetPosition, 2704).
--define(wxScrollWinEvent_GetOrientation, 2705).
--define(wxScrollWinEvent_GetPosition, 2706).
--define(wxMouseEvent_AltDown, 2707).
--define(wxMouseEvent_Button, 2708).
--define(wxMouseEvent_ButtonDClick, 2709).
--define(wxMouseEvent_ButtonDown, 2710).
--define(wxMouseEvent_ButtonUp, 2711).
--define(wxMouseEvent_CmdDown, 2712).
--define(wxMouseEvent_ControlDown, 2713).
--define(wxMouseEvent_Dragging, 2714).
--define(wxMouseEvent_Entering, 2715).
--define(wxMouseEvent_GetButton, 2716).
--define(wxMouseEvent_GetPosition, 2719).
--define(wxMouseEvent_GetLogicalPosition, 2720).
--define(wxMouseEvent_GetLinesPerAction, 2721).
--define(wxMouseEvent_GetWheelRotation, 2722).
--define(wxMouseEvent_GetWheelDelta, 2723).
--define(wxMouseEvent_GetX, 2724).
--define(wxMouseEvent_GetY, 2725).
--define(wxMouseEvent_IsButton, 2726).
--define(wxMouseEvent_IsPageScroll, 2727).
--define(wxMouseEvent_Leaving, 2728).
--define(wxMouseEvent_LeftDClick, 2729).
--define(wxMouseEvent_LeftDown, 2730).
--define(wxMouseEvent_LeftIsDown, 2731).
--define(wxMouseEvent_LeftUp, 2732).
--define(wxMouseEvent_MetaDown, 2733).
--define(wxMouseEvent_MiddleDClick, 2734).
--define(wxMouseEvent_MiddleDown, 2735).
--define(wxMouseEvent_MiddleIsDown, 2736).
--define(wxMouseEvent_MiddleUp, 2737).
--define(wxMouseEvent_Moving, 2738).
--define(wxMouseEvent_RightDClick, 2739).
--define(wxMouseEvent_RightDown, 2740).
--define(wxMouseEvent_RightIsDown, 2741).
--define(wxMouseEvent_RightUp, 2742).
--define(wxMouseEvent_ShiftDown, 2743).
--define(wxSetCursorEvent_GetCursor, 2744).
--define(wxSetCursorEvent_GetX, 2745).
--define(wxSetCursorEvent_GetY, 2746).
--define(wxSetCursorEvent_HasCursor, 2747).
--define(wxSetCursorEvent_SetCursor, 2748).
--define(wxKeyEvent_AltDown, 2749).
--define(wxKeyEvent_CmdDown, 2750).
--define(wxKeyEvent_ControlDown, 2751).
--define(wxKeyEvent_GetKeyCode, 2752).
--define(wxKeyEvent_GetModifiers, 2753).
--define(wxKeyEvent_GetPosition, 2756).
--define(wxKeyEvent_GetRawKeyCode, 2757).
--define(wxKeyEvent_GetRawKeyFlags, 2758).
--define(wxKeyEvent_GetUnicodeKey, 2759).
--define(wxKeyEvent_GetX, 2760).
--define(wxKeyEvent_GetY, 2761).
--define(wxKeyEvent_HasModifiers, 2762).
--define(wxKeyEvent_MetaDown, 2763).
--define(wxKeyEvent_ShiftDown, 2764).
--define(wxSizeEvent_GetSize, 2765).
--define(wxMoveEvent_GetPosition, 2766).
--define(wxEraseEvent_GetDC, 2767).
--define(wxFocusEvent_GetWindow, 2768).
--define(wxChildFocusEvent_GetWindow, 2769).
--define(wxMenuEvent_GetMenu, 2770).
--define(wxMenuEvent_GetMenuId, 2771).
--define(wxMenuEvent_IsPopup, 2772).
--define(wxCloseEvent_CanVeto, 2773).
--define(wxCloseEvent_GetLoggingOff, 2774).
--define(wxCloseEvent_SetCanVeto, 2775).
--define(wxCloseEvent_SetLoggingOff, 2776).
--define(wxCloseEvent_Veto, 2777).
--define(wxShowEvent_SetShow, 2778).
--define(wxShowEvent_GetShow, 2779).
--define(wxIconizeEvent_Iconized, 2780).
--define(wxJoystickEvent_ButtonDown, 2781).
--define(wxJoystickEvent_ButtonIsDown, 2782).
--define(wxJoystickEvent_ButtonUp, 2783).
--define(wxJoystickEvent_GetButtonChange, 2784).
--define(wxJoystickEvent_GetButtonState, 2785).
--define(wxJoystickEvent_GetJoystick, 2786).
--define(wxJoystickEvent_GetPosition, 2787).
--define(wxJoystickEvent_GetZPosition, 2788).
--define(wxJoystickEvent_IsButton, 2789).
--define(wxJoystickEvent_IsMove, 2790).
--define(wxJoystickEvent_IsZMove, 2791).
--define(wxUpdateUIEvent_CanUpdate, 2792).
--define(wxUpdateUIEvent_Check, 2793).
--define(wxUpdateUIEvent_Enable, 2794).
--define(wxUpdateUIEvent_Show, 2795).
--define(wxUpdateUIEvent_GetChecked, 2796).
--define(wxUpdateUIEvent_GetEnabled, 2797).
--define(wxUpdateUIEvent_GetShown, 2798).
--define(wxUpdateUIEvent_GetSetChecked, 2799).
--define(wxUpdateUIEvent_GetSetEnabled, 2800).
--define(wxUpdateUIEvent_GetSetShown, 2801).
--define(wxUpdateUIEvent_GetSetText, 2802).
--define(wxUpdateUIEvent_GetText, 2803).
--define(wxUpdateUIEvent_GetMode, 2804).
--define(wxUpdateUIEvent_GetUpdateInterval, 2805).
--define(wxUpdateUIEvent_ResetUpdateTime, 2806).
--define(wxUpdateUIEvent_SetMode, 2807).
--define(wxUpdateUIEvent_SetText, 2808).
--define(wxUpdateUIEvent_SetUpdateInterval, 2809).
--define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2810).
--define(wxPaletteChangedEvent_SetChangedWindow, 2811).
--define(wxPaletteChangedEvent_GetChangedWindow, 2812).
--define(wxQueryNewPaletteEvent_SetPaletteRealized, 2813).
--define(wxQueryNewPaletteEvent_GetPaletteRealized, 2814).
--define(wxNavigationKeyEvent_GetDirection, 2815).
--define(wxNavigationKeyEvent_SetDirection, 2816).
--define(wxNavigationKeyEvent_IsWindowChange, 2817).
--define(wxNavigationKeyEvent_SetWindowChange, 2818).
--define(wxNavigationKeyEvent_IsFromTab, 2819).
--define(wxNavigationKeyEvent_SetFromTab, 2820).
--define(wxNavigationKeyEvent_GetCurrentFocus, 2821).
--define(wxNavigationKeyEvent_SetCurrentFocus, 2822).
--define(wxHelpEvent_GetOrigin, 2823).
--define(wxHelpEvent_GetPosition, 2824).
--define(wxHelpEvent_SetOrigin, 2825).
--define(wxHelpEvent_SetPosition, 2826).
--define(wxContextMenuEvent_GetPosition, 2827).
--define(wxContextMenuEvent_SetPosition, 2828).
--define(wxIdleEvent_CanSend, 2829).
--define(wxIdleEvent_GetMode, 2830).
--define(wxIdleEvent_RequestMore, 2831).
--define(wxIdleEvent_MoreRequested, 2832).
--define(wxIdleEvent_SetMode, 2833).
--define(wxGridEvent_AltDown, 2834).
--define(wxGridEvent_ControlDown, 2835).
--define(wxGridEvent_GetCol, 2836).
--define(wxGridEvent_GetPosition, 2837).
--define(wxGridEvent_GetRow, 2838).
--define(wxGridEvent_MetaDown, 2839).
--define(wxGridEvent_Selecting, 2840).
--define(wxGridEvent_ShiftDown, 2841).
--define(wxNotifyEvent_Allow, 2842).
--define(wxNotifyEvent_IsAllowed, 2843).
--define(wxNotifyEvent_Veto, 2844).
--define(wxSashEvent_GetEdge, 2845).
--define(wxSashEvent_GetDragRect, 2846).
--define(wxSashEvent_GetDragStatus, 2847).
--define(wxListEvent_GetCacheFrom, 2848).
--define(wxListEvent_GetCacheTo, 2849).
--define(wxListEvent_GetKeyCode, 2850).
--define(wxListEvent_GetIndex, 2851).
--define(wxListEvent_GetColumn, 2852).
--define(wxListEvent_GetPoint, 2853).
--define(wxListEvent_GetLabel, 2854).
--define(wxListEvent_GetText, 2855).
--define(wxListEvent_GetImage, 2856).
--define(wxListEvent_GetData, 2857).
--define(wxListEvent_GetMask, 2858).
--define(wxListEvent_GetItem, 2859).
--define(wxListEvent_IsEditCancelled, 2860).
--define(wxDateEvent_GetDate, 2861).
--define(wxCalendarEvent_GetWeekDay, 2862).
--define(wxFileDirPickerEvent_GetPath, 2863).
--define(wxColourPickerEvent_GetColour, 2864).
--define(wxFontPickerEvent_GetFont, 2865).
--define(wxStyledTextEvent_GetPosition, 2866).
--define(wxStyledTextEvent_GetKey, 2867).
--define(wxStyledTextEvent_GetModifiers, 2868).
--define(wxStyledTextEvent_GetModificationType, 2869).
--define(wxStyledTextEvent_GetText, 2870).
--define(wxStyledTextEvent_GetLength, 2871).
--define(wxStyledTextEvent_GetLinesAdded, 2872).
--define(wxStyledTextEvent_GetLine, 2873).
--define(wxStyledTextEvent_GetFoldLevelNow, 2874).
--define(wxStyledTextEvent_GetFoldLevelPrev, 2875).
--define(wxStyledTextEvent_GetMargin, 2876).
--define(wxStyledTextEvent_GetMessage, 2877).
--define(wxStyledTextEvent_GetWParam, 2878).
--define(wxStyledTextEvent_GetLParam, 2879).
--define(wxStyledTextEvent_GetListType, 2880).
--define(wxStyledTextEvent_GetX, 2881).
--define(wxStyledTextEvent_GetY, 2882).
--define(wxStyledTextEvent_GetDragText, 2883).
--define(wxStyledTextEvent_GetDragAllowMove, 2884).
--define(wxStyledTextEvent_GetDragResult, 2885).
--define(wxStyledTextEvent_GetShift, 2886).
--define(wxStyledTextEvent_GetControl, 2887).
--define(wxStyledTextEvent_GetAlt, 2888).
--define(utils_wxGetKeyState, 2889).
--define(utils_wxGetMousePosition, 2890).
--define(utils_wxGetMouseState, 2891).
--define(utils_wxSetDetectableAutoRepeat, 2892).
--define(utils_wxBell, 2893).
--define(utils_wxFindMenuItemId, 2894).
--define(utils_wxGenericFindWindowAtPoint, 2895).
--define(utils_wxFindWindowAtPoint, 2896).
--define(utils_wxBeginBusyCursor, 2897).
--define(utils_wxEndBusyCursor, 2898).
--define(utils_wxIsBusy, 2899).
--define(utils_wxShutdown, 2900).
--define(utils_wxShell, 2901).
--define(utils_wxLaunchDefaultBrowser, 2902).
--define(utils_wxGetEmailAddress, 2903).
--define(utils_wxGetUserId, 2904).
--define(utils_wxGetHomeDir, 2905).
--define(utils_wxNewId, 2906).
--define(utils_wxRegisterId, 2907).
--define(utils_wxGetCurrentId, 2908).
--define(utils_wxGetOsDescription, 2909).
--define(utils_wxIsPlatformLittleEndian, 2910).
--define(utils_wxIsPlatform64Bit, 2911).
--define(wxPrintout_new, 2912).
--define(wxPrintout_destruct, 2913).
--define(wxPrintout_GetDC, 2914).
--define(wxPrintout_GetPageSizeMM, 2915).
--define(wxPrintout_GetPageSizePixels, 2916).
--define(wxPrintout_GetPaperRectPixels, 2917).
--define(wxPrintout_GetPPIPrinter, 2918).
--define(wxPrintout_GetPPIScreen, 2919).
--define(wxPrintout_GetTitle, 2920).
--define(wxPrintout_IsPreview, 2921).
--define(wxPrintout_FitThisSizeToPaper, 2922).
--define(wxPrintout_FitThisSizeToPage, 2923).
--define(wxPrintout_FitThisSizeToPageMargins, 2924).
--define(wxPrintout_MapScreenSizeToPaper, 2925).
--define(wxPrintout_MapScreenSizeToPage, 2926).
--define(wxPrintout_MapScreenSizeToPageMargins, 2927).
--define(wxPrintout_MapScreenSizeToDevice, 2928).
--define(wxPrintout_GetLogicalPaperRect, 2929).
--define(wxPrintout_GetLogicalPageRect, 2930).
--define(wxPrintout_GetLogicalPageMarginsRect, 2931).
--define(wxPrintout_SetLogicalOrigin, 2932).
--define(wxPrintout_OffsetLogicalOrigin, 2933).
--define(wxStyledTextCtrl_new_2, 2934).
--define(wxStyledTextCtrl_new_0, 2935).
--define(wxStyledTextCtrl_destruct, 2936).
--define(wxStyledTextCtrl_Create, 2937).
--define(wxStyledTextCtrl_AddText, 2938).
--define(wxStyledTextCtrl_AddStyledText, 2939).
--define(wxStyledTextCtrl_InsertText, 2940).
--define(wxStyledTextCtrl_ClearAll, 2941).
--define(wxStyledTextCtrl_ClearDocumentStyle, 2942).
--define(wxStyledTextCtrl_GetLength, 2943).
--define(wxStyledTextCtrl_GetCharAt, 2944).
--define(wxStyledTextCtrl_GetCurrentPos, 2945).
--define(wxStyledTextCtrl_GetAnchor, 2946).
--define(wxStyledTextCtrl_GetStyleAt, 2947).
--define(wxStyledTextCtrl_Redo, 2948).
--define(wxStyledTextCtrl_SetUndoCollection, 2949).
--define(wxStyledTextCtrl_SelectAll, 2950).
--define(wxStyledTextCtrl_SetSavePoint, 2951).
--define(wxStyledTextCtrl_GetStyledText, 2952).
--define(wxStyledTextCtrl_CanRedo, 2953).
--define(wxStyledTextCtrl_MarkerLineFromHandle, 2954).
--define(wxStyledTextCtrl_MarkerDeleteHandle, 2955).
--define(wxStyledTextCtrl_GetUndoCollection, 2956).
--define(wxStyledTextCtrl_GetViewWhiteSpace, 2957).
--define(wxStyledTextCtrl_SetViewWhiteSpace, 2958).
--define(wxStyledTextCtrl_PositionFromPoint, 2959).
--define(wxStyledTextCtrl_PositionFromPointClose, 2960).
--define(wxStyledTextCtrl_GotoLine, 2961).
--define(wxStyledTextCtrl_GotoPos, 2962).
--define(wxStyledTextCtrl_SetAnchor, 2963).
--define(wxStyledTextCtrl_GetCurLine, 2964).
--define(wxStyledTextCtrl_GetEndStyled, 2965).
--define(wxStyledTextCtrl_ConvertEOLs, 2966).
--define(wxStyledTextCtrl_GetEOLMode, 2967).
--define(wxStyledTextCtrl_SetEOLMode, 2968).
--define(wxStyledTextCtrl_StartStyling, 2969).
--define(wxStyledTextCtrl_SetStyling, 2970).
--define(wxStyledTextCtrl_GetBufferedDraw, 2971).
--define(wxStyledTextCtrl_SetBufferedDraw, 2972).
--define(wxStyledTextCtrl_SetTabWidth, 2973).
--define(wxStyledTextCtrl_GetTabWidth, 2974).
--define(wxStyledTextCtrl_SetCodePage, 2975).
--define(wxStyledTextCtrl_MarkerDefine, 2976).
--define(wxStyledTextCtrl_MarkerSetForeground, 2977).
--define(wxStyledTextCtrl_MarkerSetBackground, 2978).
--define(wxStyledTextCtrl_MarkerAdd, 2979).
--define(wxStyledTextCtrl_MarkerDelete, 2980).
--define(wxStyledTextCtrl_MarkerDeleteAll, 2981).
--define(wxStyledTextCtrl_MarkerGet, 2982).
--define(wxStyledTextCtrl_MarkerNext, 2983).
--define(wxStyledTextCtrl_MarkerPrevious, 2984).
--define(wxStyledTextCtrl_MarkerDefineBitmap, 2985).
--define(wxStyledTextCtrl_MarkerAddSet, 2986).
--define(wxStyledTextCtrl_MarkerSetAlpha, 2987).
--define(wxStyledTextCtrl_SetMarginType, 2988).
--define(wxStyledTextCtrl_GetMarginType, 2989).
--define(wxStyledTextCtrl_SetMarginWidth, 2990).
--define(wxStyledTextCtrl_GetMarginWidth, 2991).
--define(wxStyledTextCtrl_SetMarginMask, 2992).
--define(wxStyledTextCtrl_GetMarginMask, 2993).
--define(wxStyledTextCtrl_SetMarginSensitive, 2994).
--define(wxStyledTextCtrl_GetMarginSensitive, 2995).
--define(wxStyledTextCtrl_StyleClearAll, 2996).
--define(wxStyledTextCtrl_StyleSetForeground, 2997).
--define(wxStyledTextCtrl_StyleSetBackground, 2998).
--define(wxStyledTextCtrl_StyleSetBold, 2999).
--define(wxStyledTextCtrl_StyleSetItalic, 3000).
--define(wxStyledTextCtrl_StyleSetSize, 3001).
--define(wxStyledTextCtrl_StyleSetFaceName, 3002).
--define(wxStyledTextCtrl_StyleSetEOLFilled, 3003).
--define(wxStyledTextCtrl_StyleResetDefault, 3004).
--define(wxStyledTextCtrl_StyleSetUnderline, 3005).
--define(wxStyledTextCtrl_StyleSetCase, 3006).
--define(wxStyledTextCtrl_StyleSetHotSpot, 3007).
--define(wxStyledTextCtrl_SetSelForeground, 3008).
--define(wxStyledTextCtrl_SetSelBackground, 3009).
--define(wxStyledTextCtrl_GetSelAlpha, 3010).
--define(wxStyledTextCtrl_SetSelAlpha, 3011).
--define(wxStyledTextCtrl_SetCaretForeground, 3012).
--define(wxStyledTextCtrl_CmdKeyAssign, 3013).
--define(wxStyledTextCtrl_CmdKeyClear, 3014).
--define(wxStyledTextCtrl_CmdKeyClearAll, 3015).
--define(wxStyledTextCtrl_SetStyleBytes, 3016).
--define(wxStyledTextCtrl_StyleSetVisible, 3017).
--define(wxStyledTextCtrl_GetCaretPeriod, 3018).
--define(wxStyledTextCtrl_SetCaretPeriod, 3019).
--define(wxStyledTextCtrl_SetWordChars, 3020).
--define(wxStyledTextCtrl_BeginUndoAction, 3021).
--define(wxStyledTextCtrl_EndUndoAction, 3022).
--define(wxStyledTextCtrl_IndicatorSetStyle, 3023).
--define(wxStyledTextCtrl_IndicatorGetStyle, 3024).
--define(wxStyledTextCtrl_IndicatorSetForeground, 3025).
--define(wxStyledTextCtrl_IndicatorGetForeground, 3026).
--define(wxStyledTextCtrl_SetWhitespaceForeground, 3027).
--define(wxStyledTextCtrl_SetWhitespaceBackground, 3028).
--define(wxStyledTextCtrl_GetStyleBits, 3029).
--define(wxStyledTextCtrl_SetLineState, 3030).
--define(wxStyledTextCtrl_GetLineState, 3031).
--define(wxStyledTextCtrl_GetMaxLineState, 3032).
--define(wxStyledTextCtrl_GetCaretLineVisible, 3033).
--define(wxStyledTextCtrl_SetCaretLineVisible, 3034).
--define(wxStyledTextCtrl_GetCaretLineBackground, 3035).
--define(wxStyledTextCtrl_SetCaretLineBackground, 3036).
--define(wxStyledTextCtrl_AutoCompShow, 3037).
--define(wxStyledTextCtrl_AutoCompCancel, 3038).
--define(wxStyledTextCtrl_AutoCompActive, 3039).
--define(wxStyledTextCtrl_AutoCompPosStart, 3040).
--define(wxStyledTextCtrl_AutoCompComplete, 3041).
--define(wxStyledTextCtrl_AutoCompStops, 3042).
--define(wxStyledTextCtrl_AutoCompSetSeparator, 3043).
--define(wxStyledTextCtrl_AutoCompGetSeparator, 3044).
--define(wxStyledTextCtrl_AutoCompSelect, 3045).
--define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3046).
--define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3047).
--define(wxStyledTextCtrl_AutoCompSetFillUps, 3048).
--define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3049).
--define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3050).
--define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3051).
--define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3052).
--define(wxStyledTextCtrl_UserListShow, 3053).
--define(wxStyledTextCtrl_AutoCompSetAutoHide, 3054).
--define(wxStyledTextCtrl_AutoCompGetAutoHide, 3055).
--define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3056).
--define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3057).
--define(wxStyledTextCtrl_RegisterImage, 3058).
--define(wxStyledTextCtrl_ClearRegisteredImages, 3059).
--define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3060).
--define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3061).
--define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3062).
--define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3063).
--define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3064).
--define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3065).
--define(wxStyledTextCtrl_SetIndent, 3066).
--define(wxStyledTextCtrl_GetIndent, 3067).
--define(wxStyledTextCtrl_SetUseTabs, 3068).
--define(wxStyledTextCtrl_GetUseTabs, 3069).
--define(wxStyledTextCtrl_SetLineIndentation, 3070).
--define(wxStyledTextCtrl_GetLineIndentation, 3071).
--define(wxStyledTextCtrl_GetLineIndentPosition, 3072).
--define(wxStyledTextCtrl_GetColumn, 3073).
--define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3074).
--define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3075).
--define(wxStyledTextCtrl_SetIndentationGuides, 3076).
--define(wxStyledTextCtrl_GetIndentationGuides, 3077).
--define(wxStyledTextCtrl_SetHighlightGuide, 3078).
--define(wxStyledTextCtrl_GetHighlightGuide, 3079).
--define(wxStyledTextCtrl_GetLineEndPosition, 3080).
--define(wxStyledTextCtrl_GetCodePage, 3081).
--define(wxStyledTextCtrl_GetCaretForeground, 3082).
--define(wxStyledTextCtrl_GetReadOnly, 3083).
--define(wxStyledTextCtrl_SetCurrentPos, 3084).
--define(wxStyledTextCtrl_SetSelectionStart, 3085).
--define(wxStyledTextCtrl_GetSelectionStart, 3086).
--define(wxStyledTextCtrl_SetSelectionEnd, 3087).
--define(wxStyledTextCtrl_GetSelectionEnd, 3088).
--define(wxStyledTextCtrl_SetPrintMagnification, 3089).
--define(wxStyledTextCtrl_GetPrintMagnification, 3090).
--define(wxStyledTextCtrl_SetPrintColourMode, 3091).
--define(wxStyledTextCtrl_GetPrintColourMode, 3092).
--define(wxStyledTextCtrl_FindText, 3093).
--define(wxStyledTextCtrl_FormatRange, 3094).
--define(wxStyledTextCtrl_GetFirstVisibleLine, 3095).
--define(wxStyledTextCtrl_GetLine, 3096).
--define(wxStyledTextCtrl_GetLineCount, 3097).
--define(wxStyledTextCtrl_SetMarginLeft, 3098).
--define(wxStyledTextCtrl_GetMarginLeft, 3099).
--define(wxStyledTextCtrl_SetMarginRight, 3100).
--define(wxStyledTextCtrl_GetMarginRight, 3101).
--define(wxStyledTextCtrl_GetModify, 3102).
--define(wxStyledTextCtrl_SetSelection, 3103).
--define(wxStyledTextCtrl_GetSelectedText, 3104).
--define(wxStyledTextCtrl_GetTextRange, 3105).
--define(wxStyledTextCtrl_HideSelection, 3106).
--define(wxStyledTextCtrl_LineFromPosition, 3107).
--define(wxStyledTextCtrl_PositionFromLine, 3108).
--define(wxStyledTextCtrl_LineScroll, 3109).
--define(wxStyledTextCtrl_EnsureCaretVisible, 3110).
--define(wxStyledTextCtrl_ReplaceSelection, 3111).
--define(wxStyledTextCtrl_SetReadOnly, 3112).
--define(wxStyledTextCtrl_CanPaste, 3113).
--define(wxStyledTextCtrl_CanUndo, 3114).
--define(wxStyledTextCtrl_EmptyUndoBuffer, 3115).
--define(wxStyledTextCtrl_Undo, 3116).
--define(wxStyledTextCtrl_Cut, 3117).
--define(wxStyledTextCtrl_Copy, 3118).
--define(wxStyledTextCtrl_Paste, 3119).
--define(wxStyledTextCtrl_Clear, 3120).
--define(wxStyledTextCtrl_SetText, 3121).
--define(wxStyledTextCtrl_GetText, 3122).
--define(wxStyledTextCtrl_GetTextLength, 3123).
--define(wxStyledTextCtrl_GetOvertype, 3124).
--define(wxStyledTextCtrl_SetCaretWidth, 3125).
--define(wxStyledTextCtrl_GetCaretWidth, 3126).
--define(wxStyledTextCtrl_SetTargetStart, 3127).
--define(wxStyledTextCtrl_GetTargetStart, 3128).
--define(wxStyledTextCtrl_SetTargetEnd, 3129).
--define(wxStyledTextCtrl_GetTargetEnd, 3130).
--define(wxStyledTextCtrl_ReplaceTarget, 3131).
--define(wxStyledTextCtrl_SearchInTarget, 3132).
--define(wxStyledTextCtrl_SetSearchFlags, 3133).
--define(wxStyledTextCtrl_GetSearchFlags, 3134).
--define(wxStyledTextCtrl_CallTipShow, 3135).
--define(wxStyledTextCtrl_CallTipCancel, 3136).
--define(wxStyledTextCtrl_CallTipActive, 3137).
--define(wxStyledTextCtrl_CallTipPosAtStart, 3138).
--define(wxStyledTextCtrl_CallTipSetHighlight, 3139).
--define(wxStyledTextCtrl_CallTipSetBackground, 3140).
--define(wxStyledTextCtrl_CallTipSetForeground, 3141).
--define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3142).
--define(wxStyledTextCtrl_CallTipUseStyle, 3143).
--define(wxStyledTextCtrl_VisibleFromDocLine, 3144).
--define(wxStyledTextCtrl_DocLineFromVisible, 3145).
--define(wxStyledTextCtrl_WrapCount, 3146).
--define(wxStyledTextCtrl_SetFoldLevel, 3147).
--define(wxStyledTextCtrl_GetFoldLevel, 3148).
--define(wxStyledTextCtrl_GetLastChild, 3149).
--define(wxStyledTextCtrl_GetFoldParent, 3150).
--define(wxStyledTextCtrl_ShowLines, 3151).
--define(wxStyledTextCtrl_HideLines, 3152).
--define(wxStyledTextCtrl_GetLineVisible, 3153).
--define(wxStyledTextCtrl_SetFoldExpanded, 3154).
--define(wxStyledTextCtrl_GetFoldExpanded, 3155).
--define(wxStyledTextCtrl_ToggleFold, 3156).
--define(wxStyledTextCtrl_EnsureVisible, 3157).
--define(wxStyledTextCtrl_SetFoldFlags, 3158).
--define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3159).
--define(wxStyledTextCtrl_SetTabIndents, 3160).
--define(wxStyledTextCtrl_GetTabIndents, 3161).
--define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3162).
--define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3163).
--define(wxStyledTextCtrl_SetMouseDwellTime, 3164).
--define(wxStyledTextCtrl_GetMouseDwellTime, 3165).
--define(wxStyledTextCtrl_WordStartPosition, 3166).
--define(wxStyledTextCtrl_WordEndPosition, 3167).
--define(wxStyledTextCtrl_SetWrapMode, 3168).
--define(wxStyledTextCtrl_GetWrapMode, 3169).
--define(wxStyledTextCtrl_SetWrapVisualFlags, 3170).
--define(wxStyledTextCtrl_GetWrapVisualFlags, 3171).
--define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3172).
--define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3173).
--define(wxStyledTextCtrl_SetWrapStartIndent, 3174).
--define(wxStyledTextCtrl_GetWrapStartIndent, 3175).
--define(wxStyledTextCtrl_SetLayoutCache, 3176).
--define(wxStyledTextCtrl_GetLayoutCache, 3177).
--define(wxStyledTextCtrl_SetScrollWidth, 3178).
--define(wxStyledTextCtrl_GetScrollWidth, 3179).
--define(wxStyledTextCtrl_TextWidth, 3180).
--define(wxStyledTextCtrl_GetEndAtLastLine, 3181).
--define(wxStyledTextCtrl_TextHeight, 3182).
--define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3183).
--define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3184).
--define(wxStyledTextCtrl_AppendText, 3185).
--define(wxStyledTextCtrl_GetTwoPhaseDraw, 3186).
--define(wxStyledTextCtrl_SetTwoPhaseDraw, 3187).
--define(wxStyledTextCtrl_TargetFromSelection, 3188).
--define(wxStyledTextCtrl_LinesJoin, 3189).
--define(wxStyledTextCtrl_LinesSplit, 3190).
--define(wxStyledTextCtrl_SetFoldMarginColour, 3191).
--define(wxStyledTextCtrl_SetFoldMarginHiColour, 3192).
--define(wxStyledTextCtrl_LineDown, 3193).
--define(wxStyledTextCtrl_LineDownExtend, 3194).
--define(wxStyledTextCtrl_LineUp, 3195).
--define(wxStyledTextCtrl_LineUpExtend, 3196).
--define(wxStyledTextCtrl_CharLeft, 3197).
--define(wxStyledTextCtrl_CharLeftExtend, 3198).
--define(wxStyledTextCtrl_CharRight, 3199).
--define(wxStyledTextCtrl_CharRightExtend, 3200).
--define(wxStyledTextCtrl_WordLeft, 3201).
--define(wxStyledTextCtrl_WordLeftExtend, 3202).
--define(wxStyledTextCtrl_WordRight, 3203).
--define(wxStyledTextCtrl_WordRightExtend, 3204).
--define(wxStyledTextCtrl_Home, 3205).
--define(wxStyledTextCtrl_HomeExtend, 3206).
--define(wxStyledTextCtrl_LineEnd, 3207).
--define(wxStyledTextCtrl_LineEndExtend, 3208).
--define(wxStyledTextCtrl_DocumentStart, 3209).
--define(wxStyledTextCtrl_DocumentStartExtend, 3210).
--define(wxStyledTextCtrl_DocumentEnd, 3211).
--define(wxStyledTextCtrl_DocumentEndExtend, 3212).
--define(wxStyledTextCtrl_PageUp, 3213).
--define(wxStyledTextCtrl_PageUpExtend, 3214).
--define(wxStyledTextCtrl_PageDown, 3215).
--define(wxStyledTextCtrl_PageDownExtend, 3216).
--define(wxStyledTextCtrl_EditToggleOvertype, 3217).
--define(wxStyledTextCtrl_Cancel, 3218).
--define(wxStyledTextCtrl_DeleteBack, 3219).
--define(wxStyledTextCtrl_Tab, 3220).
--define(wxStyledTextCtrl_BackTab, 3221).
--define(wxStyledTextCtrl_NewLine, 3222).
--define(wxStyledTextCtrl_FormFeed, 3223).
--define(wxStyledTextCtrl_VCHome, 3224).
--define(wxStyledTextCtrl_VCHomeExtend, 3225).
--define(wxStyledTextCtrl_ZoomIn, 3226).
--define(wxStyledTextCtrl_ZoomOut, 3227).
--define(wxStyledTextCtrl_DelWordLeft, 3228).
--define(wxStyledTextCtrl_DelWordRight, 3229).
--define(wxStyledTextCtrl_LineCut, 3230).
--define(wxStyledTextCtrl_LineDelete, 3231).
--define(wxStyledTextCtrl_LineTranspose, 3232).
--define(wxStyledTextCtrl_LineDuplicate, 3233).
--define(wxStyledTextCtrl_LowerCase, 3234).
--define(wxStyledTextCtrl_UpperCase, 3235).
--define(wxStyledTextCtrl_LineScrollDown, 3236).
--define(wxStyledTextCtrl_LineScrollUp, 3237).
--define(wxStyledTextCtrl_DeleteBackNotLine, 3238).
--define(wxStyledTextCtrl_HomeDisplay, 3239).
--define(wxStyledTextCtrl_HomeDisplayExtend, 3240).
--define(wxStyledTextCtrl_LineEndDisplay, 3241).
--define(wxStyledTextCtrl_LineEndDisplayExtend, 3242).
--define(wxStyledTextCtrl_HomeWrapExtend, 3243).
--define(wxStyledTextCtrl_LineEndWrap, 3244).
--define(wxStyledTextCtrl_LineEndWrapExtend, 3245).
--define(wxStyledTextCtrl_VCHomeWrap, 3246).
--define(wxStyledTextCtrl_VCHomeWrapExtend, 3247).
--define(wxStyledTextCtrl_LineCopy, 3248).
--define(wxStyledTextCtrl_MoveCaretInsideView, 3249).
--define(wxStyledTextCtrl_LineLength, 3250).
--define(wxStyledTextCtrl_BraceHighlight, 3251).
--define(wxStyledTextCtrl_BraceBadLight, 3252).
--define(wxStyledTextCtrl_BraceMatch, 3253).
--define(wxStyledTextCtrl_GetViewEOL, 3254).
--define(wxStyledTextCtrl_SetViewEOL, 3255).
--define(wxStyledTextCtrl_SetModEventMask, 3256).
--define(wxStyledTextCtrl_GetEdgeColumn, 3257).
--define(wxStyledTextCtrl_SetEdgeColumn, 3258).
--define(wxStyledTextCtrl_GetEdgeMode, 3259).
--define(wxStyledTextCtrl_GetEdgeColour, 3260).
--define(wxStyledTextCtrl_SetEdgeColour, 3261).
--define(wxStyledTextCtrl_SearchAnchor, 3262).
--define(wxStyledTextCtrl_SearchNext, 3263).
--define(wxStyledTextCtrl_SearchPrev, 3264).
--define(wxStyledTextCtrl_LinesOnScreen, 3265).
--define(wxStyledTextCtrl_UsePopUp, 3266).
--define(wxStyledTextCtrl_SelectionIsRectangle, 3267).
--define(wxStyledTextCtrl_SetZoom, 3268).
--define(wxStyledTextCtrl_GetZoom, 3269).
--define(wxStyledTextCtrl_GetModEventMask, 3270).
--define(wxStyledTextCtrl_SetSTCFocus, 3271).
--define(wxStyledTextCtrl_GetSTCFocus, 3272).
--define(wxStyledTextCtrl_SetStatus, 3273).
--define(wxStyledTextCtrl_GetStatus, 3274).
--define(wxStyledTextCtrl_SetMouseDownCaptures, 3275).
--define(wxStyledTextCtrl_GetMouseDownCaptures, 3276).
--define(wxStyledTextCtrl_SetSTCCursor, 3277).
--define(wxStyledTextCtrl_GetSTCCursor, 3278).
--define(wxStyledTextCtrl_SetControlCharSymbol, 3279).
--define(wxStyledTextCtrl_GetControlCharSymbol, 3280).
--define(wxStyledTextCtrl_WordPartLeft, 3281).
--define(wxStyledTextCtrl_WordPartLeftExtend, 3282).
--define(wxStyledTextCtrl_WordPartRight, 3283).
--define(wxStyledTextCtrl_WordPartRightExtend, 3284).
--define(wxStyledTextCtrl_SetVisiblePolicy, 3285).
--define(wxStyledTextCtrl_DelLineLeft, 3286).
--define(wxStyledTextCtrl_DelLineRight, 3287).
--define(wxStyledTextCtrl_GetXOffset, 3288).
--define(wxStyledTextCtrl_ChooseCaretX, 3289).
--define(wxStyledTextCtrl_SetXCaretPolicy, 3290).
--define(wxStyledTextCtrl_SetYCaretPolicy, 3291).
--define(wxStyledTextCtrl_GetPrintWrapMode, 3292).
--define(wxStyledTextCtrl_SetHotspotActiveForeground, 3293).
--define(wxStyledTextCtrl_SetHotspotActiveBackground, 3294).
--define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3295).
--define(wxStyledTextCtrl_SetHotspotSingleLine, 3296).
--define(wxStyledTextCtrl_ParaDownExtend, 3297).
--define(wxStyledTextCtrl_ParaUp, 3298).
--define(wxStyledTextCtrl_ParaUpExtend, 3299).
--define(wxStyledTextCtrl_PositionBefore, 3300).
--define(wxStyledTextCtrl_PositionAfter, 3301).
--define(wxStyledTextCtrl_CopyRange, 3302).
--define(wxStyledTextCtrl_CopyText, 3303).
--define(wxStyledTextCtrl_SetSelectionMode, 3304).
--define(wxStyledTextCtrl_GetSelectionMode, 3305).
--define(wxStyledTextCtrl_LineDownRectExtend, 3306).
--define(wxStyledTextCtrl_LineUpRectExtend, 3307).
--define(wxStyledTextCtrl_CharLeftRectExtend, 3308).
--define(wxStyledTextCtrl_CharRightRectExtend, 3309).
--define(wxStyledTextCtrl_HomeRectExtend, 3310).
--define(wxStyledTextCtrl_VCHomeRectExtend, 3311).
--define(wxStyledTextCtrl_LineEndRectExtend, 3312).
--define(wxStyledTextCtrl_PageUpRectExtend, 3313).
--define(wxStyledTextCtrl_PageDownRectExtend, 3314).
--define(wxStyledTextCtrl_StutteredPageUp, 3315).
--define(wxStyledTextCtrl_StutteredPageUpExtend, 3316).
--define(wxStyledTextCtrl_StutteredPageDown, 3317).
--define(wxStyledTextCtrl_StutteredPageDownExtend, 3318).
--define(wxStyledTextCtrl_WordLeftEnd, 3319).
--define(wxStyledTextCtrl_WordLeftEndExtend, 3320).
--define(wxStyledTextCtrl_WordRightEnd, 3321).
--define(wxStyledTextCtrl_WordRightEndExtend, 3322).
--define(wxStyledTextCtrl_SetWhitespaceChars, 3323).
--define(wxStyledTextCtrl_SetCharsDefault, 3324).
--define(wxStyledTextCtrl_AutoCompGetCurrent, 3325).
--define(wxStyledTextCtrl_Allocate, 3326).
--define(wxStyledTextCtrl_FindColumn, 3327).
--define(wxStyledTextCtrl_GetCaretSticky, 3328).
--define(wxStyledTextCtrl_SetCaretSticky, 3329).
--define(wxStyledTextCtrl_ToggleCaretSticky, 3330).
--define(wxStyledTextCtrl_SetPasteConvertEndings, 3331).
--define(wxStyledTextCtrl_GetPasteConvertEndings, 3332).
--define(wxStyledTextCtrl_SelectionDuplicate, 3333).
--define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3334).
--define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3335).
--define(wxStyledTextCtrl_StartRecord, 3336).
--define(wxStyledTextCtrl_StopRecord, 3337).
--define(wxStyledTextCtrl_SetLexer, 3338).
--define(wxStyledTextCtrl_GetLexer, 3339).
--define(wxStyledTextCtrl_Colourise, 3340).
--define(wxStyledTextCtrl_SetProperty, 3341).
--define(wxStyledTextCtrl_SetKeyWords, 3342).
--define(wxStyledTextCtrl_SetLexerLanguage, 3343).
--define(wxStyledTextCtrl_GetProperty, 3344).
--define(wxStyledTextCtrl_GetStyleBitsNeeded, 3345).
--define(wxStyledTextCtrl_GetCurrentLine, 3346).
--define(wxStyledTextCtrl_StyleSetSpec, 3347).
--define(wxStyledTextCtrl_StyleSetFont, 3348).
--define(wxStyledTextCtrl_StyleSetFontAttr, 3349).
--define(wxStyledTextCtrl_StyleSetCharacterSet, 3350).
--define(wxStyledTextCtrl_StyleSetFontEncoding, 3351).
--define(wxStyledTextCtrl_CmdKeyExecute, 3352).
--define(wxStyledTextCtrl_SetMargins, 3353).
--define(wxStyledTextCtrl_GetSelection, 3354).
--define(wxStyledTextCtrl_PointFromPosition, 3355).
--define(wxStyledTextCtrl_ScrollToLine, 3356).
--define(wxStyledTextCtrl_ScrollToColumn, 3357).
--define(wxStyledTextCtrl_SendMsg, 3358).
--define(wxStyledTextCtrl_SetVScrollBar, 3359).
--define(wxStyledTextCtrl_SetHScrollBar, 3360).
--define(wxStyledTextCtrl_GetLastKeydownProcessed, 3361).
--define(wxStyledTextCtrl_SetLastKeydownProcessed, 3362).
--define(wxStyledTextCtrl_SaveFile, 3363).
--define(wxStyledTextCtrl_LoadFile, 3364).
--define(wxStyledTextCtrl_DoDragOver, 3365).
--define(wxStyledTextCtrl_DoDropText, 3366).
--define(wxStyledTextCtrl_GetUseAntiAliasing, 3367).
--define(wxStyledTextCtrl_AddTextRaw, 3368).
--define(wxStyledTextCtrl_InsertTextRaw, 3369).
--define(wxStyledTextCtrl_GetCurLineRaw, 3370).
--define(wxStyledTextCtrl_GetLineRaw, 3371).
--define(wxStyledTextCtrl_GetSelectedTextRaw, 3372).
--define(wxStyledTextCtrl_GetTextRangeRaw, 3373).
--define(wxStyledTextCtrl_SetTextRaw, 3374).
--define(wxStyledTextCtrl_GetTextRaw, 3375).
--define(wxStyledTextCtrl_AppendTextRaw, 3376).
--define(wxArtProvider_GetBitmap, 3377).
--define(wxArtProvider_GetIcon, 3378).
--define(wxTreeEvent_GetKeyCode, 3379).
--define(wxTreeEvent_GetItem, 3380).
--define(wxTreeEvent_GetKeyEvent, 3381).
--define(wxTreeEvent_GetLabel, 3382).
--define(wxTreeEvent_GetOldItem, 3383).
--define(wxTreeEvent_GetPoint, 3384).
--define(wxTreeEvent_IsEditCancelled, 3385).
--define(wxTreeEvent_SetToolTip, 3386).
--define(wxNotebookEvent_GetOldSelection, 3387).
--define(wxNotebookEvent_GetSelection, 3388).
--define(wxNotebookEvent_SetOldSelection, 3389).
--define(wxNotebookEvent_SetSelection, 3390).
--define(wxFileDataObject_new, 3391).
--define(wxFileDataObject_AddFile, 3392).
--define(wxFileDataObject_GetFilenames, 3393).
--define(wxFileDataObject_destroy, 3394).
--define(wxTextDataObject_new, 3395).
--define(wxTextDataObject_GetTextLength, 3396).
--define(wxTextDataObject_GetText, 3397).
--define(wxTextDataObject_SetText, 3398).
--define(wxTextDataObject_destroy, 3399).
--define(wxBitmapDataObject_new_1_1, 3400).
--define(wxBitmapDataObject_new_1_0, 3401).
--define(wxBitmapDataObject_GetBitmap, 3402).
--define(wxBitmapDataObject_SetBitmap, 3403).
--define(wxBitmapDataObject_destroy, 3404).
--define(wxClipboard_new, 3406).
--define(wxClipboard_destruct, 3407).
--define(wxClipboard_AddData, 3408).
--define(wxClipboard_Clear, 3409).
--define(wxClipboard_Close, 3410).
--define(wxClipboard_Flush, 3411).
--define(wxClipboard_GetData, 3412).
--define(wxClipboard_IsOpened, 3413).
--define(wxClipboard_Open, 3414).
--define(wxClipboard_SetData, 3415).
--define(wxClipboard_UsePrimarySelection, 3417).
--define(wxClipboard_IsSupported, 3418).
--define(wxClipboard_Get, 3419).
--define(wxSpinEvent_GetPosition, 3420).
--define(wxSpinEvent_SetPosition, 3421).
--define(wxSplitterWindow_new_0, 3422).
--define(wxSplitterWindow_new_2, 3423).
--define(wxSplitterWindow_destruct, 3424).
--define(wxSplitterWindow_Create, 3425).
--define(wxSplitterWindow_GetMinimumPaneSize, 3426).
--define(wxSplitterWindow_GetSashGravity, 3427).
--define(wxSplitterWindow_GetSashPosition, 3428).
--define(wxSplitterWindow_GetSplitMode, 3429).
--define(wxSplitterWindow_GetWindow1, 3430).
--define(wxSplitterWindow_GetWindow2, 3431).
--define(wxSplitterWindow_Initialize, 3432).
--define(wxSplitterWindow_IsSplit, 3433).
--define(wxSplitterWindow_ReplaceWindow, 3434).
--define(wxSplitterWindow_SetSashGravity, 3435).
--define(wxSplitterWindow_SetSashPosition, 3436).
--define(wxSplitterWindow_SetSashSize, 3437).
--define(wxSplitterWindow_SetMinimumPaneSize, 3438).
--define(wxSplitterWindow_SetSplitMode, 3439).
--define(wxSplitterWindow_SplitHorizontally, 3440).
--define(wxSplitterWindow_SplitVertically, 3441).
--define(wxSplitterWindow_Unsplit, 3442).
--define(wxSplitterWindow_UpdateSize, 3443).
--define(wxSplitterEvent_GetSashPosition, 3444).
--define(wxSplitterEvent_GetX, 3445).
--define(wxSplitterEvent_GetY, 3446).
--define(wxSplitterEvent_GetWindowBeingRemoved, 3447).
--define(wxSplitterEvent_SetSashPosition, 3448).
--define(wxHtmlWindow_new_0, 3449).
--define(wxHtmlWindow_new_2, 3450).
--define(wxHtmlWindow_AppendToPage, 3451).
--define(wxHtmlWindow_GetOpenedAnchor, 3452).
--define(wxHtmlWindow_GetOpenedPage, 3453).
--define(wxHtmlWindow_GetOpenedPageTitle, 3454).
--define(wxHtmlWindow_GetRelatedFrame, 3455).
--define(wxHtmlWindow_HistoryBack, 3456).
--define(wxHtmlWindow_HistoryCanBack, 3457).
--define(wxHtmlWindow_HistoryCanForward, 3458).
--define(wxHtmlWindow_HistoryClear, 3459).
--define(wxHtmlWindow_HistoryForward, 3460).
--define(wxHtmlWindow_LoadFile, 3461).
--define(wxHtmlWindow_LoadPage, 3462).
--define(wxHtmlWindow_SelectAll, 3463).
--define(wxHtmlWindow_SelectionToText, 3464).
--define(wxHtmlWindow_SelectLine, 3465).
--define(wxHtmlWindow_SelectWord, 3466).
--define(wxHtmlWindow_SetBorders, 3467).
--define(wxHtmlWindow_SetFonts, 3468).
--define(wxHtmlWindow_SetPage, 3469).
--define(wxHtmlWindow_SetRelatedFrame, 3470).
--define(wxHtmlWindow_SetRelatedStatusBar, 3471).
--define(wxHtmlWindow_ToText, 3472).
--define(wxHtmlWindow_destroy, 3473).
--define(wxHtmlLinkEvent_GetLinkInfo, 3474).
--define(wxAuiNotebookEvent_SetSelection, 3475).
--define(wxAuiNotebookEvent_GetSelection, 3476).
--define(wxAuiNotebookEvent_SetOldSelection, 3477).
--define(wxAuiNotebookEvent_GetOldSelection, 3478).
--define(wxAuiNotebookEvent_SetDragSource, 3479).
--define(wxAuiNotebookEvent_GetDragSource, 3480).
--define(wxAuiManagerEvent_SetManager, 3481).
--define(wxAuiManagerEvent_GetManager, 3482).
--define(wxAuiManagerEvent_SetPane, 3483).
--define(wxAuiManagerEvent_GetPane, 3484).
--define(wxAuiManagerEvent_SetButton, 3485).
--define(wxAuiManagerEvent_GetButton, 3486).
--define(wxAuiManagerEvent_SetDC, 3487).
--define(wxAuiManagerEvent_GetDC, 3488).
--define(wxAuiManagerEvent_Veto, 3489).
--define(wxAuiManagerEvent_GetVeto, 3490).
--define(wxAuiManagerEvent_SetCanVeto, 3491).
--define(wxAuiManagerEvent_CanVeto, 3492).
--define(wxLogNull_new, 3493).
--define(wxLogNull_destroy, 3494).
+-define(wxTreeCtrl_EditLabel, 2010).
+-define(wxTreeCtrl_EnsureVisible, 2011).
+-define(wxTreeCtrl_Expand, 2012).
+-define(wxTreeCtrl_GetBoundingRect, 2013).
+-define(wxTreeCtrl_GetChildrenCount, 2015).
+-define(wxTreeCtrl_GetCount, 2016).
+-define(wxTreeCtrl_GetEditControl, 2017).
+-define(wxTreeCtrl_GetFirstChild, 2018).
+-define(wxTreeCtrl_GetNextChild, 2019).
+-define(wxTreeCtrl_GetFirstVisibleItem, 2020).
+-define(wxTreeCtrl_GetImageList, 2021).
+-define(wxTreeCtrl_GetIndent, 2022).
+-define(wxTreeCtrl_GetItemBackgroundColour, 2023).
+-define(wxTreeCtrl_GetItemData, 2024).
+-define(wxTreeCtrl_GetItemFont, 2025).
+-define(wxTreeCtrl_GetItemImage_1, 2026).
+-define(wxTreeCtrl_GetItemImage_2, 2027).
+-define(wxTreeCtrl_GetItemText, 2028).
+-define(wxTreeCtrl_GetItemTextColour, 2029).
+-define(wxTreeCtrl_GetLastChild, 2030).
+-define(wxTreeCtrl_GetNextSibling, 2031).
+-define(wxTreeCtrl_GetNextVisible, 2032).
+-define(wxTreeCtrl_GetItemParent, 2033).
+-define(wxTreeCtrl_GetPrevSibling, 2034).
+-define(wxTreeCtrl_GetPrevVisible, 2035).
+-define(wxTreeCtrl_GetRootItem, 2036).
+-define(wxTreeCtrl_GetSelection, 2037).
+-define(wxTreeCtrl_GetSelections, 2038).
+-define(wxTreeCtrl_GetStateImageList, 2039).
+-define(wxTreeCtrl_HitTest, 2040).
+-define(wxTreeCtrl_InsertItem, 2042).
+-define(wxTreeCtrl_IsBold, 2043).
+-define(wxTreeCtrl_IsExpanded, 2044).
+-define(wxTreeCtrl_IsSelected, 2045).
+-define(wxTreeCtrl_IsVisible, 2046).
+-define(wxTreeCtrl_ItemHasChildren, 2047).
+-define(wxTreeCtrl_PrependItem, 2048).
+-define(wxTreeCtrl_ScrollTo, 2049).
+-define(wxTreeCtrl_SelectItem_1, 2050).
+-define(wxTreeCtrl_SelectItem_2, 2051).
+-define(wxTreeCtrl_SetIndent, 2052).
+-define(wxTreeCtrl_SetImageList, 2053).
+-define(wxTreeCtrl_SetItemBackgroundColour, 2054).
+-define(wxTreeCtrl_SetItemBold, 2055).
+-define(wxTreeCtrl_SetItemData, 2056).
+-define(wxTreeCtrl_SetItemDropHighlight, 2057).
+-define(wxTreeCtrl_SetItemFont, 2058).
+-define(wxTreeCtrl_SetItemHasChildren, 2059).
+-define(wxTreeCtrl_SetItemImage_2, 2060).
+-define(wxTreeCtrl_SetItemImage_3, 2061).
+-define(wxTreeCtrl_SetItemText, 2062).
+-define(wxTreeCtrl_SetItemTextColour, 2063).
+-define(wxTreeCtrl_SetStateImageList, 2064).
+-define(wxTreeCtrl_SetWindowStyle, 2065).
+-define(wxTreeCtrl_SortChildren, 2066).
+-define(wxTreeCtrl_Toggle, 2067).
+-define(wxTreeCtrl_ToggleItemSelection, 2068).
+-define(wxTreeCtrl_Unselect, 2069).
+-define(wxTreeCtrl_UnselectAll, 2070).
+-define(wxTreeCtrl_UnselectItem, 2071).
+-define(wxScrollBar_new_0, 2072).
+-define(wxScrollBar_new_3, 2073).
+-define(wxScrollBar_destruct, 2074).
+-define(wxScrollBar_Create, 2075).
+-define(wxScrollBar_GetRange, 2076).
+-define(wxScrollBar_GetPageSize, 2077).
+-define(wxScrollBar_GetThumbPosition, 2078).
+-define(wxScrollBar_GetThumbSize, 2079).
+-define(wxScrollBar_SetThumbPosition, 2080).
+-define(wxScrollBar_SetScrollbar, 2081).
+-define(wxSpinButton_new_2, 2083).
+-define(wxSpinButton_new_0, 2084).
+-define(wxSpinButton_Create, 2085).
+-define(wxSpinButton_GetMax, 2086).
+-define(wxSpinButton_GetMin, 2087).
+-define(wxSpinButton_GetValue, 2088).
+-define(wxSpinButton_SetRange, 2089).
+-define(wxSpinButton_SetValue, 2090).
+-define(wxSpinButton_destroy, 2091).
+-define(wxSpinCtrl_new_0, 2092).
+-define(wxSpinCtrl_new_2, 2093).
+-define(wxSpinCtrl_Create, 2095).
+-define(wxSpinCtrl_SetValue_1_1, 2098).
+-define(wxSpinCtrl_SetValue_1_0, 2099).
+-define(wxSpinCtrl_GetValue, 2101).
+-define(wxSpinCtrl_SetRange, 2103).
+-define(wxSpinCtrl_SetSelection, 2104).
+-define(wxSpinCtrl_GetMin, 2106).
+-define(wxSpinCtrl_GetMax, 2108).
+-define(wxSpinCtrl_destroy, 2109).
+-define(wxStaticText_new_0, 2110).
+-define(wxStaticText_new_4, 2111).
+-define(wxStaticText_Create, 2112).
+-define(wxStaticText_GetLabel, 2113).
+-define(wxStaticText_SetLabel, 2114).
+-define(wxStaticText_Wrap, 2115).
+-define(wxStaticText_destroy, 2116).
+-define(wxStaticBitmap_new_0, 2117).
+-define(wxStaticBitmap_new_4, 2118).
+-define(wxStaticBitmap_Create, 2119).
+-define(wxStaticBitmap_GetBitmap, 2120).
+-define(wxStaticBitmap_SetBitmap, 2121).
+-define(wxStaticBitmap_destroy, 2122).
+-define(wxRadioBox_new, 2123).
+-define(wxRadioBox_destruct, 2125).
+-define(wxRadioBox_Create, 2126).
+-define(wxRadioBox_Enable_2, 2127).
+-define(wxRadioBox_Enable_1, 2128).
+-define(wxRadioBox_GetSelection, 2129).
+-define(wxRadioBox_GetString, 2130).
+-define(wxRadioBox_SetSelection, 2131).
+-define(wxRadioBox_Show_2, 2132).
+-define(wxRadioBox_Show_1, 2133).
+-define(wxRadioBox_GetColumnCount, 2134).
+-define(wxRadioBox_GetItemHelpText, 2135).
+-define(wxRadioBox_GetItemToolTip, 2136).
+-define(wxRadioBox_GetItemFromPoint, 2138).
+-define(wxRadioBox_GetRowCount, 2139).
+-define(wxRadioBox_IsItemEnabled, 2140).
+-define(wxRadioBox_IsItemShown, 2141).
+-define(wxRadioBox_SetItemHelpText, 2142).
+-define(wxRadioBox_SetItemToolTip, 2143).
+-define(wxRadioButton_new_0, 2144).
+-define(wxRadioButton_new_4, 2145).
+-define(wxRadioButton_Create, 2146).
+-define(wxRadioButton_GetValue, 2147).
+-define(wxRadioButton_SetValue, 2148).
+-define(wxRadioButton_destroy, 2149).
+-define(wxSlider_new_6, 2151).
+-define(wxSlider_new_0, 2152).
+-define(wxSlider_Create, 2153).
+-define(wxSlider_GetLineSize, 2154).
+-define(wxSlider_GetMax, 2155).
+-define(wxSlider_GetMin, 2156).
+-define(wxSlider_GetPageSize, 2157).
+-define(wxSlider_GetThumbLength, 2158).
+-define(wxSlider_GetValue, 2159).
+-define(wxSlider_SetLineSize, 2160).
+-define(wxSlider_SetPageSize, 2161).
+-define(wxSlider_SetRange, 2162).
+-define(wxSlider_SetThumbLength, 2163).
+-define(wxSlider_SetValue, 2164).
+-define(wxSlider_destroy, 2165).
+-define(wxDialog_new_4, 2167).
+-define(wxDialog_new_0, 2168).
+-define(wxDialog_destruct, 2170).
+-define(wxDialog_Create, 2171).
+-define(wxDialog_CreateButtonSizer, 2172).
+-define(wxDialog_CreateStdDialogButtonSizer, 2173).
+-define(wxDialog_EndModal, 2174).
+-define(wxDialog_GetAffirmativeId, 2175).
+-define(wxDialog_GetReturnCode, 2176).
+-define(wxDialog_IsModal, 2177).
+-define(wxDialog_SetAffirmativeId, 2178).
+-define(wxDialog_SetReturnCode, 2179).
+-define(wxDialog_Show, 2180).
+-define(wxDialog_ShowModal, 2181).
+-define(wxColourDialog_new_0, 2182).
+-define(wxColourDialog_new_2, 2183).
+-define(wxColourDialog_destruct, 2184).
+-define(wxColourDialog_Create, 2185).
+-define(wxColourDialog_GetColourData, 2186).
+-define(wxColourData_new_0, 2187).
+-define(wxColourData_new_1, 2188).
+-define(wxColourData_destruct, 2189).
+-define(wxColourData_GetChooseFull, 2190).
+-define(wxColourData_GetColour, 2191).
+-define(wxColourData_GetCustomColour, 2193).
+-define(wxColourData_SetChooseFull, 2194).
+-define(wxColourData_SetColour, 2195).
+-define(wxColourData_SetCustomColour, 2196).
+-define(wxPalette_new_0, 2197).
+-define(wxPalette_new_4, 2198).
+-define(wxPalette_destruct, 2200).
+-define(wxPalette_Create, 2201).
+-define(wxPalette_GetColoursCount, 2202).
+-define(wxPalette_GetPixel, 2203).
+-define(wxPalette_GetRGB, 2204).
+-define(wxPalette_IsOk, 2205).
+-define(wxDirDialog_new, 2209).
+-define(wxDirDialog_destruct, 2210).
+-define(wxDirDialog_GetPath, 2211).
+-define(wxDirDialog_GetMessage, 2212).
+-define(wxDirDialog_SetMessage, 2213).
+-define(wxDirDialog_SetPath, 2214).
+-define(wxFileDialog_new, 2218).
+-define(wxFileDialog_destruct, 2219).
+-define(wxFileDialog_GetDirectory, 2220).
+-define(wxFileDialog_GetFilename, 2221).
+-define(wxFileDialog_GetFilenames, 2222).
+-define(wxFileDialog_GetFilterIndex, 2223).
+-define(wxFileDialog_GetMessage, 2224).
+-define(wxFileDialog_GetPath, 2225).
+-define(wxFileDialog_GetPaths, 2226).
+-define(wxFileDialog_GetWildcard, 2227).
+-define(wxFileDialog_SetDirectory, 2228).
+-define(wxFileDialog_SetFilename, 2229).
+-define(wxFileDialog_SetFilterIndex, 2230).
+-define(wxFileDialog_SetMessage, 2231).
+-define(wxFileDialog_SetPath, 2232).
+-define(wxFileDialog_SetWildcard, 2233).
+-define(wxPickerBase_SetInternalMargin, 2234).
+-define(wxPickerBase_GetInternalMargin, 2235).
+-define(wxPickerBase_SetTextCtrlProportion, 2236).
+-define(wxPickerBase_SetPickerCtrlProportion, 2237).
+-define(wxPickerBase_GetTextCtrlProportion, 2238).
+-define(wxPickerBase_GetPickerCtrlProportion, 2239).
+-define(wxPickerBase_HasTextCtrl, 2240).
+-define(wxPickerBase_GetTextCtrl, 2241).
+-define(wxPickerBase_IsTextCtrlGrowable, 2242).
+-define(wxPickerBase_SetPickerCtrlGrowable, 2243).
+-define(wxPickerBase_SetTextCtrlGrowable, 2244).
+-define(wxPickerBase_IsPickerCtrlGrowable, 2245).
+-define(wxFilePickerCtrl_new_0, 2246).
+-define(wxFilePickerCtrl_new_3, 2247).
+-define(wxFilePickerCtrl_Create, 2248).
+-define(wxFilePickerCtrl_GetPath, 2249).
+-define(wxFilePickerCtrl_SetPath, 2250).
+-define(wxFilePickerCtrl_destroy, 2251).
+-define(wxDirPickerCtrl_new_0, 2252).
+-define(wxDirPickerCtrl_new_3, 2253).
+-define(wxDirPickerCtrl_Create, 2254).
+-define(wxDirPickerCtrl_GetPath, 2255).
+-define(wxDirPickerCtrl_SetPath, 2256).
+-define(wxDirPickerCtrl_destroy, 2257).
+-define(wxColourPickerCtrl_new_0, 2258).
+-define(wxColourPickerCtrl_new_3, 2259).
+-define(wxColourPickerCtrl_Create, 2260).
+-define(wxColourPickerCtrl_GetColour, 2261).
+-define(wxColourPickerCtrl_SetColour_1_1, 2262).
+-define(wxColourPickerCtrl_SetColour_1_0, 2263).
+-define(wxColourPickerCtrl_destroy, 2264).
+-define(wxDatePickerCtrl_new_0, 2265).
+-define(wxDatePickerCtrl_new_3, 2266).
+-define(wxDatePickerCtrl_GetRange, 2267).
+-define(wxDatePickerCtrl_GetValue, 2268).
+-define(wxDatePickerCtrl_SetRange, 2269).
+-define(wxDatePickerCtrl_SetValue, 2270).
+-define(wxDatePickerCtrl_destroy, 2271).
+-define(wxFontPickerCtrl_new_0, 2272).
+-define(wxFontPickerCtrl_new_3, 2273).
+-define(wxFontPickerCtrl_Create, 2274).
+-define(wxFontPickerCtrl_GetSelectedFont, 2275).
+-define(wxFontPickerCtrl_SetSelectedFont, 2276).
+-define(wxFontPickerCtrl_GetMaxPointSize, 2277).
+-define(wxFontPickerCtrl_SetMaxPointSize, 2278).
+-define(wxFontPickerCtrl_destroy, 2279).
+-define(wxFindReplaceDialog_new_0, 2282).
+-define(wxFindReplaceDialog_new_4, 2283).
+-define(wxFindReplaceDialog_destruct, 2284).
+-define(wxFindReplaceDialog_Create, 2285).
+-define(wxFindReplaceDialog_GetData, 2286).
+-define(wxFindReplaceData_new_0, 2287).
+-define(wxFindReplaceData_new_1, 2288).
+-define(wxFindReplaceData_GetFindString, 2289).
+-define(wxFindReplaceData_GetReplaceString, 2290).
+-define(wxFindReplaceData_GetFlags, 2291).
+-define(wxFindReplaceData_SetFlags, 2292).
+-define(wxFindReplaceData_SetFindString, 2293).
+-define(wxFindReplaceData_SetReplaceString, 2294).
+-define(wxFindReplaceData_destroy, 2295).
+-define(wxMultiChoiceDialog_new_0, 2296).
+-define(wxMultiChoiceDialog_new_5, 2298).
+-define(wxMultiChoiceDialog_GetSelections, 2299).
+-define(wxMultiChoiceDialog_SetSelections, 2300).
+-define(wxMultiChoiceDialog_destroy, 2301).
+-define(wxSingleChoiceDialog_new_0, 2302).
+-define(wxSingleChoiceDialog_new_5, 2304).
+-define(wxSingleChoiceDialog_GetSelection, 2305).
+-define(wxSingleChoiceDialog_GetStringSelection, 2306).
+-define(wxSingleChoiceDialog_SetSelection, 2307).
+-define(wxSingleChoiceDialog_destroy, 2308).
+-define(wxTextEntryDialog_new, 2309).
+-define(wxTextEntryDialog_GetValue, 2310).
+-define(wxTextEntryDialog_SetValue, 2311).
+-define(wxTextEntryDialog_destroy, 2312).
+-define(wxPasswordEntryDialog_new, 2313).
+-define(wxPasswordEntryDialog_destroy, 2314).
+-define(wxFontData_new_0, 2315).
+-define(wxFontData_new_1, 2316).
+-define(wxFontData_destruct, 2317).
+-define(wxFontData_EnableEffects, 2318).
+-define(wxFontData_GetAllowSymbols, 2319).
+-define(wxFontData_GetColour, 2320).
+-define(wxFontData_GetChosenFont, 2321).
+-define(wxFontData_GetEnableEffects, 2322).
+-define(wxFontData_GetInitialFont, 2323).
+-define(wxFontData_GetShowHelp, 2324).
+-define(wxFontData_SetAllowSymbols, 2325).
+-define(wxFontData_SetChosenFont, 2326).
+-define(wxFontData_SetColour, 2327).
+-define(wxFontData_SetInitialFont, 2328).
+-define(wxFontData_SetRange, 2329).
+-define(wxFontData_SetShowHelp, 2330).
+-define(wxFontDialog_new_0, 2334).
+-define(wxFontDialog_new_2, 2336).
+-define(wxFontDialog_Create, 2338).
+-define(wxFontDialog_GetFontData, 2339).
+-define(wxFontDialog_destroy, 2341).
+-define(wxProgressDialog_new, 2342).
+-define(wxProgressDialog_destruct, 2343).
+-define(wxProgressDialog_Resume, 2344).
+-define(wxProgressDialog_Update_2, 2345).
+-define(wxProgressDialog_Update_0, 2346).
+-define(wxMessageDialog_new, 2347).
+-define(wxMessageDialog_destruct, 2348).
+-define(wxPageSetupDialog_new, 2349).
+-define(wxPageSetupDialog_destruct, 2350).
+-define(wxPageSetupDialog_GetPageSetupData, 2351).
+-define(wxPageSetupDialog_ShowModal, 2352).
+-define(wxPageSetupDialogData_new_0, 2353).
+-define(wxPageSetupDialogData_new_1_0, 2354).
+-define(wxPageSetupDialogData_new_1_1, 2355).
+-define(wxPageSetupDialogData_destruct, 2356).
+-define(wxPageSetupDialogData_EnableHelp, 2357).
+-define(wxPageSetupDialogData_EnableMargins, 2358).
+-define(wxPageSetupDialogData_EnableOrientation, 2359).
+-define(wxPageSetupDialogData_EnablePaper, 2360).
+-define(wxPageSetupDialogData_EnablePrinter, 2361).
+-define(wxPageSetupDialogData_GetDefaultMinMargins, 2362).
+-define(wxPageSetupDialogData_GetEnableMargins, 2363).
+-define(wxPageSetupDialogData_GetEnableOrientation, 2364).
+-define(wxPageSetupDialogData_GetEnablePaper, 2365).
+-define(wxPageSetupDialogData_GetEnablePrinter, 2366).
+-define(wxPageSetupDialogData_GetEnableHelp, 2367).
+-define(wxPageSetupDialogData_GetDefaultInfo, 2368).
+-define(wxPageSetupDialogData_GetMarginTopLeft, 2369).
+-define(wxPageSetupDialogData_GetMarginBottomRight, 2370).
+-define(wxPageSetupDialogData_GetMinMarginTopLeft, 2371).
+-define(wxPageSetupDialogData_GetMinMarginBottomRight, 2372).
+-define(wxPageSetupDialogData_GetPaperId, 2373).
+-define(wxPageSetupDialogData_GetPaperSize, 2374).
+-define(wxPageSetupDialogData_GetPrintData, 2376).
+-define(wxPageSetupDialogData_IsOk, 2377).
+-define(wxPageSetupDialogData_SetDefaultInfo, 2378).
+-define(wxPageSetupDialogData_SetDefaultMinMargins, 2379).
+-define(wxPageSetupDialogData_SetMarginTopLeft, 2380).
+-define(wxPageSetupDialogData_SetMarginBottomRight, 2381).
+-define(wxPageSetupDialogData_SetMinMarginTopLeft, 2382).
+-define(wxPageSetupDialogData_SetMinMarginBottomRight, 2383).
+-define(wxPageSetupDialogData_SetPaperId, 2384).
+-define(wxPageSetupDialogData_SetPaperSize_1_1, 2385).
+-define(wxPageSetupDialogData_SetPaperSize_1_0, 2386).
+-define(wxPageSetupDialogData_SetPrintData, 2387).
+-define(wxPrintDialog_new_2_0, 2388).
+-define(wxPrintDialog_new_2_1, 2389).
+-define(wxPrintDialog_destruct, 2390).
+-define(wxPrintDialog_GetPrintDialogData, 2391).
+-define(wxPrintDialog_GetPrintDC, 2392).
+-define(wxPrintDialogData_new_0, 2393).
+-define(wxPrintDialogData_new_1_1, 2394).
+-define(wxPrintDialogData_new_1_0, 2395).
+-define(wxPrintDialogData_destruct, 2396).
+-define(wxPrintDialogData_EnableHelp, 2397).
+-define(wxPrintDialogData_EnablePageNumbers, 2398).
+-define(wxPrintDialogData_EnablePrintToFile, 2399).
+-define(wxPrintDialogData_EnableSelection, 2400).
+-define(wxPrintDialogData_GetAllPages, 2401).
+-define(wxPrintDialogData_GetCollate, 2402).
+-define(wxPrintDialogData_GetFromPage, 2403).
+-define(wxPrintDialogData_GetMaxPage, 2404).
+-define(wxPrintDialogData_GetMinPage, 2405).
+-define(wxPrintDialogData_GetNoCopies, 2406).
+-define(wxPrintDialogData_GetPrintData, 2407).
+-define(wxPrintDialogData_GetPrintToFile, 2408).
+-define(wxPrintDialogData_GetSelection, 2409).
+-define(wxPrintDialogData_GetToPage, 2410).
+-define(wxPrintDialogData_IsOk, 2411).
+-define(wxPrintDialogData_SetCollate, 2412).
+-define(wxPrintDialogData_SetFromPage, 2413).
+-define(wxPrintDialogData_SetMaxPage, 2414).
+-define(wxPrintDialogData_SetMinPage, 2415).
+-define(wxPrintDialogData_SetNoCopies, 2416).
+-define(wxPrintDialogData_SetPrintData, 2417).
+-define(wxPrintDialogData_SetPrintToFile, 2418).
+-define(wxPrintDialogData_SetSelection, 2419).
+-define(wxPrintDialogData_SetToPage, 2420).
+-define(wxPrintData_new_0, 2421).
+-define(wxPrintData_new_1, 2422).
+-define(wxPrintData_destruct, 2423).
+-define(wxPrintData_GetCollate, 2424).
+-define(wxPrintData_GetBin, 2425).
+-define(wxPrintData_GetColour, 2426).
+-define(wxPrintData_GetDuplex, 2427).
+-define(wxPrintData_GetNoCopies, 2428).
+-define(wxPrintData_GetOrientation, 2429).
+-define(wxPrintData_GetPaperId, 2430).
+-define(wxPrintData_GetPrinterName, 2431).
+-define(wxPrintData_GetQuality, 2432).
+-define(wxPrintData_IsOk, 2433).
+-define(wxPrintData_SetBin, 2434).
+-define(wxPrintData_SetCollate, 2435).
+-define(wxPrintData_SetColour, 2436).
+-define(wxPrintData_SetDuplex, 2437).
+-define(wxPrintData_SetNoCopies, 2438).
+-define(wxPrintData_SetOrientation, 2439).
+-define(wxPrintData_SetPaperId, 2440).
+-define(wxPrintData_SetPrinterName, 2441).
+-define(wxPrintData_SetQuality, 2442).
+-define(wxPrintPreview_new_2, 2445).
+-define(wxPrintPreview_new_3, 2446).
+-define(wxPrintPreview_destruct, 2448).
+-define(wxPrintPreview_GetCanvas, 2449).
+-define(wxPrintPreview_GetCurrentPage, 2450).
+-define(wxPrintPreview_GetFrame, 2451).
+-define(wxPrintPreview_GetMaxPage, 2452).
+-define(wxPrintPreview_GetMinPage, 2453).
+-define(wxPrintPreview_GetPrintout, 2454).
+-define(wxPrintPreview_GetPrintoutForPrinting, 2455).
+-define(wxPrintPreview_IsOk, 2456).
+-define(wxPrintPreview_PaintPage, 2457).
+-define(wxPrintPreview_Print, 2458).
+-define(wxPrintPreview_RenderPage, 2459).
+-define(wxPrintPreview_SetCanvas, 2460).
+-define(wxPrintPreview_SetCurrentPage, 2461).
+-define(wxPrintPreview_SetFrame, 2462).
+-define(wxPrintPreview_SetPrintout, 2463).
+-define(wxPrintPreview_SetZoom, 2464).
+-define(wxPreviewFrame_new, 2465).
+-define(wxPreviewFrame_destruct, 2466).
+-define(wxPreviewFrame_CreateControlBar, 2467).
+-define(wxPreviewFrame_CreateCanvas, 2468).
+-define(wxPreviewFrame_Initialize, 2469).
+-define(wxPreviewFrame_OnCloseWindow, 2470).
+-define(wxPreviewControlBar_new, 2471).
+-define(wxPreviewControlBar_destruct, 2472).
+-define(wxPreviewControlBar_CreateButtons, 2473).
+-define(wxPreviewControlBar_GetPrintPreview, 2474).
+-define(wxPreviewControlBar_GetZoomControl, 2475).
+-define(wxPreviewControlBar_SetZoomControl, 2476).
+-define(wxPrinter_new, 2478).
+-define(wxPrinter_CreateAbortWindow, 2479).
+-define(wxPrinter_GetAbort, 2480).
+-define(wxPrinter_GetLastError, 2481).
+-define(wxPrinter_GetPrintDialogData, 2482).
+-define(wxPrinter_Print, 2483).
+-define(wxPrinter_PrintDialog, 2484).
+-define(wxPrinter_ReportError, 2485).
+-define(wxPrinter_Setup, 2486).
+-define(wxPrinter_destroy, 2487).
+-define(wxXmlResource_new_1, 2488).
+-define(wxXmlResource_new_2, 2489).
+-define(wxXmlResource_destruct, 2490).
+-define(wxXmlResource_AttachUnknownControl, 2491).
+-define(wxXmlResource_ClearHandlers, 2492).
+-define(wxXmlResource_CompareVersion, 2493).
+-define(wxXmlResource_Get, 2494).
+-define(wxXmlResource_GetFlags, 2495).
+-define(wxXmlResource_GetVersion, 2496).
+-define(wxXmlResource_GetXRCID, 2497).
+-define(wxXmlResource_InitAllHandlers, 2498).
+-define(wxXmlResource_Load, 2499).
+-define(wxXmlResource_LoadBitmap, 2500).
+-define(wxXmlResource_LoadDialog_2, 2501).
+-define(wxXmlResource_LoadDialog_3, 2502).
+-define(wxXmlResource_LoadFrame_2, 2503).
+-define(wxXmlResource_LoadFrame_3, 2504).
+-define(wxXmlResource_LoadIcon, 2505).
+-define(wxXmlResource_LoadMenu, 2506).
+-define(wxXmlResource_LoadMenuBar_2, 2507).
+-define(wxXmlResource_LoadMenuBar_1, 2508).
+-define(wxXmlResource_LoadPanel_2, 2509).
+-define(wxXmlResource_LoadPanel_3, 2510).
+-define(wxXmlResource_LoadToolBar, 2511).
+-define(wxXmlResource_Set, 2512).
+-define(wxXmlResource_SetFlags, 2513).
+-define(wxXmlResource_Unload, 2514).
+-define(wxXmlResource_xrcctrl, 2515).
+-define(wxHtmlEasyPrinting_new, 2516).
+-define(wxHtmlEasyPrinting_destruct, 2517).
+-define(wxHtmlEasyPrinting_GetPrintData, 2518).
+-define(wxHtmlEasyPrinting_GetPageSetupData, 2519).
+-define(wxHtmlEasyPrinting_PreviewFile, 2520).
+-define(wxHtmlEasyPrinting_PreviewText, 2521).
+-define(wxHtmlEasyPrinting_PrintFile, 2522).
+-define(wxHtmlEasyPrinting_PrintText, 2523).
+-define(wxHtmlEasyPrinting_PageSetup, 2524).
+-define(wxHtmlEasyPrinting_SetFonts, 2525).
+-define(wxHtmlEasyPrinting_SetHeader, 2526).
+-define(wxHtmlEasyPrinting_SetFooter, 2527).
+-define(wxGLCanvas_new_2, 2529).
+-define(wxGLCanvas_new_3_1, 2530).
+-define(wxGLCanvas_new_3_0, 2531).
+-define(wxGLCanvas_GetContext, 2532).
+-define(wxGLCanvas_SetCurrent, 2534).
+-define(wxGLCanvas_SwapBuffers, 2535).
+-define(wxGLCanvas_destroy, 2536).
+-define(wxAuiManager_new, 2537).
+-define(wxAuiManager_destruct, 2538).
+-define(wxAuiManager_AddPane_2_1, 2539).
+-define(wxAuiManager_AddPane_3, 2540).
+-define(wxAuiManager_AddPane_2_0, 2541).
+-define(wxAuiManager_DetachPane, 2542).
+-define(wxAuiManager_GetAllPanes, 2543).
+-define(wxAuiManager_GetArtProvider, 2544).
+-define(wxAuiManager_GetDockSizeConstraint, 2545).
+-define(wxAuiManager_GetFlags, 2546).
+-define(wxAuiManager_GetManagedWindow, 2547).
+-define(wxAuiManager_GetManager, 2548).
+-define(wxAuiManager_GetPane_1_1, 2549).
+-define(wxAuiManager_GetPane_1_0, 2550).
+-define(wxAuiManager_HideHint, 2551).
+-define(wxAuiManager_InsertPane, 2552).
+-define(wxAuiManager_LoadPaneInfo, 2553).
+-define(wxAuiManager_LoadPerspective, 2554).
+-define(wxAuiManager_SavePaneInfo, 2555).
+-define(wxAuiManager_SavePerspective, 2556).
+-define(wxAuiManager_SetArtProvider, 2557).
+-define(wxAuiManager_SetDockSizeConstraint, 2558).
+-define(wxAuiManager_SetFlags, 2559).
+-define(wxAuiManager_SetManagedWindow, 2560).
+-define(wxAuiManager_ShowHint, 2561).
+-define(wxAuiManager_UnInit, 2562).
+-define(wxAuiManager_Update, 2563).
+-define(wxAuiPaneInfo_new_0, 2564).
+-define(wxAuiPaneInfo_new_1, 2565).
+-define(wxAuiPaneInfo_destruct, 2566).
+-define(wxAuiPaneInfo_BestSize_1, 2567).
+-define(wxAuiPaneInfo_BestSize_2, 2568).
+-define(wxAuiPaneInfo_Bottom, 2569).
+-define(wxAuiPaneInfo_BottomDockable, 2570).
+-define(wxAuiPaneInfo_Caption, 2571).
+-define(wxAuiPaneInfo_CaptionVisible, 2572).
+-define(wxAuiPaneInfo_Centre, 2573).
+-define(wxAuiPaneInfo_CentrePane, 2574).
+-define(wxAuiPaneInfo_CloseButton, 2575).
+-define(wxAuiPaneInfo_DefaultPane, 2576).
+-define(wxAuiPaneInfo_DestroyOnClose, 2577).
+-define(wxAuiPaneInfo_Direction, 2578).
+-define(wxAuiPaneInfo_Dock, 2579).
+-define(wxAuiPaneInfo_Dockable, 2580).
+-define(wxAuiPaneInfo_Fixed, 2581).
+-define(wxAuiPaneInfo_Float, 2582).
+-define(wxAuiPaneInfo_Floatable, 2583).
+-define(wxAuiPaneInfo_FloatingPosition_1, 2584).
+-define(wxAuiPaneInfo_FloatingPosition_2, 2585).
+-define(wxAuiPaneInfo_FloatingSize_1, 2586).
+-define(wxAuiPaneInfo_FloatingSize_2, 2587).
+-define(wxAuiPaneInfo_Gripper, 2588).
+-define(wxAuiPaneInfo_GripperTop, 2589).
+-define(wxAuiPaneInfo_HasBorder, 2590).
+-define(wxAuiPaneInfo_HasCaption, 2591).
+-define(wxAuiPaneInfo_HasCloseButton, 2592).
+-define(wxAuiPaneInfo_HasFlag, 2593).
+-define(wxAuiPaneInfo_HasGripper, 2594).
+-define(wxAuiPaneInfo_HasGripperTop, 2595).
+-define(wxAuiPaneInfo_HasMaximizeButton, 2596).
+-define(wxAuiPaneInfo_HasMinimizeButton, 2597).
+-define(wxAuiPaneInfo_HasPinButton, 2598).
+-define(wxAuiPaneInfo_Hide, 2599).
+-define(wxAuiPaneInfo_IsBottomDockable, 2600).
+-define(wxAuiPaneInfo_IsDocked, 2601).
+-define(wxAuiPaneInfo_IsFixed, 2602).
+-define(wxAuiPaneInfo_IsFloatable, 2603).
+-define(wxAuiPaneInfo_IsFloating, 2604).
+-define(wxAuiPaneInfo_IsLeftDockable, 2605).
+-define(wxAuiPaneInfo_IsMovable, 2606).
+-define(wxAuiPaneInfo_IsOk, 2607).
+-define(wxAuiPaneInfo_IsResizable, 2608).
+-define(wxAuiPaneInfo_IsRightDockable, 2609).
+-define(wxAuiPaneInfo_IsShown, 2610).
+-define(wxAuiPaneInfo_IsToolbar, 2611).
+-define(wxAuiPaneInfo_IsTopDockable, 2612).
+-define(wxAuiPaneInfo_Layer, 2613).
+-define(wxAuiPaneInfo_Left, 2614).
+-define(wxAuiPaneInfo_LeftDockable, 2615).
+-define(wxAuiPaneInfo_MaxSize_1, 2616).
+-define(wxAuiPaneInfo_MaxSize_2, 2617).
+-define(wxAuiPaneInfo_MaximizeButton, 2618).
+-define(wxAuiPaneInfo_MinSize_1, 2619).
+-define(wxAuiPaneInfo_MinSize_2, 2620).
+-define(wxAuiPaneInfo_MinimizeButton, 2621).
+-define(wxAuiPaneInfo_Movable, 2622).
+-define(wxAuiPaneInfo_Name, 2623).
+-define(wxAuiPaneInfo_PaneBorder, 2624).
+-define(wxAuiPaneInfo_PinButton, 2625).
+-define(wxAuiPaneInfo_Position, 2626).
+-define(wxAuiPaneInfo_Resizable, 2627).
+-define(wxAuiPaneInfo_Right, 2628).
+-define(wxAuiPaneInfo_RightDockable, 2629).
+-define(wxAuiPaneInfo_Row, 2630).
+-define(wxAuiPaneInfo_SafeSet, 2631).
+-define(wxAuiPaneInfo_SetFlag, 2632).
+-define(wxAuiPaneInfo_Show, 2633).
+-define(wxAuiPaneInfo_ToolbarPane, 2634).
+-define(wxAuiPaneInfo_Top, 2635).
+-define(wxAuiPaneInfo_TopDockable, 2636).
+-define(wxAuiPaneInfo_Window, 2637).
+-define(wxAuiNotebook_new_0, 2638).
+-define(wxAuiNotebook_new_2, 2639).
+-define(wxAuiNotebook_AddPage, 2640).
+-define(wxAuiNotebook_Create, 2641).
+-define(wxAuiNotebook_DeletePage, 2642).
+-define(wxAuiNotebook_GetArtProvider, 2643).
+-define(wxAuiNotebook_GetPage, 2644).
+-define(wxAuiNotebook_GetPageBitmap, 2645).
+-define(wxAuiNotebook_GetPageCount, 2646).
+-define(wxAuiNotebook_GetPageIndex, 2647).
+-define(wxAuiNotebook_GetPageText, 2648).
+-define(wxAuiNotebook_GetSelection, 2649).
+-define(wxAuiNotebook_InsertPage, 2650).
+-define(wxAuiNotebook_RemovePage, 2651).
+-define(wxAuiNotebook_SetArtProvider, 2652).
+-define(wxAuiNotebook_SetFont, 2653).
+-define(wxAuiNotebook_SetPageBitmap, 2654).
+-define(wxAuiNotebook_SetPageText, 2655).
+-define(wxAuiNotebook_SetSelection, 2656).
+-define(wxAuiNotebook_SetTabCtrlHeight, 2657).
+-define(wxAuiNotebook_SetUniformBitmapSize, 2658).
+-define(wxAuiNotebook_destroy, 2659).
+-define(wxMDIParentFrame_new_0, 2660).
+-define(wxMDIParentFrame_new_4, 2661).
+-define(wxMDIParentFrame_destruct, 2662).
+-define(wxMDIParentFrame_ActivateNext, 2663).
+-define(wxMDIParentFrame_ActivatePrevious, 2664).
+-define(wxMDIParentFrame_ArrangeIcons, 2665).
+-define(wxMDIParentFrame_Cascade, 2666).
+-define(wxMDIParentFrame_Create, 2667).
+-define(wxMDIParentFrame_GetActiveChild, 2668).
+-define(wxMDIParentFrame_GetClientWindow, 2669).
+-define(wxMDIParentFrame_Tile, 2670).
+-define(wxMDIChildFrame_new_0, 2671).
+-define(wxMDIChildFrame_new_4, 2672).
+-define(wxMDIChildFrame_destruct, 2673).
+-define(wxMDIChildFrame_Activate, 2674).
+-define(wxMDIChildFrame_Create, 2675).
+-define(wxMDIChildFrame_Maximize, 2676).
+-define(wxMDIChildFrame_Restore, 2677).
+-define(wxMDIClientWindow_new_0, 2678).
+-define(wxMDIClientWindow_new_2, 2679).
+-define(wxMDIClientWindow_destruct, 2680).
+-define(wxMDIClientWindow_CreateClient, 2681).
+-define(wxLayoutAlgorithm_new, 2682).
+-define(wxLayoutAlgorithm_LayoutFrame, 2683).
+-define(wxLayoutAlgorithm_LayoutMDIFrame, 2684).
+-define(wxLayoutAlgorithm_LayoutWindow, 2685).
+-define(wxLayoutAlgorithm_destroy, 2686).
+-define(wxEvent_GetId, 2687).
+-define(wxEvent_GetSkipped, 2688).
+-define(wxEvent_GetTimestamp, 2689).
+-define(wxEvent_IsCommandEvent, 2690).
+-define(wxEvent_ResumePropagation, 2691).
+-define(wxEvent_ShouldPropagate, 2692).
+-define(wxEvent_Skip, 2693).
+-define(wxEvent_StopPropagation, 2694).
+-define(wxCommandEvent_getClientData, 2695).
+-define(wxCommandEvent_GetExtraLong, 2696).
+-define(wxCommandEvent_GetInt, 2697).
+-define(wxCommandEvent_GetSelection, 2698).
+-define(wxCommandEvent_GetString, 2699).
+-define(wxCommandEvent_IsChecked, 2700).
+-define(wxCommandEvent_IsSelection, 2701).
+-define(wxCommandEvent_SetInt, 2702).
+-define(wxCommandEvent_SetString, 2703).
+-define(wxScrollEvent_GetOrientation, 2704).
+-define(wxScrollEvent_GetPosition, 2705).
+-define(wxScrollWinEvent_GetOrientation, 2706).
+-define(wxScrollWinEvent_GetPosition, 2707).
+-define(wxMouseEvent_AltDown, 2708).
+-define(wxMouseEvent_Button, 2709).
+-define(wxMouseEvent_ButtonDClick, 2710).
+-define(wxMouseEvent_ButtonDown, 2711).
+-define(wxMouseEvent_ButtonUp, 2712).
+-define(wxMouseEvent_CmdDown, 2713).
+-define(wxMouseEvent_ControlDown, 2714).
+-define(wxMouseEvent_Dragging, 2715).
+-define(wxMouseEvent_Entering, 2716).
+-define(wxMouseEvent_GetButton, 2717).
+-define(wxMouseEvent_GetPosition, 2720).
+-define(wxMouseEvent_GetLogicalPosition, 2721).
+-define(wxMouseEvent_GetLinesPerAction, 2722).
+-define(wxMouseEvent_GetWheelRotation, 2723).
+-define(wxMouseEvent_GetWheelDelta, 2724).
+-define(wxMouseEvent_GetX, 2725).
+-define(wxMouseEvent_GetY, 2726).
+-define(wxMouseEvent_IsButton, 2727).
+-define(wxMouseEvent_IsPageScroll, 2728).
+-define(wxMouseEvent_Leaving, 2729).
+-define(wxMouseEvent_LeftDClick, 2730).
+-define(wxMouseEvent_LeftDown, 2731).
+-define(wxMouseEvent_LeftIsDown, 2732).
+-define(wxMouseEvent_LeftUp, 2733).
+-define(wxMouseEvent_MetaDown, 2734).
+-define(wxMouseEvent_MiddleDClick, 2735).
+-define(wxMouseEvent_MiddleDown, 2736).
+-define(wxMouseEvent_MiddleIsDown, 2737).
+-define(wxMouseEvent_MiddleUp, 2738).
+-define(wxMouseEvent_Moving, 2739).
+-define(wxMouseEvent_RightDClick, 2740).
+-define(wxMouseEvent_RightDown, 2741).
+-define(wxMouseEvent_RightIsDown, 2742).
+-define(wxMouseEvent_RightUp, 2743).
+-define(wxMouseEvent_ShiftDown, 2744).
+-define(wxSetCursorEvent_GetCursor, 2745).
+-define(wxSetCursorEvent_GetX, 2746).
+-define(wxSetCursorEvent_GetY, 2747).
+-define(wxSetCursorEvent_HasCursor, 2748).
+-define(wxSetCursorEvent_SetCursor, 2749).
+-define(wxKeyEvent_AltDown, 2750).
+-define(wxKeyEvent_CmdDown, 2751).
+-define(wxKeyEvent_ControlDown, 2752).
+-define(wxKeyEvent_GetKeyCode, 2753).
+-define(wxKeyEvent_GetModifiers, 2754).
+-define(wxKeyEvent_GetPosition, 2757).
+-define(wxKeyEvent_GetRawKeyCode, 2758).
+-define(wxKeyEvent_GetRawKeyFlags, 2759).
+-define(wxKeyEvent_GetUnicodeKey, 2760).
+-define(wxKeyEvent_GetX, 2761).
+-define(wxKeyEvent_GetY, 2762).
+-define(wxKeyEvent_HasModifiers, 2763).
+-define(wxKeyEvent_MetaDown, 2764).
+-define(wxKeyEvent_ShiftDown, 2765).
+-define(wxSizeEvent_GetSize, 2766).
+-define(wxMoveEvent_GetPosition, 2767).
+-define(wxEraseEvent_GetDC, 2768).
+-define(wxFocusEvent_GetWindow, 2769).
+-define(wxChildFocusEvent_GetWindow, 2770).
+-define(wxMenuEvent_GetMenu, 2771).
+-define(wxMenuEvent_GetMenuId, 2772).
+-define(wxMenuEvent_IsPopup, 2773).
+-define(wxCloseEvent_CanVeto, 2774).
+-define(wxCloseEvent_GetLoggingOff, 2775).
+-define(wxCloseEvent_SetCanVeto, 2776).
+-define(wxCloseEvent_SetLoggingOff, 2777).
+-define(wxCloseEvent_Veto, 2778).
+-define(wxShowEvent_SetShow, 2779).
+-define(wxShowEvent_GetShow, 2780).
+-define(wxIconizeEvent_Iconized, 2781).
+-define(wxJoystickEvent_ButtonDown, 2782).
+-define(wxJoystickEvent_ButtonIsDown, 2783).
+-define(wxJoystickEvent_ButtonUp, 2784).
+-define(wxJoystickEvent_GetButtonChange, 2785).
+-define(wxJoystickEvent_GetButtonState, 2786).
+-define(wxJoystickEvent_GetJoystick, 2787).
+-define(wxJoystickEvent_GetPosition, 2788).
+-define(wxJoystickEvent_GetZPosition, 2789).
+-define(wxJoystickEvent_IsButton, 2790).
+-define(wxJoystickEvent_IsMove, 2791).
+-define(wxJoystickEvent_IsZMove, 2792).
+-define(wxUpdateUIEvent_CanUpdate, 2793).
+-define(wxUpdateUIEvent_Check, 2794).
+-define(wxUpdateUIEvent_Enable, 2795).
+-define(wxUpdateUIEvent_Show, 2796).
+-define(wxUpdateUIEvent_GetChecked, 2797).
+-define(wxUpdateUIEvent_GetEnabled, 2798).
+-define(wxUpdateUIEvent_GetShown, 2799).
+-define(wxUpdateUIEvent_GetSetChecked, 2800).
+-define(wxUpdateUIEvent_GetSetEnabled, 2801).
+-define(wxUpdateUIEvent_GetSetShown, 2802).
+-define(wxUpdateUIEvent_GetSetText, 2803).
+-define(wxUpdateUIEvent_GetText, 2804).
+-define(wxUpdateUIEvent_GetMode, 2805).
+-define(wxUpdateUIEvent_GetUpdateInterval, 2806).
+-define(wxUpdateUIEvent_ResetUpdateTime, 2807).
+-define(wxUpdateUIEvent_SetMode, 2808).
+-define(wxUpdateUIEvent_SetText, 2809).
+-define(wxUpdateUIEvent_SetUpdateInterval, 2810).
+-define(wxMouseCaptureChangedEvent_GetCapturedWindow, 2811).
+-define(wxPaletteChangedEvent_SetChangedWindow, 2812).
+-define(wxPaletteChangedEvent_GetChangedWindow, 2813).
+-define(wxQueryNewPaletteEvent_SetPaletteRealized, 2814).
+-define(wxQueryNewPaletteEvent_GetPaletteRealized, 2815).
+-define(wxNavigationKeyEvent_GetDirection, 2816).
+-define(wxNavigationKeyEvent_SetDirection, 2817).
+-define(wxNavigationKeyEvent_IsWindowChange, 2818).
+-define(wxNavigationKeyEvent_SetWindowChange, 2819).
+-define(wxNavigationKeyEvent_IsFromTab, 2820).
+-define(wxNavigationKeyEvent_SetFromTab, 2821).
+-define(wxNavigationKeyEvent_GetCurrentFocus, 2822).
+-define(wxNavigationKeyEvent_SetCurrentFocus, 2823).
+-define(wxHelpEvent_GetOrigin, 2824).
+-define(wxHelpEvent_GetPosition, 2825).
+-define(wxHelpEvent_SetOrigin, 2826).
+-define(wxHelpEvent_SetPosition, 2827).
+-define(wxContextMenuEvent_GetPosition, 2828).
+-define(wxContextMenuEvent_SetPosition, 2829).
+-define(wxIdleEvent_CanSend, 2830).
+-define(wxIdleEvent_GetMode, 2831).
+-define(wxIdleEvent_RequestMore, 2832).
+-define(wxIdleEvent_MoreRequested, 2833).
+-define(wxIdleEvent_SetMode, 2834).
+-define(wxGridEvent_AltDown, 2835).
+-define(wxGridEvent_ControlDown, 2836).
+-define(wxGridEvent_GetCol, 2837).
+-define(wxGridEvent_GetPosition, 2838).
+-define(wxGridEvent_GetRow, 2839).
+-define(wxGridEvent_MetaDown, 2840).
+-define(wxGridEvent_Selecting, 2841).
+-define(wxGridEvent_ShiftDown, 2842).
+-define(wxNotifyEvent_Allow, 2843).
+-define(wxNotifyEvent_IsAllowed, 2844).
+-define(wxNotifyEvent_Veto, 2845).
+-define(wxSashEvent_GetEdge, 2846).
+-define(wxSashEvent_GetDragRect, 2847).
+-define(wxSashEvent_GetDragStatus, 2848).
+-define(wxListEvent_GetCacheFrom, 2849).
+-define(wxListEvent_GetCacheTo, 2850).
+-define(wxListEvent_GetKeyCode, 2851).
+-define(wxListEvent_GetIndex, 2852).
+-define(wxListEvent_GetColumn, 2853).
+-define(wxListEvent_GetPoint, 2854).
+-define(wxListEvent_GetLabel, 2855).
+-define(wxListEvent_GetText, 2856).
+-define(wxListEvent_GetImage, 2857).
+-define(wxListEvent_GetData, 2858).
+-define(wxListEvent_GetMask, 2859).
+-define(wxListEvent_GetItem, 2860).
+-define(wxListEvent_IsEditCancelled, 2861).
+-define(wxDateEvent_GetDate, 2862).
+-define(wxCalendarEvent_GetWeekDay, 2863).
+-define(wxFileDirPickerEvent_GetPath, 2864).
+-define(wxColourPickerEvent_GetColour, 2865).
+-define(wxFontPickerEvent_GetFont, 2866).
+-define(wxStyledTextEvent_GetPosition, 2867).
+-define(wxStyledTextEvent_GetKey, 2868).
+-define(wxStyledTextEvent_GetModifiers, 2869).
+-define(wxStyledTextEvent_GetModificationType, 2870).
+-define(wxStyledTextEvent_GetText, 2871).
+-define(wxStyledTextEvent_GetLength, 2872).
+-define(wxStyledTextEvent_GetLinesAdded, 2873).
+-define(wxStyledTextEvent_GetLine, 2874).
+-define(wxStyledTextEvent_GetFoldLevelNow, 2875).
+-define(wxStyledTextEvent_GetFoldLevelPrev, 2876).
+-define(wxStyledTextEvent_GetMargin, 2877).
+-define(wxStyledTextEvent_GetMessage, 2878).
+-define(wxStyledTextEvent_GetWParam, 2879).
+-define(wxStyledTextEvent_GetLParam, 2880).
+-define(wxStyledTextEvent_GetListType, 2881).
+-define(wxStyledTextEvent_GetX, 2882).
+-define(wxStyledTextEvent_GetY, 2883).
+-define(wxStyledTextEvent_GetDragText, 2884).
+-define(wxStyledTextEvent_GetDragAllowMove, 2885).
+-define(wxStyledTextEvent_GetDragResult, 2886).
+-define(wxStyledTextEvent_GetShift, 2887).
+-define(wxStyledTextEvent_GetControl, 2888).
+-define(wxStyledTextEvent_GetAlt, 2889).
+-define(utils_wxGetKeyState, 2890).
+-define(utils_wxGetMousePosition, 2891).
+-define(utils_wxGetMouseState, 2892).
+-define(utils_wxSetDetectableAutoRepeat, 2893).
+-define(utils_wxBell, 2894).
+-define(utils_wxFindMenuItemId, 2895).
+-define(utils_wxGenericFindWindowAtPoint, 2896).
+-define(utils_wxFindWindowAtPoint, 2897).
+-define(utils_wxBeginBusyCursor, 2898).
+-define(utils_wxEndBusyCursor, 2899).
+-define(utils_wxIsBusy, 2900).
+-define(utils_wxShutdown, 2901).
+-define(utils_wxShell, 2902).
+-define(utils_wxLaunchDefaultBrowser, 2903).
+-define(utils_wxGetEmailAddress, 2904).
+-define(utils_wxGetUserId, 2905).
+-define(utils_wxGetHomeDir, 2906).
+-define(utils_wxNewId, 2907).
+-define(utils_wxRegisterId, 2908).
+-define(utils_wxGetCurrentId, 2909).
+-define(utils_wxGetOsDescription, 2910).
+-define(utils_wxIsPlatformLittleEndian, 2911).
+-define(utils_wxIsPlatform64Bit, 2912).
+-define(wxPrintout_new, 2913).
+-define(wxPrintout_destruct, 2914).
+-define(wxPrintout_GetDC, 2915).
+-define(wxPrintout_GetPageSizeMM, 2916).
+-define(wxPrintout_GetPageSizePixels, 2917).
+-define(wxPrintout_GetPaperRectPixels, 2918).
+-define(wxPrintout_GetPPIPrinter, 2919).
+-define(wxPrintout_GetPPIScreen, 2920).
+-define(wxPrintout_GetTitle, 2921).
+-define(wxPrintout_IsPreview, 2922).
+-define(wxPrintout_FitThisSizeToPaper, 2923).
+-define(wxPrintout_FitThisSizeToPage, 2924).
+-define(wxPrintout_FitThisSizeToPageMargins, 2925).
+-define(wxPrintout_MapScreenSizeToPaper, 2926).
+-define(wxPrintout_MapScreenSizeToPage, 2927).
+-define(wxPrintout_MapScreenSizeToPageMargins, 2928).
+-define(wxPrintout_MapScreenSizeToDevice, 2929).
+-define(wxPrintout_GetLogicalPaperRect, 2930).
+-define(wxPrintout_GetLogicalPageRect, 2931).
+-define(wxPrintout_GetLogicalPageMarginsRect, 2932).
+-define(wxPrintout_SetLogicalOrigin, 2933).
+-define(wxPrintout_OffsetLogicalOrigin, 2934).
+-define(wxStyledTextCtrl_new_2, 2935).
+-define(wxStyledTextCtrl_new_0, 2936).
+-define(wxStyledTextCtrl_destruct, 2937).
+-define(wxStyledTextCtrl_Create, 2938).
+-define(wxStyledTextCtrl_AddText, 2939).
+-define(wxStyledTextCtrl_AddStyledText, 2940).
+-define(wxStyledTextCtrl_InsertText, 2941).
+-define(wxStyledTextCtrl_ClearAll, 2942).
+-define(wxStyledTextCtrl_ClearDocumentStyle, 2943).
+-define(wxStyledTextCtrl_GetLength, 2944).
+-define(wxStyledTextCtrl_GetCharAt, 2945).
+-define(wxStyledTextCtrl_GetCurrentPos, 2946).
+-define(wxStyledTextCtrl_GetAnchor, 2947).
+-define(wxStyledTextCtrl_GetStyleAt, 2948).
+-define(wxStyledTextCtrl_Redo, 2949).
+-define(wxStyledTextCtrl_SetUndoCollection, 2950).
+-define(wxStyledTextCtrl_SelectAll, 2951).
+-define(wxStyledTextCtrl_SetSavePoint, 2952).
+-define(wxStyledTextCtrl_GetStyledText, 2953).
+-define(wxStyledTextCtrl_CanRedo, 2954).
+-define(wxStyledTextCtrl_MarkerLineFromHandle, 2955).
+-define(wxStyledTextCtrl_MarkerDeleteHandle, 2956).
+-define(wxStyledTextCtrl_GetUndoCollection, 2957).
+-define(wxStyledTextCtrl_GetViewWhiteSpace, 2958).
+-define(wxStyledTextCtrl_SetViewWhiteSpace, 2959).
+-define(wxStyledTextCtrl_PositionFromPoint, 2960).
+-define(wxStyledTextCtrl_PositionFromPointClose, 2961).
+-define(wxStyledTextCtrl_GotoLine, 2962).
+-define(wxStyledTextCtrl_GotoPos, 2963).
+-define(wxStyledTextCtrl_SetAnchor, 2964).
+-define(wxStyledTextCtrl_GetCurLine, 2965).
+-define(wxStyledTextCtrl_GetEndStyled, 2966).
+-define(wxStyledTextCtrl_ConvertEOLs, 2967).
+-define(wxStyledTextCtrl_GetEOLMode, 2968).
+-define(wxStyledTextCtrl_SetEOLMode, 2969).
+-define(wxStyledTextCtrl_StartStyling, 2970).
+-define(wxStyledTextCtrl_SetStyling, 2971).
+-define(wxStyledTextCtrl_GetBufferedDraw, 2972).
+-define(wxStyledTextCtrl_SetBufferedDraw, 2973).
+-define(wxStyledTextCtrl_SetTabWidth, 2974).
+-define(wxStyledTextCtrl_GetTabWidth, 2975).
+-define(wxStyledTextCtrl_SetCodePage, 2976).
+-define(wxStyledTextCtrl_MarkerDefine, 2977).
+-define(wxStyledTextCtrl_MarkerSetForeground, 2978).
+-define(wxStyledTextCtrl_MarkerSetBackground, 2979).
+-define(wxStyledTextCtrl_MarkerAdd, 2980).
+-define(wxStyledTextCtrl_MarkerDelete, 2981).
+-define(wxStyledTextCtrl_MarkerDeleteAll, 2982).
+-define(wxStyledTextCtrl_MarkerGet, 2983).
+-define(wxStyledTextCtrl_MarkerNext, 2984).
+-define(wxStyledTextCtrl_MarkerPrevious, 2985).
+-define(wxStyledTextCtrl_MarkerDefineBitmap, 2986).
+-define(wxStyledTextCtrl_MarkerAddSet, 2987).
+-define(wxStyledTextCtrl_MarkerSetAlpha, 2988).
+-define(wxStyledTextCtrl_SetMarginType, 2989).
+-define(wxStyledTextCtrl_GetMarginType, 2990).
+-define(wxStyledTextCtrl_SetMarginWidth, 2991).
+-define(wxStyledTextCtrl_GetMarginWidth, 2992).
+-define(wxStyledTextCtrl_SetMarginMask, 2993).
+-define(wxStyledTextCtrl_GetMarginMask, 2994).
+-define(wxStyledTextCtrl_SetMarginSensitive, 2995).
+-define(wxStyledTextCtrl_GetMarginSensitive, 2996).
+-define(wxStyledTextCtrl_StyleClearAll, 2997).
+-define(wxStyledTextCtrl_StyleSetForeground, 2998).
+-define(wxStyledTextCtrl_StyleSetBackground, 2999).
+-define(wxStyledTextCtrl_StyleSetBold, 3000).
+-define(wxStyledTextCtrl_StyleSetItalic, 3001).
+-define(wxStyledTextCtrl_StyleSetSize, 3002).
+-define(wxStyledTextCtrl_StyleSetFaceName, 3003).
+-define(wxStyledTextCtrl_StyleSetEOLFilled, 3004).
+-define(wxStyledTextCtrl_StyleResetDefault, 3005).
+-define(wxStyledTextCtrl_StyleSetUnderline, 3006).
+-define(wxStyledTextCtrl_StyleSetCase, 3007).
+-define(wxStyledTextCtrl_StyleSetHotSpot, 3008).
+-define(wxStyledTextCtrl_SetSelForeground, 3009).
+-define(wxStyledTextCtrl_SetSelBackground, 3010).
+-define(wxStyledTextCtrl_GetSelAlpha, 3011).
+-define(wxStyledTextCtrl_SetSelAlpha, 3012).
+-define(wxStyledTextCtrl_SetCaretForeground, 3013).
+-define(wxStyledTextCtrl_CmdKeyAssign, 3014).
+-define(wxStyledTextCtrl_CmdKeyClear, 3015).
+-define(wxStyledTextCtrl_CmdKeyClearAll, 3016).
+-define(wxStyledTextCtrl_SetStyleBytes, 3017).
+-define(wxStyledTextCtrl_StyleSetVisible, 3018).
+-define(wxStyledTextCtrl_GetCaretPeriod, 3019).
+-define(wxStyledTextCtrl_SetCaretPeriod, 3020).
+-define(wxStyledTextCtrl_SetWordChars, 3021).
+-define(wxStyledTextCtrl_BeginUndoAction, 3022).
+-define(wxStyledTextCtrl_EndUndoAction, 3023).
+-define(wxStyledTextCtrl_IndicatorSetStyle, 3024).
+-define(wxStyledTextCtrl_IndicatorGetStyle, 3025).
+-define(wxStyledTextCtrl_IndicatorSetForeground, 3026).
+-define(wxStyledTextCtrl_IndicatorGetForeground, 3027).
+-define(wxStyledTextCtrl_SetWhitespaceForeground, 3028).
+-define(wxStyledTextCtrl_SetWhitespaceBackground, 3029).
+-define(wxStyledTextCtrl_GetStyleBits, 3030).
+-define(wxStyledTextCtrl_SetLineState, 3031).
+-define(wxStyledTextCtrl_GetLineState, 3032).
+-define(wxStyledTextCtrl_GetMaxLineState, 3033).
+-define(wxStyledTextCtrl_GetCaretLineVisible, 3034).
+-define(wxStyledTextCtrl_SetCaretLineVisible, 3035).
+-define(wxStyledTextCtrl_GetCaretLineBackground, 3036).
+-define(wxStyledTextCtrl_SetCaretLineBackground, 3037).
+-define(wxStyledTextCtrl_AutoCompShow, 3038).
+-define(wxStyledTextCtrl_AutoCompCancel, 3039).
+-define(wxStyledTextCtrl_AutoCompActive, 3040).
+-define(wxStyledTextCtrl_AutoCompPosStart, 3041).
+-define(wxStyledTextCtrl_AutoCompComplete, 3042).
+-define(wxStyledTextCtrl_AutoCompStops, 3043).
+-define(wxStyledTextCtrl_AutoCompSetSeparator, 3044).
+-define(wxStyledTextCtrl_AutoCompGetSeparator, 3045).
+-define(wxStyledTextCtrl_AutoCompSelect, 3046).
+-define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3047).
+-define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3048).
+-define(wxStyledTextCtrl_AutoCompSetFillUps, 3049).
+-define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3050).
+-define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3051).
+-define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3052).
+-define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3053).
+-define(wxStyledTextCtrl_UserListShow, 3054).
+-define(wxStyledTextCtrl_AutoCompSetAutoHide, 3055).
+-define(wxStyledTextCtrl_AutoCompGetAutoHide, 3056).
+-define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3057).
+-define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3058).
+-define(wxStyledTextCtrl_RegisterImage, 3059).
+-define(wxStyledTextCtrl_ClearRegisteredImages, 3060).
+-define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3061).
+-define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3062).
+-define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3063).
+-define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3064).
+-define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3065).
+-define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3066).
+-define(wxStyledTextCtrl_SetIndent, 3067).
+-define(wxStyledTextCtrl_GetIndent, 3068).
+-define(wxStyledTextCtrl_SetUseTabs, 3069).
+-define(wxStyledTextCtrl_GetUseTabs, 3070).
+-define(wxStyledTextCtrl_SetLineIndentation, 3071).
+-define(wxStyledTextCtrl_GetLineIndentation, 3072).
+-define(wxStyledTextCtrl_GetLineIndentPosition, 3073).
+-define(wxStyledTextCtrl_GetColumn, 3074).
+-define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3075).
+-define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3076).
+-define(wxStyledTextCtrl_SetIndentationGuides, 3077).
+-define(wxStyledTextCtrl_GetIndentationGuides, 3078).
+-define(wxStyledTextCtrl_SetHighlightGuide, 3079).
+-define(wxStyledTextCtrl_GetHighlightGuide, 3080).
+-define(wxStyledTextCtrl_GetLineEndPosition, 3081).
+-define(wxStyledTextCtrl_GetCodePage, 3082).
+-define(wxStyledTextCtrl_GetCaretForeground, 3083).
+-define(wxStyledTextCtrl_GetReadOnly, 3084).
+-define(wxStyledTextCtrl_SetCurrentPos, 3085).
+-define(wxStyledTextCtrl_SetSelectionStart, 3086).
+-define(wxStyledTextCtrl_GetSelectionStart, 3087).
+-define(wxStyledTextCtrl_SetSelectionEnd, 3088).
+-define(wxStyledTextCtrl_GetSelectionEnd, 3089).
+-define(wxStyledTextCtrl_SetPrintMagnification, 3090).
+-define(wxStyledTextCtrl_GetPrintMagnification, 3091).
+-define(wxStyledTextCtrl_SetPrintColourMode, 3092).
+-define(wxStyledTextCtrl_GetPrintColourMode, 3093).
+-define(wxStyledTextCtrl_FindText, 3094).
+-define(wxStyledTextCtrl_FormatRange, 3095).
+-define(wxStyledTextCtrl_GetFirstVisibleLine, 3096).
+-define(wxStyledTextCtrl_GetLine, 3097).
+-define(wxStyledTextCtrl_GetLineCount, 3098).
+-define(wxStyledTextCtrl_SetMarginLeft, 3099).
+-define(wxStyledTextCtrl_GetMarginLeft, 3100).
+-define(wxStyledTextCtrl_SetMarginRight, 3101).
+-define(wxStyledTextCtrl_GetMarginRight, 3102).
+-define(wxStyledTextCtrl_GetModify, 3103).
+-define(wxStyledTextCtrl_SetSelection, 3104).
+-define(wxStyledTextCtrl_GetSelectedText, 3105).
+-define(wxStyledTextCtrl_GetTextRange, 3106).
+-define(wxStyledTextCtrl_HideSelection, 3107).
+-define(wxStyledTextCtrl_LineFromPosition, 3108).
+-define(wxStyledTextCtrl_PositionFromLine, 3109).
+-define(wxStyledTextCtrl_LineScroll, 3110).
+-define(wxStyledTextCtrl_EnsureCaretVisible, 3111).
+-define(wxStyledTextCtrl_ReplaceSelection, 3112).
+-define(wxStyledTextCtrl_SetReadOnly, 3113).
+-define(wxStyledTextCtrl_CanPaste, 3114).
+-define(wxStyledTextCtrl_CanUndo, 3115).
+-define(wxStyledTextCtrl_EmptyUndoBuffer, 3116).
+-define(wxStyledTextCtrl_Undo, 3117).
+-define(wxStyledTextCtrl_Cut, 3118).
+-define(wxStyledTextCtrl_Copy, 3119).
+-define(wxStyledTextCtrl_Paste, 3120).
+-define(wxStyledTextCtrl_Clear, 3121).
+-define(wxStyledTextCtrl_SetText, 3122).
+-define(wxStyledTextCtrl_GetText, 3123).
+-define(wxStyledTextCtrl_GetTextLength, 3124).
+-define(wxStyledTextCtrl_GetOvertype, 3125).
+-define(wxStyledTextCtrl_SetCaretWidth, 3126).
+-define(wxStyledTextCtrl_GetCaretWidth, 3127).
+-define(wxStyledTextCtrl_SetTargetStart, 3128).
+-define(wxStyledTextCtrl_GetTargetStart, 3129).
+-define(wxStyledTextCtrl_SetTargetEnd, 3130).
+-define(wxStyledTextCtrl_GetTargetEnd, 3131).
+-define(wxStyledTextCtrl_ReplaceTarget, 3132).
+-define(wxStyledTextCtrl_SearchInTarget, 3133).
+-define(wxStyledTextCtrl_SetSearchFlags, 3134).
+-define(wxStyledTextCtrl_GetSearchFlags, 3135).
+-define(wxStyledTextCtrl_CallTipShow, 3136).
+-define(wxStyledTextCtrl_CallTipCancel, 3137).
+-define(wxStyledTextCtrl_CallTipActive, 3138).
+-define(wxStyledTextCtrl_CallTipPosAtStart, 3139).
+-define(wxStyledTextCtrl_CallTipSetHighlight, 3140).
+-define(wxStyledTextCtrl_CallTipSetBackground, 3141).
+-define(wxStyledTextCtrl_CallTipSetForeground, 3142).
+-define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3143).
+-define(wxStyledTextCtrl_CallTipUseStyle, 3144).
+-define(wxStyledTextCtrl_VisibleFromDocLine, 3145).
+-define(wxStyledTextCtrl_DocLineFromVisible, 3146).
+-define(wxStyledTextCtrl_WrapCount, 3147).
+-define(wxStyledTextCtrl_SetFoldLevel, 3148).
+-define(wxStyledTextCtrl_GetFoldLevel, 3149).
+-define(wxStyledTextCtrl_GetLastChild, 3150).
+-define(wxStyledTextCtrl_GetFoldParent, 3151).
+-define(wxStyledTextCtrl_ShowLines, 3152).
+-define(wxStyledTextCtrl_HideLines, 3153).
+-define(wxStyledTextCtrl_GetLineVisible, 3154).
+-define(wxStyledTextCtrl_SetFoldExpanded, 3155).
+-define(wxStyledTextCtrl_GetFoldExpanded, 3156).
+-define(wxStyledTextCtrl_ToggleFold, 3157).
+-define(wxStyledTextCtrl_EnsureVisible, 3158).
+-define(wxStyledTextCtrl_SetFoldFlags, 3159).
+-define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3160).
+-define(wxStyledTextCtrl_SetTabIndents, 3161).
+-define(wxStyledTextCtrl_GetTabIndents, 3162).
+-define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3163).
+-define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3164).
+-define(wxStyledTextCtrl_SetMouseDwellTime, 3165).
+-define(wxStyledTextCtrl_GetMouseDwellTime, 3166).
+-define(wxStyledTextCtrl_WordStartPosition, 3167).
+-define(wxStyledTextCtrl_WordEndPosition, 3168).
+-define(wxStyledTextCtrl_SetWrapMode, 3169).
+-define(wxStyledTextCtrl_GetWrapMode, 3170).
+-define(wxStyledTextCtrl_SetWrapVisualFlags, 3171).
+-define(wxStyledTextCtrl_GetWrapVisualFlags, 3172).
+-define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3173).
+-define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3174).
+-define(wxStyledTextCtrl_SetWrapStartIndent, 3175).
+-define(wxStyledTextCtrl_GetWrapStartIndent, 3176).
+-define(wxStyledTextCtrl_SetLayoutCache, 3177).
+-define(wxStyledTextCtrl_GetLayoutCache, 3178).
+-define(wxStyledTextCtrl_SetScrollWidth, 3179).
+-define(wxStyledTextCtrl_GetScrollWidth, 3180).
+-define(wxStyledTextCtrl_TextWidth, 3181).
+-define(wxStyledTextCtrl_GetEndAtLastLine, 3182).
+-define(wxStyledTextCtrl_TextHeight, 3183).
+-define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3184).
+-define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3185).
+-define(wxStyledTextCtrl_AppendText, 3186).
+-define(wxStyledTextCtrl_GetTwoPhaseDraw, 3187).
+-define(wxStyledTextCtrl_SetTwoPhaseDraw, 3188).
+-define(wxStyledTextCtrl_TargetFromSelection, 3189).
+-define(wxStyledTextCtrl_LinesJoin, 3190).
+-define(wxStyledTextCtrl_LinesSplit, 3191).
+-define(wxStyledTextCtrl_SetFoldMarginColour, 3192).
+-define(wxStyledTextCtrl_SetFoldMarginHiColour, 3193).
+-define(wxStyledTextCtrl_LineDown, 3194).
+-define(wxStyledTextCtrl_LineDownExtend, 3195).
+-define(wxStyledTextCtrl_LineUp, 3196).
+-define(wxStyledTextCtrl_LineUpExtend, 3197).
+-define(wxStyledTextCtrl_CharLeft, 3198).
+-define(wxStyledTextCtrl_CharLeftExtend, 3199).
+-define(wxStyledTextCtrl_CharRight, 3200).
+-define(wxStyledTextCtrl_CharRightExtend, 3201).
+-define(wxStyledTextCtrl_WordLeft, 3202).
+-define(wxStyledTextCtrl_WordLeftExtend, 3203).
+-define(wxStyledTextCtrl_WordRight, 3204).
+-define(wxStyledTextCtrl_WordRightExtend, 3205).
+-define(wxStyledTextCtrl_Home, 3206).
+-define(wxStyledTextCtrl_HomeExtend, 3207).
+-define(wxStyledTextCtrl_LineEnd, 3208).
+-define(wxStyledTextCtrl_LineEndExtend, 3209).
+-define(wxStyledTextCtrl_DocumentStart, 3210).
+-define(wxStyledTextCtrl_DocumentStartExtend, 3211).
+-define(wxStyledTextCtrl_DocumentEnd, 3212).
+-define(wxStyledTextCtrl_DocumentEndExtend, 3213).
+-define(wxStyledTextCtrl_PageUp, 3214).
+-define(wxStyledTextCtrl_PageUpExtend, 3215).
+-define(wxStyledTextCtrl_PageDown, 3216).
+-define(wxStyledTextCtrl_PageDownExtend, 3217).
+-define(wxStyledTextCtrl_EditToggleOvertype, 3218).
+-define(wxStyledTextCtrl_Cancel, 3219).
+-define(wxStyledTextCtrl_DeleteBack, 3220).
+-define(wxStyledTextCtrl_Tab, 3221).
+-define(wxStyledTextCtrl_BackTab, 3222).
+-define(wxStyledTextCtrl_NewLine, 3223).
+-define(wxStyledTextCtrl_FormFeed, 3224).
+-define(wxStyledTextCtrl_VCHome, 3225).
+-define(wxStyledTextCtrl_VCHomeExtend, 3226).
+-define(wxStyledTextCtrl_ZoomIn, 3227).
+-define(wxStyledTextCtrl_ZoomOut, 3228).
+-define(wxStyledTextCtrl_DelWordLeft, 3229).
+-define(wxStyledTextCtrl_DelWordRight, 3230).
+-define(wxStyledTextCtrl_LineCut, 3231).
+-define(wxStyledTextCtrl_LineDelete, 3232).
+-define(wxStyledTextCtrl_LineTranspose, 3233).
+-define(wxStyledTextCtrl_LineDuplicate, 3234).
+-define(wxStyledTextCtrl_LowerCase, 3235).
+-define(wxStyledTextCtrl_UpperCase, 3236).
+-define(wxStyledTextCtrl_LineScrollDown, 3237).
+-define(wxStyledTextCtrl_LineScrollUp, 3238).
+-define(wxStyledTextCtrl_DeleteBackNotLine, 3239).
+-define(wxStyledTextCtrl_HomeDisplay, 3240).
+-define(wxStyledTextCtrl_HomeDisplayExtend, 3241).
+-define(wxStyledTextCtrl_LineEndDisplay, 3242).
+-define(wxStyledTextCtrl_LineEndDisplayExtend, 3243).
+-define(wxStyledTextCtrl_HomeWrapExtend, 3244).
+-define(wxStyledTextCtrl_LineEndWrap, 3245).
+-define(wxStyledTextCtrl_LineEndWrapExtend, 3246).
+-define(wxStyledTextCtrl_VCHomeWrap, 3247).
+-define(wxStyledTextCtrl_VCHomeWrapExtend, 3248).
+-define(wxStyledTextCtrl_LineCopy, 3249).
+-define(wxStyledTextCtrl_MoveCaretInsideView, 3250).
+-define(wxStyledTextCtrl_LineLength, 3251).
+-define(wxStyledTextCtrl_BraceHighlight, 3252).
+-define(wxStyledTextCtrl_BraceBadLight, 3253).
+-define(wxStyledTextCtrl_BraceMatch, 3254).
+-define(wxStyledTextCtrl_GetViewEOL, 3255).
+-define(wxStyledTextCtrl_SetViewEOL, 3256).
+-define(wxStyledTextCtrl_SetModEventMask, 3257).
+-define(wxStyledTextCtrl_GetEdgeColumn, 3258).
+-define(wxStyledTextCtrl_SetEdgeColumn, 3259).
+-define(wxStyledTextCtrl_GetEdgeMode, 3260).
+-define(wxStyledTextCtrl_GetEdgeColour, 3261).
+-define(wxStyledTextCtrl_SetEdgeColour, 3262).
+-define(wxStyledTextCtrl_SearchAnchor, 3263).
+-define(wxStyledTextCtrl_SearchNext, 3264).
+-define(wxStyledTextCtrl_SearchPrev, 3265).
+-define(wxStyledTextCtrl_LinesOnScreen, 3266).
+-define(wxStyledTextCtrl_UsePopUp, 3267).
+-define(wxStyledTextCtrl_SelectionIsRectangle, 3268).
+-define(wxStyledTextCtrl_SetZoom, 3269).
+-define(wxStyledTextCtrl_GetZoom, 3270).
+-define(wxStyledTextCtrl_GetModEventMask, 3271).
+-define(wxStyledTextCtrl_SetSTCFocus, 3272).
+-define(wxStyledTextCtrl_GetSTCFocus, 3273).
+-define(wxStyledTextCtrl_SetStatus, 3274).
+-define(wxStyledTextCtrl_GetStatus, 3275).
+-define(wxStyledTextCtrl_SetMouseDownCaptures, 3276).
+-define(wxStyledTextCtrl_GetMouseDownCaptures, 3277).
+-define(wxStyledTextCtrl_SetSTCCursor, 3278).
+-define(wxStyledTextCtrl_GetSTCCursor, 3279).
+-define(wxStyledTextCtrl_SetControlCharSymbol, 3280).
+-define(wxStyledTextCtrl_GetControlCharSymbol, 3281).
+-define(wxStyledTextCtrl_WordPartLeft, 3282).
+-define(wxStyledTextCtrl_WordPartLeftExtend, 3283).
+-define(wxStyledTextCtrl_WordPartRight, 3284).
+-define(wxStyledTextCtrl_WordPartRightExtend, 3285).
+-define(wxStyledTextCtrl_SetVisiblePolicy, 3286).
+-define(wxStyledTextCtrl_DelLineLeft, 3287).
+-define(wxStyledTextCtrl_DelLineRight, 3288).
+-define(wxStyledTextCtrl_GetXOffset, 3289).
+-define(wxStyledTextCtrl_ChooseCaretX, 3290).
+-define(wxStyledTextCtrl_SetXCaretPolicy, 3291).
+-define(wxStyledTextCtrl_SetYCaretPolicy, 3292).
+-define(wxStyledTextCtrl_GetPrintWrapMode, 3293).
+-define(wxStyledTextCtrl_SetHotspotActiveForeground, 3294).
+-define(wxStyledTextCtrl_SetHotspotActiveBackground, 3295).
+-define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3296).
+-define(wxStyledTextCtrl_SetHotspotSingleLine, 3297).
+-define(wxStyledTextCtrl_ParaDownExtend, 3298).
+-define(wxStyledTextCtrl_ParaUp, 3299).
+-define(wxStyledTextCtrl_ParaUpExtend, 3300).
+-define(wxStyledTextCtrl_PositionBefore, 3301).
+-define(wxStyledTextCtrl_PositionAfter, 3302).
+-define(wxStyledTextCtrl_CopyRange, 3303).
+-define(wxStyledTextCtrl_CopyText, 3304).
+-define(wxStyledTextCtrl_SetSelectionMode, 3305).
+-define(wxStyledTextCtrl_GetSelectionMode, 3306).
+-define(wxStyledTextCtrl_LineDownRectExtend, 3307).
+-define(wxStyledTextCtrl_LineUpRectExtend, 3308).
+-define(wxStyledTextCtrl_CharLeftRectExtend, 3309).
+-define(wxStyledTextCtrl_CharRightRectExtend, 3310).
+-define(wxStyledTextCtrl_HomeRectExtend, 3311).
+-define(wxStyledTextCtrl_VCHomeRectExtend, 3312).
+-define(wxStyledTextCtrl_LineEndRectExtend, 3313).
+-define(wxStyledTextCtrl_PageUpRectExtend, 3314).
+-define(wxStyledTextCtrl_PageDownRectExtend, 3315).
+-define(wxStyledTextCtrl_StutteredPageUp, 3316).
+-define(wxStyledTextCtrl_StutteredPageUpExtend, 3317).
+-define(wxStyledTextCtrl_StutteredPageDown, 3318).
+-define(wxStyledTextCtrl_StutteredPageDownExtend, 3319).
+-define(wxStyledTextCtrl_WordLeftEnd, 3320).
+-define(wxStyledTextCtrl_WordLeftEndExtend, 3321).
+-define(wxStyledTextCtrl_WordRightEnd, 3322).
+-define(wxStyledTextCtrl_WordRightEndExtend, 3323).
+-define(wxStyledTextCtrl_SetWhitespaceChars, 3324).
+-define(wxStyledTextCtrl_SetCharsDefault, 3325).
+-define(wxStyledTextCtrl_AutoCompGetCurrent, 3326).
+-define(wxStyledTextCtrl_Allocate, 3327).
+-define(wxStyledTextCtrl_FindColumn, 3328).
+-define(wxStyledTextCtrl_GetCaretSticky, 3329).
+-define(wxStyledTextCtrl_SetCaretSticky, 3330).
+-define(wxStyledTextCtrl_ToggleCaretSticky, 3331).
+-define(wxStyledTextCtrl_SetPasteConvertEndings, 3332).
+-define(wxStyledTextCtrl_GetPasteConvertEndings, 3333).
+-define(wxStyledTextCtrl_SelectionDuplicate, 3334).
+-define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3335).
+-define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3336).
+-define(wxStyledTextCtrl_StartRecord, 3337).
+-define(wxStyledTextCtrl_StopRecord, 3338).
+-define(wxStyledTextCtrl_SetLexer, 3339).
+-define(wxStyledTextCtrl_GetLexer, 3340).
+-define(wxStyledTextCtrl_Colourise, 3341).
+-define(wxStyledTextCtrl_SetProperty, 3342).
+-define(wxStyledTextCtrl_SetKeyWords, 3343).
+-define(wxStyledTextCtrl_SetLexerLanguage, 3344).
+-define(wxStyledTextCtrl_GetProperty, 3345).
+-define(wxStyledTextCtrl_GetStyleBitsNeeded, 3346).
+-define(wxStyledTextCtrl_GetCurrentLine, 3347).
+-define(wxStyledTextCtrl_StyleSetSpec, 3348).
+-define(wxStyledTextCtrl_StyleSetFont, 3349).
+-define(wxStyledTextCtrl_StyleSetFontAttr, 3350).
+-define(wxStyledTextCtrl_StyleSetCharacterSet, 3351).
+-define(wxStyledTextCtrl_StyleSetFontEncoding, 3352).
+-define(wxStyledTextCtrl_CmdKeyExecute, 3353).
+-define(wxStyledTextCtrl_SetMargins, 3354).
+-define(wxStyledTextCtrl_GetSelection, 3355).
+-define(wxStyledTextCtrl_PointFromPosition, 3356).
+-define(wxStyledTextCtrl_ScrollToLine, 3357).
+-define(wxStyledTextCtrl_ScrollToColumn, 3358).
+-define(wxStyledTextCtrl_SendMsg, 3359).
+-define(wxStyledTextCtrl_SetVScrollBar, 3360).
+-define(wxStyledTextCtrl_SetHScrollBar, 3361).
+-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3362).
+-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3363).
+-define(wxStyledTextCtrl_SaveFile, 3364).
+-define(wxStyledTextCtrl_LoadFile, 3365).
+-define(wxStyledTextCtrl_DoDragOver, 3366).
+-define(wxStyledTextCtrl_DoDropText, 3367).
+-define(wxStyledTextCtrl_GetUseAntiAliasing, 3368).
+-define(wxStyledTextCtrl_AddTextRaw, 3369).
+-define(wxStyledTextCtrl_InsertTextRaw, 3370).
+-define(wxStyledTextCtrl_GetCurLineRaw, 3371).
+-define(wxStyledTextCtrl_GetLineRaw, 3372).
+-define(wxStyledTextCtrl_GetSelectedTextRaw, 3373).
+-define(wxStyledTextCtrl_GetTextRangeRaw, 3374).
+-define(wxStyledTextCtrl_SetTextRaw, 3375).
+-define(wxStyledTextCtrl_GetTextRaw, 3376).
+-define(wxStyledTextCtrl_AppendTextRaw, 3377).
+-define(wxArtProvider_GetBitmap, 3378).
+-define(wxArtProvider_GetIcon, 3379).
+-define(wxTreeEvent_GetKeyCode, 3380).
+-define(wxTreeEvent_GetItem, 3381).
+-define(wxTreeEvent_GetKeyEvent, 3382).
+-define(wxTreeEvent_GetLabel, 3383).
+-define(wxTreeEvent_GetOldItem, 3384).
+-define(wxTreeEvent_GetPoint, 3385).
+-define(wxTreeEvent_IsEditCancelled, 3386).
+-define(wxTreeEvent_SetToolTip, 3387).
+-define(wxNotebookEvent_GetOldSelection, 3388).
+-define(wxNotebookEvent_GetSelection, 3389).
+-define(wxNotebookEvent_SetOldSelection, 3390).
+-define(wxNotebookEvent_SetSelection, 3391).
+-define(wxFileDataObject_new, 3392).
+-define(wxFileDataObject_AddFile, 3393).
+-define(wxFileDataObject_GetFilenames, 3394).
+-define(wxFileDataObject_destroy, 3395).
+-define(wxTextDataObject_new, 3396).
+-define(wxTextDataObject_GetTextLength, 3397).
+-define(wxTextDataObject_GetText, 3398).
+-define(wxTextDataObject_SetText, 3399).
+-define(wxTextDataObject_destroy, 3400).
+-define(wxBitmapDataObject_new_1_1, 3401).
+-define(wxBitmapDataObject_new_1_0, 3402).
+-define(wxBitmapDataObject_GetBitmap, 3403).
+-define(wxBitmapDataObject_SetBitmap, 3404).
+-define(wxBitmapDataObject_destroy, 3405).
+-define(wxClipboard_new, 3407).
+-define(wxClipboard_destruct, 3408).
+-define(wxClipboard_AddData, 3409).
+-define(wxClipboard_Clear, 3410).
+-define(wxClipboard_Close, 3411).
+-define(wxClipboard_Flush, 3412).
+-define(wxClipboard_GetData, 3413).
+-define(wxClipboard_IsOpened, 3414).
+-define(wxClipboard_Open, 3415).
+-define(wxClipboard_SetData, 3416).
+-define(wxClipboard_UsePrimarySelection, 3418).
+-define(wxClipboard_IsSupported, 3419).
+-define(wxClipboard_Get, 3420).
+-define(wxSpinEvent_GetPosition, 3421).
+-define(wxSpinEvent_SetPosition, 3422).
+-define(wxSplitterWindow_new_0, 3423).
+-define(wxSplitterWindow_new_2, 3424).
+-define(wxSplitterWindow_destruct, 3425).
+-define(wxSplitterWindow_Create, 3426).
+-define(wxSplitterWindow_GetMinimumPaneSize, 3427).
+-define(wxSplitterWindow_GetSashGravity, 3428).
+-define(wxSplitterWindow_GetSashPosition, 3429).
+-define(wxSplitterWindow_GetSplitMode, 3430).
+-define(wxSplitterWindow_GetWindow1, 3431).
+-define(wxSplitterWindow_GetWindow2, 3432).
+-define(wxSplitterWindow_Initialize, 3433).
+-define(wxSplitterWindow_IsSplit, 3434).
+-define(wxSplitterWindow_ReplaceWindow, 3435).
+-define(wxSplitterWindow_SetSashGravity, 3436).
+-define(wxSplitterWindow_SetSashPosition, 3437).
+-define(wxSplitterWindow_SetSashSize, 3438).
+-define(wxSplitterWindow_SetMinimumPaneSize, 3439).
+-define(wxSplitterWindow_SetSplitMode, 3440).
+-define(wxSplitterWindow_SplitHorizontally, 3441).
+-define(wxSplitterWindow_SplitVertically, 3442).
+-define(wxSplitterWindow_Unsplit, 3443).
+-define(wxSplitterWindow_UpdateSize, 3444).
+-define(wxSplitterEvent_GetSashPosition, 3445).
+-define(wxSplitterEvent_GetX, 3446).
+-define(wxSplitterEvent_GetY, 3447).
+-define(wxSplitterEvent_GetWindowBeingRemoved, 3448).
+-define(wxSplitterEvent_SetSashPosition, 3449).
+-define(wxHtmlWindow_new_0, 3450).
+-define(wxHtmlWindow_new_2, 3451).
+-define(wxHtmlWindow_AppendToPage, 3452).
+-define(wxHtmlWindow_GetOpenedAnchor, 3453).
+-define(wxHtmlWindow_GetOpenedPage, 3454).
+-define(wxHtmlWindow_GetOpenedPageTitle, 3455).
+-define(wxHtmlWindow_GetRelatedFrame, 3456).
+-define(wxHtmlWindow_HistoryBack, 3457).
+-define(wxHtmlWindow_HistoryCanBack, 3458).
+-define(wxHtmlWindow_HistoryCanForward, 3459).
+-define(wxHtmlWindow_HistoryClear, 3460).
+-define(wxHtmlWindow_HistoryForward, 3461).
+-define(wxHtmlWindow_LoadFile, 3462).
+-define(wxHtmlWindow_LoadPage, 3463).
+-define(wxHtmlWindow_SelectAll, 3464).
+-define(wxHtmlWindow_SelectionToText, 3465).
+-define(wxHtmlWindow_SelectLine, 3466).
+-define(wxHtmlWindow_SelectWord, 3467).
+-define(wxHtmlWindow_SetBorders, 3468).
+-define(wxHtmlWindow_SetFonts, 3469).
+-define(wxHtmlWindow_SetPage, 3470).
+-define(wxHtmlWindow_SetRelatedFrame, 3471).
+-define(wxHtmlWindow_SetRelatedStatusBar, 3472).
+-define(wxHtmlWindow_ToText, 3473).
+-define(wxHtmlWindow_destroy, 3474).
+-define(wxHtmlLinkEvent_GetLinkInfo, 3475).
+-define(wxSystemSettings_GetColour, 3476).
+-define(wxSystemSettings_GetFont, 3477).
+-define(wxSystemSettings_GetMetric, 3478).
+-define(wxSystemSettings_GetScreenType, 3479).
+-define(wxAuiNotebookEvent_SetSelection, 3480).
+-define(wxAuiNotebookEvent_GetSelection, 3481).
+-define(wxAuiNotebookEvent_SetOldSelection, 3482).
+-define(wxAuiNotebookEvent_GetOldSelection, 3483).
+-define(wxAuiNotebookEvent_SetDragSource, 3484).
+-define(wxAuiNotebookEvent_GetDragSource, 3485).
+-define(wxAuiManagerEvent_SetManager, 3486).
+-define(wxAuiManagerEvent_GetManager, 3487).
+-define(wxAuiManagerEvent_SetPane, 3488).
+-define(wxAuiManagerEvent_GetPane, 3489).
+-define(wxAuiManagerEvent_SetButton, 3490).
+-define(wxAuiManagerEvent_GetButton, 3491).
+-define(wxAuiManagerEvent_SetDC, 3492).
+-define(wxAuiManagerEvent_GetDC, 3493).
+-define(wxAuiManagerEvent_Veto, 3494).
+-define(wxAuiManagerEvent_GetVeto, 3495).
+-define(wxAuiManagerEvent_SetCanVeto, 3496).
+-define(wxAuiManagerEvent_CanVeto, 3497).
+-define(wxLogNull_new, 3498).
+-define(wxLogNull_destroy, 3499).
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 76df6e4a23..6f43247d74 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -137,6 +137,9 @@ treeCtrl(Config) ->
wxFrame:connect(Tree, command_tree_item_expanded),
wxFrame:connect(Tree, command_tree_item_collapsed),
wxFrame:connect(Frame, close_window),
+
+ wxTreeCtrl:editLabel(Tree, Root),
+
wx_test_lib:wx_destroy(Frame,Config).
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 4ed22d2256..c3ad3920a4 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1,9 +1 @@
WX_VSN = 0.98.6
-
-TICKETS = OTP-8656
-
-TICKETS_0.98.5 = OTP-8330 OTP-8461 OTP-8408 OTP-8455 OTP-8462
-TICKETS_0.98.4 = OTP-8243 OTP-8250 OTP-8292
-TICKETS_0.98.3 = OTP-8138 OTP-8126 OTP-8083
-TICKETS_0.98.2 = OTP-7943
-TICKETS_0.98.1 = OTP-7875 \ No newline at end of file
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index aee7546c3c..2239604b59 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -18,113 +18,3 @@
#
XMERL_VSN = 1.2.5
-
-
-TICKETS = \
- OTP-8537 \
- OTP-8599
-
-TICKETS_1.2.5 = \
- OTP-8537
-
-TICKETS_1.2.4 = \
- OTP-8343
-
-TICKETS_1.2.3 = \
- OTP-8251 \
- OTP-8252 \
- OTP-8253
-
-TICKETS_1.2.2 = \
- OTP-8213 \
- OTP-8214
-
-TICKETS_1.2.1 = \
- OTP-8084 \
- OTP-8153 \
- OTP-8156
-
-TICKETS_1.2 = \
- OTP-6635
-
-TICKETS_1.1.12 = \
- OTP-7847
-
-TICKETS_1.1.11 = \
- OTP-7736
-
-TICKETS_1.1.10 = \
- OTP-6053 \
- OTP-6873 \
- OTP-7430 \
- OTP-7473 \
- OTP-7496
-
-TICKETS_1.1.9 = \
- OTP-5998 \
- OTP-6947 \
- OTP-7288
-
-TICKETS_1.1.8 = \
- OTP-7211 \
- OTP-7214
-
-TICKETS_1.1.7 = \
- OTP-7190
-
-TICKETS_1.1.6 = \
- OTP-6773 \
- OTP-6777 \
- OTP-6877 \
- OTP-6910
-
-TICKETS_1.1.5 = \
- OTP-6720 \
- OTP-6739 \
- OTP-6752
-
-TICKETS_1.1.4 = \
- OTP-6679
-
-TICKETS_1.1.3 = \
- OTP-6599
-
-TICKETS_1.1.2 = \
- OTP-6507 \
- OTP-6460
-
-TICKETS_1.1.1 = \
- OTP-6402
-
-TICKETS_1.1 = \
- OTP-6043 \
- OTP-6099 \
- OTP-6401
-
-TICKETS_1.0.5 = \
-
-
-TICKETS_1.0.4 = \
- OTP-5599 \
- OTP-5718 \
- OTP-5734 \
- OTP-5895 \
- OTP-5902 \
- OTP-5905
-
-TICKETS_1.0.3 = \
- OTP-5587
-
-TICKETS_1.0.2 = \
- OTP-5498 \
- OTP-5500 \
- OTP-5531
-
-TICKETS_1.0.1 = \
- OTP-5268 \
- OTP-5301 \
- OTP-5407
-
-TICKETS_1.0 = \
- OTP-5174 \
-
diff --git a/make/otp.mk.in b/make/otp.mk.in
index 9f0486a609..6ae7c5b456 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -25,6 +25,11 @@
.3 .1 .fig .dvi .tex .class .java .pdf .fo .psframe .pscrop .el .elc
# ----------------------------------------------------
+# Cross Compiling
+# ----------------------------------------------------
+CROSS_COMPILING = @CROSS_COMPILING@
+
+# ----------------------------------------------------
# Common macros
# ----------------------------------------------------
DEFAULT_TARGETS = opt debug release release_docs clean docs
diff --git a/otp_build b/otp_build
index 1744351f8b..41bce4ec42 100755
--- a/otp_build
+++ b/otp_build
@@ -21,9 +21,6 @@
# Expected autoconf version
EXPECTED_AUTOCONF_VERSION=2.59
-# clearmake command to use
-clearmake=false
-
# Global configuration variables
#
# NOTE: lazy_configure depends on '.' always being last directory
@@ -77,14 +74,6 @@ usage ()
case $version_controller in
none)
;;
- clearcase)
- echo ""
- echo "Handle the primary bootstrap in Clearcase:"
- echo " prepare_primary - prepare for building a primary bootstrap"
- echo " update_primary - create the primary bootstrap"
- echo " commit_primary - commit a primary bootstrap"
- echo " cancel_primary - uncheckout a primary bootstrap"
- ;;
git)
echo ""
echo "update_primary - build and commit a new primary bootstrap"
@@ -94,14 +83,6 @@ usage ()
case $version_controller in
none)
;;
- clearcase)
- echo ""
- echo "Handle the preloaded modules in Clearcase:"
- echo " prepare_preloaded - prepares for building preloaded code"
- echo " update_preloaded - creates the preloaded code"
- echo " commit_preloaded - commits the preloaded code"
- echo " cancel_preloaded - uncheckout preloaded code"
- ;;
git)
echo ""
echo "update_preloaded - build and commit the preloaded modules"
@@ -109,6 +90,12 @@ usage ()
esac
}
+git_required ()
+{
+ echo "This operation must be run in a git repository."
+ exit 1
+}
+
hide_vars ()
{
script=
@@ -164,17 +151,11 @@ determine_version_controller ()
{
version_controller=none
- # The current directory is now $ERL_TOP. Check for
- # either this directory being controlled by git or
- # for the "otp_build" file being a Clearcase controlled
- # object.
+ # The current directory is now $ERL_TOP. Find out whether
+ # this directory is a git repository.
if { git rev-parse --git-dir; } 2>/dev/null >/dev/null; then
version_controller=git
- else
- if test -d "otp_build@@/"; then
- version_controller=clearcase
- fi
fi
}
# Execution of the different options
@@ -875,47 +856,16 @@ setup_make ()
win32)
MAKE=make;;
*)
- if [ "X$CLEARCASE_MAKE_COMPAT" = "Xgnu" -a \
- X"$CLEARCASE_ROOT" != X"" -a \
- -n "`lookup_prog_in_path clearmake`" ]; then
- clearmake="clearmake -V"
- MAKE=$clearmake
- else
- if [ -n "`lookup_prog_in_path gmake`" ]; then
- MAKE=gmake
- else
- MAKE=make
- fi
+ if [ -n "`lookup_prog_in_path gmake`" ]; then
+ MAKE=gmake
+ else
+ MAKE=make
fi;;
esac
fi
export MAKE
}
-do_noboot_lib_and_erts ()
-{
- setup_make
- EMULATORS=emulator
- if [ X`$MAKE is_cross_configured` = Xyes ]; then
- TARGET=`$MAKE target_configured`
- fi
- if [ "x$MAKE" != "x$clearmake" ]; then
- $MAKE MAKE="$MAKE" TARGET=$TARGET OTP_SMALL_BUILD=$OTP_SMALL_BUILD depend || exit 1;
- fi
- $MAKE MAKE="$MAKE" TARGET=$TARGET OTP_SMALL_BUILD=$OTP_SMALL_BUILD TYPE=$TYPE FLAVOR=$FLAVOR noboot || exit 1
-}
-
-do_primary ()
-{
- setup_make
- if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
- echo "OVERRIDE_TARGET set" >&2
- exit 1
- else
- $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET primary_bootstrap || exit 1;
- fi
-}
-
do_primary_git ()
{
setup_make
@@ -932,124 +882,6 @@ do_primary_git ()
git commit --no-verify -m 'Update primary bootstrap'
}
-
-do_prepare ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of primary bootstrap, you need to run in a clearcase view." >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
-
- $CT ls -rec -view_only $ERL_TOP/bootstrap | xargs rm -rf
-
- $CT find $ERL_TOP/bootstrap -cview -nxname -print | xargs $CT co -nc
- echo '*****************************************************'
- echo "Prepared for new bootstrap build - "
- echo "directory bootstrap clean and completely checked out."
- echo '*****************************************************'
-}
-
-do_commit ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of primary bootstrap, you need to run in a clearcase view." >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
-
-
- for x in compiler kernel stdlib orber/include; do
- files=`$CT lspriv -do $ERL_TOP/bootstrap/lib/$x`
- for y in $files; do
- echo "Creating $y"
- $CT mkelem -nc $y
- done
- done
- $CT lsco -rec -me -cview -s $ERL_TOP/bootstrap | xargs $CT ci -nc -ident
- $CT lsco -d -me -cview -s $ERL_TOP/bootstrap | xargs $CT ci -nc -ident
-
- $CT ls -rec -view_only -nxname $ERL_TOP/bootstrap | xargs rm -rf
-
-
- echo '*****************************************************'
- echo "Checked in primary bootstrap."
- echo '*****************************************************'
-}
-
-do_cancel ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of primary bootstrap, you need to run in a clearcase view." >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
- NOTEMPTY=`$CT lsco -rec -me -cview -s $ERL_TOP/bootstrap`
- if [ X"$NOTEMPTY" != X"" ]; then
- $CT lsco -rec -me -cview -s $ERL_TOP/bootstrap | xargs $CT unco -rm
- $CT unco $ERL_TOP/bootstrap
- fi
- $CT ls -rec -view_only $ERL_TOP/bootstrap | xargs rm -rf
- echo '*****************************************************'
- echo "Cancelled all checkouts for primary bootstrap."
- echo '*****************************************************'
-
-}
-do_prepare_prel ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of preloaded code, you have to run in a Clearcase view" >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
-
- setup_make
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET prepare) || exit 1
- echo '*****************************************************'
- echo "Prepared for new preloaded code build - "
- echo "Directory ERL_TOP/erts/preloaded/ebin completely"
- echo "checked out."
- echo '*****************************************************'
-}
-
-do_update_prel ()
-{
- CT=`lookup_prog_in_path cleartool`
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
-
- setup_make
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET clean)
- $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET preloaded || exit 1
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET copy)
- echo '*****************************************************'
- echo "Rebuilt preloaded code."
- echo '*****************************************************'
-}
-
do_update_prel_git ()
{
setup_make
@@ -1060,48 +892,6 @@ do_update_prel_git ()
git commit -m 'Update preloaded modules'
}
-do_commit_prel ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of primary bootstrap, you need to run in a clearcase view." >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
- setup_make
-
- (cd $ERL_TOP/erts/preloaded/ebin && $CT ci -ident -nc *.beam)
- (cd $ERL_TOP/erts/preloaded && $CT ci -ident -nc ebin)
-
- echo '*****************************************************'
- echo "Checked in preloaded code."
- echo '*****************************************************'
-}
-
-do_cancel_prel ()
-{
- CT=`lookup_prog_in_path cleartool`
- if [ X"$CLEARCASE_ROOT" = X"" -o X"$CT" = X"" ]; then
- echo "To prepare for update of primary bootstrap, you need to run in a clearcase view." >&2
- return
- fi
-
- if [ X"$ERL_TOP" = X"" ]; then
- echo "ERL_TOP is not set." >&2
- return
- fi
- setup_make
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET cancel) || exit 1
- echo '*****************************************************'
- echo "Cancelled all checkouts for preloaded code."
- echo '*****************************************************'
-
-}
-
do_boot ()
{
setup_make
@@ -1376,30 +1166,16 @@ case "$1" in
FLAVOR=plain
fi
do_boot;;
- prepare_primary)
- do_prepare;;
update_primary)
case $version_controller in
git) do_primary_git ;;
- clearcase) do_primary ;;
- none) do_primary ;;
+ none) git_required ;;
esac ;;
- commit_primary)
- do_commit;;
- cancel_primary)
- do_cancel;;
- prepare_preloaded)
- do_prepare_prel;;
update_preloaded)
case $version_controller in
git) do_update_prel_git ;;
- clearcase) do_update_prel ;;
- none) do_update_prel ;;
+ none) git_required ;;
esac ;;
- commit_preloaded)
- do_commit_prel;;
- cancel_preloaded)
- do_cancel_prel;;
primary)
echo "Primary bootstrap is under version control since R13";
echo "Use {prepare,update,commit}_primary if you really are";
diff --git a/prebuild.delete b/prebuild.delete
index 901480a63d..b1b18adbcb 100644
--- a/prebuild.delete
+++ b/prebuild.delete
@@ -1 +1,2 @@
bootstrap/lib
+bootstrap/target
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index a3660713e4..52dc0c943e 100755
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -96,7 +96,7 @@ Type :: any() %% The top type, the set of all Erlang terms.
| none() %% The bottom type, contains no terms.
| pid()
| port()
- | ref()
+ | reference()
| [] %% nil
| Atom
| Binary