aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el9
-rw-r--r--.travis.yml7
-rw-r--r--CONTRIBUTING.md98
-rw-r--r--OTP_VERSION2
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bsm.beambin12632 -> 12600 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin39112 -> 39452 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin52472 -> 52532 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app2
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin14076 -> 17420 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin20460 -> 20488 bytes
-rw-r--r--erts/configure.in17
-rw-r--r--erts/doc/src/erl.xml28
-rw-r--r--erts/doc/src/erlang.xml8
-rw-r--r--erts/doc/src/notes.xml173
-rw-r--r--erts/emulator/Makefile.in7
-rw-r--r--erts/emulator/beam/atom.c4
-rw-r--r--erts/emulator/beam/atom.h4
-rw-r--r--erts/emulator/beam/beam_bif_load.c38
-rw-r--r--erts/emulator/beam/beam_bp.c58
-rw-r--r--erts/emulator/beam/beam_bp.h6
-rw-r--r--erts/emulator/beam/beam_debug.c4
-rw-r--r--erts/emulator/beam/beam_emu.c241
-rw-r--r--erts/emulator/beam/beam_load.c11
-rw-r--r--erts/emulator/beam/break.c142
-rw-r--r--erts/emulator/beam/dist.c14
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c4
-rw-r--r--erts/emulator/beam/erl_alloc.c12
-rw-r--r--erts/emulator/beam/erl_alloc.h6
-rw-r--r--erts/emulator/beam/erl_alloc_util.c41
-rw-r--r--erts/emulator/beam/erl_alloc_util.h10
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c4
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c4
-rw-r--r--erts/emulator/beam/erl_bif_info.c6
-rw-r--r--erts/emulator/beam/erl_bif_trace.c7
-rw-r--r--erts/emulator/beam/erl_db.c6
-rw-r--r--erts/emulator/beam/erl_db.h2
-rw-r--r--erts/emulator/beam/erl_db_hash.c4
-rw-r--r--erts/emulator/beam/erl_db_tree.c4
-rw-r--r--erts/emulator/beam/erl_db_util.h2
-rw-r--r--erts/emulator/beam/erl_debug.c10
-rw-r--r--erts/emulator/beam/erl_fun.c4
-rw-r--r--erts/emulator/beam/erl_fun.h4
-rw-r--r--erts/emulator/beam/erl_gc.c217
-rw-r--r--erts/emulator/beam/erl_gc.h5
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c4
-rw-r--r--erts/emulator/beam/erl_hl_timer.c9
-rw-r--r--erts/emulator/beam/erl_hl_timer.h4
-rw-r--r--erts/emulator/beam/erl_init.c16
-rw-r--r--erts/emulator/beam/erl_instrument.c74
-rw-r--r--erts/emulator/beam/erl_instrument.h4
-rw-r--r--erts/emulator/beam/erl_lock_check.c2
-rw-r--r--erts/emulator/beam/erl_lock_count.c4
-rw-r--r--erts/emulator/beam/erl_message.c2
-rw-r--r--erts/emulator/beam/erl_msacc.c2
-rw-r--r--erts/emulator/beam/erl_msacc.h2
-rw-r--r--erts/emulator/beam/erl_nif.c43
-rw-r--r--erts/emulator/beam/erl_node_tables.c8
-rw-r--r--erts/emulator/beam/erl_node_tables.h6
-rw-r--r--erts/emulator/beam/erl_port.h2
-rw-r--r--erts/emulator/beam/erl_process.c330
-rw-r--r--erts/emulator/beam/erl_process.h18
-rw-r--r--erts/emulator/beam/erl_process_dict.c6
-rw-r--r--erts/emulator/beam/erl_process_dict.h6
-rw-r--r--erts/emulator/beam/erl_process_dump.c51
-rw-r--r--erts/emulator/beam/erl_trace.c5
-rw-r--r--erts/emulator/beam/export.c4
-rw-r--r--erts/emulator/beam/export.h2
-rw-r--r--erts/emulator/beam/global.h17
-rw-r--r--erts/emulator/beam/hash.c2
-rw-r--r--erts/emulator/beam/hash.h4
-rw-r--r--erts/emulator/beam/index.c11
-rw-r--r--erts/emulator/beam/index.h16
-rw-r--r--erts/emulator/beam/io.c4
-rw-r--r--erts/emulator/beam/module.c2
-rw-r--r--erts/emulator/beam/module.h2
-rw-r--r--erts/emulator/beam/register.c2
-rw-r--r--erts/emulator/beam/register.h2
-rw-r--r--erts/emulator/beam/sys.h21
-rw-r--r--erts/emulator/beam/utils.c31
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c10
-rw-r--r--erts/emulator/nifs/common/erl_tracer_nif.c2
-rw-r--r--erts/emulator/sys/common/erl_mmap.c8
-rw-r--r--erts/emulator/sys/common/erl_mmap.h5
-rw-r--r--erts/emulator/sys/common/erl_mseg.c20
-rw-r--r--erts/emulator/sys/common/erl_mseg.h4
-rw-r--r--erts/emulator/sys/unix/sys.c46
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h2
-rw-r--r--erts/emulator/sys/win32/sys.c9
-rw-r--r--erts/emulator/test/bif_SUITE.erl200
-rw-r--r--erts/emulator/test/call_trace_SUITE.erl6
-rw-r--r--erts/emulator/test/code_SUITE.erl2
-rw-r--r--erts/emulator/test/dirty_nif_SUITE.erl2
-rw-r--r--erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c2
-rw-r--r--erts/emulator/test/emulator_smoke.spec12
-rw-r--r--erts/emulator/test/lttng_SUITE.erl2
-rw-r--r--erts/emulator/test/port_SUITE.erl2
-rw-r--r--erts/emulator/test/port_SUITE_data/Makefile.src6
-rw-r--r--erts/emulator/test/port_SUITE_data/port_test.c16
-rw-r--r--erts/emulator/test/port_trace_SUITE.erl2
-rw-r--r--erts/emulator/test/process_SUITE.erl21
-rw-r--r--erts/emulator/test/tracer_SUITE.erl2
-rw-r--r--erts/emulator/test/tracer_SUITE_data/tracer_test.c2
-rw-r--r--erts/emulator/test/tracer_test.erl2
-rw-r--r--erts/etc/common/heart.c40
-rw-r--r--erts/etc/unix/etp-commands.in135
-rw-r--r--erts/etc/unix/run_erl.c2
-rw-r--r--erts/example/time_compat.erl2
-rw-r--r--erts/include/internal/erl_printf.h7
-rw-r--r--erts/include/internal/erl_printf_format.h3
-rw-r--r--erts/lib_src/common/erl_printf.c37
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin55804 -> 55784 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2200 -> 2188 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin105116 -> 105124 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin12068 -> 12072 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_code_checker.beambin2144 -> 2128 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin11132 -> 11140 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3304 -> 3288 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50040 -> 50044 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1444 -> 1432 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1312 -> 1300 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44764 -> 44748 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin76544 -> 76472 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23152 -> 23136 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin14136 -> 14124 bytes
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/common_test/doc/src/ct.xml86
-rw-r--r--lib/common_test/doc/src/notes.xml59
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml44
-rw-r--r--lib/common_test/src/Makefile1
-rw-r--r--lib/common_test/src/common_test.app.src1
-rw-r--r--lib/common_test/src/ct.erl96
-rw-r--r--lib/common_test/src/ct_default_gl.erl83
-rw-r--r--lib/common_test/src/ct_framework.erl14
-rw-r--r--lib/common_test/src/ct_logs.erl91
-rw-r--r--lib/common_test/src/ct_run.erl15
-rw-r--r--lib/common_test/src/ct_snmp.erl2
-rw-r--r--lib/common_test/src/ct_telnet.erl2
-rw-r--r--lib/common_test/src/ct_util.erl18
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/src/test_server_gl.erl14
-rw-r--r--lib/common_test/src/test_server_io.erl6
-rw-r--r--lib/common_test/test/Makefile3
-rw-r--r--lib/common_test/test/ct_SUITE.erl53
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl134
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/notes.xml35
-rw-r--r--lib/compiler/src/compile.erl45
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl2
-rw-r--r--lib/compiler/test/warnings_SUITE.erl28
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/doc/src/notes.xml40
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/src/dbg_wx_win.erl2
-rw-r--r--lib/dialyzer/RELEASE_NOTES2
-rw-r--r--lib/dialyzer/doc/manual.txt2
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml2
-rw-r--r--lib/dialyzer/doc/src/notes.xml35
-rw-r--r--lib/dialyzer/src/dialyzer.erl16
-rw-r--r--lib/dialyzer/src/dialyzer.hrl2
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl113
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl13
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl94
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl14
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl204
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl87
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl79
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl7
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl130
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl33
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl54
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl118
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/map_in_guard24
-rw-r--r--lib/dialyzer/test/map_SUITE_data/results/opaque_key8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/array4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/dict18
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/ets6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/my_queue2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/opaque2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/para4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/queue6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/rec4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/simple46
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/timer4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/union8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/wings8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl6
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl8
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl26
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl4
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/chars4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/guards2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/anno.erl18
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/chars.erl32
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/examples/code/relay.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl2
-rw-r--r--lib/diameter/test/diameter_codec_test.erl2
-rw-r--r--lib/diameter/test/diameter_relay_SUITE.erl2
-rw-r--r--lib/edoc/doc/src/notes.xml15
-rw-r--r--lib/edoc/include/edoc_doclet.hrl2
-rw-r--r--lib/edoc/src/edoc.erl2
-rw-r--r--lib/edoc/src/edoc.hrl2
-rw-r--r--lib/edoc/src/edoc_data.erl2
-rw-r--r--lib/edoc/src/edoc_doclet.erl2
-rw-r--r--lib/edoc/src/edoc_extract.erl2
-rw-r--r--lib/edoc/src/edoc_layout.erl2
-rw-r--r--lib/edoc/src/edoc_lib.erl2
-rw-r--r--lib/edoc/src/edoc_macros.erl2
-rw-r--r--lib/edoc/src/edoc_refs.erl2
-rw-r--r--lib/edoc/src/edoc_report.erl2
-rw-r--r--lib/edoc/src/edoc_run.erl2
-rw-r--r--lib/edoc/src/edoc_tags.erl2
-rw-r--r--lib/edoc/src/edoc_types.erl2
-rw-r--r--lib/edoc/src/edoc_types.hrl2
-rw-r--r--lib/edoc/src/edoc_wiki.erl2
-rw-r--r--lib/edoc/src/otpsgml_layout.erl2
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/test/Makefile2
-rw-r--r--lib/eldap/test/eldap.cover3
-rw-r--r--lib/erl_docgen/doc/src/notes.xml19
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/doc/src/notes.xml29
-rw-r--r--lib/erl_interface/src/prog/erl_start.c73
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/eunit/doc/src/notes.xml16
-rw-r--r--lib/eunit/include/eunit.hrl2
-rw-r--r--lib/eunit/src/eunit.erl2
-rw-r--r--lib/eunit/src/eunit_autoexport.erl2
-rw-r--r--lib/eunit/src/eunit_data.erl2
-rw-r--r--lib/eunit/src/eunit_lib.erl2
-rw-r--r--lib/eunit/src/eunit_proc.erl2
-rw-r--r--lib/eunit/src/eunit_serial.erl2
-rw-r--r--lib/eunit/src/eunit_server.erl2
-rw-r--r--lib/eunit/src/eunit_striptests.erl2
-rw-r--r--lib/eunit/src/eunit_surefire.erl2
-rw-r--r--lib/eunit/src/eunit_test.erl2
-rw-r--r--lib/eunit/src/eunit_tests.erl2
-rw-r--r--lib/eunit/src/eunit_tty.erl2
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/hipe/cerl/erl_types.erl193
-rw-r--r--lib/hipe/doc/src/notes.xml45
-rw-r--r--lib/hipe/icode/hipe_icode.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_call_elim.erl3
-rw-r--r--lib/hipe/main/hipe.erl91
-rw-r--r--lib/hipe/main/hipe.hrl.src12
-rw-r--r--lib/hipe/main/hipe_main.erl2
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_num_bif.erl217
-rw-r--r--lib/hipe/test/hipe_SUITE.erl6
-rw-r--r--lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl14
-rw-r--r--lib/hipe/test/opt_verify_SUITE.erl39
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/inets/doc/src/http_uri.xml4
-rw-r--r--lib/inets/doc/src/httpc.xml2
-rw-r--r--lib/inets/doc/src/notes.xml61
-rw-r--r--lib/inets/src/http_client/httpc.erl92
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl682
-rw-r--r--lib/inets/src/http_client/httpc_request.erl6
-rw-r--r--lib/inets/src/http_client/httpc_response.erl2
-rw-r--r--lib/inets/src/http_lib/http_internal.hrl2
-rw-r--r--lib/inets/src/http_server/httpd_response.erl2
-rw-r--r--lib/inets/src/http_server/mod_auth_server.erl2
-rw-r--r--lib/inets/src/inets_app/inets_lib.erl2
-rw-r--r--lib/inets/test/http_format_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_SUITE.erl73
-rw-r--r--lib/inets/test/httpd_SUITE.erl7
-rw-r--r--lib/inets/test/inets_socketwrap_SUITE.erl2
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/kernel/doc/src/heart.xml17
-rw-r--r--lib/kernel/doc/src/inet.xml5
-rw-r--r--lib/kernel/doc/src/notes.xml33
-rw-r--r--lib/kernel/doc/src/rpc.xml16
-rw-r--r--lib/kernel/src/global_group.erl2
-rw-r--r--lib/kernel/src/heart.erl15
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl2
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/src/app/megaco.appup.src2
-rw-r--r--lib/megaco/test/megaco_app_test.erl308
-rw-r--r--lib/megaco/test/megaco_appup_test.erl498
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/notes.xml34
-rw-r--r--lib/mnesia/src/mnesia.erl7
-rw-r--r--lib/mnesia/src/mnesia_tm.erl1
-rw-r--r--lib/mnesia/test/ext_test.erl2
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml54
-rwxr-xr-xlib/observer/priv/bin/cdv2
-rw-r--r--lib/observer/priv/bin/cdv.bat2
-rw-r--r--lib/observer/priv/crashdump_viewer.tool2
-rw-r--r--lib/observer/priv/crashdump_viewer/collapsd.gifbin141 -> 0 bytes
-rw-r--r--lib/observer/priv/crashdump_viewer/exploded.gifbin143 -> 0 bytes
-rw-r--r--lib/observer/src/Makefile10
-rw-r--r--lib/observer/src/cdv_ets_cb.erl7
-rw-r--r--lib/observer/src/cdv_mem_cb.erl4
-rw-r--r--lib/observer/src/crashdump_viewer.erl94
-rw-r--r--lib/observer/src/etop.erl24
-rw-r--r--lib/observer/src/etop_txt.erl24
-rw-r--r--lib/observer/src/observer_alloc_wx.erl2
-rw-r--r--lib/observer/src/observer_lib.erl30
-rw-r--r--lib/observer/src/observer_perf_wx.erl8
-rw-r--r--lib/observer/src/observer_port_wx.erl105
-rw-r--r--lib/observer/src/observer_pro_wx.erl8
-rw-r--r--lib/observer/src/observer_procinfo.erl2
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl10
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/configure.in24
-rw-r--r--lib/odbc/doc/src/notes.xml23
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/notes.xml20
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/doc/src/notes.xml17
-rw-r--r--lib/public_key/doc/src/public_key.xml32
-rw-r--r--lib/public_key/src/public_key.erl41
-rw-r--r--lib/public_key/test/public_key.cover2
-rw-r--r--lib/public_key/test/public_key_SUITE.erl82
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/src/reltool.hrl2
-rw-r--r--lib/runtime_tools/doc/src/notes.xml27
-rw-r--r--lib/runtime_tools/src/msacc.erl2
-rw-r--r--lib/runtime_tools/src/observer_backend.erl60
-rw-r--r--lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c2
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/notes.xml18
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl2
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/start3
-rwxr-xr-xlib/sasl/test/release_handler_SUITE_data/start_client3
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/src/app/snmp.app.src2
-rw-r--r--lib/snmp/src/compile/snmpc.erl2
-rw-r--r--lib/ssh/doc/src/introduction.xml2
-rw-r--r--lib/ssh/doc/src/notes.xml44
-rw-r--r--lib/ssh/doc/src/ssh.xml14
-rw-r--r--lib/ssh/doc/src/ssh_protocol.xml4
-rw-r--r--lib/ssh/src/Makefile2
-rw-r--r--lib/ssh/src/ssh.appup.src2
-rw-r--r--lib/ssh/src/ssh.erl9
-rw-r--r--lib/ssh/src/ssh_acceptor.erl2
-rw-r--r--lib/ssh/src/ssh_auth.erl6
-rw-r--r--lib/ssh/src/ssh_connection.erl5
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl25
-rw-r--r--lib/ssh/src/ssh_dbg.erl3
-rw-r--r--lib/ssh/src/ssh_dbg.hrl27
-rw-r--r--lib/ssh/src/ssh_info.erl2
-rw-r--r--lib/ssh/src/ssh_sftpd.erl2
-rw-r--r--lib/ssh/src/ssh_sftpd_file_api.erl2
-rw-r--r--lib/ssh/src/ssh_transport.erl16
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_encode_decode.erl365
-rw-r--r--lib/ssh/test/ssh.cover1
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE.erl8
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl140
-rw-r--r--lib/ssh/test/ssh_options_SUITE.erl104
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE.erl3
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl24
-rw-r--r--lib/ssh/test/ssh_test_lib.erl47
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl22
-rw-r--r--lib/ssh/test/ssh_trpt_test_lib.erl2
-rw-r--r--lib/ssh/test/ssh_upgrade_SUITE.erl4
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml36
-rw-r--r--lib/ssl/doc/src/ssl.xml8
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache_api.xml2
-rw-r--r--lib/ssl/src/Makefile7
-rw-r--r--lib/ssl/src/dtls_connection.erl606
-rw-r--r--lib/ssl/src/dtls_connection.hrl20
-rw-r--r--lib/ssl/src/dtls_connection_sup.erl2
-rw-r--r--lib/ssl/src/dtls_handshake.erl555
-rw-r--r--lib/ssl/src/dtls_handshake.hrl15
-rw-r--r--lib/ssl/src/dtls_record.erl342
-rw-r--r--lib/ssl/src/dtls_record.hrl9
-rw-r--r--lib/ssl/src/dtls_socket.erl148
-rw-r--r--lib/ssl/src/dtls_udp_listener.erl205
-rw-r--r--lib/ssl/src/dtls_udp_sup.erl62
-rw-r--r--lib/ssl/src/dtls_v1.erl12
-rw-r--r--lib/ssl/src/ssl.app.src5
-rw-r--r--lib/ssl/src/ssl.erl189
-rw-r--r--lib/ssl/src/ssl_alert.erl13
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl29
-rw-r--r--lib/ssl/src/ssl_connection.erl87
-rw-r--r--lib/ssl/src/ssl_connection.hrl19
-rw-r--r--lib/ssl/src/ssl_crl.erl2
-rw-r--r--lib/ssl/src/ssl_crl_cache.erl2
-rw-r--r--lib/ssl/src/ssl_crl_cache_api.erl2
-rw-r--r--lib/ssl/src/ssl_dist_sup.erl4
-rw-r--r--lib/ssl/src/ssl_handshake.hrl3
-rw-r--r--lib/ssl/src/ssl_internal.hrl8
-rw-r--r--lib/ssl/src/ssl_listen_tracker_sup.erl4
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl2
-rw-r--r--lib/ssl/src/ssl_record.erl140
-rw-r--r--lib/ssl/src/ssl_sup.erl43
-rw-r--r--lib/ssl/src/tls_connection.erl91
-rw-r--r--lib/ssl/src/tls_handshake.erl2
-rw-r--r--lib/ssl/src/tls_record.erl382
-rw-r--r--lib/ssl/src/tls_socket.erl (renamed from lib/ssl/src/ssl_socket.erl)93
-rw-r--r--lib/ssl/test/make_certs.erl2
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl37
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl29
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_upgrade_SUITE.erl2
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/assert_hrl.xml2
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml2
-rw-r--r--lib/stdlib/doc/src/gb_trees.xml2
-rw-r--r--lib/stdlib/doc/src/introduction.xml2
-rw-r--r--lib/stdlib/doc/src/notes.xml42
-rw-r--r--lib/stdlib/doc/src/orddict.xml2
-rw-r--r--lib/stdlib/doc/src/rand.xml2
-rw-r--r--lib/stdlib/doc/src/sets.xml2
-rw-r--r--lib/stdlib/doc/src/sys.xml2
-rw-r--r--lib/stdlib/src/erl_eval.erl1
-rw-r--r--lib/stdlib/src/erl_parse.yrl42
-rw-r--r--lib/stdlib/src/escript.erl85
-rw-r--r--lib/stdlib/test/escript_SUITE.erl15
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/two_lines2
-rw-r--r--lib/stdlib/test/shell_SUITE.erl2
-rw-r--r--lib/stdlib/test/tar_SUITE.erl26
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/src/notes.xml16
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl2
-rw-r--r--lib/syntax_tools/src/erl_comment_scan.erl2
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl2
-rw-r--r--lib/syntax_tools/src/erl_recomment.erl2
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl2
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl2
-rw-r--r--lib/syntax_tools/src/erl_tidy.erl2
-rw-r--r--lib/syntax_tools/src/igor.erl2
-rw-r--r--lib/syntax_tools/src/prettypr.erl2
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/tools/doc/src/notes.xml36
-rw-r--r--lib/tools/emacs/erlang-edoc.el2
-rw-r--r--lib/tools/emacs/erlang.el25
-rw-r--r--lib/tools/src/tags.erl2
-rw-r--r--lib/tools/src/tools.app.src2
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/typer/src/typer.erl22
-rw-r--r--lib/wx/api_gen/gl_gen.erl33
-rw-r--r--lib/wx/api_gen/gl_gen_c.erl31
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl41
-rw-r--r--lib/wx/api_gen/glapi.conf6
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl3
-rw-r--r--lib/wx/c_src/gen/gl_funcs.cpp1052
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp2
-rw-r--r--lib/wx/doc/src/notes.xml29
-rw-r--r--lib/wx/src/gen/gl.erl1209
-rw-r--r--lib/wx/src/gen/glu.erl4
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/src/xmerl_scan.erl22
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl18
-rw-r--r--otp_versions.table2
-rwxr-xr-xscripts/run-smoke-tests10
-rw-r--r--system/doc/efficiency_guide/advanced.xml12
-rw-r--r--system/doc/reference_manual/code_loading.xml2
-rw-r--r--system/doc/reference_manual/macros.xml2
-rw-r--r--system/doc/reference_manual/typespec.xml89
-rw-r--r--system/doc/tutorial/c_port.xmlsrc2
-rw-r--r--system/doc/tutorial/c_portdriver.xmlsrc4
469 files changed, 9314 insertions, 5949 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000000..17bf4b636c
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,9 @@
+;; Project-wide Emacs settings
+(
+ ;; `nil' settings apply to all language modes
+ (nil
+ ;; Use only spaces for indentation
+ (indent-tabs-mode . nil))
+ (c-mode
+ ;; In C code, indentation is four spaces
+ (c-basic-offset . 4)))
diff --git a/.travis.yml b/.travis.yml
index 48d8031bd0..42151a16d2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,9 +32,10 @@ script:
- ./otp_build all -a
after_success:
+ - $ERL_TOP/bin/dialyzer --build_plt --apps asn1 compiler crypto dialyzer edoc erts et hipe inets kernel mnesia observer public_key runtime_tools snmp ssh ssl stdlib syntax_tools wx xmerl --statistics
+ - $ERL_TOP/bin/dialyzer -n -Wunknown -Wunmatched_returns --apps compiler erts kernel stdlib asn1 crypto dialyzer hipe parsetools public_key runtime_tools sasl tools --statistics
+ - $ERL_TOP/bin/dialyzer -n --apps common_test debugger edoc inets mnesia observer ssh ssl syntax_tools tools wx xmerl --statistics
- ./otp_build tests && make release_docs
after_script:
- - cd $ERL_TOP/release/tests/test_server && $ERL_TOP/bin/erl -s ts install -s ts smoke_test batch -s init stop
-
-
+ - ./scripts/run-smoke-tests
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..328b9f7859
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,98 @@
+# Contributing to Erlang/OTP
+
+## Reporting a bug
+
+Report bugs at https://bugs.erlang.org. See [Bug reports](https://github.com/erlang/otp/wiki/Bug-reports)
+for more information.
+
+## Submitting Pull Requests
+
+You can contribute to Erlang/OTP by opening a Pull Request.
+
+## Fixing a bug
+
+* In most cases, pull requests for bug fixes should be based on the `maint` branch.
+There are exceptions, for example corrections to bugs that have been introduced in the `master` branch.
+
+* Include a test case to ensure that the bug is fixed **and that it stays fixed**.
+
+* TIP: Write the test case **before** fixing the bug so that you can know that it catches the bug.
+
+* For applications without a test suite in the git repository, it would be appreciated if you provide a
+small code sample in the commit message or email a module that will provoke the failure.
+
+## Adding a new feature
+
+* In most cases, pull requests for new features should be based on the `master` branch.
+
+* It is recommended to discuss new features on
+[the erlang-questions mailing list](http://erlang.org/mailman/listinfo/erlang-questions),
+especially for major new features or any new features in ERTS, Kernel, or STDLIB.
+
+* It is important to write a good commit message explaining **why** the feature is needed.
+We prefer that the information is in the commit message, so that anyone that want to know
+two years later why a particular feature can easily find out. It does no harm to provide
+the same information in the pull request (if the pull request consists of a single commit,
+the commit message will be added to the pull request automatically).
+
+* With few exceptions, it is mandatory to write a new test case that tests the feature.
+The test case is needed to ensure that the features does not stop working in the future.
+
+* Update the [Documentation](https://github.com/erlang/otp/wiki/Documentation) to describe the feature.
+
+* Make sure that the new feature builds and works on all major platforms. Exceptions are features
+that only makes sense one some platforms, for example the `win32reg` module for accessing the Windows registry.
+
+* Make sure that your feature does not break backward compatibility. In general, we only break backward
+compatibility in major releases and only for a very good reason. Usually we first deprecate the
+feature one or two releases beforehand.
+
+* In general, language changes/extensions require an
+[EEP (Erlang Enhancement Proposal)](https://github.com/erlang/eep) to be written and approved before they
+can be included in OTP. Major changes or new features in ERTS, Kernel, or STDLIB will need an EEP or at least
+a discussion on the mailing list.
+
+## Before you submit your pull request
+
+* Make sure existing test cases don't fail. It is not necessary to run all tests (that would take many hours),
+but you should at least run the tests for the application you have changed.
+See [Running tests](https://github.com/erlang/otp/wiki/Running-tests).
+
+Make sure that your branch contains clean commits:
+
+* Don't make the first line in the commit message longer than 72 characters.
+**Don't end the first line with a period.**
+
+* Follow the guidelines for [Writing good commit messages](https://github.com/erlang/otp/wiki/Writing-good-commit-messages).
+
+* Don't merge `maint` or `master` into your branch. Use `git rebase` if you need to resolve merge
+conflicts or include the latest changes.
+
+* To make it possible to use the powerful `git bisect` command, make sure that each commit can be
+compiled and that it works.
+
+* Check for unnecessary whitespace before committing with `git diff --check`.
+
+Check your coding style:
+
+* Make sure your changes follow the coding and indentation style of the code surrounding your changes.
+
+* Do not commit commented-out code or files that are no longer needed. Remove the code or the files.
+
+* In most code (Erlang and C), indentation is 4 steps. Indentation using only spaces is **strongly recommended**.
+
+### Configuring Emacs
+
+If you use Emacs, use the Erlang mode, and add the following lines to `.emacs`:
+
+ (setq-default indent-tabs-mode nil)
+ (setq c-basic-offset 4)
+
+If you want to change the setting only for the Erlang mode, you can use a hook like this:
+
+```
+(add-hook 'erlang-mode-hook 'my-erlang-hook)
+
+(defun my-erlang-hook ()
+ (setq indent-tabs-mode nil))
+```
diff --git a/OTP_VERSION b/OTP_VERSION
index 87c0f53ffe..34716091d4 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-19.1.6
+19.2.1
diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam
index 48e8f80f79..fbea0b152b 100644
--- a/bootstrap/lib/compiler/ebin/beam_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index 044ed03d93..163d9b8432 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/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 3ba8d92655..f3bbc3401c 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 569e0fb5b1..1c82da1c01 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -118,6 +118,6 @@
{applications, []},
{env, [{error_logger, tty}]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-8.0", "stdlib-3.0", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-8.1", "stdlib-3.0", "sasl-3.0"]}
]
}.
diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam
index e4f06a8278..c52a159368 100644
--- a/bootstrap/lib/stdlib/ebin/gen_statem.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index 2c0eb8a742..c72dd5c717 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index 4799178583..ad9a66126f 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2794,6 +2794,23 @@ if test "$cross_compiling" != "yes" && test X${enable_hipe} != Xno; then
fi
fi
+dnl Check to disable -fPIE and friends for HiPE on amd64
+if test X${enable_hipe} = Xyes && test X$ARCH = Xamd64; then
+ AC_TRY_COMPILE(, [#if defined(__pie__) || defined(__PIE__)
+ #error -fPIE is enabled by default
+ #endif],
+ [AC_MSG_NOTICE([No -fPIE enabled by default])],
+ [AC_MSG_WARN([Security feature -fPIE will be disabled for HiPE])
+ STATIC_CFLAGS="-fno-PIE $STATIC_CFLAGS"
+ saved_LDFLAGS=$LDFLAGS
+ LDFLAGS="-no-pie $LDFLAGS"
+ AC_TRY_LINK(,, [],
+ [AC_MSG_WARN([Linked does not accept option -no-pie])
+ LDFLAGS=$saved_LDFLAGS])])
+
+fi
+
+
if test X${enable_fp_exceptions} = Xauto ; then
case $host_os in
*linux*)
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index f39b640c7e..8da832ac37 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -1540,6 +1540,15 @@
</item>
</taglist>
</item>
+ <tag><c><![CDATA[ERL_CRASH_DUMP_BYTES]]></c></tag>
+ <item>
+ <p>This variable sets the maximum size of a crash dump file in bytes.
+ The crash dump will be truncated if this limit is exceeded. If the
+ variable is not set, no size limit is enforced by default. If the
+ variable is set to <c>0</c>, the runtime system does not even attempt
+ to write a crash dump file.</p>
+ <p>Introduced in ERTS 8.1.2 (Erlang/OTP 19.2).</p>
+ </item>
<tag><marker id="ERL_AFLAGS"/><c><![CDATA[ERL_AFLAGS]]></c></tag>
<item>
<p>The content of this variable is added to the beginning of the
@@ -1586,6 +1595,25 @@
</section>
<section>
+ <marker id="signals"></marker>
+ <title>Signals</title>
+ <p>On Unix systems, the Erlang runtime will interpret two types of signals.</p>
+ <taglist>
+ <tag><c>SIGUSR1</c></tag>
+ <item>
+ <p>A <c>SIGUSR1</c> signal forces a crash dump.</p>
+ </item>
+ <tag><c>SIGTERM</c></tag>
+ <item>
+ <p>A <c>SIGTERM</c> will produce a <c>stop</c> message to the <c>init</c> process.
+ This is equivalent to a <c>init:stop/0</c> call.</p>
+ <p>Introduced in ERTS 8.3 (Erlang/OTP 19.3)</p>
+ </item>
+ </taglist>
+ <p>The signal <c>SIGUSR2</c> is reserved for internal usage. No other signals are handled.</p>
+ </section>
+
+ <section>
<marker id="configuration"></marker>
<title>Configuration</title>
<p>The standard Erlang/OTP system can be reconfigured to change the default
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 9646953518..112682d713 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4899,7 +4899,9 @@ RealSystem = system + MissedSystem</code>
<p>Returns the current call stack back-trace (<em>stacktrace</em>)
of the process. The stack has the same format as returned by
<seealso marker="#get_stacktrace/0">
- <c>erlang:get_stacktrace/0</c></seealso>.</p>
+ <c>erlang:get_stacktrace/0</c></seealso>. The depth of the
+ stacktrace is truncated according to the <c>backtrace_depth</c>
+ system flag setting.</p>
</item>
<tag><c>{dictionary, <anno>Dictionary</anno>}</c></tag>
<item>
@@ -6611,7 +6613,9 @@ ok
<fsummary>Set system flag <c>backtrace_depth</c>.</fsummary>
<desc>
<p>Sets the maximum depth of call stack back-traces in the
- exit reason element of <c>'EXIT'</c> tuples.</p>
+ exit reason element of <c>'EXIT'</c> tuples. The flag
+ also limits the stacktrace depth returned by <c>process_info</c>
+ item <c>current_stacktrace.</c></p>
<p>Returns the old value of the flag.</p>
</desc>
</func>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index dd260f2d1f..812538729d 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -32,6 +32,179 @@
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 8.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a quite rare bug causing VM crash during code loading
+ and the use of export funs (fun M:F/A) of not yet loaded
+ modules. Requires a very specfic timing of concurrent
+ scheduler threads. Has been seen on ARM but can probably
+ also occure on other architectures. Bug has existed since
+ OTP R16.</p>
+ <p>
+ Own Id: OTP-14144 Aux Id: seq13242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 8.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed <c>configure</c> failures on MacOSX. Most important
+ <c>clock_gettime()</c> was detected when building for
+ MacOSX - El Capitan using XCode 8 despite it is not
+ available until MacOSX - Sierra.</p>
+ <p>
+ Own Id: OTP-13904 Aux Id: ERL-256 </p>
+ </item>
+ <item>
+ <p>
+ <c>code:add_pathsa/1</c> and command line option
+ <c>-pa</c> both revert the given list of directories when
+ adding it at the beginning of the code path. This is now
+ documented.</p>
+ <p>
+ Own Id: OTP-13920 Aux Id: ERL-267 </p>
+ </item>
+ <item>
+ <p>
+ Fix a compilation error of erts in OpenBSD related to the
+ usage of the __errno variable.</p>
+ <p>
+ Own Id: OTP-13927</p>
+ </item>
+ <item>
+ <p>
+ Fixed so that when enabling tracing on a process that had
+ an invalid tracer associated with it, the new tracer
+ overwrites the old tracer. Before this fix, calling
+ erlang:trace/3 would behave as if the tracer was still
+ alive and not apply the new trace.</p>
+ <p>
+ This fault was introduced in ERTS 8.0.</p>
+ <p>
+ Own Id: OTP-13928</p>
+ </item>
+ <item>
+ <p>
+ Fix parsing of <c>-profile_boot 'true' | 'false'</c></p>
+ <p>
+ Own Id: OTP-13955 Aux Id: ERL-280 </p>
+ </item>
+ <item>
+ <p>
+ A slight improvement of <c>erlang:get_stacktrace/0</c>
+ for exceptions raised in hipe compiled code. Beam
+ compiled functions in such stack trace was earlier
+ replaced by some unrelated function. They are now instead
+ omitted. This is an attempt to reduce the confusion in
+ the absence of a complete and correct stack trace for
+ mixed beam and hipe functions.</p>
+ <p>
+ Own Id: OTP-13992</p>
+ </item>
+ <item>
+ <p> Correct type declaration of match specification head.
+ </p>
+ <p>
+ Own Id: OTP-13996</p>
+ </item>
+ <item>
+ <p>
+ HiPE code loading failed for x86_64 if gcc was configured
+ with <c>--enable-default-pie</c>. Fixed by disabling PIE,
+ if needed for HiPE, when building the VM.</p>
+ <p>
+ Own Id: OTP-14031 Aux Id: ERL-294, PR-1239 </p>
+ </item>
+ <item>
+ <p>
+ Faulty arguments could be presented on exception from a
+ NIF that had rescheduled itself using
+ <c>enif_schedule_nif()</c>.</p>
+ <p>
+ Own Id: OTP-14048</p>
+ </item>
+ <item>
+ <p>
+ The runtime system could crash if a garbage collection on
+ a process was performed immediately after a NIF had been
+ rescheduled using <c>enif_schedule_nif()</c>.</p>
+ <p>
+ Own Id: OTP-14049</p>
+ </item>
+ <item>
+ <p>
+ A reference to purged code could be left undetected by
+ the purge operation if a process just had rescheduled a
+ NIF call using <c>enif_schedule_nif()</c> when the
+ process was checked. This could cause a runtime system
+ crash.</p>
+ <p>
+ Own Id: OTP-14050</p>
+ </item>
+ <item>
+ <p>Fixed a number of dirty scheduler related bugs:</p>
+ <list> <item><p>Process priority was not handled correct
+ when scheduling on a dirty scheduler.</p></item>
+ <item><p>The runtime system could crash when an exit
+ signal with a compound exit reason was sent to a process
+ executing on a dirty scheduler.</p></item> <item><p>The
+ runtime system crashed when call tracing a process
+ executing on a dirty scheduler.</p></item> <item><p>A
+ code purge operation could end up hanging forever when a
+ process executed on a dirty scheduler</p></item> </list>
+ <p>
+ Own Id: OTP-14051</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Fix minor soft purge race bug that could incorrectly
+ trigger code_server to load new code for the module if
+ the soft purge failed and no current version of the
+ module existed.</p>
+ <p>
+ Own Id: OTP-13925</p>
+ </item>
+ <item>
+ <p>
+ To ease troubleshooting, <c>erlang:load_nif/2</c> now
+ includes the return value from a failed call to
+ load/reload/upgrade in the text part of the error tuple.
+ The <c>crypto</c> NIF makes use of this feature by
+ returning the source line where/if the initialization
+ fails.</p>
+ <p>
+ Own Id: OTP-13951</p>
+ </item>
+ <item>
+ <p>
+ New environment variable <c>ERL_CRASH_DUMP_BYTES</c> can
+ be used to limit the size of crash dumps. If the limit is
+ reached, crash dump generation is aborted and the
+ generated file will be truncated.</p>
+ <p>
+ Own Id: OTP-14046</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 8.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index e0260205e3..8772befe27 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -49,6 +49,7 @@ CREATE_DIRS=
LDFLAGS=@LDFLAGS@
ARFLAGS=rc
OMIT_OMIT_FP=no
+TYPE_LIBS=
DIRTY_SCHEDULER_SUPPORT=@DIRTY_SCHEDULER_SUPPORT@
NEW_PURGE_STRATEGY=@NEW_PURGE_STRATEGY@
@@ -90,7 +91,7 @@ PURIFY =
TYPEMARKER = .gcov
TYPE_FLAGS = $(DEBUG_CFLAGS) -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE=
ifneq ($(findstring solaris,$(TARGET)),solaris)
-LIBS += -lgcov
+TYPE_LIBS = -lgcov
endif
ENABLE_ALLOC_TYPE_VARS += debug
else
@@ -146,6 +147,8 @@ endif
endif
endif
+LIBS += $(TYPE_LIBS)
+
comma:=,
space:=
space+=
@@ -931,7 +934,7 @@ $(OBJDIR)/%.o: hipe/%.c
$(V_CC) $(subst O2,O3, $(CFLAGS)) $(INCLUDES) -c $< -o $@
$(BINDIR)/hipe_mkliterals$(TF_MARKER): $(OBJDIR)/hipe_mkliterals.o
- $(ld_verbose)$(CC) $(CFLAGS) $(INCLUDES) -o $@ $<
+ $(ld_verbose)$(CC) $(LDFLAGS) -o $@ $< $(TYPE_LIBS)
$(OBJDIR)/hipe_mkliterals.o: $(HIPE_ASM) $(TTF_DIR)/erl_alloc_types.h $(DTRACE_HEADERS) \
$(TTF_DIR)/OPCODES-GENERATED $(TARGET)/TABLES-GENERATED
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index a5e778e4aa..2052afe52b 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -68,7 +68,7 @@ static Uint atom_space; /* Amount of atom text space used */
/*
* Print info about atom tables
*/
-void atom_info(int to, void *to_arg)
+void atom_info(fmtfn_t to, void *to_arg)
{
int lock = !ERTS_IS_CRASH_DUMPING;
if (lock)
@@ -470,7 +470,7 @@ init_atom_table(void)
}
void
-dump_atoms(int to, void *to_arg)
+dump_atoms(fmtfn_t to, void *to_arg)
{
int i = erts_atom_table.entries;
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index ae60904785..a82efabb9f 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -136,8 +136,8 @@ Eterm erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc);
int atom_erase(byte*, int);
int atom_static_put(byte*, int);
void init_atom_table(void);
-void atom_info(int, void *);
-void dump_atoms(int, void *);
+void atom_info(fmtfn_t, void *);
+void dump_atoms(fmtfn_t, void *);
int erts_atom_get(const char* name, int len, Eterm* ap, ErtsAtomEncoding enc);
void erts_atom_get_text_space_sizes(Uint *reserved, Uint *used);
#endif
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 8af7703f51..7f5e9ff691 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -658,7 +658,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1)
}
else if (modp->old.code_hdr) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
- erts_dsprintf(dsbufp, "Module %T must be purged before loading\n",
+ erts_dsprintf(dsbufp, "Module %T must be purged before deleting\n",
BIF_ARG_1);
erts_send_error_to_logger(BIF_P->group_leader, dsbufp);
ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
@@ -786,7 +786,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
}
if (BIF_ARG_2 == am_true) {
- int i;
+ int i, num_exps;
/*
* Make the code with the on_load function current.
@@ -802,7 +802,8 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
/*
* The on_load function succeded. Fix up export entries.
*/
- for (i = 0; i < export_list_size(code_ix); i++) {
+ num_exps = export_list_size(code_ix);
+ for (i = 0; i < num_exps; i++) {
Export *ep = export_list(i,code_ix);
if (ep == NULL || ep->code[0] != BIF_ARG_1) {
continue;
@@ -822,14 +823,15 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
modp->curr.code_hdr->on_load_function_ptr = NULL;
set_default_trace_pattern(BIF_ARG_1);
} else if (BIF_ARG_2 == am_false) {
- int i;
+ int i, num_exps;
/*
* The on_load function failed. Remove references to the
* code that is about to be purged from the export entries.
*/
- for (i = 0; i < export_list_size(code_ix); i++) {
+ num_exps = export_list_size(code_ix);
+ for (i = 0; i < num_exps; i++) {
Export *ep = export_list(i,code_ix);
if (ep == NULL || ep->code[0] != BIF_ARG_1) {
continue;
@@ -995,6 +997,12 @@ erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed
if (any_heap_refs(c_p->heap, c_p->htop, literals, lit_bsize))
goto literal_gc;
*redsp += 1;
+ if (c_p->abandoned_heap) {
+ if (any_heap_refs(c_p->abandoned_heap, c_p->abandoned_heap + c_p->heap_sz,
+ literals, lit_bsize))
+ goto literal_gc;
+ *redsp += 1;
+ }
if (any_heap_refs(c_p->old_heap, c_p->old_htop, literals, lit_bsize))
goto literal_gc;
@@ -1086,6 +1094,11 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
|| ErtsInArea(rp->cp, mod_start, mod_size)) {
return am_true;
}
+
+ *redsp += 1;
+
+ if (erts_check_nif_export_in_area(rp, mod_start, mod_size))
+ return am_true;
*redsp += (STACK_START(rp) - rp->stop) / 32;
@@ -1161,6 +1174,12 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
|| ErtsInArea(rp->cp, mod_start, mod_size)) {
return am_true;
}
+
+ *redsp += 1;
+
+ if (erts_check_nif_export_in_area(rp, mod_start, mod_size))
+ return am_true;
+
/*
* Check all continuation pointers stored on the stack.
@@ -1284,6 +1303,11 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls
#endif
if (any_heap_refs(rp->heap, rp->htop, literals, lit_bsize))
goto try_literal_gc;
+ if (rp->abandoned_heap) {
+ if (any_heap_refs(rp->abandoned_heap, rp->abandoned_heap + rp->heap_sz,
+ literals, lit_bsize))
+ goto try_literal_gc;
+ }
if (any_heap_refs(rp->old_heap, rp->old_htop, literals, lit_bsize))
goto try_literal_gc;
@@ -2011,9 +2035,9 @@ delete_code(Module* modp)
{
ErtsCodeIndex code_ix = erts_staging_code_ix();
Eterm module = make_atom(modp->module);
- int i;
+ int i, num_exps = export_list_size(code_ix);
- for (i = 0; i < export_list_size(code_ix); i++) {
+ for (i = 0; i < num_exps; i++) {
Export *ep = export_list(i, code_ix);
if (ep != NULL && (ep->code[0] == module)) {
if (ep->addressv[code_ix] == ep->code+3) {
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 920c8b1ed0..0df2df0eaa 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -74,6 +74,9 @@ extern BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
erts_smp_atomic32_t erts_active_bp_index;
erts_smp_atomic32_t erts_staging_bp_index;
+#ifdef ERTS_DIRTY_SCHEDULERS
+erts_smp_mtx_t erts_dirty_bp_ix_mtx;
+#endif
/*
* Inlined helpers
@@ -85,6 +88,31 @@ get_mtime(Process *c_p)
return erts_get_monotonic_time(erts_proc_sched_data(c_p));
}
+static ERTS_INLINE Uint32
+acquire_bp_sched_ix(Process *c_p)
+{
+ ErtsSchedulerData *esdp = erts_proc_sched_data(c_p);
+ ASSERT(esdp);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ if (ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ erts_smp_mtx_lock(&erts_dirty_bp_ix_mtx);
+ return (Uint32) erts_no_schedulers;
+ }
+#endif
+ return (Uint32) esdp->no - 1;
+}
+
+static ERTS_INLINE void
+release_bp_sched_ix(Uint32 ix)
+{
+#ifdef ERTS_DIRTY_SCHEDULERS
+ if (ix == (Uint32) erts_no_schedulers)
+ erts_smp_mtx_unlock(&erts_dirty_bp_ix_mtx);
+#endif
+}
+
+
+
/* *************************************************************************
** Local prototypes
*/
@@ -135,6 +163,9 @@ void
erts_bp_init(void) {
erts_smp_atomic32_init_nob(&erts_active_bp_index, 0);
erts_smp_atomic32_init_nob(&erts_staging_bp_index, 1);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_smp_mtx_init(&erts_dirty_bp_ix_mtx, "dirty_break_point_index");
+#endif
}
@@ -973,6 +1004,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
bp_data_time_item_t sitem, *item = NULL;
bp_time_hash_t *h = NULL;
BpDataTime *pbdt = NULL;
+ Uint32 six = acquire_bp_sched_ix(c_p);
ASSERT(c_p);
ASSERT(erts_smp_atomic32_read_acqb(&c_p->state) & (ERTS_PSFLG_RUNNING
@@ -980,7 +1012,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
/* get previous timestamp and breakpoint
* from the process psd */
-
+
pbt = ERTS_PROC_GET_CALL_TIME(c_p);
time = get_mtime(c_p);
@@ -1006,7 +1038,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
/* if null then the breakpoint was removed */
if (pbdt) {
- h = &(pbdt->hash[bp_sched2ix_proc(c_p)]);
+ h = &(pbdt->hash[six]);
ASSERT(h);
ASSERT(h->item);
@@ -1027,7 +1059,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
/* this breakpoint */
ASSERT(bdt);
- h = &(bdt->hash[bp_sched2ix_proc(c_p)]);
+ h = &(bdt->hash[six]);
ASSERT(h);
ASSERT(h->item);
@@ -1041,6 +1073,8 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
pbt->pc = I;
pbt->time = time;
+
+ release_bp_sched_ix(six);
}
void
@@ -1051,6 +1085,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc)
bp_data_time_item_t sitem, *item = NULL;
bp_time_hash_t *h = NULL;
BpDataTime *pbdt = NULL;
+ Uint32 six = acquire_bp_sched_ix(p);
ASSERT(p);
ASSERT(erts_smp_atomic32_read_acqb(&p->state) & (ERTS_PSFLG_RUNNING
@@ -1071,6 +1106,7 @@ erts_trace_time_return(Process *p, BeamInstr *pc)
*/
if (pbt) {
+
/* might have been removed due to
* trace_pattern(false)
*/
@@ -1085,7 +1121,8 @@ erts_trace_time_return(Process *p, BeamInstr *pc)
/* beware, the trace_pattern might have been removed */
if (pbdt) {
- h = &(pbdt->hash[bp_sched2ix_proc(p)]);
+
+ h = &(pbdt->hash[six]);
ASSERT(h);
ASSERT(h->item);
@@ -1096,11 +1133,15 @@ erts_trace_time_return(Process *p, BeamInstr *pc)
} else {
BP_TIME_ADD(item, &sitem);
}
+
}
pbt->pc = pc;
pbt->time = time;
+
}
+
+ release_bp_sched_ix(six);
}
int
@@ -1353,6 +1394,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) {
bp_data_time_item_t sitem, *item = NULL;
bp_time_hash_t *h = NULL;
BpDataTime *pbdt = NULL;
+ Uint32 six = acquire_bp_sched_ix(p);
ASSERT(p);
@@ -1375,7 +1417,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) {
sitem.pid = p->common.id;
sitem.count = 0;
- h = &(pbdt->hash[bp_sched2ix_proc(p)]);
+ h = &(pbdt->hash[six]);
ASSERT(h);
ASSERT(h->item);
@@ -1401,6 +1443,8 @@ void erts_schedule_time_break(Process *p, Uint schedule) {
break;
}
} /* pbt */
+
+ release_bp_sched_ix(six);
}
/* *************************************************************************
@@ -1517,7 +1561,11 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
ASSERT((bp->flags & ERTS_BPF_TIME_TRACE) == 0);
bdt = Alloc(sizeof(BpDataTime));
erts_refc_init(&bdt->refc, 1);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ bdt->n = erts_no_schedulers + 1;
+#else
bdt->n = erts_no_schedulers;
+#endif
bdt->hash = Alloc(sizeof(bp_time_hash_t)*(bdt->n));
for (i = 0; i < bdt->n; i++) {
bp_hash_init(&(bdt->hash[i]), 32);
diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h
index 541af77211..4743e4fc2f 100644
--- a/erts/emulator/beam/beam_bp.h
+++ b/erts/emulator/beam/beam_bp.h
@@ -79,10 +79,8 @@ typedef struct generic_bp {
#define ERTS_BP_CALL_TIME_SCHEDULE_OUT (1)
#define ERTS_BP_CALL_TIME_SCHEDULE_EXITING (2)
-#ifdef ERTS_SMP
-#define bp_sched2ix_proc(p) (erts_proc_sched_data(p)->no - 1)
-#else
-#define bp_sched2ix_proc(p) (0)
+#ifdef ERTS_DIRTY_SCHEDULERS
+extern erts_smp_mtx_t erts_dirty_bp_ix_mtx;
#endif
enum erts_break_op{
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index a4ad3e7886..21d336049f 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -50,7 +50,7 @@
void dbg_bt(Process* p, Eterm* sp);
void dbg_where(BeamInstr* addr, Eterm x0, Eterm* reg);
-static int print_op(int to, void *to_arg, int op, int size, BeamInstr* addr);
+static int print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr);
BIF_RETTYPE
erts_debug_same_2(BIF_ALIST_2)
@@ -377,7 +377,7 @@ dbg_where(BeamInstr* addr, Eterm x0, Eterm* reg)
}
static int
-print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
+print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
{
int i;
BeamInstr tag;
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 3be5c0d24c..f392feb06b 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1047,9 +1047,11 @@ static BeamInstr* handle_error(Process* c_p, BeamInstr* pc,
Eterm* reg, BifFunction bf) NOINLINE;
static BeamInstr* call_error_handler(Process* p, BeamInstr* ip,
Eterm* reg, Eterm func) NOINLINE;
-static BeamInstr* fixed_apply(Process* p, Eterm* reg, Uint arity) NOINLINE;
+static BeamInstr* fixed_apply(Process* p, Eterm* reg, Uint arity,
+ BeamInstr *I, Uint offs) NOINLINE;
static BeamInstr* apply(Process* p, Eterm module, Eterm function,
- Eterm args, Eterm* reg) NOINLINE;
+ Eterm args, Eterm* reg,
+ BeamInstr *I, Uint offs) NOINLINE;
static BeamInstr* call_fun(Process* p, int arity,
Eterm* reg, Eterm args) NOINLINE;
static BeamInstr* apply_fun(Process* p, Eterm fun,
@@ -3194,7 +3196,7 @@ do { \
OpCase(i_apply): {
BeamInstr *next;
HEAVY_SWAPOUT;
- next = apply(c_p, r(0), x(1), x(2), reg);
+ next = apply(c_p, r(0), x(1), x(2), reg, NULL, 0);
HEAVY_SWAPIN;
if (next != NULL) {
SET_CP(c_p, I+1);
@@ -3208,7 +3210,7 @@ do { \
OpCase(i_apply_last_P): {
BeamInstr *next;
HEAVY_SWAPOUT;
- next = apply(c_p, r(0), x(1), x(2), reg);
+ next = apply(c_p, r(0), x(1), x(2), reg, I, Arg(0));
HEAVY_SWAPIN;
if (next != NULL) {
SET_CP(c_p, (BeamInstr *) E[0]);
@@ -3223,7 +3225,7 @@ do { \
OpCase(i_apply_only): {
BeamInstr *next;
HEAVY_SWAPOUT;
- next = apply(c_p, r(0), x(1), x(2), reg);
+ next = apply(c_p, r(0), x(1), x(2), reg, I, 0);
HEAVY_SWAPIN;
if (next != NULL) {
SET_I(next);
@@ -3237,7 +3239,7 @@ do { \
BeamInstr *next;
HEAVY_SWAPOUT;
- next = fixed_apply(c_p, reg, Arg(0));
+ next = fixed_apply(c_p, reg, Arg(0), NULL, 0);
HEAVY_SWAPIN;
if (next != NULL) {
SET_CP(c_p, I+2);
@@ -3252,7 +3254,7 @@ do { \
BeamInstr *next;
HEAVY_SWAPOUT;
- next = fixed_apply(c_p, reg, Arg(0));
+ next = fixed_apply(c_p, reg, Arg(0), I, Arg(1));
HEAVY_SWAPIN;
if (next != NULL) {
SET_CP(c_p, (BeamInstr *) E[0]);
@@ -3550,18 +3552,11 @@ do { \
BifFunction vbf;
ErlHeapFragment *live_hf_end;
- if (!((FCALLS - 1) > 0 || (FCALLS - 1) > neg_o_reds)) {
- /* If we have run out of reductions, we do a context
- switch before calling the nif */
- goto context_switch;
- }
-
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_NIF);
DTRACE_NIF_ENTRY(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]);
c_p->current = I-3; /* current and vbf set to please handle_error */
- SWAPOUT;
- c_p->fcalls = FCALLS - 1;
+ HEAVY_SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
bif_nif_arity = I[-1];
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
@@ -5325,7 +5320,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
I = c_p->i;
- ASSERT(BeamOp(op_call_nif) == (BeamInstr *) *I);
+ ASSERT(em_call_nif == (BeamInstr *) *I);
/*
* Set fcalls even though we ignore it, so we don't
@@ -5844,12 +5839,13 @@ save_stacktrace(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf,
s->depth = 0;
/*
- * If the failure was in a BIF other than 'error', 'exit' or
- * 'throw', find the bif-table index and save the argument
- * registers by consing up an arglist.
+ * If the failure was in a BIF other than 'error/1', 'error/2',
+ * 'exit/1' or 'throw/1', find the bif-table index and save the
+ * argument registers by consing up an arglist.
*/
- if (bf != NULL && bf != error_1 && bf != error_2 &&
- bf != exit_1 && bf != throw_1) {
+ if (bf != NULL && bf != error_1 && bf != error_2 && bf != exit_1
+ && bf != throw_1 && bf != wrap_error_1 && bf != wrap_error_2
+ && bf != wrap_exit_1 && bf != wrap_throw_1) {
int i;
int a = 0;
for (i = 0; i < BIF_SIZE; i++) {
@@ -5945,12 +5941,30 @@ erts_save_stacktrace(Process* p, struct StackTrace* s, int depth)
p->cp) {
/* Cannot follow cp here - code may be unloaded */
BeamInstr *cpp = p->cp;
+ int trace_cp;
if (cpp == beam_exception_trace || cpp == beam_return_trace) {
/* Skip return_trace parameters */
ptr += 2;
+ trace_cp = 1;
} else if (cpp == beam_return_to_trace) {
/* Skip return_to_trace parameters */
ptr += 1;
+ trace_cp = 1;
+ }
+ else {
+ trace_cp = 0;
+ }
+ if (trace_cp && s->pc == cpp) {
+ /*
+ * If process 'cp' points to a return/exception trace
+ * instruction and 'cp' has been saved as 'pc' in
+ * stacktrace, we need to update 'pc' in stacktrace
+ * with the actual 'cp' located on the top of the
+ * stack; otherwise, we will lose the top stackframe
+ * when building the stack trace.
+ */
+ ASSERT(is_CP(p->stop[0]));
+ s->pc = cp_val(p->stop[0]);
}
}
while (ptr < STACK_START(p) && depth > 0) {
@@ -6070,12 +6084,15 @@ build_stacktrace(Process* c_p, Eterm exc) {
erts_set_current_function(&fi, s->current);
}
+ depth = s->depth;
/*
- * If fi.current is still NULL, default to the initial function
+ * If fi.current is still NULL, and we have no
+ * stack at all, default to the initial function
* (e.g. spawn_link(erlang, abs, [1])).
*/
if (fi.current == NULL) {
- erts_set_current_function(&fi, c_p->u.initial);
+ if (depth <= 0)
+ erts_set_current_function(&fi, c_p->u.initial);
args = am_true; /* Just in case */
} else {
args = get_args_from_exc(exc);
@@ -6085,10 +6102,9 @@ build_stacktrace(Process* c_p, Eterm exc) {
* Look up all saved continuation pointers and calculate
* needed heap space.
*/
- depth = s->depth;
stk = stkp = (FunctionInfo *) erts_alloc(ERTS_ALC_T_TMP,
depth*sizeof(FunctionInfo));
- heap_size = fi.needed + 2;
+ heap_size = fi.current ? fi.needed + 2 : 0;
for (i = 0; i < depth; i++) {
erts_lookup_function_info(stkp, s->trace[i], 1);
if (stkp->current) {
@@ -6107,8 +6123,10 @@ build_stacktrace(Process* c_p, Eterm exc) {
res = CONS(hp, mfa, res);
hp += 2;
}
- hp = erts_build_mfa_item(&fi, hp, args, &mfa);
- res = CONS(hp, mfa, res);
+ if (fi.current) {
+ hp = erts_build_mfa_item(&fi, hp, args, &mfa);
+ res = CONS(hp, mfa, res);
+ }
erts_free(ERTS_ALC_T_TMP, (void *) stk);
return res;
@@ -6205,8 +6223,107 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity,
return ep;
}
+static ERTS_INLINE void
+apply_bif_error_adjustment(Process *p, Export *ep,
+ Eterm *reg, Uint arity,
+ BeamInstr *I, Uint stack_offset)
+{
+ /*
+ * I is only set when the apply is a tail call, i.e.,
+ * from the instructions i_apply_only, i_apply_last_P,
+ * and apply_last_IP.
+ */
+ if (I
+ && ep->code[3] == (BeamInstr) em_apply_bif
+ && (ep == bif_export[BIF_error_1]
+ || ep == bif_export[BIF_error_2]
+ || ep == bif_export[BIF_exit_1]
+ || ep == bif_export[BIF_throw_1])) {
+ /*
+ * We are about to tail apply one of the BIFs
+ * erlang:error/1, erlang:error/2, erlang:exit/1,
+ * or erlang:throw/1. Error handling of these BIFs is
+ * special!
+ *
+ * We need 'p->cp' to point into the calling
+ * function when handling the error after the BIF has
+ * been applied. This in order to get the topmost
+ * stackframe correct. Without the following adjustment,
+ * 'p->cp' will point into the function that called
+ * current function when handling the error. We add a
+ * dummy stackframe in order to achive this.
+ *
+ * Note that these BIFs unconditionally will cause
+ * an exception to be raised. That is, our modifications
+ * of 'p->cp' as well as the stack will be corrected by
+ * the error handling code.
+ *
+ * If we find an exception/return-to trace continuation
+ * pointer as the topmost continuation pointer, we do not
+ * need to do anything since the information already will
+ * be available for generation of the stacktrace.
+ */
+ int apply_only = stack_offset == 0;
+ BeamInstr *cpp;
+
+ if (apply_only) {
+ ASSERT(p->cp != NULL);
+ cpp = p->cp;
+ }
+ else {
+ ASSERT(is_CP(p->stop[0]));
+ cpp = cp_val(p->stop[0]);
+ }
+
+ if (cpp != beam_exception_trace
+ && cpp != beam_return_trace
+ && cpp != beam_return_to_trace) {
+ Uint need = stack_offset /* bytes */ / sizeof(Eterm);
+ if (need == 0)
+ need = 1; /* i_apply_only */
+ if (p->stop - p->htop < need)
+ erts_garbage_collect(p, (int) need, reg, arity+1);
+ p->stop -= need;
+
+ if (apply_only) {
+ /*
+ * Called from the i_apply_only instruction.
+ *
+ * 'p->cp' contains continuation pointer pointing
+ * into the function that called current function.
+ * We push that continuation pointer onto the stack,
+ * and set 'p->cp' to point into current function.
+ */
+
+ p->stop[0] = make_cp(p->cp);
+ p->cp = I;
+ }
+ else {
+ /*
+ * Called from an i_apply_last_p, or apply_last_IP,
+ * instruction.
+ *
+ * Calling instruction will after we return read
+ * a continuation pointer from the stack and write
+ * it to 'p->cp', and then remove the topmost
+ * stackframe of size 'stack_offset'.
+ *
+ * We have sized the dummy-stackframe so that it
+ * will be removed by the instruction we currently
+ * are executing, and leave the stackframe that
+ * normally would have been removed intact.
+ *
+ */
+ p->stop[0] = make_cp(I);
+ }
+ }
+ }
+}
+
static BeamInstr*
-apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
+apply(
+Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg,
+BeamInstr *I, Uint stack_offset)
{
int arity;
Export* ep;
@@ -6231,21 +6348,54 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
return 0;
}
- /* The module argument may be either an atom or an abstract module
- * (currently implemented using tuples, but this might change).
- */
- this = THE_NON_VALUE;
- if (is_not_atom(module)) {
- Eterm* tp;
+ while (1) {
+ Eterm m, f, a;
+ /* The module argument may be either an atom or an abstract module
+ * (currently implemented using tuples, but this might change).
+ */
+ this = THE_NON_VALUE;
+ if (is_not_atom(module)) {
+ Eterm* tp;
+
+ if (is_not_tuple(module)) goto error;
+ tp = tuple_val(module);
+ if (arityval(tp[0]) < 1) goto error;
+ this = module;
+ module = tp[1];
+ if (is_not_atom(module)) goto error;
+ }
- if (is_not_tuple(module)) goto error;
- tp = tuple_val(module);
- if (arityval(tp[0]) < 1) goto error;
- this = module;
- module = tp[1];
- if (is_not_atom(module)) goto error;
+ if (module != am_erlang || function != am_apply)
+ break;
+
+ /* Adjust for multiple apply of apply/3... */
+
+ a = args;
+ if (is_list(a)) {
+ Eterm *consp = list_val(a);
+ m = CAR(consp);
+ a = CDR(consp);
+ if (is_list(a)) {
+ consp = list_val(a);
+ f = CAR(consp);
+ a = CDR(consp);
+ if (is_list(a)) {
+ consp = list_val(a);
+ a = CAR(consp);
+ if (is_nil(CDR(consp))) {
+ /* erlang:apply/3 */
+ module = m;
+ function = f;
+ args = a;
+ if (is_not_atom(f))
+ goto error;
+ continue;
+ }
+ }
+ }
+ }
+ break; /* != erlang:apply/3 */
}
-
/*
* Walk down the 3rd parameter of apply (the argument list) and copy
* the parameters to the x registers (reg[]). If the module argument
@@ -6283,12 +6433,14 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg)
} else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) {
save_calls(p, ep);
}
+ apply_bif_error_adjustment(p, ep, reg, arity, I, stack_offset);
DTRACE_GLOBAL_CALL_FROM_EXPORT(p, ep);
return ep->addressv[erts_active_code_ix()];
}
static BeamInstr*
-fixed_apply(Process* p, Eterm* reg, Uint arity)
+fixed_apply(Process* p, Eterm* reg, Uint arity,
+ BeamInstr *I, Uint stack_offset)
{
Export* ep;
Eterm module;
@@ -6318,6 +6470,10 @@ fixed_apply(Process* p, Eterm* reg, Uint arity)
if (is_not_atom(module)) goto error;
++arity;
}
+
+ /* Handle apply of apply/3... */
+ if (module == am_erlang && function == am_apply && arity == 3)
+ return apply(p, reg[0], reg[1], reg[2], reg, I, stack_offset);
/*
* Get the index into the export table, or failing that the export
@@ -6332,6 +6488,7 @@ fixed_apply(Process* p, Eterm* reg, Uint arity)
} else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) {
save_calls(p, ep);
}
+ apply_bif_error_adjustment(p, ep, reg, arity, I, stack_offset);
DTRACE_GLOBAL_CALL_FROM_EXPORT(p, ep);
return ep->addressv[erts_active_code_ix()];
}
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 0afdedf6c2..3f2bdf3f9d 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -797,14 +797,14 @@ erts_finish_loading(Binary* magic, Process* c_p,
} else {
ErtsCodeIndex code_ix = erts_staging_code_ix();
Eterm module = stp->module;
- int i;
+ int i, num_exps;
/*
* There is an -on_load() function. We will keep the current
* code, but we must turn off any tracing.
*/
-
- for (i = 0; i < export_list_size(code_ix); i++) {
+ num_exps = export_list_size(code_ix);
+ for (i = 0; i < num_exps; i++) {
Export *ep = export_list(i, code_ix);
if (ep == NULL || ep->code[0] != module) {
continue;
@@ -5754,12 +5754,13 @@ exported_from_module(Process* p, /* Process whose heap to use. */
ErtsCodeIndex code_ix,
Eterm mod) /* Tagged atom for module. */
{
- int i;
+ int i, num_exps;
Eterm* hp = NULL;
Eterm* hend = NULL;
Eterm result = NIL;
- for (i = 0; i < export_list_size(code_ix); i++) {
+ num_exps = export_list_size(code_ix);
+ for (i = 0; i < num_exps; i++) {
Export* ep = export_list(i,code_ix);
if (ep->code[0] == mod) {
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 3c19e82b66..dfbe1ced47 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -44,23 +44,22 @@
static void process_killer(void);
void do_break(void);
void erl_crash_dump_v(char *file, int line, char* fmt, va_list args);
-void erl_crash_dump(char* file, int line, char* fmt, ...);
#ifdef DEBUG
static void bin_check(void);
#endif
-static void print_garb_info(int to, void *to_arg, Process* p);
+static void print_garb_info(fmtfn_t to, void *to_arg, Process* p);
#ifdef OPPROF
static void dump_frequencies(void);
#endif
-static void dump_attributes(int to, void *to_arg, byte* ptr, int size);
+static void dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size);
extern char* erts_system_version[];
static void
-port_info(int to, void *to_arg)
+port_info(fmtfn_t to, void *to_arg)
{
int i, max = erts_ptab_max(&erts_port);
for (i = 0; i < max; i++) {
@@ -71,7 +70,7 @@ port_info(int to, void *to_arg)
}
void
-process_info(int to, void *to_arg)
+process_info(fmtfn_t to, void *to_arg)
{
int i, max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
@@ -148,14 +147,14 @@ process_killer(void)
typedef struct {
int is_first;
- int to;
+ fmtfn_t to;
void *to_arg;
} PrintMonitorContext;
static void doit_print_link(ErtsLink *lnk, void *vpcontext)
{
PrintMonitorContext *pcontext = vpcontext;
- int to = pcontext->to;
+ fmtfn_t to = pcontext->to;
void *to_arg = pcontext->to_arg;
if (pcontext->is_first) {
@@ -170,7 +169,7 @@ static void doit_print_link(ErtsLink *lnk, void *vpcontext)
static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext)
{
PrintMonitorContext *pcontext = vpcontext;
- int to = pcontext->to;
+ fmtfn_t to = pcontext->to;
void *to_arg = pcontext->to_arg;
char *prefix = ", ";
@@ -197,7 +196,7 @@ static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext)
/* Display info about an individual Erlang process */
void
-print_process_info(int to, void *to_arg, Process *p)
+print_process_info(fmtfn_t to, void *to_arg, Process *p)
{
time_t approx_started;
int garbing = 0;
@@ -300,7 +299,7 @@ print_process_info(int to, void *to_arg, Process *p)
/* display the links only if there are any*/
if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p)) {
- PrintMonitorContext context = {1,to};
+ PrintMonitorContext context = {1, to, to_arg};
erts_print(to, to_arg,"Link list: [");
erts_doforall_links(ERTS_P_LINKS(p), &doit_print_link, &context);
erts_doforall_monitors(ERTS_P_MONITORS(p), &doit_print_monitor, &context);
@@ -348,7 +347,7 @@ print_process_info(int to, void *to_arg, Process *p)
}
static void
-print_garb_info(int to, void *to_arg, Process* p)
+print_garb_info(fmtfn_t to, void *to_arg, Process* p)
{
#ifdef ERTS_SMP
/* ERTS_SMP: A scheduler is probably concurrently doing gc... */
@@ -365,7 +364,7 @@ print_garb_info(int to, void *to_arg, Process* p)
}
void
-info(int to, void *to_arg)
+info(fmtfn_t to, void *to_arg)
{
erts_memory(&to, to_arg, NULL, THE_NON_VALUE);
atom_info(to, to_arg);
@@ -381,7 +380,7 @@ info(int to, void *to_arg)
}
void
-loaded(int to, void *to_arg)
+loaded(fmtfn_t to, void *to_arg)
{
int i;
int old = 0;
@@ -478,7 +477,7 @@ loaded(int to, void *to_arg)
static void
-dump_attributes(int to, void *to_arg, byte* ptr, int size)
+dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size)
{
while (size-- > 0) {
erts_print(to, to_arg, "%02X", *ptr++);
@@ -662,6 +661,26 @@ bin_check(void)
#endif
+static Sint64 crash_dump_limit = ERTS_SINT64_MAX;
+static Sint64 crash_dump_written = 0;
+
+static int crash_dump_limited_writer(void* vfdp, char* buf, size_t len)
+{
+ const char stop_msg[] = "\n=abort:CRASH DUMP SIZE LIMIT REACHED\n";
+
+ crash_dump_written += len;
+ if (crash_dump_written <= crash_dump_limit) {
+ return erts_write_fd(vfdp, buf, len);
+ }
+
+ len -= (crash_dump_written - crash_dump_limit);
+ erts_write_fd(vfdp, buf, len);
+ erts_write_fd(vfdp, (char*)stop_msg, sizeof(stop_msg)-1);
+
+ /* We assume that crash dump was called from erts_exit_vv() */
+ erts_exit_epilogue();
+}
+
/* XXX THIS SHOULD BE IN SYSTEM !!!! */
void
erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
@@ -679,6 +698,8 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
int secs;
int env_erl_crash_dump_seconds_set = 1;
int i;
+ fmtfn_t to = &erts_write_fd;
+ void* to_arg;
if (ERTS_SOMEONE_IS_CRASH_DUMPING)
return;
@@ -759,6 +780,21 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
return;
}
+ crash_dump_limit = ERTS_SINT64_MAX;
+ envsz = sizeof(env);
+ if (erts_sys_getenv__("ERL_CRASH_DUMP_BYTES", env, &envsz) == 0) {
+ Sint64 limit;
+ char* endptr;
+ errno = 0;
+ limit = ErtsStrToSint64(env, &endptr, 10);
+ if (errno == 0 && limit >= 0 && endptr != env && *endptr == 0) {
+ if (limit == 0)
+ return;
+ crash_dump_limit = limit;
+ to = &crash_dump_limited_writer;
+ }
+ }
+
if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0)
dumpname = "erl_crash.dump";
else
@@ -769,39 +805,40 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640);
if (fd < 0)
return; /* Can't create the crash dump, skip it */
+ to_arg = (void*)&fd;
time(&now);
- erts_fdprintf(fd, "=erl_crash_dump:0.3\n%s", ctime(&now));
+ erts_cbprintf(to, to_arg, "=erl_crash_dump:0.3\n%s", ctime(&now));
if (file != NULL)
- erts_fdprintf(fd, "The error occurred in file %s, line %d\n", file, line);
+ erts_cbprintf(to, to_arg, "The error occurred in file %s, line %d\n", file, line);
if (fmt != NULL && *fmt != '\0') {
- erts_fdprintf(fd, "Slogan: ");
- erts_vfdprintf(fd, fmt, args);
+ erts_cbprintf(to, to_arg, "Slogan: ");
+ erts_vcbprintf(to, to_arg, fmt, args);
}
- erts_fdprintf(fd, "System version: ");
- erts_print_system_version(fd, NULL, NULL);
+ erts_cbprintf(to, to_arg, "System version: ");
+ erts_print_system_version(to, to_arg, NULL);
#if ERTS_SAVED_COMPILE_TIME
- erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE);
+ erts_cbprintf(to, to_arg, "%s\n", "Compiled: " ERLANG_COMPILE_DATE);
#endif
- erts_fdprintf(fd, "Taints: ");
- erts_print_nif_taints(fd, NULL);
- erts_fdprintf(fd, "Atoms: %d\n", atom_table_size());
+ erts_cbprintf(to, to_arg, "Taints: ");
+ erts_print_nif_taints(to, to_arg);
+ erts_cbprintf(to, to_arg, "Atoms: %d\n", atom_table_size());
#ifdef USE_THREADS
/* We want to note which thread it was that called erts_exit */
if (erts_get_scheduler_data()) {
- erts_fdprintf(fd, "Calling Thread: scheduler:%d\n",
+ erts_cbprintf(to, to_arg, "Calling Thread: scheduler:%d\n",
erts_get_scheduler_data()->no);
} else {
if (!erts_thr_getname(erts_thr_self(), dumpnamebuf, MAXPATHLEN))
- erts_fdprintf(fd, "Calling Thread: %s\n", dumpnamebuf);
+ erts_cbprintf(to, to_arg, "Calling Thread: %s\n", dumpnamebuf);
else
- erts_fdprintf(fd, "Calling Thread: %p\n", erts_thr_self());
+ erts_cbprintf(to, to_arg, "Calling Thread: %p\n", erts_thr_self());
}
#else
- erts_fdprintf(fd, "Calling Thread: scheduler:1\n");
+ erts_cbprintf(to, to_arg, "Calling Thread: scheduler:1\n");
#endif
#if defined(ERTS_HAVE_TRY_CATCH)
@@ -816,8 +853,8 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
*/
for (i = 0; i < erts_no_schedulers; i++) {
ERTS_SYS_TRY_CATCH(
- erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i)),
- erts_fdprintf(fd, "** crashed **\n"));
+ erts_print_scheduler_info(to, to_arg, ERTS_SCHEDULER_IX(i)),
+ erts_cbprintf(to, to_arg, "** crashed **\n"));
}
#endif
@@ -848,48 +885,39 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
#ifndef ERTS_HAVE_TRY_CATCH
/* This is safe to call here, as all schedulers are blocked */
for (i = 0; i < erts_no_schedulers; i++) {
- erts_print_scheduler_info(fd, NULL, ERTS_SCHEDULER_IX(i));
+ erts_print_scheduler_info(to, to_arg, ERTS_SCHEDULER_IX(i));
}
#endif
- info(fd, NULL); /* General system info */
+ info(to, to_arg); /* General system info */
if (erts_ptab_initialized(&erts_proc))
- process_info(fd, NULL); /* Info about each process and port */
- db_info(fd, NULL, 0);
- erts_print_bif_timer_info(fd, NULL);
- distribution_info(fd, NULL);
- erts_fdprintf(fd, "=loaded_modules\n");
- loaded(fd, NULL);
- erts_dump_fun_entries(fd, NULL);
- erts_deep_process_dump(fd, NULL);
- erts_fdprintf(fd, "=atoms\n");
- dump_atoms(fd, NULL);
+ process_info(to, to_arg); /* Info about each process and port */
+ db_info(to, to_arg, 0);
+ erts_print_bif_timer_info(to, to_arg);
+ distribution_info(to, to_arg);
+ erts_cbprintf(to, to_arg, "=loaded_modules\n");
+ loaded(to, to_arg);
+ erts_dump_fun_entries(to, to_arg);
+ erts_deep_process_dump(to, to_arg);
+ erts_cbprintf(to, to_arg, "=atoms\n");
+ dump_atoms(to, to_arg);
/* Keep the instrumentation data at the end of the dump */
if (erts_instr_memory_map || erts_instr_stat) {
- erts_fdprintf(fd, "=instr_data\n");
+ erts_cbprintf(to, to_arg, "=instr_data\n");
if (erts_instr_stat) {
- erts_fdprintf(fd, "=memory_status\n");
- erts_instr_dump_stat_to_fd(fd, 0);
+ erts_cbprintf(to, to_arg, "=memory_status\n");
+ erts_instr_dump_stat_to(to, to_arg, 0);
}
if (erts_instr_memory_map) {
- erts_fdprintf(fd, "=memory_map\n");
- erts_instr_dump_memory_map_to_fd(fd);
+ erts_cbprintf(to, to_arg, "=memory_map\n");
+ erts_instr_dump_memory_map_to(to, to_arg);
}
}
- erts_fdprintf(fd, "=end\n");
+ erts_cbprintf(to, to_arg, "=end\n");
close(fd);
erts_fprintf(stderr,"done\n");
}
-void
-erl_crash_dump(char* file, int line, char* fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- erl_crash_dump_v(file, line, fmt, args);
- va_end(args);
-}
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 09c83f1117..d79245e0e6 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -2402,13 +2402,13 @@ erts_kill_dist_connection(DistEntry *dep, Uint32 connection_id)
}
struct print_to_data {
- int to;
+ fmtfn_t to;
void *arg;
};
static void doit_print_monitor_info(ErtsMonitor *mon, void *vptdp)
{
- int to = ((struct print_to_data *) vptdp)->to;
+ fmtfn_t to = ((struct print_to_data *) vptdp)->to;
void *arg = ((struct print_to_data *) vptdp)->arg;
Process *rp;
ErtsMonitor *rmon;
@@ -2431,7 +2431,7 @@ static void doit_print_monitor_info(ErtsMonitor *mon, void *vptdp)
}
}
-static void print_monitor_info(int to, void *arg, ErtsMonitor *mon)
+static void print_monitor_info(fmtfn_t to, void *arg, ErtsMonitor *mon)
{
struct print_to_data ptd = {to, arg};
erts_doforall_monitors(mon,&doit_print_monitor_info,&ptd);
@@ -2457,7 +2457,7 @@ static void doit_print_link_info(ErtsLink *lnk, void *vptdp)
}
}
-static void print_link_info(int to, void *arg, ErtsLink *lnk)
+static void print_link_info(fmtfn_t to, void *arg, ErtsLink *lnk)
{
struct print_to_data ptd = {to, arg};
erts_doforall_links(lnk, &doit_print_link_info, (void *) &ptd);
@@ -2478,7 +2478,7 @@ static void doit_print_nodelink_info(ErtsLink *lnk, void *vpcontext)
"Remote monitoring: %T %T\n", lnk->pid, pcontext->sysname);
}
-static void print_nodelink_info(int to, void *arg, ErtsLink *lnk, Eterm sysname)
+static void print_nodelink_info(fmtfn_t to, void *arg, ErtsLink *lnk, Eterm sysname)
{
PrintNodeLinkContext context = {{to, arg}, sysname};
erts_doforall_links(lnk, &doit_print_nodelink_info, &context);
@@ -2486,7 +2486,7 @@ static void print_nodelink_info(int to, void *arg, ErtsLink *lnk, Eterm sysname)
static int
-info_dist_entry(int to, void *arg, DistEntry *dep, int visible, int connected)
+info_dist_entry(fmtfn_t to, void *arg, DistEntry *dep, int visible, int connected)
{
if (visible && connected) {
@@ -2535,7 +2535,7 @@ info_dist_entry(int to, void *arg, DistEntry *dep, int visible, int connected)
return 0;
}
-int distribution_info(int to, void *arg) /* Called by break handler */
+int distribution_info(fmtfn_t to, void *arg) /* Called by break handler */
{
DistEntry *dep;
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index eda3ad870a..4ebe37ee1d 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -54,7 +54,7 @@ static void link_free_block (Allctr_t *, Block_t *);
static void unlink_free_block (Allctr_t *, Block_t *);
-static Eterm info_options (Allctr_t *, char *, int *,
+static Eterm info_options (Allctr_t *, char *, fmtfn_t *,
void *arg, Uint **, Uint *);
static void init_atoms (void);
@@ -227,7 +227,7 @@ add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
static Eterm
info_options(Allctr_t *allctr,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 3c2c9def3b..214fb1f2af 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -2113,7 +2113,7 @@ add_fix_values(UWord *ap, UWord *up, ErtsAlcUFixInfo_t *fi, ErtsAlcType_t type)
}
Eterm
-erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
+erts_memory(fmtfn_t *print_to_p, void *print_to_arg, void *proc, Eterm earg)
{
/*
* NOTE! When updating this function, make sure to also update
@@ -2476,7 +2476,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
if (print_to_p) {
int i;
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
/* Print result... */
@@ -2530,7 +2530,7 @@ struct aa_values {
};
Eterm
-erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
+erts_allocated_areas(fmtfn_t *print_to_p, void *print_to_arg, void *proc)
{
#define MAX_AA_VALUES (24)
struct aa_values values[MAX_AA_VALUES];
@@ -2665,7 +2665,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
if (print_to_p) {
/* Print result... */
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to, arg, "=allocated_areas\n");
@@ -2779,7 +2779,7 @@ erts_alloc_util_allocators(void *proc)
}
void
-erts_allocator_info(int to, void *arg)
+erts_allocator_info(fmtfn_t to, void *arg)
{
ErtsAlcType_t a;
@@ -3110,7 +3110,7 @@ reply_alloc_info(void *vair)
Eterm (*info_func)(Allctr_t *,
int,
int,
- int *,
+ fmtfn_t *,
void *,
Uint **,
Uint *) = (air->only_sz
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index 925a081a02..56a3b73bf9 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -69,11 +69,11 @@ void *erts_sys_aligned_realloc(UWord alignment, void *ptr, UWord size, UWord old
void erts_sys_aligned_free(UWord alignment, void *ptr);
#endif
-Eterm erts_memory(int *, void *, void *, Eterm);
-Eterm erts_allocated_areas(int *, void *, void *);
+Eterm erts_memory(fmtfn_t *, void *, void *, Eterm);
+Eterm erts_allocated_areas(fmtfn_t *, void *, void *);
Eterm erts_alloc_util_allocators(void *proc);
-void erts_allocator_info(int, void *);
+void erts_allocator_info(fmtfn_t, void *);
Eterm erts_allocator_options(void *proc);
struct process;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 2995f2f822..230ca6ccbb 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -4153,9 +4153,9 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp)
ASSERT(IS_LAST_BLK(blk));
#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
- (*allctr->link_free_block)(allctr, blk, 0);
+ (*allctr->link_free_block)(allctr, blk);
HARD_CHECK_BLK_CARRIER(allctr, blk);
- (*allctr->unlink_free_block)(allctr, blk, 0);
+ (*allctr->unlink_free_block)(allctr, blk);
#endif
}
#endif
@@ -4473,7 +4473,7 @@ add_fix_types(Allctr_t *allctr, int internal, Uint **hpp, Uint *szp,
static Eterm
sz_info_fix(Allctr_t *allctr,
int internal,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -4494,7 +4494,7 @@ sz_info_fix(Allctr_t *allctr,
UWord used = fix->type_size * fix->u.cpool.used;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to,
arg,
@@ -4522,7 +4522,7 @@ sz_info_fix(Allctr_t *allctr,
UWord used = fix->type_size*fix->u.nocpool.used;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to,
arg,
@@ -4548,7 +4548,7 @@ static Eterm
sz_info_carriers(Allctr_t *allctr,
CarriersStats_t *cs,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -4557,7 +4557,7 @@ sz_info_carriers(Allctr_t *allctr,
UWord curr_size = cs->curr.norm.mseg.size + cs->curr.norm.sys_alloc.size;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to,
arg,
@@ -4598,7 +4598,7 @@ static Eterm
info_cpool(Allctr_t *allctr,
int sz_only,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -4615,7 +4615,7 @@ info_cpool(Allctr_t *allctr,
}
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
if (!sz_only)
erts_print(to, arg, "%sblocks: %bpu\n", prefix, nob);
@@ -4652,7 +4652,7 @@ static Eterm
info_carriers(Allctr_t *allctr,
CarriersStats_t *cs,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -4664,7 +4664,7 @@ info_carriers(Allctr_t *allctr,
curr_size = cs->curr.norm.mseg.size + cs->curr.norm.sys_alloc.size;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to,
arg,
@@ -4790,7 +4790,7 @@ make_name_atoms(Allctr_t *allctr)
static Eterm
info_calls(Allctr_t *allctr,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -4807,7 +4807,7 @@ info_calls(Allctr_t *allctr,
erts_print(TO, TOA, "%s%s calls: %b64u\n",PRFX,NAME,CC)
char *prefix = allctr->name_prefix;
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
PRINT_CC_5(to, arg, prefix, "alloc", allctr->calls.this_alloc);
@@ -4883,7 +4883,7 @@ info_calls(Allctr_t *allctr,
static Eterm
info_options(Allctr_t *allctr,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -5035,7 +5035,7 @@ reset_max_values(CarriersStats_t *cs)
\* */
Eterm
-erts_alcu_au_info_options(int *print_to_p, void *print_to_arg,
+erts_alcu_au_info_options(fmtfn_t *print_to_p, void *print_to_arg,
Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -5078,7 +5078,7 @@ erts_alcu_au_info_options(int *print_to_p, void *print_to_arg,
Eterm
erts_alcu_info_options(Allctr_t *allctr,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -5110,7 +5110,7 @@ Eterm
erts_alcu_sz_info(Allctr_t *allctr,
int internal,
int begin_max_period,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -5196,7 +5196,7 @@ Eterm
erts_alcu_info(Allctr_t *allctr,
int internal,
int begin_max_period,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -6440,11 +6440,6 @@ check_blk_carrier(Allctr_t *allctr, Block_t *iblk)
ASSERT(SBC2BLK(allctr, sbc) == iblk);
ASSERT(CARRIER_SZ(sbc) - SBC_HEADER_SIZE >= SBC_BLK_SZ(iblk));
-#if HAVE_ERTS_MSEG
- if (IS_MSEG_CARRIER(sbc)) {
- ASSERT(CARRIER_SZ(sbc) % ERTS_SACRR_UNIT_SZ == 0);
- }
-#endif
crr = sbc;
cl = &allctr->sbc_list;
}
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index f50f09907a..81180382af 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -178,10 +178,10 @@ void * erts_alcu_realloc_mv_thr_pref(ErtsAlcType_t, void *, void *, Uint);
void erts_alcu_free_thr_pref(ErtsAlcType_t, void *, void *);
#endif
#endif
-Eterm erts_alcu_au_info_options(int *, void *, Uint **, Uint *);
-Eterm erts_alcu_info_options(Allctr_t *, int *, void *, Uint **, Uint *);
-Eterm erts_alcu_sz_info(Allctr_t *, int, int, int *, void *, Uint **, Uint *);
-Eterm erts_alcu_info(Allctr_t *, int, int, int *, void *, Uint **, Uint *);
+Eterm erts_alcu_au_info_options(fmtfn_t *, void *, Uint **, Uint *);
+Eterm erts_alcu_info_options(Allctr_t *, fmtfn_t *, void *, Uint **, Uint *);
+Eterm erts_alcu_sz_info(Allctr_t *, int, int, fmtfn_t *, void *, Uint **, Uint *);
+Eterm erts_alcu_info(Allctr_t *, int, int, fmtfn_t *, void *, Uint **, Uint *);
void erts_alcu_init(AlcUInit_t *);
void erts_alcu_current_size(Allctr_t *, AllctrSize_t *,
ErtsAlcUFixInfo_t *, int);
@@ -586,7 +586,7 @@ struct Allctr_t_ {
Block_t *, Uint);
void (*link_free_block) (Allctr_t *, Block_t *);
void (*unlink_free_block) (Allctr_t *, Block_t *);
- Eterm (*info_options) (Allctr_t *, char *, int *,
+ Eterm (*info_options) (Allctr_t *, char *, fmtfn_t *,
void *, Uint **, Uint *);
Uint (*get_next_mbc_size) (Allctr_t *);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 7e239d1f5d..05ba1f9891 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -224,7 +224,7 @@ static AOFF_RBTree_t* rbt_search(AOFF_RBTree_t* root, Uint size);
static int rbt_assert_is_member(AOFF_RBTree_t* root, AOFF_RBTree_t* node);
#endif
-static Eterm info_options(Allctr_t *, char *, int *, void *, Uint **, Uint *);
+static Eterm info_options(Allctr_t *, char *, fmtfn_t *, void *, Uint **, Uint *);
static void init_atoms(void);
@@ -1014,7 +1014,7 @@ add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
static Eterm
info_options(Allctr_t *allctr,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 379cee39a1..6173c408e1 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -104,7 +104,7 @@ static void bf_link_free_block (Allctr_t *, Block_t *);
static ERTS_INLINE void bf_unlink_free_block (Allctr_t *, Block_t *);
-static Eterm info_options (Allctr_t *, char *, int *,
+static Eterm info_options (Allctr_t *, char *, fmtfn_t *,
void *, Uint **, Uint *);
static void init_atoms (void);
@@ -921,7 +921,7 @@ add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
static Eterm
info_options(Allctr_t *allctr,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 29ba12dfdb..88a052cad7 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -317,7 +317,7 @@ make_link_list(Process *p, ErtsLink *root, Eterm tail)
}
int
-erts_print_system_version(int to, void *arg, Process *c_p)
+erts_print_system_version(fmtfn_t to, void *arg, Process *c_p)
{
int i, rc = -1;
char *rc_str = "";
@@ -1672,11 +1672,11 @@ current_stacktrace(Process* p, Process* rp, Eterm** hpp)
Eterm mfa;
Eterm res = NIL;
- depth = 8;
+ depth = erts_backtrace_depth;
sz = offsetof(struct StackTrace, trace) + sizeof(BeamInstr *)*depth;
s = (struct StackTrace *) erts_alloc(ERTS_ALC_T_TMP, sz);
s->depth = 0;
- if (rp->i) {
+ if (depth > 0 && rp->i) {
s->trace[s->depth++] = rp->i;
depth--;
}
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 96275eb228..0627526d7e 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1062,9 +1062,16 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
erts_smp_thr_progress_block();
}
#endif
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_smp_mtx_lock(&erts_dirty_bp_ix_mtx);
+#endif
+
r = function_is_traced(p, mfa, &ms, &ms_meta, &meta, &count, &call_time);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_smp_mtx_unlock(&erts_dirty_bp_ix_mtx);
+#endif
#ifdef ERTS_SMP
if ( (key == am_call_time) || (key == am_all)) {
erts_smp_thr_progress_unblock();
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 128a7b3865..dceadc46f4 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -201,7 +201,7 @@ static int free_table_cont(Process *p,
DbTable *tb,
int first,
int clean_meta_tab);
-static void print_table(int to, void *to_arg, int show, DbTable* tb);
+static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb);
static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1);
static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1);
static BIF_RETTYPE ets_select_trap_1(BIF_ALIST_1);
@@ -3871,7 +3871,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
return ret;
}
-static void print_table(int to, void *to_arg, int show, DbTable* tb)
+static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb)
{
erts_print(to, to_arg, "Table: %T\n", tb->common.id);
erts_print(to, to_arg, "Name: %T\n", tb->common.the_name);
@@ -3891,7 +3891,7 @@ static void print_table(int to, void *to_arg, int show, DbTable* tb)
erts_print(to, to_arg, "Read Concurrency: %T\n", table_info(NULL, tb, am_read_concurrency));
}
-void db_info(int to, void *to_arg, int show) /* Called by break handler */
+void db_info(fmtfn_t to, void *to_arg, int show) /* Called by break handler */
{
int i;
for (i=0; i < db_max_tabs; i++)
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index 1d26c49652..b0508f2e74 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -74,7 +74,7 @@ typedef enum {
void init_db(ErtsDbSpinCount);
int erts_db_process_exiting(Process *, ErtsProcLocks);
-void db_info(int, void *, int);
+void db_info(fmtfn_t, void *, int);
void erts_db_foreach_table(void (*)(DbTable *, void *), void *);
void erts_db_foreach_offheap(DbTable *,
void (*func)(ErlOffHeap *, void *),
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 5e6fe4f460..390369fdb9 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -437,7 +437,7 @@ static int db_select_count_continue_hash(Process *p, DbTable *tbl,
static int db_select_delete_continue_hash(Process *p, DbTable *tbl,
Eterm continuation, Eterm *ret);
static int db_take_hash(Process *, DbTable *, Eterm, Eterm *);
-static void db_print_hash(int to,
+static void db_print_hash(fmtfn_t to,
void *to_arg,
int show,
DbTable *tbl);
@@ -2155,7 +2155,7 @@ int db_mark_all_deleted_hash(DbTable *tbl)
/* Display hash table contents (for dump) */
-static void db_print_hash(int to, void *to_arg, int show, DbTable *tbl)
+static void db_print_hash(fmtfn_t to, void *to_arg, int show, DbTable *tbl)
{
DbTableHash *tb = &tbl->hash;
DbHashStats stats;
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 02d211a4bb..dd9403e132 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -385,7 +385,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl,
static int db_select_delete_continue_tree(Process *p, DbTable *tbl,
Eterm continuation, Eterm *ret);
static int db_take_tree(Process *, DbTable *, Eterm, Eterm *);
-static void db_print_tree(int to, void *to_arg,
+static void db_print_tree(fmtfn_t to, void *to_arg,
int show, DbTable *tbl);
static int db_free_table_tree(DbTable *tbl);
@@ -1740,7 +1740,7 @@ static int db_take_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
/* Display tree contents (for dump) */
-static void db_print_tree(int to, void *to_arg,
+static void db_print_tree(fmtfn_t to, void *to_arg,
int show,
DbTable *tbl)
{
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 4acedbfed0..49e5f6b4cf 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -175,7 +175,7 @@ typedef struct db_table_method
int (*db_free_table)(DbTable* db /* [in out] */ );
int (*db_free_table_continue)(DbTable* db); /* [in out] */
- void (*db_print)(int to,
+ void (*db_print)(fmtfn_t to,
void* to_arg,
int show,
DbTable* tb /* [in out] */ );
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 3e3bfa03a2..3526bb684d 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -60,10 +60,10 @@ static const char dashes[PTR_SIZE+3] = {
void pps(Process*, Eterm*);
void ptd(Process*, Eterm);
-void paranoid_display(int, void*, Process*, Eterm);
+void paranoid_display(fmtfn_t, void*, Process*, Eterm);
static int dcount;
-static int pdisplay1(int to, void *to_arg, Process* p, Eterm obj);
+static int pdisplay1(fmtfn_t to, void *to_arg, Process* p, Eterm obj);
void ptd(Process* p, Eterm x)
{
@@ -77,14 +77,14 @@ void ptd(Process* p, Eterm x)
*/
void
-paranoid_display(int to, void *to_arg, Process* p, Eterm obj)
+paranoid_display(fmtfn_t to, void *to_arg, Process* p, Eterm obj)
{
dcount = 100000;
pdisplay1(to, to_arg, p, obj);
}
static int
-pdisplay1(int to, void *to_arg, Process* p, Eterm obj)
+pdisplay1(fmtfn_t to, void *to_arg, Process* p, Eterm obj)
{
int i, k;
Eterm* nobj;
@@ -201,7 +201,7 @@ pdisplay1(int to, void *to_arg, Process* p, Eterm obj)
void
pps(Process* p, Eterm* stop)
{
- int to = ERTS_PRINT_STDOUT;
+ fmtfn_t to = ERTS_PRINT_STDOUT;
void *to_arg = NULL;
Eterm* sp = STACK_START(p) - 1;
diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c
index 5258d83a18..d0a57f0ad0 100644
--- a/erts/emulator/beam/erl_fun.c
+++ b/erts/emulator/beam/erl_fun.c
@@ -74,7 +74,7 @@ erts_init_fun_table(void)
}
void
-erts_fun_info(int to, void *to_arg)
+erts_fun_info(fmtfn_t to, void *to_arg)
{
int lock = !ERTS_IS_CRASH_DUMPING;
if (lock)
@@ -263,7 +263,7 @@ erts_fun_purge_complete(ErlFunEntry **funs, Uint no)
}
void
-erts_dump_fun_entries(int to, void *to_arg)
+erts_dump_fun_entries(fmtfn_t to, void *to_arg)
{
int limit;
HashBucket** bucket;
diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h
index 73c3e19c1c..caa55c730c 100644
--- a/erts/emulator/beam/erl_fun.h
+++ b/erts/emulator/beam/erl_fun.h
@@ -71,7 +71,7 @@ typedef struct erl_fun_thing {
#define ERL_FUN_SIZE ((sizeof(ErlFunThing)/sizeof(Eterm))-1)
void erts_init_fun_table(void);
-void erts_fun_info(int, void *);
+void erts_fun_info(fmtfn_t, void *);
int erts_fun_table_sz(void);
ErlFunEntry* erts_put_fun_entry(Eterm mod, int uniq, int index);
@@ -86,6 +86,6 @@ void erts_fun_purge_prepare(BeamInstr* start, BeamInstr* end);
void erts_fun_purge_abort_prepare(ErlFunEntry **funs, Uint no);
void erts_fun_purge_abort_finalize(ErlFunEntry **funs, Uint no);
void erts_fun_purge_complete(ErlFunEntry **funs, Uint no);
-void erts_dump_fun_entries(int, void *);
+void erts_dump_fun_entries(fmtfn_t, void *);
#endif
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 6f641a1ea7..edbdbb4b8f 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -59,6 +59,10 @@
# define ERTS_GC_ASSERT(B) ((void) 1)
#endif
+#if defined(DEBUG) && 0
+# define HARDDEBUG 1
+#endif
+
/*
* Returns number of elements in an array.
*/
@@ -110,7 +114,6 @@ typedef struct {
static Uint setup_rootset(Process*, Eterm*, int, Rootset*);
static void cleanup_rootset(Rootset *rootset);
-static void remove_message_buffers(Process* p);
static Eterm *full_sweep_heaps(Process *p,
int hibernate,
Eterm *n_heap, Eterm* n_htop,
@@ -153,7 +156,7 @@ static void init_gc_info(ErtsGCInfo *gcip);
static Uint64 next_vheap_size(Process* p, Uint64 vheap, Uint64 vheap_sz);
#ifdef HARDDEBUG
-static void disallow_heap_frag_ref_in_heap(Process* p);
+static void disallow_heap_frag_ref_in_heap(Process *p, Eterm *heap, Eterm *htop);
static void disallow_heap_frag_ref_in_old_heap(Process* p);
#endif
@@ -176,6 +179,13 @@ typedef struct {
erts_smp_atomic32_t refc;
} ErtsGCInfoReq;
+#ifdef ERTS_DIRTY_SCHEDULERS
+static struct {
+ erts_mtx_t mtx;
+ ErtsGCInfo info;
+} dirty_gc;
+#endif
+
static ERTS_INLINE int
gc_cost(Uint gc_moved_live_words, Uint resize_moved_words)
{
@@ -259,6 +269,11 @@ erts_init_gc(void)
init_gc_info(&esdp->gc_info);
}
+#ifdef ERTS_DIRTY_SCHEDULERS
+ erts_smp_mtx_init(&dirty_gc.mtx, "dirty_gc_info");
+ init_gc_info(&dirty_gc.info);
+#endif
+
init_gcireq_alloc();
}
@@ -477,24 +492,26 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int
hsz = ssz + need + ERTS_DELAY_GC_EXTRA_FREE;
hfrag = new_message_buffer(hsz);
- hfrag->next = p->mbuf;
- p->mbuf = hfrag;
- p->mbuf_sz += hsz;
p->heap = p->htop = &hfrag->mem[0];
p->hend = hend = &hfrag->mem[hsz];
p->stop = stop = hend - ssz;
sys_memcpy((void *) stop, (void *) orig_stop, ssz * sizeof(Eterm));
if (p->abandoned_heap) {
- /* Active heap already in a fragment; adjust it... */
- ErlHeapFragment *hfrag = ((ErlHeapFragment *)
- (((char *) orig_heap)
- - offsetof(ErlHeapFragment, mem)));
- Uint unused = orig_hend - orig_htop;
- ASSERT(hfrag->used_size == hfrag->alloc_size);
- ASSERT(hfrag->used_size >= unused);
- hfrag->used_size -= unused;
- p->mbuf_sz -= unused;
+ /*
+ * Active heap already in a fragment; adjust it and
+ * save it into mbuf list...
+ */
+ ErlHeapFragment *hfrag = ((ErlHeapFragment *)
+ (((char *) orig_heap)
+ - offsetof(ErlHeapFragment, mem)));
+ Uint used = orig_htop - orig_heap;
+ hfrag->used_size = used;
+ p->mbuf_sz += used;
+ ASSERT(hfrag->used_size <= hfrag->alloc_size);
+ ASSERT(!hfrag->off_heap.first && !hfrag->off_heap.overhead);
+ hfrag->next = p->mbuf;
+ p->mbuf = hfrag;
}
else {
/* Do not leave a hole in the abandoned heap... */
@@ -556,17 +573,14 @@ young_gen_usage(Process *p)
}
}
+ hsz += p->htop - p->heap;
aheap = p->abandoned_heap;
- if (!aheap)
- hsz += p->htop - p->heap;
- else {
+ if (aheap) {
/* used in orig heap */
if (p->flags & F_ABANDONED_HEAP_USE)
hsz += aheap[p->heap_sz-1];
else
hsz += p->heap_sz;
- /* Remove unused part in latest fragment */
- hsz -= p->hend - p->htop;
}
return hsz;
}
@@ -602,7 +616,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
Uint reclaimed_now = 0;
Eterm gc_trace_end_tag;
int reds;
- ErtsMonotonicTime start_time = 0; /* Shut up faulty warning... */
+ ErtsMonotonicTime start_time;
ErtsSchedulerData *esdp;
erts_aint32_t state;
ERTS_MSACC_PUSH_STATE_M();
@@ -610,6 +624,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE);
#endif
+ ERTS_UNDEF(start_time, 0);
ERTS_CHK_MBUF_SZ(p);
ASSERT(CONTEXT_REDS - ERTS_REDS_LEFT(p, fcalls)
@@ -735,8 +750,19 @@ do_major_collection:
monitor_large_heap(p);
}
- esdp->gc_info.garbage_cols++;
- esdp->gc_info.reclaimed += reclaimed_now;
+#ifdef ERTS_DIRTY_SCHEDULERS
+ if (ERTS_SCHEDULER_IS_DIRTY(esdp)) {
+ erts_mtx_lock(&dirty_gc.mtx);
+ dirty_gc.info.garbage_cols++;
+ dirty_gc.info.reclaimed += reclaimed_now;
+ erts_mtx_unlock(&dirty_gc.mtx);
+ }
+ else
+#endif
+ {
+ esdp->gc_info.garbage_cols++;
+ esdp->gc_info.reclaimed += reclaimed_now;
+ }
FLAGS(p) &= ~F_FORCE_GC;
p->live_hf_end = ERTS_INVALID_HFRAG_PTR;
@@ -765,6 +791,7 @@ do_major_collection:
ASSERT(!p->mbuf);
ASSERT(!ERTS_IS_GC_DESIRED(p));
+ ASSERT(need <= HEAP_LIMIT(p) - HEAP_TOP(p));
return reds;
}
@@ -789,6 +816,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
>= erts_proc_sched_data(p)->virtual_reds);
}
+
/*
* Place all living data on a the new heap; deallocate any old heap.
* Meant to be used by hibernate/3.
@@ -835,11 +863,11 @@ erts_garbage_collect_hibernate(Process* p)
p->arg_reg,
p->arity);
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : p->heap),
- p->heap_sz * sizeof(Eterm));
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, heap, htop);
+#endif
+
+ erts_deallocate_young_generation(p);
p->heap = heap;
p->high_water = htop;
@@ -874,8 +902,6 @@ erts_garbage_collect_hibernate(Process* p)
sys_memcpy((void *) heap, (void *) p->heap, actual_size*sizeof(Eterm));
ERTS_HEAP_FREE(ERTS_ALC_T_TMP_HEAP, p->heap, p->heap_sz*sizeof(Eterm));
- remove_message_buffers(p);
-
p->stop = p->hend = heap + heap_size;
offs = heap - p->heap;
@@ -1494,22 +1520,16 @@ do_minor(Process *p, ErlHeapFragment *live_hf_end,
}
#endif
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : HEAP_START(p)),
- HEAP_SIZE(p) * sizeof(Eterm));
- p->abandoned_heap = NULL;
- p->flags &= ~F_ABANDONED_HEAP_USE;
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, n_heap, n_htop);
+#endif
+
+ erts_deallocate_young_generation(p);
+
HEAP_START(p) = n_heap;
HEAP_TOP(p) = n_htop;
HEAP_SIZE(p) = new_sz;
HEAP_END(p) = n_heap + new_sz;
-
-#ifdef HARDDEBUG
- disallow_heap_frag_ref_in_heap(p);
-#endif
- remove_message_buffers(p);
}
/*
@@ -1598,13 +1618,12 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end,
}
#endif
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
- (p->abandoned_heap
- ? p->abandoned_heap
- : HEAP_START(p)),
- p->heap_sz * sizeof(Eterm));
- p->abandoned_heap = NULL;
- p->flags &= ~F_ABANDONED_HEAP_USE;
+#ifdef HARDDEBUG
+ disallow_heap_frag_ref_in_heap(p, n_heap, n_htop);
+#endif
+
+ erts_deallocate_young_generation(p);
+
HEAP_START(p) = n_heap;
HEAP_TOP(p) = n_htop;
HEAP_SIZE(p) = new_sz;
@@ -1613,11 +1632,6 @@ major_collection(Process* p, ErlHeapFragment *live_hf_end,
HIGH_WATER(p) = HEAP_TOP(p);
-#ifdef HARDDEBUG
- disallow_heap_frag_ref_in_heap(p);
-#endif
- remove_message_buffers(p);
-
if (p->flags & F_ON_HEAP_MSGQ)
move_msgq_to_heap(p);
@@ -1770,22 +1784,56 @@ adjust_after_fullsweep(Process *p, int need, Eterm *objv, int nobj)
return adjusted;
}
-/*
- * Remove all message buffers.
- */
-static void
-remove_message_buffers(Process* p)
+void
+erts_deallocate_young_generation(Process *c_p)
{
- if (MBUF(p) != NULL) {
- free_message_buffer(MBUF(p));
- MBUF(p) = NULL;
+ Eterm *orig_heap;
+
+ if (!c_p->abandoned_heap) {
+ orig_heap = c_p->heap;
+ ASSERT(!(c_p->flags & F_ABANDONED_HEAP_USE));
+ }
+ else {
+ ErlHeapFragment *hfrag;
+
+ orig_heap = c_p->abandoned_heap;
+ c_p->abandoned_heap = NULL;
+ c_p->flags &= ~F_ABANDONED_HEAP_USE;
+
+ /*
+ * Temporary heap located in heap fragment
+ * only referred to by 'c_p->heap'. Add it to
+ * 'c_p->mbuf' list and deallocate it as any
+ * other heap fragment...
+ */
+ hfrag = ((ErlHeapFragment *)
+ (((char *) c_p->heap)
+ - offsetof(ErlHeapFragment, mem)));
+
+ ASSERT(!hfrag->off_heap.first);
+ ASSERT(!hfrag->off_heap.overhead);
+ ASSERT(!hfrag->next);
+ ASSERT(c_p->htop - c_p->heap <= hfrag->alloc_size);
+
+ hfrag->next = c_p->mbuf;
+ c_p->mbuf = hfrag;
+ }
+
+ if (c_p->mbuf) {
+ free_message_buffer(c_p->mbuf);
+ c_p->mbuf = NULL;
}
- if (p->msg_frag) {
- erts_cleanup_messages(p->msg_frag);
- p->msg_frag = NULL;
+ if (c_p->msg_frag) {
+ erts_cleanup_messages(c_p->msg_frag);
+ c_p->msg_frag = NULL;
}
- MBUF_SIZE(p) = 0;
+ c_p->mbuf_sz = 0;
+
+ ERTS_HEAP_FREE(ERTS_ALC_T_HEAP,
+ orig_heap,
+ c_p->heap_sz * sizeof(Eterm));
}
+
#ifdef HARDDEBUG
/*
@@ -1797,19 +1845,15 @@ remove_message_buffers(Process* p)
*/
static void
-disallow_heap_frag_ref_in_heap(Process* p)
+disallow_heap_frag_ref_in_heap(Process *p, Eterm *heap, Eterm *htop)
{
Eterm* hp;
- Eterm* htop;
- Eterm* heap;
Uint heap_size;
if (p->mbuf == 0) {
return;
}
- htop = p->htop;
- heap = p->heap;
heap_size = (htop - heap)*sizeof(Eterm);
hp = heap;
@@ -2325,6 +2369,11 @@ move_msgq_to_heap(Process *p)
static Uint
setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset)
{
+ /*
+ * NOTE!
+ * Remember to update offset_rootset() when changing
+ * this function.
+ */
Roots* roots;
Uint n;
@@ -2969,6 +3018,12 @@ offset_one_rootset(Process *p, Sint offs, char* area, Uint area_size,
offset_heap_ptr(objv, nobj, offs, area, area_size);
}
offset_off_heap(p, offs, area, area_size);
+ if (ERTS_PROC_GET_NIF_TRAP_EXPORT(p)) {
+ Eterm* argv;
+ int argc;
+ if (erts_setup_nif_gc(p, &argv, &argc))
+ offset_heap_ptr(argv, argc, offs, area, area_size);
+ }
}
static void
@@ -3006,6 +3061,18 @@ reply_gc_info(void *vgcirp)
reclaimed = esdp->gc_info.reclaimed;
garbage_cols = esdp->gc_info.garbage_cols;
+#ifdef ERTS_DIRTY_SCHEDULERS
+ /*
+ * Add dirty schedulers info on requesting
+ * schedulers info
+ */
+ if (gcirp->req_sched == esdp->no) {
+ erts_mtx_lock(&dirty_gc.mtx);
+ reclaimed += dirty_gc.info.reclaimed;
+ garbage_cols += dirty_gc.info.garbage_cols;
+ erts_mtx_unlock(&dirty_gc.mtx);
+ }
+#endif
sz = 0;
hpp = NULL;
@@ -3286,13 +3353,15 @@ within2(Eterm *ptr, Process *p, Eterm *real_htop)
ErtsMessage* mp;
Eterm *htop, *heap;
- if (p->abandoned_heap)
+ if (p->abandoned_heap) {
ERTS_GET_ORIG_HEAP(p, heap, htop);
- else {
- heap = p->heap;
- htop = real_htop ? real_htop : HEAP_TOP(p);
+ if (heap <= ptr && ptr < htop)
+ return 1;
}
+ heap = p->heap;
+ htop = real_htop ? real_htop : HEAP_TOP(p);
+
if (OLD_HEAP(p) && (OLD_HEAP(p) <= ptr && ptr < OLD_HEND(p))) {
return 1;
}
diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h
index 54ea9ca3c0..2521379664 100644
--- a/erts/emulator/beam/erl_gc.h
+++ b/erts/emulator/beam/erl_gc.h
@@ -27,10 +27,6 @@
#include "erl_map.h"
-#if defined(DEBUG) && !ERTS_GLB_INLINE_INCL_FUNC_DEF
-# define HARDDEBUG 1
-#endif
-
#define IS_MOVED_BOXED(x) (!is_header((x)))
#define IS_MOVED_CONS(x) (is_non_value((x)))
@@ -157,5 +153,6 @@ void erts_offset_heap(Eterm*, Uint, Sint, Eterm*, Eterm*);
void erts_free_heap_frags(struct process* p);
Eterm erts_max_heap_size_map(Sint, Uint, Eterm **, Uint *);
int erts_max_heap_size(Eterm, Uint *, Uint *);
+void erts_deallocate_young_generation(Process *c_p);
#endif /* __ERL_GC_H__ */
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index 223ba193da..50aa41b4d2 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -168,7 +168,7 @@ static Block_t * get_free_block (Allctr_t *, Uint,
static void link_free_block (Allctr_t *, Block_t *);
static void unlink_free_block (Allctr_t *, Block_t *);
static void update_last_aux_mbc (Allctr_t *, Carrier_t *);
-static Eterm info_options (Allctr_t *, char *, int *,
+static Eterm info_options (Allctr_t *, char *, fmtfn_t *,
void *, Uint **, Uint *);
static void init_atoms (void);
@@ -551,7 +551,7 @@ add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
static Eterm
info_options(Allctr_t *allctr,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c
index f1bef28186..647fa26811 100644
--- a/erts/emulator/beam/erl_hl_timer.c
+++ b/erts/emulator/beam/erl_hl_timer.c
@@ -2666,7 +2666,7 @@ erts_start_timer_callback(ErtsMonotonicTime tmo,
tmo);
twt = tmo < ERTS_TIMER_WHEEL_MSEC;
- if (esdp)
+ if (esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp))
start_callback_timer(esdp,
twt,
timeout_pos,
@@ -2851,7 +2851,7 @@ erts_read_port_timer(Port *c_prt)
*/
typedef struct {
- int to;
+ fmtfn_t to;
void *to_arg;
ErtsMonotonicTime now;
} ErtsBTMPrint;
@@ -2865,7 +2865,8 @@ btm_print(ErtsHLTimer *tmr, void *vbtmp)
if (tmr->timeout <= btmp->now)
left = 0;
- left = ERTS_CLKTCKS_TO_MSEC(tmr->timeout - btmp->now);
+ else
+ left = ERTS_CLKTCKS_TO_MSEC(tmr->timeout - btmp->now);
receiver = ((tmr->head.roflgs & ERTS_TMR_ROFLG_REG_NAME)
? tmr->receiver.name
@@ -2881,7 +2882,7 @@ btm_print(ErtsHLTimer *tmr, void *vbtmp)
}
void
-erts_print_bif_timer_info(int to, void *to_arg)
+erts_print_bif_timer_info(fmtfn_t to, void *to_arg)
{
ErtsBTMPrint btmp;
int six;
diff --git a/erts/emulator/beam/erl_hl_timer.h b/erts/emulator/beam/erl_hl_timer.h
index 0931bb8965..9cdcd581a0 100644
--- a/erts/emulator/beam/erl_hl_timer.h
+++ b/erts/emulator/beam/erl_hl_timer.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2015. All Rights Reserved.
+ * Copyright Ericsson AB 2015-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ erts_handle_canceled_timers(void *vesdp,
#endif
Uint erts_bif_timer_memory_size(void);
-void erts_print_bif_timer_info(int to, void *to_arg);
+void erts_print_bif_timer_info(fmtfn_t to, void *to_arg);
void erts_debug_bif_timer_foreach(void (*func)(Eterm,
Eterm,
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 781bf024dd..2fd97208cc 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -795,9 +795,6 @@ early_init(int *argc, char **argv) /*
erts_thr_progress_pre_init();
#endif
-#ifdef ERTS_ENABLE_LOCK_CHECK
- erts_lc_init();
-#endif
#ifdef ERTS_SMP
erts_smp_atomic32_init_nob(&erts_writing_erl_crash_dump, 0L);
erts_tsd_key_create(&erts_is_crash_dumping_key,"erts_is_crash_dumping_key");
@@ -2374,6 +2371,8 @@ system_cleanup(int flush_async)
erts_exit_flush_async();
}
+static int erts_exit_code;
+
static __decl_noreturn void __noreturn
erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2)
{
@@ -2385,12 +2384,21 @@ erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2)
if (fmt != NULL && *fmt != '\0')
erl_error(fmt, args2); /* Print error message. */
- /* Produce an Erlang core dump if error */
+ erts_exit_code = n;
+
+ /* Produce an Erlang crash dump if error */
if (((n == ERTS_ERROR_EXIT && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT)
&& erts_initialized) {
erl_crash_dump_v((char*) NULL, 0, fmt, args1);
}
+ erts_exit_epilogue();
+}
+
+__decl_noreturn void __noreturn erts_exit_epilogue(void)
+{
+ int n = erts_exit_code;
+
sys_tty_reset(n);
if (n == ERTS_INTR_EXIT)
diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c
index f84c63e7a4..4d4defd8b5 100644
--- a/erts/emulator/beam/erl_instrument.c
+++ b/erts/emulator/beam/erl_instrument.c
@@ -539,7 +539,7 @@ map_stat_free(ErtsAlcType_t n, void *extra, void *ptr)
}
-static void dump_memory_map_to_stream(FILE *fp)
+static void dump_memory_map_to_stream(fmtfn_t to, void* to_arg)
{
ErtsAlcType_t n;
MapStatBlock_t *bp;
@@ -551,7 +551,7 @@ static void dump_memory_map_to_stream(FILE *fp)
/* Write header */
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"{instr_hdr,\n"
" %lu,\n"
" %lu,\n"
@@ -574,7 +574,7 @@ static void dump_memory_map_to_stream(FILE *fp)
else
astr = ERTS_ALC_A2AD(ERTS_ALC_A_SYSTEM);
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"%s{%s,%s,%s}%s",
(n == ERTS_ALC_N_MIN) ? "" : " ",
ERTS_ALC_N2TD(n),
@@ -583,12 +583,12 @@ static void dump_memory_map_to_stream(FILE *fp)
(n == ERTS_ALC_N_MAX) ? "" : ",\n");
}
- fprintf(fp, "}}.\n");
+ erts_cbprintf(to, to_arg, "}}.\n");
/* Write memory data */
for (bp = mem_anchor; bp; bp = bp->next) {
if (is_internal_pid(bp->pid))
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"{%lu, %lu, %lu, {%lu,%lu,%lu}}.\n",
(UWord) bp->type_no,
(UWord) bp->mem,
@@ -597,7 +597,7 @@ static void dump_memory_map_to_stream(FILE *fp)
(UWord) pid_number(bp->pid),
(UWord) pid_serial(bp->pid));
else
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"{%lu, %lu, %lu, undefined}.\n",
(UWord) bp->type_no,
(UWord) bp->mem,
@@ -608,40 +608,29 @@ static void dump_memory_map_to_stream(FILE *fp)
erts_mtx_unlock(&instr_mutex);
}
-int erts_instr_dump_memory_map_to_fd(int fd)
+int erts_instr_dump_memory_map_to(fmtfn_t to, void* to_arg)
{
- char buf[BUFSIZ];
- FILE *f;
-
if (!erts_instr_memory_map)
return 0;
- f = fdopen(fd, "w");
- if (f == NULL)
- return 0;
-
- /* Avoid allocating memory; we may have run out of it at this point. */
- setbuf(f, buf);
-
- dump_memory_map_to_stream(f);
- fflush(f);
+ dump_memory_map_to_stream(to, to_arg);
return 1;
}
int erts_instr_dump_memory_map(const char *name)
{
- FILE *f;
+ int fd;
if (!erts_instr_memory_map)
return 0;
- f = fopen(name, "w");
- if (f == NULL)
+ fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+ if (fd < 0)
return 0;
- dump_memory_map_to_stream(f);
+ dump_memory_map_to_stream(erts_write_fd, (void*)&fd);
- fclose(f);
+ close(fd);
return 1;
}
@@ -998,19 +987,19 @@ erts_instr_get_stat(Process *proc, Eterm what, int begin_max_period)
}
static void
-dump_stat_to_stream(FILE *fp, int begin_max_period)
+dump_stat_to_stream(fmtfn_t to, void* to_arg, int begin_max_period)
{
ErtsAlcType_t i, a_max, a_min;
erts_mtx_lock(&instr_mutex);
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"{instr_vsn,%lu}.\n",
(unsigned long) ERTS_INSTR_VSN);
update_max_ever_values(&stats->tot, 0, 0);
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"{total,[{total,[{sizes,%lu,%lu,%lu},{blocks,%lu,%lu,%lu}]}]}.\n",
(UWord) stats->tot.size,
(UWord) stats->tot.max_size,
@@ -1038,7 +1027,7 @@ dump_stat_to_stream(FILE *fp, int begin_max_period)
for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
if (erts_allctrs_info[i].enabled) {
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"%s{%s,[{sizes,%lu,%lu,%lu},{blocks,%lu,%lu,%lu}]}%s",
i == a_min ? "{allocators,\n [" : " ",
ERTS_ALC_A2AD(i),
@@ -1055,7 +1044,7 @@ dump_stat_to_stream(FILE *fp, int begin_max_period)
update_max_ever_values(stats->c, ERTS_ALC_C_MIN, ERTS_ALC_C_MAX);
for (i = ERTS_ALC_C_MIN; i <= ERTS_ALC_C_MAX; i++) {
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"%s{%s,[{sizes,%lu,%lu,%lu},{blocks,%lu,%lu,%lu}]}%s",
i == ERTS_ALC_C_MIN ? "{classes,\n [" : " ",
ERTS_ALC_C2CD(i),
@@ -1071,7 +1060,7 @@ dump_stat_to_stream(FILE *fp, int begin_max_period)
update_max_ever_values(stats->n, ERTS_ALC_N_MIN, ERTS_ALC_N_MAX);
for (i = ERTS_ALC_N_MIN; i <= ERTS_ALC_N_MAX; i++) {
- fprintf(fp,
+ erts_cbprintf(to, to_arg,
"%s{%s,[{sizes,%lu,%lu,%lu},{blocks,%lu,%lu,%lu}]}%s",
i == ERTS_ALC_N_MIN ? "{types,\n [" : " ",
ERTS_ALC_N2TD(i),
@@ -1095,40 +1084,29 @@ dump_stat_to_stream(FILE *fp, int begin_max_period)
}
-int erts_instr_dump_stat_to_fd(int fd, int begin_max_period)
+int erts_instr_dump_stat_to(fmtfn_t to, void* to_arg, int begin_max_period)
{
- char buf[BUFSIZ];
- FILE *fp;
-
if (!erts_instr_stat)
return 0;
- fp = fdopen(fd, "w");
- if (fp == NULL)
- return 0;
-
- /* Avoid allocating memory; we may have run out of it at this point. */
- setbuf(fp, buf);
-
- dump_stat_to_stream(fp, begin_max_period);
- fflush(fp);
+ dump_stat_to_stream(to, to_arg, begin_max_period);
return 1;
}
int erts_instr_dump_stat(const char *name, int begin_max_period)
{
- FILE *file;
+ int fd;
if (!erts_instr_stat)
return 0;
- file = fopen(name, "w");
- if (file == NULL)
+ fd = open(name, O_WRONLY | O_CREAT | O_TRUNC,0640);
+ if (fd < 0)
return 0;
- dump_stat_to_stream(file, begin_max_period);
+ dump_stat_to_stream(erts_write_fd, (void*)&fd, begin_max_period);
- fclose(file);
+ close(fd);
return 1;
}
diff --git a/erts/emulator/beam/erl_instrument.h b/erts/emulator/beam/erl_instrument.h
index 1f04c91d5e..351172b2fa 100644
--- a/erts/emulator/beam/erl_instrument.h
+++ b/erts/emulator/beam/erl_instrument.h
@@ -29,10 +29,10 @@ extern int erts_instr_memory_map;
extern int erts_instr_stat;
Uint erts_instr_init(int stat, int map_stat);
-int erts_instr_dump_memory_map_to_fd(int fd);
+int erts_instr_dump_memory_map_to(fmtfn_t to, void* to_arg);
int erts_instr_dump_memory_map(const char *name);
Eterm erts_instr_get_memory_map(Process *process);
-int erts_instr_dump_stat_to_fd(int fd, int begin_max_period);
+int erts_instr_dump_stat_to(fmtfn_t to, void* to_arg, int begin_max_period);
int erts_instr_dump_stat(const char *name, int begin_max_period);
Eterm erts_instr_get_stat(Process *proc, Eterm what, int begin_max_period);
Eterm erts_instr_get_type_info(Process *proc);
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 06266363b5..5d4823c077 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -129,6 +129,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "run_queue", "address" },
#ifdef ERTS_DIRTY_SCHEDULERS
{ "dirty_run_queue_sleep_list", "address" },
+ { "dirty_gc_info", NULL },
+ { "dirty_break_point_index", NULL },
#endif
{ "process_table", NULL },
{ "cpu_info", NULL },
diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c
index a00e0f0fff..481e92b2cd 100644
--- a/erts/emulator/beam/erl_lock_count.c
+++ b/erts/emulator/beam/erl_lock_count.c
@@ -274,11 +274,11 @@ void erts_lcnt_init() {
lcnt_unlock();
- /* set start timer and zero statistics */
- erts_lcnt_clear_counters();
}
void erts_lcnt_late_init() {
+ /* set start timer and zero statistics */
+ erts_lcnt_clear_counters();
erts_thr_install_exit_handler(erts_lcnt_thread_exit_handler);
}
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index e4c696ae3b..f45e6974cd 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -193,7 +193,7 @@ free_message_buffer(ErlHeapFragment* bp)
erts_cleanup_offheap(&bp->off_heap);
ERTS_HEAP_FREE(ERTS_ALC_T_HEAP_FRAG, (void *) bp,
- ERTS_HEAP_FRAG_SIZE(bp->size));
+ ERTS_HEAP_FRAG_SIZE(bp->alloc_size));
bp = next_bp;
}while (bp != NULL);
}
diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c
index 421445fbad..7ddf49937f 100644
--- a/erts/emulator/beam/erl_msacc.c
+++ b/erts/emulator/beam/erl_msacc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_msacc.h b/erts/emulator/beam/erl_msacc.h
index ad7c8c5eee..4c8e1c8e22 100644
--- a/erts/emulator/beam/erl_msacc.h
+++ b/erts/emulator/beam/erl_msacc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 9a873857b9..19ce0f6965 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -2309,6 +2309,17 @@ erts_setup_nif_gc(Process* proc, Eterm** objv, int* nobj)
return gc;
}
+int
+erts_check_nif_export_in_area(Process *p, char *start, Uint size)
+{
+ NifExport *nep = ERTS_PROC_GET_NIF_TRAP_EXPORT(p);
+ if (!nep || !nep->saved_current)
+ return 0;
+ if (ErtsInArea(nep->saved_current, start, size))
+ return 1;
+ return 0;
+}
+
/*
* Allocate a NifExport and set it in proc specific data
*/
@@ -2360,6 +2371,7 @@ init_nif_sched_data(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirec
Eterm* reg;
NifExport* ep;
int i, scheduler;
+ int orig_argc;
execution_state(env, &proc, &scheduler);
@@ -2370,11 +2382,14 @@ init_nif_sched_data(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirec
reg = erts_proc_sched_data(proc)->x_reg_array;
+ ASSERT(!need_save || proc->current);
+ orig_argc = need_save ? (int) proc->current[2] : 0;
+
ep = (NifExport*) ERTS_PROC_GET_NIF_TRAP_EXPORT(proc);
if (!ep)
- ep = allocate_nif_sched_data(proc, argc);
- else if (need_save && ep->rootset_extra < argc) {
- NifExport* new_ep = allocate_nif_sched_data(proc, argc);
+ ep = allocate_nif_sched_data(proc, orig_argc);
+ else if (need_save && ep->rootset_extra < orig_argc) {
+ NifExport* new_ep = allocate_nif_sched_data(proc, orig_argc);
destroy_nif_export(ep);
ep = new_ep;
}
@@ -2387,16 +2402,14 @@ init_nif_sched_data(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirec
}
if (scheduler > 0)
ERTS_VBUMP_ALL_REDS(proc);
- for (i = 0; i < argc; i++) {
- if (need_save)
- ep->rootset[i+1] = reg[i];
- reg[i] = (Eterm) argv[i];
- }
if (need_save) {
- ASSERT(proc->current);
ep->saved_current = proc->current;
- ep->saved_argc = argc;
+ ep->saved_argc = orig_argc;
+ for (i = 0; i < orig_argc; i++)
+ ep->rootset[i+1] = reg[i];
}
+ for (i = 0; i < argc; i++)
+ reg[i] = (Eterm) argv[i];
proc->i = (BeamInstr*) ep->exp.addressv[0];
ep->exp.code[0] = (BeamInstr) proc->current[0];
ep->exp.code[1] = (BeamInstr) proc->current[1];
@@ -3068,16 +3081,16 @@ Eterm erts_nif_taints(Process* p)
return list;
}
-void erts_print_nif_taints(int to, void* to_arg)
+void erts_print_nif_taints(fmtfn_t to, void* to_arg)
{
struct tainted_module_t* t;
const char* delim = "";
for (t=first_tainted_module ; t!=NULL; t=t->next) {
const Atom* atom = atom_tab(atom_val(t->module_atom));
- erts_print(to,to_arg,"%s%.*s", delim, atom->len, atom->name);
+ erts_cbprintf(to,to_arg,"%s%.*s", delim, atom->len, atom->name);
delim = ",";
}
- erts_print(to,to_arg,"\n");
+ erts_cbprintf(to,to_arg,"\n");
}
@@ -3548,8 +3561,8 @@ Eterm erts_nif_call_function(Process *p, Process *tracee,
#endif
if (p) {
/* This is almost a normal nif call like in beam_emu,
- except that any heap fragment created in the nif will be
- discarded without checking if anything in it is live.
+ except that any heap consumed by the nif will be
+ released without checking if anything in it is live.
This is because we cannot do a GC here as we don't know
the number of live registers that have to be preserved.
This means that any heap part of the returned term may
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 646f786651..70500ed6e1 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -188,7 +188,7 @@ dist_table_free(void *vdep)
void
-erts_dist_table_info(int to, void *to_arg)
+erts_dist_table_info(fmtfn_t to, void *to_arg)
{
int lock = !ERTS_IS_CRASH_DUMPING;
if (lock)
@@ -564,7 +564,7 @@ erts_node_table_size(void)
}
void
-erts_node_table_info(int to, void *to_arg)
+erts_node_table_info(fmtfn_t to, void *to_arg)
{
int lock = !ERTS_IS_CRASH_DUMPING;
if (lock)
@@ -649,7 +649,7 @@ void erts_schedule_delete_node(ErlNode *enp)
}
struct pn_data {
- int to;
+ fmtfn_t to;
void *to_arg;
Eterm sysname;
int no_sysname;
@@ -679,7 +679,7 @@ static void print_node(void *venp, void *vpndp)
pndp->no_total++;
}
-void erts_print_node_info(int to,
+void erts_print_node_info(fmtfn_t to,
void *to_arg,
Eterm sysname,
int *no_sysname,
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index 7a4434acbf..47a6724c21 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -179,7 +179,7 @@ DistEntry *erts_find_or_insert_dist_entry(Eterm);
DistEntry *erts_find_dist_entry(Eterm);
void erts_schedule_delete_dist_entry(DistEntry *);
Uint erts_dist_table_size(void);
-void erts_dist_table_info(int, void *);
+void erts_dist_table_info(fmtfn_t, void *);
void erts_set_dist_entry_not_connected(DistEntry *);
void erts_set_dist_entry_connected(DistEntry *, Eterm, Uint);
ErlNode *erts_find_or_insert_node(Eterm, Uint32);
@@ -187,8 +187,8 @@ void erts_schedule_delete_node(ErlNode *);
void erts_set_this_node(Eterm, Uint);
Uint erts_node_table_size(void);
void erts_init_node_tables(int);
-void erts_node_table_info(int, void *);
-void erts_print_node_info(int, void *, Eterm, int*, int*);
+void erts_node_table_info(fmtfn_t, void *);
+void erts_print_node_info(fmtfn_t, void *, Eterm, int*, int*);
Eterm erts_get_node_and_dist_references(struct process *);
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
int erts_lc_is_de_rwlocked(DistEntry *);
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index f90844ccc8..c59b42cdae 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -369,7 +369,7 @@ Eterm erts_request_io_bytes(Process *c_p);
#define ERTS_PORT_REDS_INFO (CONTEXT_REDS/100)
#define ERTS_PORT_REDS_TERMINATE (CONTEXT_REDS/50)
-void print_port_info(Port *, int, void *);
+void print_port_info(Port *, fmtfn_t, void *);
void erts_port_free(Port *);
#ifndef ERTS_SMP
void erts_port_cleanup(Port *);
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index bc59147c6c..41741764e8 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -154,6 +154,7 @@ int ERTS_WRITE_UNLIKELY(erts_eager_check_io) = 1;
int ERTS_WRITE_UNLIKELY(erts_sched_compact_load);
int ERTS_WRITE_UNLIKELY(erts_sched_balance_util) = 0;
Uint ERTS_WRITE_UNLIKELY(erts_no_schedulers);
+Uint ERTS_WRITE_UNLIKELY(erts_no_total_schedulers);
Uint ERTS_WRITE_UNLIKELY(erts_no_dirty_cpu_schedulers) = 0;
Uint ERTS_WRITE_UNLIKELY(erts_no_dirty_io_schedulers) = 0;
@@ -557,8 +558,8 @@ do { \
*/
static void exec_misc_ops(ErtsRunQueue *);
-static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
-static int stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg);
+static void print_function_from_pc(fmtfn_t to, void *to_arg, BeamInstr* x);
+static int stack_element_dump(fmtfn_t to, void *to_arg, Eterm* sp, int yreg);
static void aux_work_timeout(void *unused);
static void aux_work_timeout_early_init(int no_schedulers);
@@ -2059,6 +2060,7 @@ handle_thr_prgr_later_op(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int wait
#endif
for (lops = 0; lops < ERTS_MAX_THR_PRGR_LATER_OPS; lops++) {
ErtsThrPrgrLaterOp *lop = awdp->later_op.first;
+
if (!erts_thr_progress_has_reached_this(current, lop->later))
return aux_work & ~ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP;
awdp->later_op.first = lop->next;
@@ -5908,9 +5910,12 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online
n = (int) no_schedulers;
erts_no_schedulers = n;
+ erts_no_total_schedulers = n;
#ifdef ERTS_DIRTY_SCHEDULERS
erts_no_dirty_cpu_schedulers = no_dirty_cpu_schedulers;
+ erts_no_total_schedulers += no_dirty_cpu_schedulers;
erts_no_dirty_io_schedulers = no_dirty_io_schedulers;
+ erts_no_total_schedulers += no_dirty_io_schedulers;
#endif
/* Create and initialize scheduler sleep info */
@@ -6230,6 +6235,12 @@ check_dirty_enqueue_in_prio_queue(Process *c_p,
int queue;
erts_aint32_t dact, max_qbit;
+ /* Do not enqueue free process... */
+ if (actual & ERTS_PSFLG_FREE) {
+ *newp &= ~ERTS_PSFLGS_DIRTY_WORK;
+ return ERTS_ENQUEUE_NOT;
+ }
+
/* Termination should be done on an ordinary scheduler */
if ((*newp) & ERTS_PSFLG_EXITING) {
*newp &= ~ERTS_PSFLGS_DIRTY_WORK;
@@ -6271,7 +6282,11 @@ check_dirty_enqueue_in_prio_queue(Process *c_p,
return -1*queue;
}
- *newp |= ERTS_PSFLG_IN_RUNQ;
+ /*
+ * Enqueue using process struct.
+ */
+ *newp &= ~ERTS_PSFLGS_PRQ_PRIO_MASK;
+ *newp |= ERTS_PSFLG_IN_RUNQ | (aprio << ERTS_PSFLGS_PRQ_PRIO_OFFSET);
return queue;
}
@@ -6418,6 +6433,9 @@ select_enqueue_run_queue(int enqueue, int enq_prio, Process *p, erts_aint32_t st
/*
* schedule_out_process() return with c_rq locked.
+ *
+ * Return non-zero value if caller should decrease
+ * reference count on the process when done with it...
*/
static ERTS_INLINE int
schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p,
@@ -6472,12 +6490,18 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p,
erts_smp_runq_lock(c_rq);
- return 0;
-
+#if !defined(ERTS_SMP)
+ /* Decrement refc if process struct is free... */
+ return !!(n & ERTS_PSFLG_FREE);
+#else
+ /* Decrement refc if scheduled out from dirty scheduler... */
+ return !is_normal_sched;
+#endif
}
else {
Process* sched_p;
+ ASSERT(!(n & ERTS_PSFLG_FREE));
ASSERT(!(n & ERTS_PSFLG_SUSPENDED) || (n & (ERTS_PSFLG_ACTIVE_SYS
| ERTS_PSFLG_DIRTY_ACTIVE_SYS)));
@@ -6493,11 +6517,14 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p,
erts_smp_runq_lock(runq);
+ if (is_normal_sched && sched_p == p && ERTS_RUNQ_IX_IS_DIRTY(runq->ix))
+ erts_proc_inc_refc(p); /* Needs to be done before enqueue_process() */
+
/* Enqueue the process */
enqueue_process(runq, (int) enq_prio, sched_p);
if (runq == c_rq)
- return 1;
+ return 0;
erts_smp_runq_unlock(runq);
@@ -6505,9 +6532,15 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p,
erts_smp_runq_lock(c_rq);
- return 1;
+ /*
+ * Decrement refc if process is scheduled out by a
+ * dirty scheduler, and we have not just scheduled
+ * the process using the ordinary process struct
+ * on a dirty run-queue again...
+ */
+ return !is_normal_sched && (sched_p != p
+ || !ERTS_RUNQ_IX_IS_DIRTY(runq->ix));
}
-
}
static ERTS_INLINE void
@@ -6522,8 +6555,17 @@ add2runq(int enqueue, erts_aint32_t prio,
if (runq) {
Process *sched_p;
- if (enqueue > 0)
+ if (enqueue > 0) {
sched_p = proc;
+ /*
+ * Refc on process struct (i.e. true struct,
+ * not proxy-struct) increased while in a
+ * dirty run-queue or executing on a dirty
+ * scheduler.
+ */
+ if (ERTS_RUNQ_IX_IS_DIRTY(runq->ix))
+ erts_proc_inc_refc(proc);
+ }
else {
Process *pxy;
@@ -6683,15 +6725,8 @@ schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st,
erts_aint32_t fail_state, state, a, n, enq_prio;
int enqueue; /* < 0 -> use proxy */
unsigned int prof_runnable_procs;
- int strict_fail_state;
fail_state = *fail_state_p;
- /*
- * If fail state something other than just exiting process,
- * ensure that the task wont be scheduled when the
- * receiver is in the failure state.
- */
- strict_fail_state = fail_state != ERTS_PSFLG_EXITING;
res = 1; /* prepare for success */
st->next = st->prev = st; /* Prep for empty prio queue */
@@ -6773,7 +6808,7 @@ schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st,
/* Status lock prevents out of order "runnable proc" trace msgs */
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
- if (!prof_runnable_procs && !strict_fail_state) {
+ if (!prof_runnable_procs) {
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
locked = 0;
}
@@ -6784,11 +6819,6 @@ schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st,
erts_aint32_t e;
n = e = a;
- if (strict_fail_state && (a & fail_state)) {
- *fail_state_p = (a & fail_state);
- goto cleanup;
- }
-
if (a & ERTS_PSFLG_FREE)
goto cleanup; /* We don't want to schedule free processes... */
@@ -7059,12 +7089,18 @@ typedef struct {
} ErtsSchdlrSspndResume;
static void
-schdlr_sspnd_resume_proc(Eterm pid)
+schdlr_sspnd_resume_proc(ErtsSchedType sched_type, Eterm pid)
{
- Process *p = erts_pid2proc(NULL, 0, pid, ERTS_PROC_LOCK_STATUS);
+ Process *p;
+ p = erts_pid2proc_opt(NULL, 0, pid, ERTS_PROC_LOCK_STATUS,
+ (sched_type != ERTS_SCHED_NORMAL
+ ? ERTS_P2P_FLG_INC_REFC
+ : 0));
if (p) {
resume_process(p, ERTS_PROC_LOCK_STATUS);
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ if (sched_type != ERTS_SCHED_NORMAL)
+ erts_proc_dec_refc(p);
}
}
@@ -7073,17 +7109,20 @@ schdlr_sspnd_resume_procs(ErtsSchedType sched_type,
ErtsSchdlrSspndResume *resume)
{
if (is_internal_pid(resume->onln.chngr)) {
- schdlr_sspnd_resume_proc(resume->onln.chngr);
+ schdlr_sspnd_resume_proc(sched_type,
+ resume->onln.chngr);
resume->onln.chngr = NIL;
}
if (is_internal_pid(resume->onln.nxt)) {
- schdlr_sspnd_resume_proc(resume->onln.nxt);
+ schdlr_sspnd_resume_proc(sched_type,
+ resume->onln.nxt);
resume->onln.nxt = NIL;
}
while (resume->msb.chngrs) {
ErtsProcList *plp = resume->msb.chngrs;
resume->msb.chngrs = plp->next;
- schdlr_sspnd_resume_proc(plp->pid);
+ schdlr_sspnd_resume_proc(sched_type,
+ plp->pid);
proclist_destroy(plp);
}
}
@@ -7135,16 +7174,8 @@ suspend_scheduler(ErtsSchedulerData *esdp)
ASSERT(sched_type != ERTS_SCHED_NORMAL || no != 1);
- if (sched_type != ERTS_SCHED_NORMAL) {
- if (erts_smp_mtx_trylock(&schdlr_sspnd.mtx) == EBUSY) {
- erts_smp_runq_unlock(esdp->run_queue);
- erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- erts_smp_runq_lock(esdp->run_queue);
- }
- if (schdlr_sspnd.msb.ongoing)
- evacuate_run_queue(esdp->run_queue, &sbp);
+ if (sched_type != ERTS_SCHED_NORMAL)
erts_smp_runq_unlock(esdp->run_queue);
- }
else {
evacuate_run_queue(esdp->run_queue, &sbp);
@@ -7157,8 +7188,8 @@ suspend_scheduler(ErtsSchedulerData *esdp)
sched_wall_time_change(esdp, 0);
- erts_smp_mtx_lock(&schdlr_sspnd.mtx);
}
+ erts_smp_mtx_lock(&schdlr_sspnd.mtx);
flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED);
if (flgs & ERTS_SSI_FLG_SUSPENDED) {
@@ -7202,15 +7233,18 @@ suspend_scheduler(ErtsSchedulerData *esdp)
(void) erts_proclist_fetch(&msb[i]->chngq, &end_plp);
/* resume processes that initiated the multi scheduling block... */
plp = msb[i]->chngq;
- while (plp) {
- erts_proclist_store_last(&msb[i]->blckrs,
- proclist_copy(plp));
- plp = plp->next;
- }
- if (end_plp)
+ if (plp) {
+ ASSERT(end_plp);
+ ASSERT(msb[i]->ongoing);
+ do {
+ erts_proclist_store_last(&msb[i]->blckrs,
+ proclist_copy(plp));
+ plp = plp->next;
+ } while (plp);
end_plp->next = resume.msb.chngrs;
- resume.msb.chngrs = msb[i]->chngq;
- msb[i]->chngq = NULL;
+ resume.msb.chngrs = msb[i]->chngq;
+ msb[i]->chngq = NULL;
+ }
}
}
}
@@ -7274,24 +7308,14 @@ suspend_scheduler(ErtsSchedulerData *esdp)
while (1) {
ErtsMonotonicTime current_time;
- erts_aint32_t qmask;
erts_aint32_t flgs;
- qmask = (ERTS_RUNQ_FLGS_GET(esdp->run_queue)
- & ERTS_RUNQ_FLGS_QMASK);
-
- if (sched_type != ERTS_SCHED_NORMAL) {
- if (qmask) {
- erts_smp_mtx_lock(&schdlr_sspnd.mtx);
- erts_smp_runq_lock(esdp->run_queue);
- if (schdlr_sspnd.msb.ongoing)
- evacuate_run_queue(esdp->run_queue, &sbp);
- erts_smp_runq_unlock(esdp->run_queue);
- erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
- }
+ if (sched_type != ERTS_SCHED_NORMAL)
aux_work = 0;
- }
else {
+ erts_aint32_t qmask;
+ qmask = (ERTS_RUNQ_FLGS_GET(esdp->run_queue)
+ & ERTS_RUNQ_FLGS_QMASK);
aux_work = erts_atomic32_read_acqb(&ssi->aux_work);
@@ -7419,12 +7443,23 @@ suspend_scheduler(ErtsSchedulerData *esdp)
schdlr_sspnd_inc_nscheds(&schdlr_sspnd.active, sched_type);
changing = erts_smp_atomic32_read_nob(&schdlr_sspnd.changing);
- if ((changing & ERTS_SCHDLR_SSPND_CHNG_MSB)
- && schdlr_sspnd.online == schdlr_sspnd.active) {
- erts_smp_atomic32_read_band_nob(&schdlr_sspnd.changing,
- ~ERTS_SCHDLR_SSPND_CHNG_MSB);
- }
-
+ if (changing) {
+ if ((changing & ERTS_SCHDLR_SSPND_CHNG_MSB)
+ && !schdlr_sspnd.msb.ongoing
+ && schdlr_sspnd.online == schdlr_sspnd.active) {
+ erts_smp_atomic32_read_band_nob(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_MSB);
+ }
+ if ((changing & ERTS_SCHDLR_SSPND_CHNG_NMSB)
+ && !schdlr_sspnd.nmsb.ongoing
+ && (schdlr_sspnd_get_nscheds(&schdlr_sspnd.online,
+ ERTS_SCHED_NORMAL)
+ == schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
+ ERTS_SCHED_NORMAL))) {
+ erts_smp_atomic32_read_band_nob(&schdlr_sspnd.changing,
+ ~ERTS_SCHDLR_SSPND_CHNG_NMSB);
+ }
+ }
ASSERT(no <= schdlr_sspnd_get_nscheds(&schdlr_sspnd.online, sched_type));
ASSERT((sched_type == ERTS_SCHED_NORMAL
? !(schdlr_sspnd.msb.ongoing|schdlr_sspnd.nmsb.ongoing)
@@ -7557,7 +7592,7 @@ abort_sched_onln_chng_waitq(Process *p)
erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
if (is_internal_pid(resume))
- schdlr_sspnd_resume_proc(resume);
+ schdlr_sspnd_resume_proc(ERTS_SCHED_NORMAL, resume);
}
ErtsSchedSuspendResult
@@ -7955,21 +7990,20 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int normal
}
else { /* ------ UNBLOCK ------ */
if (p->flags & have_blckd_flg) {
- ErtsProcList *plps[2];
+ ErtsProcList **plpps[3] = {0};
ErtsProcList *plp;
- int limit = 0;
- plps[limit++] = erts_proclist_peek_first(msbp->blckrs);
- if (all)
- plps[limit++] = erts_proclist_peek_first(msbp->chngq);
+ plpps[0] = &msbp->blckrs;
+ if (all)
+ plpps[1] = &msbp->chngq;
- for (ix = 0; ix < limit; ix++) {
- plp = plps[ix];
+ for (ix = 0; plpps[ix]; ix++) {
+ plp = erts_proclist_peek_first(*plpps[ix]);
while (plp) {
ErtsProcList *tmp_plp = plp;
- plp = erts_proclist_peek_next(msbp->blckrs, plp);
+ plp = erts_proclist_peek_next(*plpps[ix], plp);
if (erts_proclist_same(tmp_plp, p)) {
- erts_proclist_remove(&msbp->blckrs, tmp_plp);
+ erts_proclist_remove(plpps[ix], tmp_plp);
proclist_destroy(tmp_plp);
if (!all)
break;
@@ -8608,8 +8642,15 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
* from being selected for normal execution regardless
* of locks held or not held on it...
*/
- ASSERT(!((ERTS_PSFLG_RUNNING|ERTS_PSFLG_DIRTY_RUNNING_SYS)
- & erts_smp_atomic32_read_nob(&rp->state)));
+#ifdef DEBUG
+ {
+ erts_aint32_t state;
+ state = erts_smp_atomic32_read_nob(&rp->state);
+ ASSERT((state & ERTS_PSFLG_PENDING_EXIT)
+ || !(state & (ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)));
+ }
+#endif
if (!suspend)
resume_process(rp, pid_locks|ERTS_PROC_LOCK_STATUS);
@@ -9591,40 +9632,45 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
esdp->reductions += reds;
- /* schedule_out_process() returns with rq locked! */
- schedule_out_process(rq, state, p, proxy_p, is_normal_sched);
- proxy_p = NULL;
+ {
+ int dec_refc;
- ERTS_PROC_REDUCTIONS_EXECUTED(esdp, rq,
- (int) ERTS_PSFLGS_GET_USR_PRIO(state),
- reds,
- actual_reds);
+ /* schedule_out_process() returns with rq locked! */
+ dec_refc = schedule_out_process(rq, state, p,
+ proxy_p, is_normal_sched);
+ proxy_p = NULL;
- esdp->current_process = NULL;
+ ERTS_PROC_REDUCTIONS_EXECUTED(esdp, rq,
+ (int) ERTS_PSFLGS_GET_USR_PRIO(state),
+ reds,
+ actual_reds);
+
+ esdp->current_process = NULL;
#ifdef ERTS_SMP
- p->scheduler_data = NULL;
+ p->scheduler_data = NULL;
#endif
- erts_smp_proc_unlock(p, (ERTS_PROC_LOCK_MAIN
- | ERTS_PROC_LOCK_STATUS
- | ERTS_PROC_LOCK_TRACE));
+ erts_smp_proc_unlock(p, (ERTS_PROC_LOCK_MAIN
+ | ERTS_PROC_LOCK_STATUS
+ | ERTS_PROC_LOCK_TRACE));
- ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_OTHER);
+ ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_OTHER);
- if (state & ERTS_PSFLG_FREE) {
- if (!is_normal_sched) {
- ASSERT(p->flags & F_DELAYED_DEL_PROC);
- erts_proc_dec_refc(p);
- }
- else {
#ifdef ERTS_SMP
- ASSERT(esdp->free_process == p);
- esdp->free_process = NULL;
-#else
- erts_proc_dec_refc(p);
+ if (state & ERTS_PSFLG_FREE) {
+ if (!is_normal_sched) {
+ ASSERT(p->flags & F_DELAYED_DEL_PROC);
+ }
+ else {
+ ASSERT(esdp->free_process == p);
+ esdp->free_process = NULL;
+ }
+ }
#endif
- }
- }
+
+ if (dec_refc)
+ erts_proc_dec_refc(p);
+ }
#ifdef ERTS_SMP
ASSERT(!esdp->free_process);
@@ -9900,8 +9946,12 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (!(state & ERTS_PSFLG_PROXY))
psflg_band_mask &= ~ERTS_PSFLG_IN_RUNQ;
else {
+ Eterm pid = p->common.id;
proxy_p = p;
- p = erts_proc_lookup_raw(proxy_p->common.id);
+ p = (is_normal_sched
+ ? erts_proc_lookup_raw(pid)
+ : erts_pid2proc_opt(NULL, 0, pid, 0,
+ ERTS_P2P_FLG_INC_REFC));
if (!p) {
free_proxy_proc(proxy_p);
proxy_p = NULL;
@@ -9933,6 +9983,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
| ERTS_PSFLG_FREE)))
#ifdef ERTS_DIRTY_SCHEDULERS
| (((state & (ERTS_PSFLG_RUNNING
+
| ERTS_PSFLG_FREE
| ERTS_PSFLG_RUNNING_SYS
| ERTS_PSFLG_EXITING))
@@ -9965,6 +10016,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
/* free and not queued by proxy */
erts_proc_dec_refc(p);
}
+ if (!is_normal_sched)
+ erts_proc_dec_refc(p);
goto pick_next_process;
}
state = new;
@@ -11916,7 +11969,6 @@ erts_cleanup_empty_process(Process* p)
static void
delete_process(Process* p)
{
- Eterm *heap;
ErtsPSD *psd;
struct saved_calls *scb;
process_breakpoint_time_t *pbt;
@@ -11971,13 +12023,8 @@ delete_process(Process* p)
hipe_delete_process(&p->hipe);
#endif
- heap = p->abandoned_heap ? p->abandoned_heap : p->heap;
+ erts_deallocate_young_generation(p);
-#ifdef DEBUG
- sys_memset(heap, DEBUG_BAD_BYTE, p->heap_sz*sizeof(Eterm));
-#endif
-
- ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void*) heap, p->heap_sz*sizeof(Eterm));
if (p->old_heap != NULL) {
#ifdef DEBUG
@@ -11989,16 +12036,6 @@ delete_process(Process* p)
(p->old_hend-p->old_heap)*sizeof(Eterm));
}
- /*
- * Free all pending message buffers.
- */
- if (p->mbuf != NULL) {
- free_message_buffer(p->mbuf);
- }
-
- if (p->msg_frag)
- erts_cleanup_messages(p->msg_frag);
-
erts_erase_dicts(p);
/* free all pending messages */
@@ -12401,6 +12438,8 @@ send_exit_signal(Process *c_p, /* current process if and only
else if (!(state & (ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS))) {
/* Process not running ... */
ErtsProcLocks need_locks = ~(*rp_locks) & ERTS_PROC_LOCKS_ALL;
+ ErlHeapFragment *bp = NULL;
+ Eterm rsn_cpy;
if (need_locks
&& erts_smp_proc_trylock(rp, need_locks) == EBUSY) {
/* ... but we havn't got all locks on it ... */
@@ -12413,12 +12452,32 @@ send_exit_signal(Process *c_p, /* current process if and only
}
/* ...and we have all locks on it... */
*rp_locks = ERTS_PROC_LOCKS_ALL;
- set_proc_exiting(rp,
- state,
- (is_immed(rsn)
- ? rsn
- : copy_object(rsn, rp)),
- NULL);
+
+ state = erts_smp_atomic32_read_nob(&rp->state);
+
+ if (is_immed(rsn))
+ rsn_cpy = rsn;
+ else {
+ Eterm *hp;
+ ErlOffHeap *ohp;
+ Uint rsn_sz = size_object(rsn);
+#ifdef ERTS_DIRTY_SCHEDULERS
+ if (state & (ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ bp = new_message_buffer(rsn_sz);
+ ohp = &bp->off_heap;
+ hp = &bp->mem[0];
+ }
+ else
+#endif
+ {
+ hp = HAlloc(rp, rsn_sz);
+ ohp = &rp->off_heap;
+ }
+ rsn_cpy = copy_struct(rsn, rsn_sz, &hp, ohp);
+ }
+
+ set_proc_exiting(rp, state, rsn_cpy, bp);
}
else { /* Process running... */
@@ -13073,15 +13132,14 @@ erts_continue_exit_process(Process *p)
}
#ifdef ERTS_DIRTY_SCHEDULERS
- if (a & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ if (a & (ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
p->flags |= F_DELAYED_DEL_PROC;
delay_del_proc = 1;
/*
- * The dirty scheduler will also decrease
- * refc when done...
+ * The dirty scheduler decrease refc
+ * when done with the process...
*/
- erts_proc_inc_refc(p);
}
#endif
@@ -13171,7 +13229,7 @@ erts_continue_exit_process(Process *p)
*/
void
-erts_stack_dump(int to, void *to_arg, Process *p)
+erts_stack_dump(fmtfn_t to, void *to_arg, Process *p)
{
Eterm* sp;
int yreg = -1;
@@ -13186,7 +13244,7 @@ erts_stack_dump(int to, void *to_arg, Process *p)
}
void
-erts_program_counter_info(int to, void *to_arg, Process *p)
+erts_program_counter_info(fmtfn_t to, void *to_arg, Process *p)
{
erts_aint32_t state;
int i;
@@ -13216,7 +13274,7 @@ erts_program_counter_info(int to, void *to_arg, Process *p)
}
static void
-print_function_from_pc(int to, void *to_arg, BeamInstr* x)
+print_function_from_pc(fmtfn_t to, void *to_arg, BeamInstr* x)
{
BeamInstr* addr = find_function_from_pc(x);
if (addr == NULL) {
@@ -13238,7 +13296,7 @@ print_function_from_pc(int to, void *to_arg, BeamInstr* x)
}
static int
-stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg)
+stack_element_dump(fmtfn_t to, void *to_arg, Eterm* sp, int yreg)
{
Eterm x = *sp;
@@ -13270,7 +13328,7 @@ stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg)
* Print scheduler information
*/
void
-erts_print_scheduler_info(int to, void *to_arg, ErtsSchedulerData *esdp) {
+erts_print_scheduler_info(fmtfn_t to, void *to_arg, ErtsSchedulerData *esdp) {
int i;
erts_aint32_t flg;
Process *p;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3347a7a60e..68fbb10602 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -111,6 +111,7 @@ extern int erts_eager_check_io;
extern int erts_sched_compact_load;
extern int erts_sched_balance_util;
extern Uint erts_no_schedulers;
+extern Uint erts_no_total_schedulers;
#ifdef ERTS_DIRTY_SCHEDULERS
extern Uint erts_no_dirty_cpu_schedulers;
extern Uint erts_no_dirty_io_schedulers;
@@ -1586,6 +1587,7 @@ Uint64 erts_step_proc_interval(void);
int erts_setup_nif_gc(Process* proc, Eterm** objv, int* nobj); /* see erl_nif.c */
void erts_destroy_nif_export(void *); /* see erl_nif.c */
+int erts_check_nif_export_in_area(Process *p, char *start, Uint size);
ErtsProcList *erts_proclist_create(Process *);
ErtsProcList *erts_proclist_copy(ErtsProcList *);
@@ -1682,7 +1684,7 @@ ERTS_GLB_INLINE ErtsProcList *erts_proclist_fetch_first(ErtsProcList **list)
return NULL;
else {
ErtsProcList *res = *list;
- if (res == *list)
+ if (res->next == *list)
*list = NULL;
else
*list = res->next;
@@ -1837,12 +1839,12 @@ void erts_cleanup_empty_process(Process* p);
#ifdef DEBUG
void erts_debug_verify_clean_empty_process(Process* p);
#endif
-void erts_stack_dump(int to, void *to_arg, Process *);
-void erts_limited_stack_trace(int to, void *to_arg, Process *);
-void erts_program_counter_info(int to, void *to_arg, Process *);
-void erts_print_scheduler_info(int to, void *to_arg, ErtsSchedulerData *esdp);
-void erts_dump_extended_process_state(int to, void *to_arg, erts_aint32_t psflg);
-void erts_dump_process_state(int to, void *to_arg, erts_aint32_t psflg);
+void erts_stack_dump(fmtfn_t to, void *to_arg, Process *);
+void erts_limited_stack_trace(fmtfn_t to, void *to_arg, Process *);
+void erts_program_counter_info(fmtfn_t to, void *to_arg, Process *);
+void erts_print_scheduler_info(fmtfn_t to, void *to_arg, ErtsSchedulerData *esdp);
+void erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg);
+void erts_dump_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg);
Eterm erts_get_process_priority(Process *p);
Eterm erts_set_process_priority(Process *p, Eterm prio);
@@ -1878,7 +1880,7 @@ void erts_handle_pending_exit(Process *, ErtsProcLocks);
#define ERTS_PROC_PENDING_EXIT(P) 0
#endif
-void erts_deep_process_dump(int, void *);
+void erts_deep_process_dump(fmtfn_t, void *);
Eterm erts_get_reader_groups_map(Process *c_p);
Eterm erts_debug_reader_groups_map(Process *c_p, int groups);
diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index d8c2eaba94..42654604cb 100644
--- a/erts/emulator/beam/erl_process_dict.c
+++ b/erts/emulator/beam/erl_process_dict.c
@@ -156,7 +156,7 @@ erts_pd_set_initial_size(int size)
* Called from break handler
*/
void
-erts_dictionary_dump(int to, void *to_arg, ProcDict *pd)
+erts_dictionary_dump(fmtfn_t to, void *to_arg, ProcDict *pd)
{
unsigned int i;
#ifdef DEBUG
@@ -196,8 +196,8 @@ erts_dictionary_dump(int to, void *to_arg, ProcDict *pd)
}
void
-erts_deep_dictionary_dump(int to, void *to_arg,
- ProcDict* pd, void (*cb)(int, void *, Eterm))
+erts_deep_dictionary_dump(fmtfn_t to, void *to_arg,
+ ProcDict* pd, void (*cb)(fmtfn_t, void *, Eterm))
{
unsigned int i;
Eterm t;
diff --git a/erts/emulator/beam/erl_process_dict.h b/erts/emulator/beam/erl_process_dict.h
index 387562058c..b50a2af72c 100644
--- a/erts/emulator/beam/erl_process_dict.h
+++ b/erts/emulator/beam/erl_process_dict.h
@@ -37,9 +37,9 @@ typedef struct proc_dict {
int erts_pd_set_initial_size(int size);
Uint erts_dicts_mem_size(struct process *p);
void erts_erase_dicts(struct process *p);
-void erts_dictionary_dump(int to, void *to_arg, ProcDict *pd);
-void erts_deep_dictionary_dump(int to, void *to_arg,
- ProcDict* pd, void (*cb)(int, void *, Eterm obj));
+void erts_dictionary_dump(fmtfn_t to, void *to_arg, ProcDict *pd);
+void erts_deep_dictionary_dump(fmtfn_t to, void *to_arg,
+ ProcDict* pd, void (*cb)(fmtfn_t, void *, Eterm obj));
Eterm erts_dictionary_copy(struct process *p, ProcDict *pd);
Eterm erts_pd_hash_get(struct process *p, Eterm id);
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a70dfb8e73..a19db74763 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -40,17 +40,17 @@
#define OUR_NIL _make_header(0,_TAG_HEADER_FLOAT)
-static void dump_process_info(int to, void *to_arg, Process *p);
-static void dump_element(int to, void *to_arg, Eterm x);
-static void dump_dist_ext(int to, void *to_arg, ErtsDistExternal *edep);
-static void dump_element_nl(int to, void *to_arg, Eterm x);
-static int stack_element_dump(int to, void *to_arg, Eterm* sp,
+static void dump_process_info(fmtfn_t to, void *to_arg, Process *p);
+static void dump_element(fmtfn_t to, void *to_arg, Eterm x);
+static void dump_dist_ext(fmtfn_t to, void *to_arg, ErtsDistExternal *edep);
+static void dump_element_nl(fmtfn_t to, void *to_arg, Eterm x);
+static int stack_element_dump(fmtfn_t to, void *to_arg, Eterm* sp,
int yreg);
-static void stack_trace_dump(int to, void *to_arg, Eterm* sp);
-static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
-static void heap_dump(int to, void *to_arg, Eterm x);
-static void dump_binaries(int to, void *to_arg, Binary* root);
-static void dump_externally(int to, void *to_arg, Eterm term);
+static void stack_trace_dump(fmtfn_t to, void *to_arg, Eterm* sp);
+static void print_function_from_pc(fmtfn_t to, void *to_arg, BeamInstr* x);
+static void heap_dump(fmtfn_t to, void *to_arg, Eterm x);
+static void dump_binaries(fmtfn_t to, void *to_arg, Binary* root);
+static void dump_externally(fmtfn_t to, void *to_arg, Eterm term);
static Binary* all_binaries;
@@ -60,7 +60,7 @@ extern BeamInstr beam_continue_exit[];
void
-erts_deep_process_dump(int to, void *to_arg)
+erts_deep_process_dump(fmtfn_t to, void *to_arg)
{
int i, max = erts_ptab_max(&erts_proc);
@@ -90,9 +90,12 @@ Uint erts_process_memory(Process *p, int incl_msg_inq) {
erts_doforall_links(ERTS_P_LINKS(p), &erts_one_link_size, &size);
erts_doforall_monitors(ERTS_P_MONITORS(p), &erts_one_mon_size, &size);
size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
+ if (p->abandoned_heap)
+ size += (p->hend - p->heap) * sizeof(Eterm);
if (p->old_hend && p->old_heap)
size += (p->old_hend - p->old_heap) * sizeof(Eterm);
+
size += p->msg.len * sizeof(ErtsMessage);
for (mp = p->msg.first; mp; mp = mp->next)
@@ -117,7 +120,7 @@ Uint erts_process_memory(Process *p, int incl_msg_inq) {
}
static void
-dump_process_info(int to, void *to_arg, Process *p)
+dump_process_info(fmtfn_t to, void *to_arg, Process *p)
{
Eterm* sp;
ErtsMessage* mp;
@@ -176,7 +179,7 @@ dump_process_info(int to, void *to_arg, Process *p)
}
static void
-dump_dist_ext(int to, void *to_arg, ErtsDistExternal *edep)
+dump_dist_ext(fmtfn_t to, void *to_arg, ErtsDistExternal *edep)
{
if (!edep)
erts_print(to, to_arg, "D0:E0:");
@@ -210,7 +213,7 @@ dump_dist_ext(int to, void *to_arg, ErtsDistExternal *edep)
}
static void
-dump_element(int to, void *to_arg, Eterm x)
+dump_element(fmtfn_t to, void *to_arg, Eterm x)
{
if (is_list(x)) {
erts_print(to, to_arg, "H" PTR_FMT, list_val(x));
@@ -240,14 +243,14 @@ dump_element(int to, void *to_arg, Eterm x)
}
static void
-dump_element_nl(int to, void *to_arg, Eterm x)
+dump_element_nl(fmtfn_t to, void *to_arg, Eterm x)
{
dump_element(to, to_arg, x);
erts_putc(to, to_arg, '\n');
}
static void
-stack_trace_dump(int to, void *to_arg, Eterm *sp) {
+stack_trace_dump(fmtfn_t to, void *to_arg, Eterm *sp) {
Eterm x = *sp;
if (is_CP(x)) {
erts_print(to, to_arg, "%p:", sp);
@@ -258,7 +261,7 @@ stack_trace_dump(int to, void *to_arg, Eterm *sp) {
}
void
-erts_limited_stack_trace(int to, void *to_arg, Process *p)
+erts_limited_stack_trace(fmtfn_t to, void *to_arg, Process *p)
{
Eterm* sp;
@@ -304,7 +307,7 @@ erts_limited_stack_trace(int to, void *to_arg, Process *p)
}
static int
-stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg)
+stack_element_dump(fmtfn_t to, void *to_arg, Eterm* sp, int yreg)
{
Eterm x = *sp;
@@ -332,7 +335,7 @@ stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg)
}
static void
-print_function_from_pc(int to, void *to_arg, BeamInstr* x)
+print_function_from_pc(fmtfn_t to, void *to_arg, BeamInstr* x)
{
BeamInstr* addr = find_function_from_pc(x);
if (addr == NULL) {
@@ -352,7 +355,7 @@ print_function_from_pc(int to, void *to_arg, BeamInstr* x)
}
static void
-heap_dump(int to, void *to_arg, Eterm x)
+heap_dump(fmtfn_t to, void *to_arg, Eterm x)
{
DeclareTmpHeapNoproc(last,1);
Eterm* next = last;
@@ -512,7 +515,7 @@ heap_dump(int to, void *to_arg, Eterm x)
}
static void
-dump_binaries(int to, void *to_arg, Binary* current)
+dump_binaries(fmtfn_t to, void *to_arg, Binary* current)
{
while (current) {
long i;
@@ -530,7 +533,7 @@ dump_binaries(int to, void *to_arg, Binary* current)
}
static void
-dump_externally(int to, void *to_arg, Eterm term)
+dump_externally(fmtfn_t to, void *to_arg, Eterm term)
{
byte sbuf[1024]; /* encode and hope for the best ... */
byte* s;
@@ -573,7 +576,7 @@ dump_externally(int to, void *to_arg, Eterm term)
}
}
-void erts_dump_process_state(int to, void *to_arg, erts_aint32_t psflg)
+void erts_dump_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg)
{
char *s;
switch (erts_process_state2status(psflg)) {
@@ -591,7 +594,7 @@ void erts_dump_process_state(int to, void *to_arg, erts_aint32_t psflg)
}
void
-erts_dump_extended_process_state(int to, void *to_arg, erts_aint32_t psflg) {
+erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg) {
int i;
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 8c84303997..ac9e91e31f 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1436,6 +1436,7 @@ void
trace_gc(Process *p, Eterm what, Uint size, Eterm msg)
{
ErtsTracerNif *tnif = NULL;
+ Eterm* o_hp = NULL;
Eterm* hp;
Uint sz = 0;
Eterm tup;
@@ -1446,7 +1447,7 @@ trace_gc(Process *p, Eterm what, Uint size, Eterm msg)
if (is_non_value(msg)) {
(void) erts_process_gc_info(p, &sz, NULL, 0, 0);
- hp = HAlloc(p, sz + 3 + 2);
+ o_hp = hp = erts_alloc(ERTS_ALC_T_TMP, (sz + 3 + 2) * sizeof(Eterm));
msg = erts_process_gc_info(p, NULL, &hp, 0, 0);
tup = TUPLE2(hp, am_wordsize, make_small(size)); hp += 3;
@@ -1455,6 +1456,8 @@ trace_gc(Process *p, Eterm what, Uint size, Eterm msg)
send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_GC,
what, msg, THE_NON_VALUE, am_true);
+ if (o_hp)
+ erts_free(ERTS_ALC_T_TMP, o_hp);
}
}
diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c
index 2a19211987..00fa452f79 100644
--- a/erts/emulator/beam/export.c
+++ b/erts/emulator/beam/export.c
@@ -83,7 +83,7 @@ static struct export_blob* entry_to_blob(struct export_entry* ee)
}
void
-export_info(int to, void *to_arg)
+export_info(fmtfn_t to, void *to_arg)
{
#ifdef ERTS_SMP
int lock = !ERTS_IS_CRASH_DUMPING;
@@ -348,7 +348,7 @@ Export *export_list(int i, ErtsCodeIndex code_ix)
int export_list_size(ErtsCodeIndex code_ix)
{
- return export_tables[code_ix].entries;
+ return erts_index_num_entries(&export_tables[code_ix]);
}
int export_table_sz(void)
diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h
index 1e7bb8514b..17fc4828ca 100644
--- a/erts/emulator/beam/export.h
+++ b/erts/emulator/beam/export.h
@@ -53,7 +53,7 @@ typedef struct export
void init_export_table(void);
-void export_info(int, void *);
+void export_info(fmtfn_t, void *);
ERTS_GLB_INLINE Export* erts_active_export_entry(Eterm m, Eterm f, unsigned a);
Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index b2c76aa605..d6df85034c 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -68,7 +68,7 @@ extern void erts_pre_dirty_nif(ErtsSchedulerData *,
extern void erts_post_dirty_nif(struct enif_environment_t* env);
#endif
extern Eterm erts_nif_taints(Process* p);
-extern void erts_print_nif_taints(int to, void* to_arg);
+extern void erts_print_nif_taints(fmtfn_t to, void* to_arg);
void erts_unload_nif(struct erl_module_nif* nif);
extern void erl_nif_init(void);
extern int erts_nif_get_funcs(struct erl_module_nif*,
@@ -1069,16 +1069,17 @@ void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info);
void init_break_handler(void);
void erts_set_ignore_break(void);
void erts_replace_intr(void);
-void process_info(int, void *);
-void print_process_info(int, void *, Process*);
-void info(int, void *);
-void loaded(int, void *);
+void process_info(fmtfn_t, void *);
+void print_process_info(fmtfn_t, void *, Process*);
+void info(fmtfn_t, void *);
+void loaded(fmtfn_t, void *);
/* erl_arith.c */
double erts_get_positive_zero_float(void);
/* config.c */
+__decl_noreturn void __noreturn erts_exit_epilogue(void);
__decl_noreturn void __noreturn erts_exit(int n, char*, ...);
__decl_noreturn void __noreturn erts_flush_async_exit(int n, char*, ...);
void erl_error(char*, va_list);
@@ -1161,7 +1162,7 @@ extern void erts_delete_nodes_monitors(Process *, ErtsProcLocks);
extern Eterm erts_monitor_nodes(Process *, Eterm, Eterm);
extern Eterm erts_processes_monitoring_nodes(Process *);
extern int erts_do_net_exits(DistEntry*, Eterm);
-extern int distribution_info(int, void *);
+extern int distribution_info(fmtfn_t, void *);
extern int is_node_name_atom(Eterm a);
extern int erts_net_message(Port *, DistEntry *,
@@ -1350,7 +1351,7 @@ int erts_utf8_to_latin1(byte* dest, const byte* source, int slen);
#define ERTS_UTF8_ANALYZE_MORE 3
#define ERTS_UTF8_OK_MAX_CHARS 4
-void bin_write(int, void*, byte*, size_t);
+void bin_write(fmtfn_t, void*, byte*, size_t);
Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */
struct Sint_buf {
@@ -1466,7 +1467,7 @@ Eterm erts_gc_binary_part_2(Process* p, Eterm* reg, Uint live);
Uint erts_current_reductions(Process* current, Process *p);
-int erts_print_system_version(int to, void *arg, Process *c_p);
+int erts_print_system_version(fmtfn_t to, void *arg, Process *c_p);
int erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* reg);
diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c
index cd038d100b..8548e30e8b 100644
--- a/erts/emulator/beam/hash.c
+++ b/erts/emulator/beam/hash.c
@@ -95,7 +95,7 @@ void hash_get_info(HashInfo *hi, Hash *h)
**
*/
-void hash_info(int to, void *arg, Hash* h)
+void hash_info(fmtfn_t to, void *arg, Hash* h)
{
HashInfo hi;
diff --git a/erts/emulator/beam/hash.h b/erts/emulator/beam/hash.h
index 4e769c0119..d319aaca83 100644
--- a/erts/emulator/beam/hash.h
+++ b/erts/emulator/beam/hash.h
@@ -37,7 +37,7 @@ typedef void (*HFREE_FUN)(void*);
/* Meta functions */
typedef void* (*HMALLOC_FUN)(int,size_t);
typedef void (*HMFREE_FUN)(int,void*);
-typedef int (*HMPRINT_FUN)(int,void*,char*, ...);
+typedef int (*HMPRINT_FUN)(fmtfn_t,void*,char*, ...);
/*
** This bucket must be placed in top of
@@ -89,7 +89,7 @@ Hash* hash_init(int, Hash*, char*, int, HashFunctions);
void hash_delete(Hash*);
void hash_get_info(HashInfo*, Hash*);
-void hash_info(int, void *, Hash*);
+void hash_info(fmtfn_t, void *, Hash*);
int hash_table_sz(Hash *);
void* hash_get(Hash*, void*);
diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c
index 26d6c04ea0..cd834e2c12 100644
--- a/erts/emulator/beam/index.c
+++ b/erts/emulator/beam/index.c
@@ -27,7 +27,7 @@
#include "global.h"
#include "index.h"
-void index_info(int to, void *arg, IndexTable *t)
+void index_info(fmtfn_t to, void *arg, IndexTable *t)
{
hash_info(to, arg, &t->htable);
erts_print(to, arg, "=index_table:%s\n", t->htable.name);
@@ -91,9 +91,16 @@ index_put_entry(IndexTable* t, void* tmpl)
t->seg_table[ix>>INDEX_PAGE_SHIFT] = erts_alloc(t->type, sz);
t->size += INDEX_PAGE_SIZE;
}
- t->entries++;
p->index = ix;
t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK] = p;
+
+ /*
+ * Do a write barrier here to allow readers to do lock free iteration.
+ * erts_index_num_entries() does matching read barrier.
+ */
+ ERTS_SMP_WRITE_MEMORY_BARRIER;
+ t->entries++;
+
return p;
}
diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h
index 0a109d8699..10f5d1eb39 100644
--- a/erts/emulator/beam/index.h
+++ b/erts/emulator/beam/index.h
@@ -51,7 +51,7 @@ typedef struct index_table
#define INDEX_PAGE_MASK ((1 << INDEX_PAGE_SHIFT)-1)
IndexTable *erts_index_init(ErtsAlcType_t,IndexTable*,char*,int,int,HashFunctions);
-void index_info(int, void *, IndexTable*);
+void index_info(fmtfn_t, void *, IndexTable*);
int index_table_sz(IndexTable *);
int index_get(IndexTable*, void*);
@@ -65,6 +65,7 @@ void index_erase_latest_from(IndexTable*, Uint ix);
ERTS_GLB_INLINE int index_put(IndexTable*, void*);
ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint);
+ERTS_GLB_INLINE int erts_index_num_entries(IndexTable* t);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
@@ -78,6 +79,19 @@ erts_index_lookup(IndexTable* t, Uint ix)
{
return t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK];
}
+
+ERTS_GLB_INLINE int erts_index_num_entries(IndexTable* t)
+{
+ int ret = t->entries;
+ /*
+ * Do a read barrier here to allow lock free iteration
+ * on tables where entries are never erased.
+ * index_put_entry() does matching write barrier.
+ */
+ ERTS_SMP_READ_MEMORY_BARRIER;
+ return ret;
+}
+
#endif
#endif
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 77dbe92241..4f131c74de 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -5480,7 +5480,7 @@ erts_request_io_bytes(Process *c_p)
typedef struct {
- int to;
+ fmtfn_t to;
void *arg;
} prt_one_lnk_data;
@@ -5497,7 +5497,7 @@ static void prt_one_lnk(ErtsLink *lnk, void *vprtd)
}
void
-print_port_info(Port *p, int to, void *arg)
+print_port_info(Port *p, fmtfn_t to, void *arg)
{
erts_aint32_t state = erts_atomic32_read_nob(&p->state);
diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c
index 4f36377450..5978478323 100644
--- a/erts/emulator/beam/module.c
+++ b/erts/emulator/beam/module.c
@@ -50,7 +50,7 @@ static erts_smp_atomic_t tot_module_bytes;
#include "erl_smp.h"
-void module_info(int to, void *to_arg)
+void module_info(fmtfn_t to, void *to_arg)
{
index_info(to, to_arg, &module_tables[erts_active_code_ix()]);
}
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index 1c1afc8461..f105b3f401 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -48,7 +48,7 @@ Module* erts_put_module(Eterm mod);
void init_module_table(void);
void module_start_staging(void);
void module_end_staging(int commit);
-void module_info(int, void *);
+void module_info(fmtfn_t, void *);
Module *module_code(int, ErtsCodeIndex);
int module_code_size(ErtsCodeIndex);
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index ac7096745e..acda51c9fc 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -102,7 +102,7 @@ is_proc_alive(Process *p)
return !ERTS_PROC_IS_EXITING(p);
}
-void register_info(int to, void *to_arg)
+void register_info(fmtfn_t to, void *to_arg)
{
int lock = !ERTS_IS_CRASH_DUMPING;
if (lock)
diff --git a/erts/emulator/beam/register.h b/erts/emulator/beam/register.h
index d839f55d6b..27a314ca78 100644
--- a/erts/emulator/beam/register.h
+++ b/erts/emulator/beam/register.h
@@ -44,7 +44,7 @@ typedef struct reg_proc
int process_reg_size(void);
int process_reg_sz(void);
void init_register_table(void);
-void register_info(int, void *);
+void register_info(fmtfn_t, void *);
int erts_register_name(Process *, Eterm, Eterm);
Eterm erts_whereis_name_to_id(Process *, Eterm);
void erts_whereis_name(Process *, ErtsProcLocks,
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index dfe82cab44..7740dd4373 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -378,6 +378,7 @@ typedef long Sint64;
# ifdef LONG_MIN
# define ERTS_SINT64_MIN LONG_MIN
# endif
+# define ErtsStrToSint64 strtol
# elif SIZEOF_LONG_LONG == 8
# define HAVE_INT64 1
typedef unsigned long long Uint64;
@@ -391,6 +392,7 @@ typedef long long Sint64;
# ifdef LLONG_MIN
# define ERTS_SINT64_MIN LLONG_MIN
# endif
+# define ErtsStrToSint64 strtoll
# else
# error "No 64-bit integer type found"
# endif
@@ -610,22 +612,21 @@ Uint erts_sys_misc_mem_sz(void);
#include "erl_printf.h"
/* Io constants to erts_print and erts_putc */
-#define ERTS_PRINT_STDERR (2)
-#define ERTS_PRINT_STDOUT (1)
-#define ERTS_PRINT_FILE (-1)
-#define ERTS_PRINT_SBUF (-2)
-#define ERTS_PRINT_SNBUF (-3)
-#define ERTS_PRINT_DSBUF (-4)
-
-#define ERTS_PRINT_MIN ERTS_PRINT_DSBUF
+#define ERTS_PRINT_STDERR ((fmtfn_t)0)
+#define ERTS_PRINT_STDOUT ((fmtfn_t)1)
+#define ERTS_PRINT_FILE ((fmtfn_t)2)
+#define ERTS_PRINT_SBUF ((fmtfn_t)3)
+#define ERTS_PRINT_SNBUF ((fmtfn_t)4)
+#define ERTS_PRINT_DSBUF ((fmtfn_t)5)
+#define ERTS_PRINT_FD ((fmtfn_t)6)
typedef struct {
char *buf;
size_t size;
} erts_print_sn_buf;
-int erts_print(int to, void *arg, char *format, ...); /* in utils.c */
-int erts_putc(int to, void *arg, char); /* in utils.c */
+int erts_print(fmtfn_t to, void *arg, char *format, ...); /* in utils.c */
+int erts_putc(fmtfn_t to, void *arg, char); /* in utils.c */
/* logger stuff is declared here instead of in global.h, so sys files
won't have to include global.h */
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 6786657faf..87ea4f05a1 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -348,40 +348,41 @@ int erts_fit_in_bits_uint(Uint value)
}
int
-erts_print(int to, void *arg, char *format, ...)
+erts_print(fmtfn_t to, void *arg, char *format, ...)
{
int res;
va_list arg_list;
va_start(arg_list, format);
- if (to < ERTS_PRINT_MIN)
- res = -EINVAL;
- else {
- switch (to) {
- case ERTS_PRINT_STDOUT:
+ {
+ switch ((UWord)to) {
+ case (UWord)ERTS_PRINT_STDOUT:
res = erts_vprintf(format, arg_list);
break;
- case ERTS_PRINT_STDERR:
+ case (UWord)ERTS_PRINT_STDERR:
res = erts_vfprintf(stderr, format, arg_list);
break;
- case ERTS_PRINT_FILE:
+ case (UWord)ERTS_PRINT_FILE:
res = erts_vfprintf((FILE *) arg, format, arg_list);
break;
- case ERTS_PRINT_SBUF:
+ case (UWord)ERTS_PRINT_SBUF:
res = erts_vsprintf((char *) arg, format, arg_list);
break;
- case ERTS_PRINT_SNBUF:
+ case (UWord)ERTS_PRINT_SNBUF:
res = erts_vsnprintf(((erts_print_sn_buf *) arg)->buf,
((erts_print_sn_buf *) arg)->size,
format,
arg_list);
break;
- case ERTS_PRINT_DSBUF:
+ case (UWord)ERTS_PRINT_DSBUF:
res = erts_vdsprintf((erts_dsprintf_buf_t *) arg, format, arg_list);
break;
- default:
- res = erts_vfdprintf((int) to, format, arg_list);
+ case (UWord)ERTS_PRINT_FD:
+ res = erts_vfdprintf((int)(SWord) arg, format, arg_list);
break;
+ default:
+ res = erts_vcbprintf(to, arg, format, arg_list);
+ break;
}
}
@@ -390,7 +391,7 @@ erts_print(int to, void *arg, char *format, ...)
}
int
-erts_putc(int to, void *arg, char c)
+erts_putc(fmtfn_t to, void *arg, char c)
{
return erts_print(to, arg, "%c", c);
}
@@ -3876,7 +3877,7 @@ store_external_or_ref_in_proc_(Process *proc, Eterm ns)
return store_external_or_ref_(&hp, &MSO(proc), ns);
}
-void bin_write(int to, void *to_arg, byte* buf, size_t sz)
+void bin_write(fmtfn_t to, void *to_arg, byte* buf, size_t sz)
{
size_t i;
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index 9c03b3811c..801cef2e56 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -226,11 +226,6 @@ void hipe_handle_exception(Process *c_p)
ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. */
- if (c_p->mbuf) {
- erts_printf("%s line %u: p==%p, p->mbuf==%p\n", __FUNCTION__, __LINE__, c_p, c_p->mbuf);
- /* erts_garbage_collect(c_p, 0, NULL, 0); */
- }
-
/*
* Check if we have an arglist for the top level call. If so, this
* is encoded in Value, so we have to dig out the real Value as well
@@ -259,11 +254,6 @@ void hipe_handle_exception(Process *c_p)
/* Synthesized to avoid having to generate code for it. */
c_p->def_arg_reg[0] = exception_tag[GET_EXC_CLASS(c_p->freason)];
- if (c_p->mbuf) {
- /* erts_printf("%s line %u: p==%p, p->mbuf==%p, p->lastbif==%p\n", __FUNCTION__, __LINE__, c_p, c_p->mbuf, c_p->hipe.lastbif); */
- erts_garbage_collect(c_p, 0, NULL, 0);
- }
-
hipe_find_handler(c_p);
}
diff --git a/erts/emulator/nifs/common/erl_tracer_nif.c b/erts/emulator/nifs/common/erl_tracer_nif.c
index c0cc48ff42..0bde60d057 100644
--- a/erts/emulator/nifs/common/erl_tracer_nif.c
+++ b/erts/emulator/nifs/common/erl_tracer_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson 2015. All Rights Reserved.
+ * Copyright Ericsson 2015-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c
index 7bbb406f29..a5714f8325 100644
--- a/erts/emulator/sys/common/erl_mmap.c
+++ b/erts/emulator/sys/common/erl_mmap.c
@@ -2390,7 +2390,7 @@ add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
}
Eterm erts_mmap_info(ErtsMemMapper* mm,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Eterm** hpp, Uint* szp,
struct erts_mmap_info_struct* emis)
@@ -2431,7 +2431,7 @@ Eterm erts_mmap_info(ErtsMemMapper* mm,
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
if (mm->supercarrier) {
const char* prefix = "supercarrier ";
@@ -2485,7 +2485,7 @@ Eterm erts_mmap_info(ErtsMemMapper* mm,
Eterm erts_mmap_info_options(ErtsMemMapper* mm,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -2496,7 +2496,7 @@ Eterm erts_mmap_info_options(ErtsMemMapper* mm,
Eterm res = THE_NON_VALUE;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to, arg, "%sscs: %bpu\n", prefix, scs);
if (mm->supercarrier) {
diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h
index fa51b663fa..623b5188ac 100644
--- a/erts/emulator/sys/common/erl_mmap.h
+++ b/erts/emulator/sys/common/erl_mmap.h
@@ -22,6 +22,7 @@
#define ERL_MMAP_H__
#include "sys.h"
+#include "erl_printf.h"
#define ERTS_MMAP_SUPERALIGNED_BITS (18)
/* Affects hard limits for sbct and lmbcs documented in erts_alloc.xml */
@@ -146,10 +147,10 @@ struct erts_mmap_info_struct
UWord segs[6];
UWord os_used;
};
-Eterm erts_mmap_info(ErtsMemMapper*, int *print_to_p, void *print_to_arg,
+Eterm erts_mmap_info(ErtsMemMapper*, fmtfn_t *print_to_p, void *print_to_arg,
Eterm** hpp, Uint* szp, struct erts_mmap_info_struct*);
Eterm erts_mmap_info_options(ErtsMemMapper*,
- char *prefix, int *print_to_p, void *print_to_arg,
+ char *prefix, fmtfn_t *print_to_p, void *print_to_arg,
Uint **hpp, Uint *szp);
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index f3306a888c..882c93a83c 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -991,7 +991,7 @@ add_4tup(Uint **hpp, Uint *szp, Eterm *lp,
static Eterm
info_options(ErtsMsegAllctr_t *ma,
char *prefix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
Uint **hpp,
Uint *szp)
@@ -999,7 +999,7 @@ info_options(ErtsMsegAllctr_t *ma,
Eterm res = NIL;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
erts_print(to, arg, "%samcbf: %beu\n", prefix, ma->abs_max_cache_bad_fit);
erts_print(to, arg, "%srmcbf: %beu\n", prefix, ma->rel_max_cache_bad_fit);
@@ -1027,7 +1027,7 @@ info_options(ErtsMsegAllctr_t *ma,
}
static Eterm
-info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
+info_calls(ErtsMsegAllctr_t *ma, fmtfn_t *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -1040,7 +1040,7 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp
erts_print(TO, TOA, "mseg_%s calls: %b32u%09b32u\n", #CC, \
ma->calls.CC.giga_no, ma->calls.CC.no)
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
PRINT_CC(to, arg, alloc);
@@ -1106,7 +1106,7 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp
}
static Eterm
-info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
+info_status(ErtsMsegAllctr_t *ma, fmtfn_t *print_to_p, void *print_to_arg,
int begin_new_max_period, int only_sz, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -1117,7 +1117,7 @@ info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
ma->segments.max_ever.sz = ma->segments.max.sz;
if (print_to_p) {
- int to = *print_to_p;
+ fmtfn_t to = *print_to_p;
void *arg = print_to_arg;
if (!only_sz) {
@@ -1165,7 +1165,7 @@ info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
return res;
}
-static Eterm info_memkind(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
+static Eterm info_memkind(ErtsMsegAllctr_t *ma, fmtfn_t *print_to_p, void *print_to_arg,
int begin_max_per, int only_sz, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -1196,7 +1196,7 @@ static Eterm info_memkind(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_
}
static Eterm
-info_version(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
+info_version(ErtsMsegAllctr_t *ma, fmtfn_t *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -1218,7 +1218,7 @@ info_version(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **h
Eterm
erts_mseg_info_options(int ix,
- int *print_to_p, void *print_to_arg,
+ fmtfn_t *print_to_p, void *print_to_arg,
Uint **hpp, Uint *szp)
{
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(ix);
@@ -1231,7 +1231,7 @@ erts_mseg_info_options(int ix,
Eterm
erts_mseg_info(int ix,
- int *print_to_p,
+ fmtfn_t *print_to_p,
void *print_to_arg,
int begin_max_per,
int only_sz,
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index a43b409e94..bba0dec499 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -98,8 +98,8 @@ Uint erts_mseg_unit_size(void);
void erts_mseg_init(ErtsMsegInit_t *init);
void erts_mseg_late_init(void); /* Have to be called after all allocators,
threads and timers have been initialized. */
-Eterm erts_mseg_info_options(int, int *, void*, Uint **, Uint *);
-Eterm erts_mseg_info(int, int *, void*, int, int, Uint **, Uint *);
+Eterm erts_mseg_info_options(int, fmtfn_t*, void*, Uint **, Uint *);
+Eterm erts_mseg_info(int, fmtfn_t *, void*, int, int, Uint **, Uint *);
#endif /* #if HAVE_ERTS_MSEG */
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 99e0aea4b5..2fc802a2c6 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -90,8 +90,6 @@ extern void erl_sys_args(int*, char**);
extern void erts_sys_init_float(void);
-extern void erl_crash_dump(char* file, int line, char* fmt, ...);
-
#ifdef DEBUG
static int debug_log = 0;
@@ -409,11 +407,16 @@ erts_sys_pre_init(void)
#ifdef ERTS_THR_HAVE_SIG_FUNCS
sigemptyset(&thr_create_sigmask);
sigaddset(&thr_create_sigmask, SIGINT); /* block interrupt */
+ sigaddset(&thr_create_sigmask, SIGTERM); /* block terminate signal */
sigaddset(&thr_create_sigmask, SIGUSR1); /* block user defined signal */
#endif
erts_thr_init(&eid);
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_init();
+#endif
+
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init();
#endif
@@ -653,6 +656,40 @@ static RETSIGTYPE request_break(int signum)
#endif
}
+static void stop_requested(void) {
+ Process* p = NULL;
+ Eterm msg, *hp;
+ ErtsProcLocks locks = 0;
+ ErlOffHeap *ohp;
+ Eterm id = erts_whereis_name_to_id(NULL, am_init);
+
+ if ((p = (erts_pid2proc_opt(NULL, 0, id, 0, ERTS_P2P_FLG_INC_REFC))) != NULL) {
+ ErtsMessage *msgp = erts_alloc_message_heap(p, &locks, 3, &hp, &ohp);
+
+ /* init ! {stop,stop} */
+ msg = TUPLE2(hp, am_stop, am_stop);
+ erts_queue_message(p, locks, msgp, msg, am_system);
+
+ if (locks)
+ erts_smp_proc_unlock(p, locks);
+ erts_proc_dec_refc(p);
+ }
+}
+
+#if (defined(SIG_SIGSET) || defined(SIG_SIGNAL))
+static RETSIGTYPE request_stop(void)
+#else
+static RETSIGTYPE request_stop(int signum)
+#endif
+{
+#ifdef ERTS_SMP
+ smp_sig_notify('S');
+#else
+ stop_requested();
+#endif
+}
+
+
static ERTS_INLINE void
sigusr1_exit(void)
{
@@ -749,6 +786,7 @@ static RETSIGTYPE do_quit(int signum)
/* Disable break */
void erts_set_ignore_break(void) {
sys_signal(SIGINT, SIG_IGN);
+ sys_signal(SIGTERM, SIG_IGN);
sys_signal(SIGQUIT, SIG_IGN);
sys_signal(SIGTSTP, SIG_IGN);
}
@@ -774,6 +812,7 @@ void erts_replace_intr(void) {
void init_break_handler(void)
{
sys_signal(SIGINT, request_break);
+ sys_signal(SIGTERM, request_stop);
#ifndef ETHR_UNUSABLE_SIGUSRX
sys_signal(SIGUSR1, user_signal1);
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
@@ -1287,6 +1326,9 @@ signal_dispatcher_thread_func(void *unused)
switch (buf[i]) {
case 0: /* Emulator initialized */
break;
+ case 'S': /* SIGTERM */
+ stop_requested();
+ break;
case 'I': /* SIGINT */
break_requested();
break;
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 04fbf23109..78005aada9 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -182,6 +182,8 @@ typedef LONGLONG ErtsMonotonicTime;
typedef LONGLONG ErtsSysHrTime;
#endif
+#define ErtsStrToSint64 _strtoi64
+
typedef ErtsMonotonicTime ErtsSystemTime;
typedef ErtsMonotonicTime ErtsSysPerfCounter;
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index cf821b05cb..f3881e0736 100644
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -40,7 +40,6 @@ void erts_sys_init_float(void);
void erl_start(int, char**);
void erts_exit(int n, char*, ...);
void erl_error(char*, va_list);
-void erl_crash_dump(char*, int, char*, ...);
/*
* Microsoft-specific function to map a WIN32 error code to a Posix errno.
@@ -3187,16 +3186,16 @@ erts_sys_pre_init(void)
eid.thread_create_parent_func = thr_create_cleanup;
erts_thr_init(&eid);
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_init();
#endif
-
- erts_init_sys_time_sup();
-
-#ifdef USE_THREADS
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init();
#endif
#endif
+ erts_init_sys_time_sup();
+
erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0);
}
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index d31399e4af..f70fb0e501 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -31,7 +31,9 @@
t_list_to_existing_atom/1,os_env/1,otp_7526/1,
binary_to_atom/1,binary_to_existing_atom/1,
atom_to_binary/1,min_max/1, erlang_halt/1,
- is_builtin/1]).
+ erl_crash_dump_bytes/1,
+ is_builtin/1, error_stacktrace/1,
+ error_stacktrace_during_call_trace/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -43,7 +45,8 @@ all() ->
t_list_to_existing_atom, os_env, otp_7526,
display,
atom_to_binary, binary_to_atom, binary_to_existing_atom,
- min_max, erlang_halt, is_builtin].
+ erl_crash_dump_bytes, min_max, erlang_halt, is_builtin,
+ error_stacktrace, error_stacktrace_during_call_trace].
%% Uses erlang:display to test that erts_printf does not do deep recursion
display(Config) when is_list(Config) ->
@@ -664,7 +667,7 @@ erlang_halt(Config) when is_list(Config) ->
[available_internal_state, true]),
{badrpc,nodedown} = rpc:call(N4, erts_debug, set_internal_state,
[broken_halt, "Validate correct crash dump"]),
- ok = wait_until_stable_size(CrashDump,-1),
+ {ok,_} = wait_until_stable_size(CrashDump,-1),
{ok, Bin} = file:read_file(CrashDump),
case {string:str(binary_to_list(Bin),"\n=end\n"),
string:str(binary_to_list(Bin),"\r\n=end\r\n")} of
@@ -681,11 +684,34 @@ wait_until_stable_size(File,PrevSz) ->
wait_until_stable_size(File,PrevSz-1);
{ok,#file_info{size = PrevSz }} when PrevSz /= -1 ->
io:format("Crashdump file size was: ~p (~s)~n",[PrevSz,File]),
- ok;
+ {ok,PrevSz};
{ok,#file_info{size = NewSz }} ->
wait_until_stable_size(File,NewSz)
end.
+% Test erlang:halt with ERL_CRASH_DUMP_BYTES
+erl_crash_dump_bytes(Config) when is_list(Config) ->
+ Bytes = 1000,
+ CrashDump = do_limited_crash_dump(Config, Bytes),
+ {ok,ActualBytes} = wait_until_stable_size(CrashDump,-1),
+ true = ActualBytes < (Bytes + 100),
+
+ NoDump = do_limited_crash_dump(Config,0),
+ {error,enoent} = wait_until_stable_size(NoDump,-8),
+ ok.
+
+do_limited_crash_dump(Config, Bytes) ->
+ H = hostname(),
+ {ok,N} = slave:start(H, halt_node),
+ BytesStr = integer_to_list(Bytes),
+ CrashDump = filename:join(proplists:get_value(priv_dir,Config),
+ "erl_crash." ++ BytesStr ++ ".dump"),
+ true = rpc:call(N, os, putenv, ["ERL_CRASH_DUMP",CrashDump]),
+ true = rpc:call(N, os, putenv, ["ERL_CRASH_DUMP_BYTES",BytesStr]),
+ {badrpc,nodedown} = rpc:call(N, erlang, halt, ["Testing ERL_CRASH_DUMP_BYTES"]),
+ CrashDump.
+
+
is_builtin(_Config) ->
Exp0 = [{M,F,A} || {M,_} <- code:all_loaded(),
{F,A} <- M:module_info(exports)],
@@ -702,6 +728,172 @@ is_builtin(_Config) ->
ok.
+error_stacktrace(Config) when is_list(Config) ->
+ error_stacktrace_test().
+
+error_stacktrace_during_call_trace(Config) when is_list(Config) ->
+ Tracer = spawn_link(fun () ->
+ receive after infinity -> ok end
+ end),
+ Mprog = [{'_',[],[{exception_trace}]}],
+ erlang:trace_pattern({?MODULE,'_','_'}, Mprog, [local]),
+ 1 = erlang:trace_pattern({erlang,error,2}, Mprog, [local]),
+ 1 = erlang:trace_pattern({erlang,error,1}, Mprog, [local]),
+ erlang:trace(all, true, [call,return_to,timestamp,{tracer, Tracer}]),
+ try
+ error_stacktrace_test()
+ after
+ erlang:trace(all, false, [call,return_to,timestamp,{tracer, Tracer}]),
+ erlang:trace_pattern({erlang,error,2}, false, [local]),
+ erlang:trace_pattern({erlang,error,1}, false, [local]),
+ erlang:trace_pattern({?MODULE,'_','_'}, false, [local]),
+ unlink(Tracer),
+ exit(Tracer, kill),
+ Mon = erlang:monitor(process, Tracer),
+ receive
+ {'DOWN', Mon, process, Tracer, _} -> ok
+ end
+ end,
+ ok.
+
+
+error_stacktrace_test() ->
+ Types = [apply_const_last, apply_const, apply_last,
+ apply, double_apply_const_last, double_apply_const,
+ double_apply_last, double_apply, multi_apply_const_last,
+ multi_apply_const, multi_apply_last, multi_apply,
+ call_const_last, call_last, call_const, call],
+ lists:foreach(fun (Type) ->
+ {Pid, Mon} = spawn_monitor(
+ fun () ->
+ stk([a,b,c,d], Type, error_2)
+ end),
+ receive
+ {'DOWN', Mon, process, Pid, Reason} ->
+ {oops, Stack} = Reason,
+%% io:format("Type: ~p Stack: ~p~n",
+%% [Type, Stack]),
+ [{?MODULE, do_error_2, [Type], _},
+ {?MODULE, stk, 3, _},
+ {?MODULE, stk, 3, _}] = Stack
+ end
+ end,
+ Types),
+ lists:foreach(fun (Type) ->
+ {Pid, Mon} = spawn_monitor(
+ fun () ->
+ stk([a,b,c,d], Type, error_1)
+ end),
+ receive
+ {'DOWN', Mon, process, Pid, Reason} ->
+ {oops, Stack} = Reason,
+%% io:format("Type: ~p Stack: ~p~n",
+%% [Type, Stack]),
+ [{?MODULE, do_error_1, 1, _},
+ {?MODULE, stk, 3, _},
+ {?MODULE, stk, 3, _}] = Stack
+ end
+ end,
+ Types),
+ ok.
+
+stk([], Type, Func) ->
+ tail(Type, Func, jump),
+ ok;
+stk([_|L], Type, Func) ->
+ stk(L, Type, Func),
+ ok.
+
+tail(Type, Func, jump) ->
+ tail(Type, Func, do);
+tail(Type, error_1, do) ->
+ do_error_1(Type);
+tail(Type, error_2, do) ->
+ do_error_2(Type).
+
+do_error_2(apply_const_last) ->
+ erlang:apply(erlang, error, [oops, [apply_const_last]]);
+do_error_2(apply_const) ->
+ erlang:apply(erlang, error, [oops, [apply_const]]),
+ ok;
+do_error_2(apply_last) ->
+ erlang:apply(id(erlang), id(error), id([oops, [apply_last]]));
+do_error_2(apply) ->
+ erlang:apply(id(erlang), id(error), id([oops, [apply]])),
+ ok;
+do_error_2(double_apply_const_last) ->
+ erlang:apply(erlang, apply, [erlang, error, [oops, [double_apply_const_last]]]);
+do_error_2(double_apply_const) ->
+ erlang:apply(erlang, apply, [erlang, error, [oops, [double_apply_const]]]),
+ ok;
+do_error_2(double_apply_last) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops, [double_apply_last]])]);
+do_error_2(double_apply) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops, [double_apply]])]),
+ ok;
+do_error_2(multi_apply_const_last) ->
+ erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops, [multi_apply_const_last]]]]]);
+do_error_2(multi_apply_const) ->
+ erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops, [multi_apply_const]]]]]),
+ ok;
+do_error_2(multi_apply_last) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops, [multi_apply_last]])]]]);
+do_error_2(multi_apply) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops, [multi_apply]])]]]),
+ ok;
+do_error_2(call_const_last) ->
+ erlang:error(oops, [call_const_last]);
+do_error_2(call_last) ->
+ erlang:error(id(oops), id([call_last]));
+do_error_2(call_const) ->
+ erlang:error(oops, [call_const]),
+ ok;
+do_error_2(call) ->
+ erlang:error(id(oops), id([call])).
+
+
+do_error_1(apply_const_last) ->
+ erlang:apply(erlang, error, [oops]);
+do_error_1(apply_const) ->
+ erlang:apply(erlang, error, [oops]),
+ ok;
+do_error_1(apply_last) ->
+ erlang:apply(id(erlang), id(error), id([oops]));
+do_error_1(apply) ->
+ erlang:apply(id(erlang), id(error), id([oops])),
+ ok;
+do_error_1(double_apply_const_last) ->
+ erlang:apply(erlang, apply, [erlang, error, [oops]]);
+do_error_1(double_apply_const) ->
+ erlang:apply(erlang, apply, [erlang, error, [oops]]),
+ ok;
+do_error_1(double_apply_last) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops])]);
+do_error_1(double_apply) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(error), id([oops])]),
+ ok;
+do_error_1(multi_apply_const_last) ->
+ erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops]]]]);
+do_error_1(multi_apply_const) ->
+ erlang:apply(erlang, apply, [erlang, apply, [erlang, apply, [erlang, error, [oops]]]]),
+ ok;
+do_error_1(multi_apply_last) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops])]]]);
+do_error_1(multi_apply) ->
+ erlang:apply(id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(apply), [id(erlang), id(error), id([oops])]]]),
+ ok;
+do_error_1(call_const_last) ->
+ erlang:error(oops);
+do_error_1(call_last) ->
+ erlang:error(id(oops));
+do_error_1(call_const) ->
+ erlang:error(oops),
+ ok;
+do_error_1(call) ->
+ erlang:error(id(oops)).
+
+
+
%% Helpers
diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl
index 6ba6301c7c..f7ff04430a 100644
--- a/erts/emulator/test/call_trace_SUITE.erl
+++ b/erts/emulator/test/call_trace_SUITE.erl
@@ -1090,8 +1090,7 @@ exception_nocatch() ->
{trace,t2,exception_from,{erlang,throw,1},
{error,{nocatch,Q2}}}],
exception_from, {error,{nocatch,Q2}}),
- expect({trace,T2,exit,{{nocatch,Q2},[{erlang,throw,[Q2],[]},
- {?MODULE,deep_4,1,
+ expect({trace,T2,exit,{{nocatch,Q2},[{?MODULE,deep_4,1,
Deep4LocThrow}]}}),
Q3 = {dump,[dump,{dump}]},
T3 =
@@ -1100,8 +1099,7 @@ exception_nocatch() ->
{trace,t3,exception_from,{erlang,error,1},
{error,Q3}}],
exception_from, {error,Q3}),
- expect({trace,T3,exit,{Q3,[{erlang,error,[Q3],[]},
- {?MODULE,deep_4,1,Deep4LocError}]}}),
+ expect({trace,T3,exit,{Q3,[{?MODULE,deep_4,1,Deep4LocError}]}}),
T4 =
exception_nocatch(?LINE, '=', [17,4711], 5, [],
exception_from, {error,{badmatch,4711}}),
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 34515efa3d..3ee14f2d1c 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -66,9 +66,9 @@ versions(Config) when is_list(Config) ->
2 = versions:version(),
%% Kill processes, unload code.
- P1 ! P2 ! done,
_ = monitor(process, P1),
_ = monitor(process, P2),
+ P1 ! P2 ! done,
receive
{'DOWN',_,process,P1,normal} -> ok
end,
diff --git a/erts/emulator/test/dirty_nif_SUITE.erl b/erts/emulator/test/dirty_nif_SUITE.erl
index 658bdc41b6..a61fd92a18 100644
--- a/erts/emulator/test/dirty_nif_SUITE.erl
+++ b/erts/emulator/test/dirty_nif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
index a0019e5d95..08efa23c81 100644
--- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
+++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/emulator_smoke.spec b/erts/emulator/test/emulator_smoke.spec
index 3219aeb823..b2d0de8835 100644
--- a/erts/emulator/test/emulator_smoke.spec
+++ b/erts/emulator/test/emulator_smoke.spec
@@ -1,3 +1,9 @@
-{suites,"../emulator_test",[smoke_test_SUITE,time_SUITE]}.
-{cases,"../emulator_test",crypto_SUITE,[t_md5]}.
-{cases,"../emulator_test",float_SUITE,[fpe,cmp_integer]}. \ No newline at end of file
+{define,'Dir',"../emulator_test"}.
+{suites,'Dir',[smoke_test_SUITE]}.
+{suites,'Dir',[time_SUITE]}.
+{skip_cases,'Dir',time_SUITE,
+ [univ_to_local,local_to_univ],"Depends on CET timezone"}.
+{skip_cases,'Dir',time_SUITE,
+ [consistency],"Not reliable in October and March"}.
+{cases,'Dir',crypto_SUITE,[t_md5]}.
+{cases,'Dir',float_SUITE,[fpe,cmp_integer]}.
diff --git a/erts/emulator/test/lttng_SUITE.erl b/erts/emulator/test/lttng_SUITE.erl
index 6b7ad836f5..c12f63706a 100644
--- a/erts/emulator/test/lttng_SUITE.erl
+++ b/erts/emulator/test/lttng_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index d4e77d634a..23594aa8c4 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -2292,7 +2292,7 @@ maybe_to_list(List) ->
List.
format({Eol,List}) ->
- io_lib:format("tuple<~w,~s>",[Eol, maybe_to_list(List)]);
+ io_lib:format("tuple<~w,~w>",[Eol, maybe_to_list(List)]);
format(List) when is_list(List) ->
case list_at_least(50, List) of
true ->
diff --git a/erts/emulator/test/port_SUITE_data/Makefile.src b/erts/emulator/test/port_SUITE_data/Makefile.src
index fb7685c4b6..3a343e6d17 100644
--- a/erts/emulator/test/port_SUITE_data/Makefile.src
+++ b/erts/emulator/test/port_SUITE_data/Makefile.src
@@ -20,6 +20,12 @@ echo_args@exe@: echo_args@obj@
echo_args@obj@: echo_args.c
$(CC) -c -o echo_args@obj@ $(CFLAGS) echo_args.c
+dead_port@exe@: dead_port@obj@
+ $(LD) $(CROSSLDFLAGS) -o dead_port dead_port@obj@ @LIBS@
+
+dead_port@obj@: dead_port.c
+ $(CC) -c -o dead_port@obj@ $(CFLAGS) dead_port.c
+
port_test.@EMULATOR@: port_test.erl
@erl_name@ -compile port_test
diff --git a/erts/emulator/test/port_SUITE_data/port_test.c b/erts/emulator/test/port_SUITE_data/port_test.c
index cc3ebdf0f8..e199a0fc13 100644
--- a/erts/emulator/test/port_SUITE_data/port_test.c
+++ b/erts/emulator/test/port_SUITE_data/port_test.c
@@ -10,6 +10,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <ctype.h>
#ifndef __WIN32__
#include <unistd.h>
@@ -33,7 +34,7 @@
exit(1); \
}
-#define MAIN(argc, argv) main(argc, argv)
+#define ASSERT(e) ((void) ((e) ? 1 : abort()))
extern int errno;
@@ -105,9 +106,7 @@ int err;
#endif
-MAIN(argc, argv)
-int argc;
-char *argv[];
+int main(int argc, char *argv[])
{
int ret, fd_count;
if((port_data = (PORT_TEST_DATA *) malloc(sizeof(PORT_TEST_DATA))) == NULL) {
@@ -377,9 +376,11 @@ write_reply(buf, size)
int size; /* Size of buffer to send. */
{
int n; /* Temporary to hold size. */
+ int rv;
if (port_data->slow_writes <= 0) { /* Normal, "fast", write. */
- write(port_data->fd_to_erl, buf, size);
+ rv = write(port_data->fd_to_erl, buf, size);
+ ASSERT(rv == size);
} else {
/*
* Write chunks with delays in between.
@@ -387,7 +388,8 @@ write_reply(buf, size)
while (size > 0) {
n = size > port_data->slow_writes ? port_data->slow_writes : size;
- write(port_data->fd_to_erl, buf, n);
+ rv = write(port_data->fd_to_erl, buf, n);
+ ASSERT(rv == n);
size -= n;
buf += n;
if (size)
@@ -558,7 +560,7 @@ char* spec; /* Specification for reply. */
buf = (char *) malloc(total_size);
if (buf == NULL) {
fprintf(stderr, "%s: insufficent memory for reply buffer of size %d\n",
- port_data->progname, total_size);
+ port_data->progname, (int)total_size);
exit(1);
}
diff --git a/erts/emulator/test/port_trace_SUITE.erl b/erts/emulator/test/port_trace_SUITE.erl
index 5d9a75bcd3..03efdc15db 100644
--- a/erts/emulator/test/port_trace_SUITE.erl
+++ b/erts/emulator/test/port_trace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 0f999e0efe..0a6eb7ffac 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -437,11 +437,22 @@ t_process_info(Config) when is_list(Config) ->
verify_loc(Line2, Res2),
pi_stacktrace([{?MODULE,t_process_info,1,?LINE}]),
+ verify_stacktrace_depth(),
+
Gleader = group_leader(),
{group_leader, Gleader} = process_info(self(), group_leader),
{'EXIT',{badarg,_Info}} = (catch process_info('not_a_pid')),
ok.
+verify_stacktrace_depth() ->
+ CS = current_stacktrace,
+ OldDepth = erlang:system_flag(backtrace_depth, 0),
+ {CS,[]} = erlang:process_info(self(), CS),
+ _ = erlang:system_flag(backtrace_depth, 8),
+ {CS,[{?MODULE,verify_stacktrace_depth,0,_},_|_]} =
+ erlang:process_info(self(), CS),
+ _ = erlang:system_flag(backtrace_depth, OldDepth).
+
pi_stacktrace(Expected0) ->
{Line,Res} = {?LINE,erlang:process_info(self(), current_stacktrace)},
{current_stacktrace,Stack} = Res,
@@ -1611,6 +1622,7 @@ spawn_initial_hangarounds(_Cleaner, NP, Max, Len, HAs) when NP > Max ->
{Len, HAs};
spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
Skip = 30,
+ wait_for_proc_slots(Skip+3),
HA1 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, low}]),
HA2 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
@@ -1620,6 +1632,15 @@ spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
spawn_drop(Skip),
spawn_initial_hangarounds(Cleaner, NP+Skip, Max, Len+3, [HA1,HA2,HA3|HAs]).
+wait_for_proc_slots(MinFreeSlots) ->
+ case erlang:system_info(process_limit) - erlang:system_info(process_count) of
+ FreeSlots when FreeSlots < MinFreeSlots ->
+ receive after 10 -> ok end,
+ wait_for_proc_slots(MinFreeSlots);
+ _FreeSlots ->
+ ok
+ end.
+
spawn_drop(N) when N =< 0 ->
ok;
spawn_drop(N) ->
diff --git a/erts/emulator/test/tracer_SUITE.erl b/erts/emulator/test/tracer_SUITE.erl
index 9eb55c9af3..730c43d8c2 100644
--- a/erts/emulator/test/tracer_SUITE.erl
+++ b/erts/emulator/test/tracer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/tracer_SUITE_data/tracer_test.c b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
index a26bb33600..d9543b7ab9 100644
--- a/erts/emulator/test/tracer_SUITE_data/tracer_test.c
+++ b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/tracer_test.erl b/erts/emulator/test/tracer_test.erl
index 1da80bfe31..a82fd04d2e 100644
--- a/erts/emulator/test/tracer_test.erl
+++ b/erts/emulator/test/tracer_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index d67b997d6d..bc353e384e 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -48,13 +48,10 @@
*
* HEART_BEATING
*
- * This program expects a heart beat messages. If it does not receive a
- * heart beat message from Erlang within heart_beat_timeout seconds, it
- * reboots the system. The variable heart_beat_timeout is exported (so
- * that it can be set from the shell in VxWorks, as is the variable
- * heart_beat_report_delay). When using Solaris, the system is rebooted
- * by executing the command stored in the environment variable
- * HEART_COMMAND.
+ * This program expects a heart beat message. If it does not receive a
+ * heart beat message from Erlang within heart_beat_timeout seconds, it
+ * reboots the system. The system is rebooted by executing the command
+ * stored in the environment variable HEART_COMMAND.
*
* BLOCKING DESCRIPTORS
*
@@ -149,27 +146,17 @@ struct msg {
/* Maybe interesting to change */
/* Times in seconds */
-#define HEART_BEAT_BOOT_DELAY 60 /* 1 minute */
#define SELECT_TIMEOUT 5 /* Every 5 seconds we reset the
watchdog timer */
/* heart_beat_timeout is the maximum gap in seconds between two
- consecutive heart beat messages from Erlang, and HEART_BEAT_BOOT_DELAY
- is the the extra delay that wd_keeper allows for, to give heart a
- chance to reboot in the "normal" way before the hardware watchdog
- enters the scene. heart_beat_report_delay is the time allowed for reporting
- before rebooting under VxWorks. */
+ consecutive heart beat messages from Erlang. */
int heart_beat_timeout = 60;
-int heart_beat_report_delay = 30;
-int heart_beat_boot_delay = HEART_BEAT_BOOT_DELAY;
/* All current platforms have a process identifier that
fits in an unsigned long and where 0 is an impossible or invalid value */
unsigned long heart_beat_kill_pid = 0;
-#define VW_WD_TIMEOUT (heart_beat_timeout+heart_beat_report_delay+heart_beat_boot_delay)
-#define SOL_WD_TIMEOUT (heart_beat_timeout+heart_beat_boot_delay)
-
/* reasons for reboot */
#define R_TIMEOUT (1)
#define R_CLOSED (2)
@@ -297,7 +284,6 @@ free_env_val(char *value)
static void get_arguments(int argc, char** argv) {
int i = 1;
int h;
- int w;
unsigned long p;
while (i < argc) {
@@ -313,15 +299,6 @@ static void get_arguments(int argc, char** argv) {
i++;
}
break;
- case 'w':
- if (strcmp(argv[i], "-wt") == 0)
- if (sscanf(argv[i+1],"%i",&w) ==1)
- if ((w > 10) && (w <= 65535)) {
- heart_beat_boot_delay = w;
- fprintf(stderr,"heart_beat_boot_delay = %d\n",w);
- i++;
- }
- break;
case 'p':
if (strcmp(argv[i], "-pid") == 0)
if (sscanf(argv[i+1],"%lu",&p) ==1){
@@ -347,7 +324,7 @@ static void get_arguments(int argc, char** argv) {
}
i++;
}
- debugf("arguments -ht %d -wt %d -pid %lu\n",h,w,p);
+ debugf("arguments -ht %d -pid %lu\n",h,p);
}
int main(int argc, char **argv) {
@@ -674,11 +651,6 @@ void win_system(char *command)
*/
static void
do_terminate(int erlin_fd, int reason) {
- /*
- When we get here, we have HEART_BEAT_BOOT_DELAY secs to finish
- (plus heart_beat_report_delay if under VxWorks), so we don't need
- to call wd_reset().
- */
int ret = 0, tmo=0;
char *tmo_env;
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 1a4f641301..f2babc48d2 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1322,7 +1322,11 @@ define etp-stacktrace
set $etp_stacktrace_p = ($arg0)->stop
set $etp_stacktrace_end = ($arg0)->hend
printf "%% Stacktrace (%u): ", $etp_stacktrace_end-$etp_stacktrace_p
- etp ($arg0)->cp
+ if ($arg0)->cp == 0x0
+ printf "NULL\n"
+ else
+ etp ($arg0)->cp
+ end
while $etp_stacktrace_p < $etp_stacktrace_end
if ($etp_stacktrace_p[0] & 0x3) == 0x0
# Continuation pointer
@@ -1350,7 +1354,11 @@ define etp-stackdump
set $etp_stackdump_p = ($arg0)->stop
set $etp_stackdump_end = ($arg0)->hend
printf "%% Stackdump (%u): ", $etp_stackdump_end-$etp_stackdump_p
- etp ($arg0)->cp
+ if ($arg0)->cp == 0x0
+ printf "NULL\n"
+ else
+ etp ($arg0)->cp
+ end
while $etp_stackdump_p < $etp_stackdump_end
etp $etp_stackdump_p[0]
set $etp_stackdump_p++
@@ -2443,46 +2451,36 @@ define etp-schedulers
if (!erts_initialized)
printf "No schedulers, since system isn't initialized!\n"
else
+ set $sched_type = 0
set $sched_ix = 0
while $sched_ix < erts_no_schedulers
- printf "--- Scheduler %d ---\n", $sched_ix+1
- printf " IX: %d\n", $sched_ix
- if (erts_aligned_scheduler_data[$sched_ix].esd.cpu_id < 0)
- printf " CPU Binding: unbound\n"
- else
- printf " CPU Binding: %d\n", erts_aligned_scheduler_data[$sched_ix].esd.cpu_id
- end
- printf " Aux work Flags:"
- set $aux_work_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->aux_work)
- etp-aux-work-flags $aux_work_flags
- printf " Sleep Info Flags:"
- set $ssi_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->flags)
- etp-ssi-flags $ssi_flags
- printf " Pointer: (ErtsSchedulerData *) %p\n", &erts_aligned_scheduler_data[$sched_ix].esd
- printf " - Run Queue -\n"
- if (etp_smp_compiled)
- set $runq = erts_aligned_scheduler_data[$sched_ix].esd.run_queue
- else
- set $runq = &erts_aligned_run_queues[0].runq
- end
- printf " Length: total=%d", *((Uint32 *) &($runq->len))
- printf ", max=%d", *((Uint32 *) &($runq->procs.prio_info[0].len))
- printf ", high=%d", *((Uint32 *) &($runq->procs.prio_info[1].len))
- printf ", normal=%d", *((Uint32 *) &($runq->procs.prio_info[2].len))
- printf ", low=%d", *((Uint32 *) &($runq->procs.prio_info[3].len))
- printf ", port=%d\n", *((Uint32 *) &($runq->ports.info.len))
- if ($runq->misc.start)
- printf " Misc Jobs: yes\n"
- else
- printf " Misc Jobs: no\n"
- end
- set $rq_flags = *((Uint32 *) &($runq->flags))
- etp-rq-flags-int $rq_flags
- printf " Pointer: (ErtsRunQueue *) %p\n", $runq
-
+ etp-scheduler-info-internal
+ etp-run-queue-info-internal
set $sched_ix++
end
- printf "-------------------\n",
+ printf "---------------------\n"
+ if (erts_no_dirty_cpu_schedulers)
+ printf "\n\n"
+ set $sched_type = 1
+ set $sched_ix = 0
+ while $sched_ix < erts_no_dirty_cpu_schedulers
+ etp-scheduler-info-internal
+ set $sched_ix++
+ end
+ etp-run-queue-info-internal
+ printf "---------------------\n"
+ end
+ if (erts_no_dirty_io_schedulers)
+ printf "\n\n"
+ set $sched_type = 2
+ set $sched_ix = 0
+ while $sched_ix < erts_no_dirty_io_schedulers
+ etp-scheduler-info-internal
+ set $sched_ix++
+ end
+ etp-run-queue-info-internal
+ printf "---------------------\n"
+ end
end
end
@@ -2494,6 +2492,67 @@ document etp-schedulers
%---------------------------------------------------------------------------
end
+define etp-scheduler-info-internal
+ if ($sched_type == 0)
+ printf "--- Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_scheduler_data[$sched_ix].esd
+ else
+ if ($sched_type == 1)
+ printf "--- Dirty CPU Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_dirty_cpu_scheduler_data[$sched_ix].esd
+ else
+ printf "--- Dirty I/O Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_dirty_io_scheduler_data[$sched_ix].esd
+ end
+ end
+ printf " IX: %d\n", $sched_ix
+ if ($sched_data->cpu_id < 0)
+ printf " CPU Binding: unbound\n"
+ else
+ printf " CPU Binding: %d\n", $sched_data->cpu_id
+ end
+ printf " Aux work Flags:"
+ set $aux_work_flags = *((Uint32 *) &$sched_data->ssi->aux_work)
+ etp-aux-work-flags $aux_work_flags
+ printf " Sleep Info Flags:"
+ set $ssi_flags = *((Uint32 *) &$sched_data->ssi->flags)
+ etp-ssi-flags $ssi_flags
+ printf " Pointer: (ErtsSchedulerData *) %p\n", $sched_data
+end
+
+define etp-run-queue-info-internal
+ if ($sched_type == 0)
+ printf " - Run Queue -\n"
+ if (etp_smp_compiled)
+ set $runq = erts_aligned_scheduler_data[$sched_ix].esd.run_queue
+ else
+ set $runq = &erts_aligned_run_queues[0].runq
+ end
+ else
+ if ($sched_type == 1)
+ printf "\n--- Dirty CPU Run Queue ---\n"
+ set $runq = &erts_aligned_run_queues[-1].runq
+ else
+ printf "\n--- Dirty I/O Run Queue ---\n"
+ set $runq = &erts_aligned_run_queues[-2].runq
+ end
+ end
+ printf " Length: total=%d", *((Uint32 *) &($runq->len))
+ printf ", max=%d", *((Uint32 *) &($runq->procs.prio_info[0].len))
+ printf ", high=%d", *((Uint32 *) &($runq->procs.prio_info[1].len))
+ printf ", normal=%d", *((Uint32 *) &($runq->procs.prio_info[2].len))
+ printf ", low=%d", *((Uint32 *) &($runq->procs.prio_info[3].len))
+ printf ", port=%d\n", *((Uint32 *) &($runq->ports.info.len))
+ if ($runq->misc.start)
+ printf " Misc Jobs: yes\n"
+ else
+ printf " Misc Jobs: no\n"
+ end
+ set $rq_flags = *((Uint32 *) &($runq->flags))
+ etp-rq-flags-int $rq_flags
+ printf " Pointer: (ErtsRunQueue *) %p\n", $runq
+
+
define etp-disasm-1
set $code_ptr = ((BeamInstr*)$arg0)
set $addr = *$code_ptr
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 6a92e18648..debd643da7 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2015. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/example/time_compat.erl b/erts/example/time_compat.erl
index 589781c8e8..6472a271b6 100644
--- a/erts/example/time_compat.erl
+++ b/erts/example/time_compat.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/include/internal/erl_printf.h b/erts/include/internal/erl_printf.h
index c4565dfafc..f180a53f18 100644
--- a/erts/include/internal/erl_printf.h
+++ b/erts/include/internal/erl_printf.h
@@ -41,12 +41,18 @@ struct erts_dsprintf_buf_t_ {
#define ERTS_DSPRINTF_BUF_INITER(GFUNC) {NULL, 0, 0, (GFUNC)}
+typedef int (*fmtfn_t)(void*, char*, size_t);
+
+int erts_write_fd(void *vfdp, char* buf, size_t len);
+int erts_write_ds(void *vdsbufp, char* buf, size_t len);
+
int erts_printf(const char *, ...);
int erts_fprintf(FILE *, const char *, ...);
int erts_fdprintf(int, const char *, ...);
int erts_sprintf(char *, const char *, ...);
int erts_snprintf(char *, size_t, const char *, ...);
int erts_dsprintf(erts_dsprintf_buf_t *, const char *, ...);
+int erts_cbprintf(fmtfn_t, void*, const char*, ...);
int erts_vprintf(const char *, va_list);
int erts_vfprintf(FILE *, const char *, va_list);
@@ -54,5 +60,6 @@ int erts_vfdprintf(int, const char *, va_list);
int erts_vsprintf(char *, const char *, va_list);
int erts_vsnprintf(char *, size_t, const char *, va_list);
int erts_vdsprintf(erts_dsprintf_buf_t *, const char *, va_list);
+int erts_vcbprintf(fmtfn_t, void*, const char*, va_list);
#endif /* #ifndef ERL_PRINTF_H_ */
diff --git a/erts/include/internal/erl_printf_format.h b/erts/include/internal/erl_printf_format.h
index 4f969bdbcb..56ec032bd1 100644
--- a/erts/include/internal/erl_printf_format.h
+++ b/erts/include/internal/erl_printf_format.h
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include "erl_int_sizes_config.h"
+#include "erl_printf.h"
#if SIZEOF_VOID_P == SIZEOF_LONG
typedef unsigned long ErlPfUWord;
@@ -44,8 +45,6 @@ typedef long long ErlPfSWord;
#error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint'
#endif
-typedef int (*fmtfn_t)(void*, char*, size_t);
-
extern int erts_printf_format(fmtfn_t, void*, char*, va_list);
extern int erts_printf_char(fmtfn_t, void*, char);
diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c
index b5e90dfeef..7781fc2196 100644
--- a/erts/lib_src/common/erl_printf.c
+++ b/erts/lib_src/common/erl_printf.c
@@ -165,8 +165,8 @@ write_f(void *vfp, char* buf, size_t len)
return len;
}
-static int
-write_fd(void *vfdp, char* buf, size_t len)
+int
+erts_write_fd(void *vfdp, char* buf, size_t len)
{
ssize_t size;
size_t res = len;
@@ -226,8 +226,8 @@ write_sn(void *vwsnap, char* buf, size_t len)
return rv;
}
-static int
-write_ds(void *vdsbufp, char* buf, size_t len)
+int
+erts_write_ds(void *vdsbufp, char* buf, size_t len)
{
erts_dsprintf_buf_t *dsbufp = (erts_dsprintf_buf_t *) vdsbufp;
size_t need_len = len + 1; /* Also trailing '\0' */
@@ -301,7 +301,7 @@ erts_fdprintf(int fd, const char *format, ...)
va_list arglist;
va_start(arglist, format);
errno = 0;
- res = erts_printf_format(write_fd,(void *)&fd,(char *)format,arglist);
+ res = erts_printf_format(erts_write_fd,(void *)&fd,(char *)format,arglist);
va_end(arglist);
return res;
}
@@ -355,7 +355,7 @@ erts_dsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, ...)
return -EINVAL;
va_start(arglist, format);
errno = 0;
- res = erts_printf_format(write_ds, (void *)dsbufp, (char *)format, arglist);
+ res = erts_printf_format(erts_write_ds, (void *)dsbufp, (char *)format, arglist);
if (dsbufp->str) {
if (res < 0)
dsbufp->str[0] = '\0';
@@ -366,6 +366,20 @@ erts_dsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, ...)
return res;
}
+/*
+ * Callback printf
+ */
+int erts_cbprintf(fmtfn_t cb_fn, void* cb_arg, const char* format, ...)
+{
+ int res;
+ va_list arglist;
+ va_start(arglist, format);
+ errno = 0;
+ res = erts_printf_format(cb_fn, cb_arg, (char *)format, arglist);
+ va_end(arglist);
+ return res;
+}
+
int
erts_vprintf(const char *format, va_list arglist)
{
@@ -411,7 +425,7 @@ erts_vfdprintf(int fd, const char *format, va_list arglist)
{
int res;
errno = 0;
- res = erts_printf_format(write_fd,(void *)&fd,(char *)format,arglist);
+ res = erts_printf_format(erts_write_fd,(void *)&fd,(char *)format,arglist);
return res;
}
@@ -456,7 +470,7 @@ erts_vdsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, va_list arglist)
if (!dsbufp)
return -EINVAL;
errno = 0;
- res = erts_printf_format(write_ds, (void *)dsbufp, (char *)format, arglist);
+ res = erts_printf_format(erts_write_ds, (void *)dsbufp, (char *)format, arglist);
if (dsbufp->str) {
if (res < 0)
dsbufp->str[0] = '\0';
@@ -465,3 +479,10 @@ erts_vdsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, va_list arglist)
}
return res;
}
+
+int
+erts_vcbprintf(fmtfn_t cb_fn, void* cb_arg, const char *format, va_list arglist)
+{
+ errno = 0;
+ return erts_printf_format(cb_fn, cb_arg, (char *)format, arglist);
+}
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 64d1a70e61..d91b5ed079 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index 4406a82a36..d6c987178b 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index fbbfefa462..72898e6d8a 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index 6956eee740..21463a2286 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
index a7ac116c05..423f33b99a 100644
--- a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index 2a7bfb8b86..4f81b5089d 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index 71f3c2ec8c..0926cf1f95 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 74a0184818..c8db150d64 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index b601c048b3..dc29a3eaad 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 77909b01f0..a50a628a27 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 5bbbaf14d5..6bf3c7313c 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 1a573ce297..bae6291d87 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 6afeb454d6..134497411f 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 4c48742344..34c342371b 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 317d731cd7..028b114068 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 8.1.1
+VSN = 8.2.1
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index 53ef41dd5b..ea9f956271 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -740,7 +740,7 @@
<v>Format = string()</v>
<v>FormatArgs = list()</v>
<v>Opts = [Opt]</v>
- <v>Opt = no_css | esc_chars</v>
+ <v>Opt = {heading,string()} | no_css | esc_chars</v>
</type>
<desc><marker id="log-5"/>
<p>Prints from a test case to the log file.</p>
@@ -798,53 +798,71 @@
<func>
<name>pal(Format) -&gt; ok</name>
- <fsummary>Equivalent to pal(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary>
<desc><marker id="pal-1"/>
<p>Equivalent to
- <seealso marker="#pal-4"><c>ct:pal(default, 50, Format,
- [])</c></seealso>.</p>
+ <seealso marker="#pal-5"><c>ct:pal(default, 50, Format,
+ [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="pal-2"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="pal-3"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pal(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to pal(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="pal-4"/>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>pal(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>pal(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints and logs from a test case.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()} | no_css</v>
</type>
- <desc><marker id="pal-4"/>
+ <desc><marker id="pal-5"/>
<p>Prints and logs from a test case.</p>
<p>This function is meant for printing a string from a test case,
@@ -888,52 +906,70 @@
<func>
<name>print(Format) -&gt; ok</name>
- <fsummary>Equivalent to print(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary>
<desc><marker id="print-1"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(default,
- 50, Format, [])</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(default,
+ 50, Format, [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="print-2"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="print-3"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>print(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to print(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="print-4"/>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>print(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>print(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints from a test case to the console.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()}</v>
</type>
- <desc><marker id="print-4"/>
+ <desc><marker id="print-5"/>
<p>Prints from a test case to the console.</p>
<p>This function is meant for printing a string from a test case to
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 7653670d30..83e6511c04 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -33,6 +33,65 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some types of printouts to screen during test runs
+ (including <c>ct:print/1,2,3,4</c>) used the local
+ <c>user</c> process as IO device and these printouts
+ would not be visible when e.g. running tests via a shell
+ on a remote node. A default Common Test group leader
+ process has been introduced to solve the problem. This
+ process routes printouts to the group leader of the
+ starting process, if available, otherwise to <c>user</c>.</p>
+ <p>
+ Own Id: OTP-13973 Aux Id: ERL-279 </p>
+ </item>
+ <item>
+ <p>
+ Some Common Test processes, that act as I/O group leaders
+ for test cases, would not terminate as expected at the
+ end of test runs. This error has been corrected.</p>
+ <p>
+ Own Id: OTP-14026 Aux Id: ERL-287 </p>
+ </item>
+ <item>
+ <p>
+ The logging verbosity feature was incorrectly documented.
+ The default verbosity levels for test runs is e.g. not 50
+ (<c>?STD_VERBOSITY</c>), but 100 (<c>?MAX_VERBOSITY</c>).
+ Also, some of the examples had errors and flaws. The
+ corresponding chapter (5.18) in the User's Guide has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14044 Aux Id: seq13223 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A feature to let the user specify headings to log
+ printouts has been added. The heading is specified as
+ <c>{heading,string()}</c> in the <c>Opts</c> list
+ argument to <c>ct:pal/3,4,5</c>, <c>ct:print/3,4,5</c>,
+ or <c>ct:log/3,4,5</c>. If the heading option is omitted,
+ the category name, or <c>"User"</c>, is used as the
+ heading instead.</p>
+ <p>
+ Own Id: OTP-14043 Aux Id: seq13226 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.12.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 1d3fbb6f76..f70bdb16c5 100644
--- a/lib/common_test/doc/src/write_test_chapter.xml
+++ b/lib/common_test/doc/src/write_test_chapter.xml
@@ -986,15 +986,17 @@
<c>io:put_chars/1</c>, and so on.</p>
<p><c>Importance</c> is compared to a verbosity level set by the
- <c>verbosity</c> start flag/option. The verbosity level can be set per
- category or generally, or both. The default verbosity level,
- <c>?STD_VERBOSITY</c>, is 50, that is, all standard I/O gets printed.
- If a lower verbosity level is set, standard I/O printouts are ignored.
- <c>Common Test</c> performs the following test:</p>
+ <c>verbosity</c> start flag/option. The level can be set per
+ category or generally, or both. If <c>verbosity</c> is not set by the user,
+ a level of 100 (<c>?MAX_VERBOSITY</c> = all printouts visible) is used as
+ default value. <c>Common Test</c> performs the following test:</p>
<pre>
- Importance >= (100-VerbosityLevel)</pre>
- <p>This also means that verbosity level 0 effectively turns all logging off
- (except from printouts made by <c>Common Test</c> itself).</p>
+Importance >= (100-VerbosityLevel)</pre>
+ <p>The constant <c>?STD_VERBOSITY</c> has value 50 (see <c>ct.hrl</c>).
+ At this level, all standard I/O gets printed. If a lower verbosity level
+ is set, standard I/O printouts are ignored. Verbosity level 0 effectively
+ turns all logging off (except from printouts made by <c>Common Test</c>
+ itself).</p>
<p>The general verbosity level is not associated with any particular
category. This level sets the threshold for the standard I/O printouts,
@@ -1003,17 +1005,17 @@
<p><em>Examples:</em></p>
<p>Some printouts during test case execution:</p>
- <pre>
+ <pre>
io:format("1. Standard IO, importance = ~w~n", [?STD_IMPORTANCE]),
ct:log("2. Uncategorized, importance = ~w", [?STD_IMPORTANCE]),
- ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]]),
+ ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]),
ct:log(info, ?LOW_IMPORTANCE, "4. Categorized info, importance = ~w", [?LOW_IMPORTANCE]),
- ct:log(error, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
- ct:log(error, ?HI_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
+ ct:log(error, ?HI_IMPORTANCE, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
+ ct:log(error, ?MAX_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
- <p>If starting the test without specifying any verbosity levels as follows:</p>
+ <p>If starting the test with a general verbosity level of 50 (<c>?STD_VERBOSITY</c>):</p>
<pre>
- $ ct_run ...</pre>
+ $ ct_run -verbosity 50</pre>
<p>the following is printed:</p>
<pre>
1. Standard IO, importance = 50
@@ -1031,10 +1033,22 @@
4. Categorized info, importance = 25
6. Categorized error, importance = 99</pre>
+ <p>Note that the category argument is not required in order to only specify the
+ importance of a printout. Example:</p>
+ <pre>
+<c>ct:pal(?LOW_IMPORTANCE, "Info report: ~p", [Info])</c></pre>
+ <p>Or perhaps in combination with constants:</p>
+ <pre>
+-define(INFO, ?LOW_IMPORTANCE).
+-define(ERROR, ?HI_IMPORTANCE).
+
+ct:log(?INFO, "Info report: ~p", [Info])
+ct:pal(?ERROR, "Error report: ~p", [Error])</pre>
+
<p>The functions <seealso marker="ct#set_verbosity-2"><c>ct:set_verbosity/2</c></seealso>
and <seealso marker="ct#get_verbosity-1"><c>ct:get_verbosity/1</c></seealso> may be used
to modify and read verbosity levels during test execution.</p>
-
+
<p>The arguments <c>Format</c> and <c>FormatArgs</c> in <c>ct:log/print/pal</c> are
always passed on to the STDLIB function <c>io:format/3</c> (For details,
see the <seealso marker="stdlib:io"><c>io</c></seealso> manual page).</p>
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 0f9e044f9e..9d751996ad 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -80,6 +80,7 @@ MODULES= \
ct_groups \
ct_property_test \
ct_release_test \
+ ct_default_gl \
erl2html2 \
test_server_ctrl \
test_server_gl \
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index 77588af59b..dfa321c901 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -22,6 +22,7 @@
{vsn, "%VSN%"},
{modules, [ct_cover,
ct,
+ ct_default_gl,
ct_event,
ct_framework,
ct_ftp,
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index f9f845e1a9..43abb91819 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -66,8 +66,8 @@
reload_config/1,
escape_chars/1, escape_chars/2,
log/1, log/2, log/3, log/4, log/5,
- print/1, print/2, print/3, print/4,
- pal/1, pal/2, pal/3, pal/4,
+ print/1, print/2, print/3, print/4, print/5,
+ pal/1, pal/2, pal/3, pal/4, pal/5,
set_verbosity/2, get_verbosity/1,
capture_start/0, capture_stop/0, capture_get/0, capture_get/1,
fail/1, fail/2, comment/1, comment/2, make_priv_dir/0,
@@ -592,7 +592,7 @@ log(X1,X2,X3,X4) ->
%%% Format = string()
%%% Args = list()
%%% Opts = [Opt]
-%%% Opt = esc_chars | no_css
+%%% Opt = {heading,string()} | esc_chars | no_css
%%%
%%% @doc Printout from a test case to the log file.
%%%
@@ -610,43 +610,61 @@ log(Category,Importance,Format,Args,Opts) ->
%%%-----------------------------------------------------------------
%%% @spec print(Format) -> ok
-%%% @equiv print(default,50,Format,[])
+%%% @equiv print(default,50,Format,[],[])
print(Format) ->
- print(default,?STD_IMPORTANCE,Format,[]).
+ print(default,?STD_IMPORTANCE,Format,[],[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
+%%% @equiv print(Category,Importance,Format,Args,[])
print(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ print(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec print(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
-print(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec print(Category,Importance,Format,Args) -> ok
+%%% @spec print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()}
%%%
%%% @doc Printout from a test case to the console.
%%%
@@ -658,13 +676,13 @@ print(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-print(Category,Importance,Format,Args) ->
- ct_logs:tc_print(Category,Importance,Format,Args).
+print(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
%%% @spec pal(Format) -> ok
-%%% @equiv pal(default,50,Format,[])
+%%% @equiv pal(default,50,Format,[],[])
pal(Format) ->
pal(default,?STD_IMPORTANCE,Format,[]).
@@ -672,35 +690,53 @@ pal(Format) ->
%%% @spec pal(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
+%%% @equiv pal(Category,Importance,Format,Args,[])
pal(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec pal(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ pal(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec pal(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
-pal(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec pal(Category,Importance,Format,Args) -> ok
+%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()} | no_css
%%%
%%% @doc Print and log from a test case.
%%%
@@ -712,8 +748,8 @@ pal(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-pal(Category,Importance,Format,Args) ->
- ct_logs:tc_pal(Category,Importance,Format,Args).
+pal(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_pal(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
%%% @spec set_verbosity(Category, Level) -> ok
diff --git a/lib/common_test/src/ct_default_gl.erl b/lib/common_test/src/ct_default_gl.erl
new file mode 100644
index 0000000000..d1b52e5f4f
--- /dev/null
+++ b/lib/common_test/src/ct_default_gl.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ct_default_gl).
+-export([start_link/1, stop/0]).
+
+-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
+
+%% start_link()
+%% Start a new group leader process.
+start_link(ParentGL) ->
+ do_start(ParentGL, 3).
+
+do_start(_ParentGL, 0) ->
+ exit({?MODULE,startup});
+do_start(ParentGL, Retries) ->
+ case whereis(?MODULE) of
+ undefined ->
+ case gen_server:start_link(?MODULE, [ParentGL], []) of
+ {ok,Pid} ->
+ {ok,Pid};
+ Other ->
+ Other
+ end;
+ Pid ->
+ exit(Pid, kill),
+ timer:sleep(1000),
+ do_start(ParentGL, Retries-1)
+ end.
+
+%% stop(Pid)
+%% Stop a group leader process.
+stop() ->
+ gen_server:cast(whereis(?MODULE), stop).
+
+
+%%% Internal functions.
+
+init([ParentGL]) ->
+ register(?MODULE, self()),
+ {ok,#{parent_gl_pid => ParentGL,
+ parent_gl_monitor => erlang:monitor(process,ParentGL)}}.
+
+handle_cast(stop, St) ->
+ {stop,normal,St}.
+
+%% If the parent group leader dies, fall back on using the local user process
+handle_info({'DOWN',Ref,process,_,_Reason}, #{parent_gl_monitor := Ref} = St) ->
+ User = whereis(user),
+ {noreply,St#{parent_gl_pid => User,
+ parent_gl_monitor => erlang:monitor(process,User)}};
+
+handle_info({io_request,_From,_ReplyAs,_Req} = IoReq,
+ #{parent_gl_pid := ParentGL} = St) ->
+ ParentGL ! IoReq,
+ {noreply,St};
+
+handle_info(Msg, St) ->
+ io:format(user, "Common Test Group Leader process got: ~tp~n", [Msg]),
+ {noreply,St}.
+
+handle_call(_Req, _From, St) ->
+ {reply,ok,St}.
+
+terminate(_, _) ->
+ ok.
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 104515e57e..291a4d716c 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -307,7 +307,7 @@ add_defaults(Mod,Func, GroupPath) ->
"~w:suite/0 failed: ~p~n",
[Suite,Reason]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,{exited,Reason}};
SuiteInfo when is_list(SuiteInfo) ->
case lists:all(fun(E) when is_tuple(E) -> true;
@@ -330,7 +330,7 @@ add_defaults(Mod,Func, GroupPath) ->
"~w:suite/0: ~p~n",
[Suite,SuiteInfo]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,bad_return_value}
end;
SuiteInfo ->
@@ -338,7 +338,7 @@ add_defaults(Mod,Func, GroupPath) ->
"Invalid return value from "
"~w:suite/0: ~p~n", [Suite,SuiteInfo]),
io:format(ErrStr, []),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
{suite0_failed,bad_return_value}
end.
@@ -366,7 +366,7 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"~w:group(~w): ~p~n",
[Mod,GrName,BadGr0Val]),
io:format(Gr0ErrStr, []),
- io:format(user, Gr0ErrStr, []),
+ io:format(?def_gl, Gr0ErrStr, []),
{group0_failed,bad_return_value};
_ ->
Args = if Func == init_per_group ; Func == end_per_group ->
@@ -388,7 +388,7 @@ add_defaults1(Mod,Func, GroupPath, SuiteInfo) ->
"~w:~w/0: ~p~n",
[Mod,Func,BadTC0Val]),
io:format(TC0ErrStr, []),
- io:format(user, TC0ErrStr, []),
+ io:format(?def_gl, TC0ErrStr, []),
{testcase0_failed,bad_return_value};
_ ->
%% let test case info (also for all config funcs) override
@@ -927,7 +927,7 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
Div = "~n- - - - - - - - - - - - - - - - - - - "
"- - - - - - - - - - - - - - - - - - - - -~n",
ErrorStr2 = io_lib:format(ErrorFormat, ErrorArgs),
- io:format(user, lists:concat([Div,ErrorStr2,Div,"~n"]),
+ io:format(?def_gl, lists:concat([Div,ErrorStr2,Div,"~n"]),
[]),
Link =
"\n\n<a href=\"#end\">"
@@ -1133,7 +1133,7 @@ get_all(Mod, ConfTests) ->
ErrStr = io_lib:format("~n*** ERROR *** "
"~w:all/0 failed: ~p~n",
[Mod,ExitReason]),
- io:format(user, ErrStr, []),
+ io:format(?def_gl, ErrStr, []),
%% save the error info so it doesn't get printed twice
ct_util:set_testdata_async({{error_in_suite,Mod},
ExitReason});
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 9282a9f81d..09ad709da5 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -45,8 +45,8 @@
%% Logging stuff directly from testcase
-export([tc_log/3, tc_log/4, tc_log/5, tc_log/6,
tc_log_async/3, tc_log_async/5,
- tc_print/3, tc_print/4,
- tc_pal/3, tc_pal/4, ct_log/3,
+ tc_print/3, tc_print/4, tc_print/5,
+ tc_pal/3, tc_pal/4, tc_pal/5, ct_log/3,
basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -447,10 +447,10 @@ tc_log(Category,Importance,Format,Args,Opts) ->
tc_log(Category,Importance,"User",Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Printer,Format,Args,Opts) -> ok
+%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
@@ -460,13 +460,18 @@ tc_log(Category,Importance,Format,Args,Opts) ->
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase (i.e. not from within the CT
%%% framework).</p>
-tc_log(Category,Importance,Printer,Format,Args,Opts) ->
+tc_log(Category,Importance,Heading,Format,Args,Opts) ->
Data =
case lists:member(no_css, Opts) of
true ->
[{Format,Args}];
false ->
- [{hd,div_header(Category,Printer),[]},
+ Heading1 =
+ case proplists:get_value(heading, Opts) of
+ undefined -> Heading;
+ Str -> Str
+ end,
+ [{hd,div_header(Category,Heading1),[]},
{Format,Args},
{ft,div_footer(),[]}]
end,
@@ -484,7 +489,7 @@ tc_log_async(Category,Format,Args) ->
%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -495,31 +500,38 @@ tc_log_async(Category,Format,Args) ->
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
%%% asks ct_logs for an html wrapper.</p>
-tc_log_async(Category,Importance,Printer,Format,Args) ->
+tc_log_async(Category,Importance,Heading,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category,Printer),[]},
+ [{hd,div_header(Category,Heading),[]},
{Format,Args},
{ft,div_footer(),[]}],
true}),
ok.
%%%-----------------------------------------------------------------
%%% @spec tc_print(Category,Format,Args)
-%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args)
+%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
tc_print(Category,Format,Args) ->
- tc_print(Category,?STD_IMPORTANCE,Format,Args).
+ tc_print(Category,?STD_IMPORTANCE,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_print(Category,Importance,Format,Args)
+%%% @equiv tc_print(Category,Importance,Format,Args,[])
+tc_print(Category,Importance,Format,Args) ->
+ tc_print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args) -> ok
+%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Console printout from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when printing
%%% stuff from a testcase on the user console.</p>
-tc_print(Category,Importance,Format,Args) ->
+tc_print(Category,Importance,Format,Args,Opts) ->
VLvl = case ct_util:get_verbosity(Category) of
undefined ->
ct_util:get_verbosity('$unspecified');
@@ -531,50 +543,61 @@ tc_print(Category,Importance,Format,Args) ->
Val
end,
if Importance >= (100-VLvl) ->
- Head = get_heading(Category),
- io:format(user, lists:concat([Head,Format,"\n\n"]), Args),
+ Heading =
+ case proplists:get_value(heading, Opts) of
+ undefined -> atom_to_list(Category);
+ Hd -> Hd
+ end,
+ Str = lists:concat([get_header(Heading),Format,"\n\n"]),
+ try
+ io:format(?def_gl, Str, Args)
+ catch
+ %% default group leader probably not started, or has stopped
+ _:_ -> io:format(user, Str, Args)
+ end,
ok;
true ->
ok
end.
-get_heading(default) ->
+get_header("default") ->
io_lib:format("\n-----------------------------"
"-----------------------\n~s\n",
[log_timestamp(?now)]);
-get_heading(Category) ->
+get_header(Heading) ->
io_lib:format("\n-----------------------------"
- "-----------------------\n~s ~w\n",
- [log_timestamp(?now),Category]).
+ "-----------------------\n~s ~s\n",
+ [Heading,log_timestamp(?now)]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Format,Args) -> ok
-%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args) -> ok
+%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
tc_pal(Category,Format,Args) ->
- tc_pal(Category,?STD_IMPORTANCE,Format,Args).
+ tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Importance,Format,Args) -> ok
+%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok
+tc_pal(Category,Importance,Format,Args) ->
+ tc_pal(Category,Importance,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Print and log from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase. The info is written both in the
%%% log and on the console.</p>
-tc_pal(Category,Importance,Format,Args) ->
- tc_print(Category,Importance,Format,Args),
- cast({log,sync,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category),[]},
- {Format,Args},
- {ft,div_footer(),[]}],
- true}),
- ok.
-
+tc_pal(Category,Importance,Format,Args,Opts) ->
+ tc_print(Category,Importance,Format,Args,Opts),
+ tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]).
%%%-----------------------------------------------------------------
%%% @spec ct_log(Category,Format,Args) -> ok
@@ -603,9 +626,9 @@ int_footer() ->
div_header(Class) ->
div_header(Class,"User").
-div_header(Class,Printer) ->
+div_header(Class,Heading) ->
"\n</pre>\n<div class=\"" ++ atom_to_list(Class) ++ "\"><pre><b>*** "
- ++ Printer ++ " " ++ log_timestamp(?now) ++ " ***</b>".
+ ++ Heading ++ " " ++ log_timestamp(?now) ++ " ***</b>".
div_footer() ->
"</pre></div>\n<pre>".
@@ -679,7 +702,7 @@ logger(Parent, Mode, Verbosity) ->
PrivFilesDestRun = [filename:join(AbsDir, F) || F <- PrivFiles],
case copy_priv_files(PrivFilesSrc, PrivFilesDestTop) of
{error,Src1,Dest1,Reason1} ->
- io:format(user, "ERROR! "++
+ io:format(?def_gl, "ERROR! "++
"Priv file ~p could not be copied to ~p. "++
"Reason: ~p~n",
[Src1,Dest1,Reason1]),
@@ -687,7 +710,7 @@ logger(Parent, Mode, Verbosity) ->
ok ->
case copy_priv_files(PrivFilesSrc, PrivFilesDestRun) of
{error,Src2,Dest2,Reason2} ->
- io:format(user,
+ io:format(?def_gl,
"ERROR! "++
"Priv file ~p could not be copied to ~p. "
++"Reason: ~p~n",
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index fbb9c7ab60..a049ef5695 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -2155,8 +2155,8 @@ continue(_MakeErrors, true) ->
false;
continue(_MakeErrors, _AbortIfMissingSuites) ->
io:nl(),
- OldGl = group_leader(),
- case set_group_leader_same_as_shell() of
+ OldGL = group_leader(),
+ case set_group_leader_same_as_shell(OldGL) of
true ->
S = self(),
io:format("Failed to compile or locate one "
@@ -2172,7 +2172,7 @@ continue(_MakeErrors, _AbortIfMissingSuites) ->
S ! false
end
end),
- group_leader(OldGl, self()),
+ group_leader(OldGL, self()),
receive R when R==true; R==false ->
R
after 15000 ->
@@ -2184,7 +2184,9 @@ continue(_MakeErrors, _AbortIfMissingSuites) ->
true
end.
-set_group_leader_same_as_shell() ->
+set_group_leader_same_as_shell(OldGL) ->
+ %% find the group leader process on the node in a dirty fashion
+ %% (check initial function call and look in the process dictionary)
GS2or3 = fun(P) ->
case process_info(P,initial_call) of
{initial_call,{group,server,X}} when X == 2 ; X == 3 ->
@@ -2197,7 +2199,10 @@ set_group_leader_same_as_shell() ->
true == lists:keymember(shell,1,
element(2,process_info(P,dictionary)))] of
[GL|_] ->
- group_leader(GL, self());
+ %% check if started from remote node (skip interaction)
+ if node(OldGL) /= node(GL) -> false;
+ true -> group_leader(GL, self())
+ end;
[] ->
false
end.
diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl
index 2c59b19196..5844909d17 100644
--- a/lib/common_test/src/ct_snmp.erl
+++ b/lib/common_test/src/ct_snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 34d27ed5f4..bff1112ab9 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 82a8743cf0..4d3a2ae7e3 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -188,6 +188,8 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
+ ct_default_gl:start_link(group_leader()),
+
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
ct_event:notify(#event{name=test_start,
@@ -474,6 +476,7 @@ loop(Mode,TestData,StartDir) ->
ct_logs:close(Info, StartDir),
ct_event:stop(),
ct_config:stop(),
+ ct_default_gl:stop(),
ok = file:set_cwd(StartDir),
return(From, Info);
{Ref, _Msg} when is_reference(Ref) ->
@@ -926,7 +929,8 @@ warn_duplicates(Suites) ->
[] ->
ok;
_ ->
- io:format(user,"~nWARNING! Deprecated function: ~w:sequences/0.~n"
+ io:format(?def_gl,
+ "~nWARNING! Deprecated function: ~w:sequences/0.~n"
" Use group with sequence property instead.~n",[Mod])
end
end,
@@ -980,12 +984,12 @@ get_profile_data(Profile, Key, StartDir) ->
end,
case Result of
{error,enoent} when Profile /= default ->
- io:format(user, "~nERROR! Missing profile file ~p~n", [File]),
+ io:format(?def_gl, "~nERROR! Missing profile file ~p~n", [File]),
undefined;
{error,enoent} when Profile == default ->
undefined;
{error,Reason} ->
- io:format(user,"~nERROR! Error in profile file ~p: ~p~n",
+ io:format(?def_gl,"~nERROR! Error in profile file ~p: ~p~n",
[WhichFile,Reason]),
undefined;
{ok,Data} ->
@@ -995,7 +999,7 @@ get_profile_data(Profile, Key, StartDir) ->
_ when is_list(Data) ->
Data;
_ ->
- io:format(user,
+ io:format(?def_gl,
"~nERROR! Invalid profile data in ~p~n",
[WhichFile]),
[]
@@ -1082,10 +1086,10 @@ open_url(iexplore, Args, URL) ->
Path = proplists:get_value(default, Paths),
[Cmd | _] = string:tokens(Path, "%"),
Cmd1 = Cmd ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd1]),
open_port({spawn,Cmd1}, []);
_ ->
- io:format("~nNo path to iexplore.exe~n",[])
+ io:format(?def_gl, "~nNo path to iexplore.exe~n",[])
end,
win32reg:close(R),
ok;
@@ -1095,6 +1099,6 @@ open_url(Prog, Args, URL) ->
is_list(Prog) -> Prog
end,
Cmd = ProgStr ++ " " ++ Args ++ " " ++ URL,
- io:format(user, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
+ io:format(?def_gl, "~nOpening ~ts with command:~n ~ts~n", [URL,Cmd]),
open_port({spawn,Cmd},[]),
ok.
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index d7efa26863..039c8168ec 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -23,6 +23,7 @@
-define(board_table,ct_boards).
-define(suite_table,ct_suite_data).
-define(verbosity_table,ct_verbosity_table).
+-define(def_gl, ct_default_gl).
-record(conn, {handle,
targetref,
diff --git a/lib/common_test/src/test_server_gl.erl b/lib/common_test/src/test_server_gl.erl
index 7d6fe64b92..4845b86dd3 100644
--- a/lib/common_test/src/test_server_gl.erl
+++ b/lib/common_test/src/test_server_gl.erl
@@ -24,7 +24,7 @@
%% through the test_server_io module/process.
-module(test_server_gl).
--export([start_link/0,stop/1,set_minor_fd/3,unset_minor_fd/1,
+-export([start_link/1,stop/1,set_minor_fd/3,unset_minor_fd/1,
get_tc_supervisor/1,print/4,set_props/2]).
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
@@ -33,6 +33,7 @@
tc :: mfa() | 'undefined', %Current test case MFA
minor :: 'none'|pid(), %Minor fd
minor_monitor, %Monitor ref for minor fd
+ tsio_monitor, %Monitor red for controlling proc
capture :: 'none'|pid(), %Capture output
reject_io :: boolean(), %Reject I/O requests...
permit_io, %... and exceptions
@@ -45,8 +46,8 @@
%% Start a new group leader process. Only to be called by
%% the test_server_io process.
-start_link() ->
- case gen_server:start_link(?MODULE, [], []) of
+start_link(TSIO) ->
+ case gen_server:start_link(?MODULE, [TSIO], []) of
{ok,Pid} ->
{ok,Pid};
Other ->
@@ -130,14 +131,16 @@ set_props(GL, PropList) ->
%%% Internal functions.
-init([]) ->
+init([TSIO]) ->
EscChars = case application:get_env(test_server, esc_chars) of
{ok,ECBool} -> ECBool;
_ -> true
end,
+ Ref = erlang:monitor(process, TSIO),
{ok,#st{tc_supervisor=none,
minor=none,
minor_monitor=none,
+ tsio_monitor=Ref,
capture=none,
reject_io=false,
permit_io=gb_sets:empty(),
@@ -176,6 +179,9 @@ handle_info({'DOWN',Ref,process,_,Reason}=D, #st{minor_monitor=Ref}=St) ->
test_server_io:print_unexpected(Data)
end,
{noreply,St#st{minor=none,minor_monitor=none}};
+handle_info({'DOWN',Ref,process,_,_}, #st{tsio_monitor=Ref}=St) ->
+ %% controlling process (test_server_io) terminated, we're done
+ {stop,normal,St};
handle_info({permit_io,Pid}, #st{permit_io=P}=St) ->
{noreply,St#st{permit_io=gb_sets:add(Pid, P)}};
handle_info({capture,Cap0}, St) ->
diff --git a/lib/common_test/src/test_server_io.erl b/lib/common_test/src/test_server_io.erl
index 3d5238052b..fdabf17b08 100644
--- a/lib/common_test/src/test_server_io.erl
+++ b/lib/common_test/src/test_server_io.erl
@@ -185,7 +185,7 @@ reset_state() ->
init([]) ->
process_flag(trap_exit, true),
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
@@ -200,7 +200,7 @@ req(Req) ->
gen_server:call(?MODULE, Req, infinity).
handle_call({get_gl,false}, _From, #st{gls=Gls,gl_props=Props}=St) ->
- {ok,Pid} = test_server_gl:start_link(),
+ {ok,Pid} = test_server_gl:start_link(self()),
test_server_gl:set_props(Pid, Props),
{reply,Pid,St#st{gls=gb_sets:insert(Pid, Gls)}};
handle_call({get_gl,true}, _From, #st{shared_gl=Shared}=St) ->
@@ -285,7 +285,7 @@ handle_call(reset_state, _From, #st{fds=Fds,tags=Tags,gls=Gls,
ok
end,
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{reply,ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index b1eddfedd7..2f0fc2e05a 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -70,7 +70,8 @@ MODULES= \
test_server_SUITE \
test_server_test_lib \
ct_release_test_SUITE \
- ct_log_SUITE
+ ct_log_SUITE \
+ ct_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
diff --git a/lib/common_test/test/ct_SUITE.erl b/lib/common_test/test/ct_SUITE.erl
new file mode 100644
index 0000000000..eb98c2544f
--- /dev/null
+++ b/lib/common_test/test/ct_SUITE.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ct_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{timetrap,{seconds,30}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [app_file, appup_file].
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+
+app_file(_Config) ->
+ ok = test_server:app_test(common_test),
+ ok.
+
+appup_file(_Config) ->
+ ok = test_server:appup_test(common_test).
+
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
index 9bdd44cbdf..93affda398 100644
--- a/lib/common_test/test/ct_log_SUITE.erl
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -86,18 +86,7 @@ print(Config) ->
io:format("5. Printing a pid: ~w~n", [Pid]),
io:format("6. Printing HTML: <pre>~s</pre>~n", [String]),
- %% --- API ---
- %% pal(Format) ->
- %% = ct:pal(default, 50, Format, []).
- %% pal(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% pal(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% pal(Category, Importance, Format, FormatArgs) -> ok
- %% ------
+ %% ct:pal
ct:pal("1. Printing nothing"),
ct:pal("2. Printing nothing", []),
ct:pal("3. Printing a string: ~s", [String]),
@@ -111,23 +100,16 @@ print(Config) ->
ct:pal(50, "11. Printing with ~s", ["importance"]),
ct:pal(ct_internal, 50, "12. Printing with ~s", ["category and importance"]),
- %% --- API ---
- %% log(Format) -> ok
- %% = ct:log(default, 50, Format, [], []).
- %% log(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% log(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs | Opts
- %% log(X1, X2, X3, X4) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% X4 = FormatArgs | Opts
- %% log(Category, Importance, Format, FormatArgs, Opts) -> ok
- %% ------
+ ct:pal("13. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, "14. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(50, "15. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, 50, "16. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
+ %% ct:log
ct:log("1. Printing nothing"),
ct:log("2. Printing nothing", []),
ct:log("3. Printing a string: ~s", [String]),
@@ -153,8 +135,37 @@ print(Config) ->
ct:log(ct_internal, 50, "21. Printing a pid escaped with ~s, no_css: ~w",
["category and importance",Pid], [esc_chars,no_css]),
+ ct:log("22. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, "23. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(50, "24. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, 50, "25. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
%% END mark
ct:log("LOGGING END", [], [no_css]),
+
+
+ %% ct:print
+ ct:print("1. Does this show??"),
+ ct:print("2. Does this ~s", ["show??"]),
+ ct:print("3. Is this a non-html pid?? ~w", [self()]),
+ ct:print(ct_internal, "4. Printing with category"),
+ ct:print(ct_internal, "5. Printing with ~s", ["category"]),
+ ct:print(50, "6. Printing with importance"),
+ ct:print(50, "7. Printing with ~s", ["importance"]),
+ ct:print(ct_internal, 50, "8. Printing with ~s", ["category and importance"]),
+ ct:print("9. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, "10. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(50, "11. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, 50, "12. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
{save_config,[{the_logfile,TcLogFile},{the_pid,Pid},{the_string,String}]}.
@@ -169,6 +180,8 @@ verify(Config) ->
{ok,Dev} = file:open(TcLogFile, [read]),
ok = read_until(Dev, "LOGGING START\n"),
+ ct:pal("VERIFYING LOG ENTRIES...", []),
+
%% io:format
match_line(Dev, "1. Printing nothing", []),
read_nl(Dev),
@@ -182,6 +195,7 @@ verify(Config) ->
read_nl(Dev),
match_line(Dev, "6. Printing HTML: &lt;pre&gt;~s&lt;/pre&gt;", [String]),
read_nl(Dev),
+
%% ct:pal
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -219,6 +233,19 @@ verify(Config) ->
read_header(Dev, "\"ct_internal\""),
match_line(Dev, "12. Printing with ~s", ["category and importance"]),
read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "13. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "14. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "15. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "16. Printing with category, importance and heading", []),
+ read_footer(Dev),
+
%% ct:log
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -275,7 +302,18 @@ verify(Config) ->
read_footer(Dev),
match_line(Dev, "21. Printing a pid escaped with ~s, no_css: ~s",
["category and importance",EscPid]),
-
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "22. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "23. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "24. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "25. Printing with category, importance and heading", []),
+ read_footer(Dev),
file:close(Dev),
ok.
@@ -298,29 +336,51 @@ read_until(Dev, Pat) ->
match_line(Dev, Format, Args) ->
Pat = lists:flatten(io_lib:format(Format, Args)),
Line = element(2, file:read_line(Dev)),
+
+ %% for debugging purposes:
+ ct:pal("L: ~tp", [Line], [no_css]),
+
case re:run(Line, Pat) of
{match,_} ->
ok;
nomatch ->
- ct:pal("ERROR! No match for ~p.\nLine = ~p", [Pat,Line]),
+ ct:pal("ERROR! No match for ~p", [Pat]),
file:close(Dev),
ct:fail({mismatch,Pat,Line})
end.
read_header(Dev) ->
- read_header(Dev, "\"default\"").
+ read_header(Dev, "\"default\"", "User").
read_header(Dev, Cat) ->
+ read_header(Dev, Cat, "User").
+
+read_header(Dev, Cat, Heading) ->
file:read_line(Dev), % \n
"</pre>\n" = element(2, file:read_line(Dev)),
- {match,_} =
- re:run(element(2, file:read_line(Dev)), "<div class="++Cat++"><pre><b>"
- "\\*\\*\\* User \\d{4}-\\d{2}-\\d{2} "
- "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>").
+ {ok,Hd} = file:read_line(Dev),
+
+ %% for debugging purposes:
+ ct:pal("H: ~tp", [Hd], [no_css]),
+
+ Pat = "<div class="++Cat++"><pre><b>"++
+ "\\*\\*\\* "++Heading++" \\d{4}-\\d{2}-\\d{2} "++
+ "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>",
+
+ case re:run(Hd, Pat) of
+ {match,_} ->
+ ok;
+ _ ->
+ ct:pal("ERROR! No match for ~p", [Pat]),
+ file:close(Dev),
+ ct:fail({mismatch,Pat,Hd})
+ end.
read_footer(Dev) ->
"</pre></div>\n" = element(2, file:read_line(Dev)),
- "<pre>\n" = element(2, file:read_line(Dev)).
+ "<pre>\n" = element(2, file:read_line(Dev)),
+ %% for debugging purposes:
+ ct:pal("F: </pre></div><pre>", [], [no_css]).
read_nl(Dev) ->
file:read_line(Dev).
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index ab5cfd7a80..2fab4d3883 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.12.3
+COMMON_TEST_VSN = 1.13
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 6aaf16e9a5..2e58b68bf0 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,41 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a compiler crash when maps were matched.</p>
+ <p>
+ Own Id: OTP-13931 Aux Id: ERL-266 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a compiler crash having to with the delayed
+ sub-creation optimization. (Thanks to Jose Valim for
+ reporting this bug.)</p>
+ <p>
+ Own Id: OTP-13947 Aux Id: ERL-268 </p>
+ </item>
+ <item>
+ <p>The compiler option <c>inline_list_funcs</c>
+ accidentally turned off some other optimizations.</p>
+ <p>
+ Own Id: OTP-13985</p>
+ </item>
+ <item>
+ <p>The compiler could sometimes generate spurious
+ warnings when inlining was enabled.</p>
+ <p>
+ Own Id: OTP-14040 Aux Id: ERL-301 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index e951a25e04..e37ca31704 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -173,17 +173,25 @@ env_default_opts() ->
do_compile(Input, Opts0) ->
Opts = expand_opts(Opts0),
- {Pid,Ref} =
- spawn_monitor(fun() ->
- exit(try
- internal(Input, Opts)
- catch
- error:Reason ->
- {error,Reason}
- end)
- end),
- receive
- {'DOWN',Ref,process,Pid,Rep} -> Rep
+ IntFun = fun() -> try
+ internal(Input, Opts)
+ catch
+ error:Reason ->
+ {error,Reason}
+ end
+ end,
+ %% Dialyzer has already spawned workers.
+ case lists:member(dialyzer, Opts) of
+ true ->
+ IntFun();
+ false ->
+ {Pid,Ref} =
+ spawn_monitor(fun() ->
+ exit(IntFun())
+ end),
+ receive
+ {'DOWN',Ref,process,Pid,Rep} -> Rep
+ end
end.
expand_opts(Opts0) ->
@@ -684,7 +692,7 @@ kernel_passes() ->
{iff,core,?pass(save_core_code)},
%% Kernel Erlang and code generation.
- {pass,v3_kernel},
+ ?pass(v3_kernel),
{iff,dkern,{listing,"kernel"}},
{iff,'to_kernel',{done,"kernel"}},
{pass,v3_life},
@@ -1241,6 +1249,17 @@ core_fold_module_after_inlining(#compile{code=Code0,options=Opts}=St) ->
{ok,Code,_Ws} = sys_core_fold:module(Code0, Opts),
{ok,St#compile{code=Code}}.
+v3_kernel(#compile{code=Code0,options=Opts,warnings=Ws0}=St) ->
+ {ok,Code,Ws} = v3_kernel:module(Code0, Opts),
+ case Ws =:= [] orelse test_core_inliner(St) of
+ false ->
+ {ok,St#compile{code=Code,warnings=Ws0++Ws}};
+ true ->
+ %% cerl_inline may produce code that generates spurious
+ %% warnings. Ignore any such warnings.
+ {ok,St#compile{code=Code}}
+ end.
+
test_old_inliner(#compile{options=Opts}) ->
%% The point of this test is to avoid loading the old inliner
%% if we know that it will not be used.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index ff31f2d3bd..27ce51eec3 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 69e2f1838d..492067ef00 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index f6d4a311bb..b76b4d17df 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f884e6e7d6..ff9bddc1e2 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -42,7 +42,7 @@
comprehensions/1,maps/1,maps_bin_opt_info/1,
redundant_boolean_clauses/1,
latin1_fallback/1,underscore/1,no_warnings/1,
- bit_syntax/1]).
+ bit_syntax/1,inlining/1]).
init_per_testcase(_Case, Config) ->
Config.
@@ -65,7 +65,7 @@ groups() ->
bin_opt_info,bin_construction,comprehensions,maps,
maps_bin_opt_info,
redundant_boolean_clauses,latin1_fallback,
- underscore,no_warnings,bit_syntax]}].
+ underscore,no_warnings,bit_syntax,inlining]}].
init_per_suite(Config) ->
Config.
@@ -823,6 +823,30 @@ bit_syntax(Config) ->
run(Config, Ts),
ok.
+inlining(Config) ->
+ %% Make sure that no spurious warnings are generated
+ %% when inlining.
+ Ts = [{inlining_1,
+ <<"-compile(inline).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []},
+ {inlining_2,
+ <<"-compile({inline,[add/2]}).
+ compute1(X) -> add(X, 0).
+ add(1, 0) -> 1;
+ add(1, Y) -> 1 + Y;
+ add(X, Y) -> X + Y.
+ ">>,
+ [],
+ []}
+ ],
+ run(Config, Ts),
+ ok.
%%%
%%% End of test cases.
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 87fde38f2b..9c3cf1f34b 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.0.2
+COMPILER_VSN = 7.0.3
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 4ae64e059e..53ea6bb58b 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,46 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The crypto application has been fixed to not use RC2
+ against OpenSSL built with RC2 disabled.</p>
+ <p>
+ Own Id: OTP-13895 Aux Id: PR-1163 </p>
+ </item>
+ <item>
+ <p>
+ The crypto application has been fixed to not use RC4
+ against OpenSSL built with RC4 disabled.</p>
+ <p>
+ Own Id: OTP-13896 Aux Id: PR-1169 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ To ease troubleshooting, <c>erlang:load_nif/2</c> now
+ includes the return value from a failed call to
+ load/reload/upgrade in the text part of the error tuple.
+ The <c>crypto</c> NIF makes use of this feature by
+ returning the source line where/if the initialization
+ fails.</p>
+ <p>
+ Own Id: OTP-13951</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index bbee24554a..38e2db9033 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.7.1
+CRYPTO_VSN = 3.7.2
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index 25ffc5054c..d302423077 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/RELEASE_NOTES b/lib/dialyzer/RELEASE_NOTES
index 4e311bb543..2457faa07a 100644
--- a/lib/dialyzer/RELEASE_NOTES
+++ b/lib/dialyzer/RELEASE_NOTES
@@ -135,7 +135,7 @@ Version 1.9.1 (in Erlang/OTP R13B)
Version 1.9.0 (in Erlang/OTP R13A)
----------------------------------
- The analysis accepts opaque type declarations and detects violations of
- opaqueness of terms of such types. Starting with R13, many Erlang/OTP
+ opacity of terms of such types. Starting with R13, many Erlang/OTP
standard libraries (array, dict, digraph, ets, gb_sets, gb_trees, queue,
and sets) contain opaque type declarations of their main data types.
Dialyzer will spit out warnings in code that explicitly depends on the
diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt
index be1fd2f8bc..a571cd2e2b 100644
--- a/lib/dialyzer/doc/manual.txt
+++ b/lib/dialyzer/doc/manual.txt
@@ -255,7 +255,7 @@ Warning options:
-Wno_match
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
- Suppress warnings for violations of opaqueness of data types.
+ Suppress warnings for violations of opacity of data types.
-Wunmatched_returns ***
Include warnings for function calls which ignore a structured return
value or do not match against one of many possible return value(s).
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 553bfef41b..4b7eb4ad68 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -346,7 +346,7 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
</item>
<tag><c>-Wno_opaque</c></tag>
<item>
- <p>Suppress warnings for violations of opaqueness of data types.</p>
+ <p>Suppress warnings for violations of opacity of data types.</p>
</item>
<tag><c>-Wno_return</c></tag>
<item>
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index b0f0a9aef0..54abd09504 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -32,6 +32,37 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 3.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix bugs regarding opaque types. </p>
+ <p>
+ Own Id: OTP-13693</p>
+ </item>
+ <item>
+ <p> Fix error handling of bad <c>-dialyzer()</c>
+ attributes. </p>
+ <p>
+ Own Id: OTP-13979 Aux Id: ERL-283 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> A few warning messages have been improved. </p>
+ <p>
+ Own Id: OTP-11403</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.0.2</title>
<section><title>Improvements and New Features</title>
@@ -522,7 +553,7 @@
or modifying opaque types within the scope of a module.
</p> <p> Hitherto the shape of terms (tuple, list, etc.)
has been used to determine the opaque terms, but now the
- contracts are used for decorating types with opaqueness.
+ contracts are used for decorating types with opacity.
</p>
<p>
Own Id: OTP-10397</p>
@@ -1505,7 +1536,7 @@
<list>
<item>
<p>The analysis accepts opaque type declarations and
- detects violations of opaqueness of terms of such types.
+ detects violations of opacity of terms of such types.
Starting with R13, many Erlang/OTP standard libraries
(array, dict, digraph, ets, gb_sets, gb_trees, queue, and
sets) contain opaque type declarations of their main data
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 7f86520c06..d25ffd02a2 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -407,6 +407,10 @@ message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]}) ->
message_to_string({invalid_contract, [M, F, A, Sig]}) ->
io_lib:format("Invalid type specification for function ~w:~w/~w."
" The success typing is ~s\n", [M, F, A, Sig]);
+message_to_string({contract_with_opaque, [M, F, A, OpaqueType, SigType]}) ->
+ io_lib:format("The specification for ~w:~w/~w"
+ " has an opaque subtype ~s which is violated by the"
+ " success typing ~s\n", [M, F, A, OpaqueType, SigType]);
message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) ->
io_lib:format("The specification for ~w:~w/~w states that the function"
" might also return ~s but the inferred return is ~s\n",
@@ -432,25 +436,25 @@ message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}) ->
io_lib:format("Guard test ~s ~s ~s contains ~s\n",
[Arg1, Infix, Arg2, form_positions(ArgNs)]);
message_to_string({opaque_guard, [Guard, Args]}) ->
- io_lib:format("Guard test ~w~s breaks the opaqueness of its argument\n",
+ io_lib:format("Guard test ~w~s breaks the opacity of its argument\n",
[Guard, Args]);
message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
Term = if OpaqueType =:= OpaqueTerm -> "the term";
true -> OpaqueTerm
end,
io_lib:format("The attempt to match a term of type ~s against the ~s"
- " breaks the opaqueness of ~s\n", [OpaqueType, Pat, Term]);
+ " breaks the opacity of ~s\n", [OpaqueType, Pat, Term]);
message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) ->
io_lib:format("Attempt to test for inequality between a term of type ~s"
" and a term of opaque type ~s\n", [Type, OpaqueType]);
message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}) ->
- io_lib:format("The type test ~s~s breaks the opaqueness of the term ~s~s\n",
+ io_lib:format("The type test ~s~s breaks the opacity of the term ~s~s\n",
[Fun, Args, Arg, ArgType]);
message_to_string({opaque_size, [SizeType, Size]}) ->
- io_lib:format("The size ~s breaks the opaqueness of ~s\n",
+ io_lib:format("The size ~s breaks the opacity of ~s\n",
[SizeType, Size]);
message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}) ->
- io_lib:format("The call ~s:~s~s breaks the opaqueness of the term ~s :: ~s\n",
+ io_lib:format("The call ~s:~s~s breaks the opacity of the term ~s :: ~s\n",
[M, F, Args, Culprit, OpaqueType]);
%%----- Warnings for concurrency errors --------------------
message_to_string({race_condition, [M, F, Args, Reason]}) ->
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index ea6a71217c..1139044ec9 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 08e55a78bd..4e18058993 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -101,9 +101,9 @@ loop(#server_state{parent = Parent} = State,
{AnalPid, cserver, CServer, Plt} ->
send_codeserver_plt(Parent, CServer, Plt),
loop(State, Analysis, ExtCalls);
- {AnalPid, done, Plt, DocPlt} ->
+ {AnalPid, done, MiniPlt, DocPlt} ->
send_ext_calls(Parent, ExtCalls),
- send_analysis_done(Parent, Plt, DocPlt);
+ send_analysis_done(Parent, MiniPlt, DocPlt);
{AnalPid, ext_calls, NewExtCalls} ->
loop(State, Analysis, NewExtCalls);
{AnalPid, ext_types, ExtTypes} ->
@@ -121,6 +121,7 @@ loop(#server_state{parent = Parent} = State,
%% The Analysis
%%--------------------------------------------------------------------
+%% Calls to erlang:garbage_collect() help to reduce the heap size.
analysis_start(Parent, Analysis, LegalWarnings) ->
CServer = dialyzer_codeserver:new(),
Plt = Analysis#analysis.plt,
@@ -157,12 +158,9 @@ analysis_start(Parent, Analysis, LegalWarnings) ->
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer0),
TmpCServer2 =
dialyzer_codeserver:finalize_exported_types(MergedExpTypes, TmpCServer1),
+ erlang:garbage_collect(),
?timing(State#analysis_state.timing_server, "remote",
- begin
- TmpCServer3 =
- dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
- end)
+ contracts_and_records(TmpCServer2))
catch
throw:{error, _ErrorMsg} = Error -> exit(Error)
end,
@@ -171,48 +169,75 @@ analysis_start(Parent, Analysis, LegalWarnings) ->
NewPlt1 = dialyzer_plt:insert_exported_types(NewPlt0, ExpTypes),
State0 = State#analysis_state{plt = NewPlt1},
dump_callgraph(Callgraph, State0, Analysis),
- State1 = State0#analysis_state{codeserver = NewCServer},
%% Remove all old versions of the files being analyzed
AllNodes = dialyzer_callgraph:all_nodes(Callgraph),
- Plt1 = dialyzer_plt:delete_list(NewPlt1, AllNodes),
+ Plt1_a = dialyzer_plt:delete_list(NewPlt1, AllNodes),
+ Plt1 = dialyzer_plt:insert_callbacks(Plt1_a, NewCServer),
+ State1 = State0#analysis_state{codeserver = NewCServer, plt = Plt1},
Exports = dialyzer_codeserver:get_exports(NewCServer),
+ NonExports = sets:subtract(sets:from_list(AllNodes), Exports),
+ NonExportsList = sets:to_list(NonExports),
NewCallgraph =
case Analysis#analysis.race_detection of
true -> dialyzer_callgraph:put_race_detection(true, Callgraph);
false -> Callgraph
end,
- State2 = analyze_callgraph(NewCallgraph, State1#analysis_state{plt = Plt1}),
+ State2 = analyze_callgraph(NewCallgraph, State1),
+ #analysis_state{plt = MiniPlt2, doc_plt = DocPlt} = State2,
dialyzer_callgraph:dispose_race_server(NewCallgraph),
rcv_and_send_ext_types(Parent),
- NonExports = sets:subtract(sets:from_list(AllNodes), Exports),
- NonExportsList = sets:to_list(NonExports),
- Plt2 = dialyzer_plt:delete_list(State2#analysis_state.plt, NonExportsList),
- send_codeserver_plt(Parent, CServer, State2#analysis_state.plt),
- send_analysis_done(Parent, Plt2, State2#analysis_state.doc_plt).
+ %% Since the PLT is never used, a dummy is sent:
+ DummyPlt = dialyzer_plt:new(),
+ send_codeserver_plt(Parent, CServer, DummyPlt),
+ MiniPlt3 = dialyzer_plt:delete_list(MiniPlt2, NonExportsList),
+ send_analysis_done(Parent, MiniPlt3, DocPlt).
+
+contracts_and_records(CodeServer) ->
+ Fun = contrs_and_recs(CodeServer),
+ {Pid, Ref} = erlang:spawn_monitor(Fun),
+ dialyzer_codeserver:give_away(CodeServer, Pid),
+ Pid ! {self(), go},
+ receive {'DOWN', Ref, process, Pid, Return} ->
+ Return
+ end.
+
+-spec contrs_and_recs(dialyzer_codeserver:codeserver()) ->
+ fun(() -> no_return()).
+
+contrs_and_recs(TmpCServer2) ->
+ fun() ->
+ Parent = receive {Pid, go} -> Pid end,
+ {TmpCServer3, RecordDict} =
+ dialyzer_utils:process_record_remote_types(TmpCServer2),
+ TmpServer4 =
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3,
+ RecordDict),
+ dialyzer_codeserver:give_away(TmpServer4, Parent),
+ exit(TmpServer4)
+ end.
analyze_callgraph(Callgraph, #analysis_state{codeserver = Codeserver,
doc_plt = DocPlt,
+ plt = Plt,
timing_server = TimingServer,
parent = Parent,
solvers = Solvers} = State) ->
- Plt = dialyzer_plt:insert_callbacks(State#analysis_state.plt, Codeserver),
- {NewPlt, NewDocPlt} =
- case State#analysis_state.analysis_type of
- plt_build ->
- NewPlt0 =
- dialyzer_succ_typings:analyze_callgraph(Callgraph, Plt, Codeserver,
- TimingServer, Solvers, Parent),
- {NewPlt0, DocPlt};
- succ_typings ->
- {Warnings, NewPlt0, NewDocPlt0} =
- dialyzer_succ_typings:get_warnings(Callgraph, Plt, DocPlt, Codeserver,
- TimingServer, Solvers, Parent),
- Warnings1 = filter_warnings(Warnings, Codeserver),
- send_warnings(State#analysis_state.parent, Warnings1),
- {NewPlt0, NewDocPlt0}
- end,
- dialyzer_callgraph:delete(Callgraph),
- State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt}.
+ case State#analysis_state.analysis_type of
+ plt_build ->
+ NewMiniPlt =
+ dialyzer_succ_typings:analyze_callgraph(Callgraph, Plt, Codeserver,
+ TimingServer, Solvers, Parent),
+ dialyzer_callgraph:delete(Callgraph),
+ State#analysis_state{plt = NewMiniPlt, doc_plt = DocPlt};
+ succ_typings ->
+ {Warnings, NewMiniPlt, NewDocPlt} =
+ dialyzer_succ_typings:get_warnings(Callgraph, Plt, DocPlt, Codeserver,
+ TimingServer, Solvers, Parent),
+ dialyzer_callgraph:delete(Callgraph),
+ Warnings1 = filter_warnings(Warnings, Codeserver),
+ send_warnings(State#analysis_state.parent, Warnings1),
+ State#analysis_state{plt = NewMiniPlt, doc_plt = NewDocPlt}
+ end.
%%--------------------------------------------------------------------
%% Build the callgraph and fill the codeserver.
@@ -569,8 +594,9 @@ is_ok_fun({_Filename, _Line, {_M, _F, _A} = MFA}, Codeserver) ->
is_ok_tag(Tag, {_F, _L, MorMFA}, Codeserver) ->
not dialyzer_utils:is_suppressed_tag(MorMFA, Tag, Codeserver).
-send_analysis_done(Parent, Plt, DocPlt) ->
- Parent ! {self(), done, Plt, DocPlt},
+send_analysis_done(Parent, MiniPlt, DocPlt) ->
+ ok = dialyzer_plt:give_away(MiniPlt, Parent),
+ Parent ! {self(), done, MiniPlt, DocPlt},
ok.
send_ext_calls(_Parent, none) ->
@@ -583,7 +609,7 @@ send_ext_types(Parent, ExtTypes) ->
Parent ! {self(), ext_types, ExtTypes},
ok.
-send_codeserver_plt(Parent, CServer, Plt ) ->
+send_codeserver_plt(Parent, CServer, Plt) ->
Parent ! {self(), cserver, CServer, Plt},
ok.
@@ -602,14 +628,14 @@ format_bad_calls([{{_, _, _}, {_, module_info, A}}|Left], CodeServer, Acc)
format_bad_calls([{FromMFA, {M, F, A} = To}|Left], CodeServer, Acc) ->
{_Var, FunCode} = dialyzer_codeserver:lookup_mfa_code(FromMFA, CodeServer),
Msg = {call_to_missing, [M, F, A]},
- {File, Line} = find_call_file_and_line(FunCode, To),
+ {File, Line} = find_call_file_and_line(FromMFA, FunCode, To, CodeServer),
WarningInfo = {File, Line, FromMFA},
NewAcc = [{?WARN_CALLGRAPH, WarningInfo, Msg}|Acc],
format_bad_calls(Left, CodeServer, NewAcc);
format_bad_calls([], _CodeServer, Acc) ->
Acc.
-find_call_file_and_line(Tree, MFA) ->
+find_call_file_and_line({Module, _, _}, Tree, MFA, CodeServer) ->
Fun =
fun(SubTree, Acc) ->
case cerl:is_c_call(SubTree) of
@@ -622,7 +648,7 @@ find_call_file_and_line(Tree, MFA) ->
case {cerl:concrete(M), cerl:concrete(F), A} of
MFA ->
Ann = cerl:get_ann(SubTree),
- [{get_file(Ann), get_line(Ann)}|Acc];
+ [{get_file(CodeServer, Module, Ann), get_line(Ann)}|Acc];
{erlang, make_fun, 3} ->
[CA1, CA2, CA3] = cerl:call_args(SubTree),
case
@@ -638,7 +664,8 @@ find_call_file_and_line(Tree, MFA) ->
of
MFA ->
Ann = cerl:get_ann(SubTree),
- [{get_file(Ann), get_line(Ann)}|Acc];
+ [{get_file(CodeServer, Module, Ann),
+ get_line(Ann)}|Acc];
_ ->
Acc
end;
@@ -658,8 +685,10 @@ get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file(Codeserver, Module, [{file, FakeFile}|_]) ->
+ dialyzer_codeserver:translate_fake_file(Codeserver, Module, FakeFile);
+get_file(Codeserver, Module, [_|Tail]) ->
+ get_file(Codeserver, Module, Tail).
-spec dump_callgraph(dialyzer_callgraph:callgraph(), #analysis_state{}, #analysis{}) ->
'ok'.
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index 5623929a43..524ae047e2 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -62,9 +62,9 @@ check_callbacks(Module, Attrs, Records, Plt, Codeserver) ->
_ ->
MFA = {Module,module_info,0},
{_Var,Code} = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
- File = get_file(cerl:get_ann(Code)),
+ File = get_file(Codeserver, Module, cerl:get_ann(Code)),
State = #state{plt = Plt, filename = File, behlines = BehLines,
- codeserver = Codeserver, records = Records},
+ codeserver = Codeserver, records = Records},
Warnings = get_warnings(Module, Behaviours, State),
[add_tag_warning_info(Module, W, State) || W <- Warnings]
end.
@@ -213,12 +213,15 @@ add_tag_warning_info(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) ->
dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity},
State#state.codeserver),
Anns = cerl:get_ann(FunCode),
- WarningInfo = {get_file(Anns), get_line(Anns), {Module, Fun, Arity}},
+ File = get_file(State#state.codeserver, Module, Anns),
+ WarningInfo = {File, get_line(Anns), {Module, Fun, Arity}},
{?WARN_BEHAVIOUR, WarningInfo, Warn}.
get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file(Codeserver, Module, [{file, FakeFile}|_]) ->
+ dialyzer_codeserver:translate_fake_file(Codeserver, Module, FakeFile);
+get_file(Codeserver, Module, [_|Tail]) ->
+ get_file(Codeserver, Module, Tail).
diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl
index 50abb22009..5e02e7a2cc 100644
--- a/lib/dialyzer/src/dialyzer_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_callgraph.erl
@@ -119,7 +119,11 @@
-opaque callgraph() :: #callgraph{}.
--type active_digraph() :: {'d', digraph:graph()} | {'e', ets:tid(), ets:tid()}.
+-type active_digraph() :: {'d', digraph:graph()}
+ | {'e',
+ Out :: ets:tid(),
+ In :: ets:tid(),
+ Map :: ets:tid()}.
%%----------------------------------------------------------------------
@@ -248,24 +252,30 @@ find_non_local_calls([], Set) ->
-spec get_depends_on(scc() | module(), callgraph()) -> [scc()].
-get_depends_on(SCC, #callgraph{active_digraph = {'e', Out, _In}}) ->
- case ets_lookup_dict(SCC, Out) of
- {ok, Value} -> Value;
- error -> []
- end;
+get_depends_on(SCC, #callgraph{active_digraph = {'e', Out, _In, Maps}}) ->
+ lookup_scc(SCC, Out, Maps);
get_depends_on(SCC, #callgraph{active_digraph = {'d', DG}}) ->
digraph:out_neighbours(DG, SCC).
-spec get_required_by(scc() | module(), callgraph()) -> [scc()].
-get_required_by(SCC, #callgraph{active_digraph = {'e', _Out, In}}) ->
- case ets_lookup_dict(SCC, In) of
- {ok, Value} -> Value;
- error -> []
- end;
+get_required_by(SCC, #callgraph{active_digraph = {'e', _Out, In, Maps}}) ->
+ lookup_scc(SCC, In, Maps);
get_required_by(SCC, #callgraph{active_digraph = {'d', DG}}) ->
digraph:in_neighbours(DG, SCC).
+lookup_scc(SCC, Table, Maps) ->
+ case ets_lookup_dict({'scc', SCC}, Maps) of
+ {ok, SCCInt} ->
+ case ets_lookup_dict(SCCInt, Table) of
+ {ok, Ints} ->
+ [ets:lookup_element(Maps, Int, 2) || Int <- Ints];
+ error ->
+ []
+ end;
+ error -> []
+ end.
+
%%----------------------------------------------------------------------
%% Handling of modules & SCCs
%%----------------------------------------------------------------------
@@ -582,9 +592,10 @@ digraph_delete(DG) ->
active_digraph_delete({'d', DG}) ->
digraph:delete(DG);
-active_digraph_delete({'e', Out, In}) ->
+active_digraph_delete({'e', Out, In, Maps}) ->
ets:delete(Out),
- ets:delete(In).
+ ets:delete(In),
+ ets:delete(Maps).
digraph_edges(DG) ->
digraph:edges(DG).
@@ -758,37 +769,28 @@ to_ps(#callgraph{} = CG, File, Args) ->
ok.
condensation(G) ->
- SCs = digraph_utils:strong_components(G),
- V2I = ets:new(condensation_v2i, []),
- I2C = ets:new(condensation_i2c, []),
- I2I = ets:new(condensation_i2i, [bag]),
- CFun =
- fun(SC, N) ->
- lists:foreach(fun(V) -> true = ets:insert(V2I, {V,N}) end, SC),
- true = ets:insert(I2C, {N, SC}),
- N + 1
- end,
- lists:foldl(CFun, 1, SCs),
- Fun1 =
- fun({V1, V2}) ->
- I1 = ets:lookup_element(V2I, V1, 2),
- I2 = ets:lookup_element(V2I, V2, 2),
- I1 =:= I2 orelse ets:insert(I2I, {I1, I2})
- end,
- lists:foreach(Fun1, digraph:edges(G)),
- Fun3 =
- fun({I1, I2}, {Out, In}) ->
- SC1 = ets:lookup_element(I2C, I1, 2),
- SC2 = ets:lookup_element(I2C, I2, 2),
- {dict:append(SC1, SC2, Out), dict:append(SC2, SC1, In)}
- end,
- {OutDict, InDict} = ets:foldl(Fun3, {dict:new(), dict:new()}, I2I),
- [OutETS, InETS] =
+ SCCs = digraph_utils:strong_components(G),
+ %% Assign unique numbers to SCCs:
+ Ints = lists:seq(1, length(SCCs)),
+ IntToSCC = lists:zip(Ints, SCCs),
+ IntScc = sofs:relation(IntToSCC, [{int, scc}]),
+ %% Subsitute strong components for vertices in edges using the
+ %% unique numbers:
+ C2V = sofs:relation([{SC, V} || SC <- SCCs, V <- SC], [{scc, v}]),
+ I2V = sofs:relative_product(IntScc, C2V), % [{v, int}]
+ Es = sofs:relation(digraph:edges(G), [{v, v}]),
+ R1 = sofs:relative_product(I2V, Es),
+ R2 = sofs:relative_product(I2V, sofs:converse(R1)),
+ %% Create in- and out-neighbours:
+ In = sofs:relation_to_family(sofs:strict_relation(R2)),
+ R3 = sofs:converse(R2),
+ Out = sofs:relation_to_family(sofs:strict_relation(R3)),
+ [OutETS, InETS, MapsETS] =
[ets:new(Name,[{read_concurrency, true}]) ||
- Name <- [callgraph_deps_out, callgraph_deps_in]],
- ets:insert(OutETS, dict:to_list(OutDict)),
- ets:insert(InETS, dict:to_list(InDict)),
- ets:delete(V2I),
- ets:delete(I2C),
- ets:delete(I2I),
- {{'e', OutETS, InETS}, SCs}.
+ Name <- [callgraph_deps_out, callgraph_deps_in, callgraph_scc_map]],
+ ets:insert(OutETS, sofs:to_external(Out)),
+ ets:insert(InETS, sofs:to_external(In)),
+ %% Create mappings from SCCs to unique integers, and the inverse:
+ ets:insert(MapsETS, lists:zip([{'scc', SCC} || SCC<- SCCs], Ints)),
+ ets:insert(MapsETS, IntToSCC),
+ {{'e', OutETS, InETS, MapsETS}, SCCs}.
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index fc56693ea3..e8c1613a33 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -637,8 +637,8 @@ cl_loop(State, LogCache) ->
{BackendPid, warnings, Warnings} ->
NewState = store_warnings(State, Warnings),
cl_loop(NewState, LogCache);
- {BackendPid, done, NewPlt, _NewDocPlt} ->
- return_value(State, NewPlt);
+ {BackendPid, done, NewMiniPlt, _NewDocPlt} ->
+ return_value(State, NewMiniPlt);
{BackendPid, ext_calls, ExtCalls} ->
cl_loop(State#cl_state{external_calls = ExtCalls}, LogCache);
{BackendPid, ext_types, ExtTypes} ->
@@ -654,6 +654,7 @@ cl_loop(State, LogCache) ->
cl_error(State, Msg);
_Other ->
%% io:format("Received ~p\n", [_Other]),
+ %% Note: {BackendPid, cserver, CodeServer, Plt} is ignored.
cl_loop(State, LogCache)
end.
@@ -699,10 +700,13 @@ return_value(State = #cl_state{erlang_mode = ErlangMode,
output_plt = OutputPlt,
plt_info = PltInfo,
stored_warnings = StoredWarnings},
- Plt) ->
+ MiniPlt) ->
case OutputPlt =:= none of
- true -> ok;
- false -> dialyzer_plt:to_file(OutputPlt, Plt, ModDeps, PltInfo)
+ true ->
+ dialyzer_plt:delete(MiniPlt);
+ false ->
+ Plt = dialyzer_plt:restore_full_plt(MiniPlt),
+ dialyzer_plt:to_file(OutputPlt, Plt, ModDeps, PltInfo)
end,
UnknownWarnings = unknown_warnings(State),
RetValue =
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index 934351aeeb..f668b81cd3 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -510,7 +510,7 @@ warning_options_msg() ->
-Wno_match
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
- Suppress warnings for violations of opaqueness of data types.
+ Suppress warnings for violations of opacity of data types.
-Wno_fail_call
Suppress warnings for failing calls.
-Wno_contracts
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index 03cd9671af..a5bb4e209c 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -29,7 +29,9 @@
-module(dialyzer_codeserver).
-export([delete/1,
- finalize_contracts/3,
+ store_temp_contracts/4,
+ give_away/2,
+ finalize_contracts/1,
finalize_exported_types/2,
finalize_records/2,
get_contracts/1,
@@ -38,7 +40,9 @@
get_exports/1,
get_records/1,
get_next_core_label/1,
- get_temp_contracts/1,
+ get_temp_contracts/2,
+ contracts_modules/1,
+ store_contracts/4,
get_temp_exported_types/1,
get_temp_records/1,
insert/3,
@@ -48,6 +52,7 @@
is_exported/2,
lookup_mod_code/2,
lookup_mfa_code/2,
+ lookup_mfa_var_label/2,
lookup_mod_records/2,
lookup_mod_contracts/2,
lookup_mfa_contract/2,
@@ -56,21 +61,22 @@
set_next_core_label/2,
set_temp_records/2,
store_temp_records/3,
- store_temp_contracts/4]).
+ translate_fake_file/3]).
--export_type([codeserver/0, fun_meta_info/0]).
+-export_type([codeserver/0, fun_meta_info/0, contracts/0]).
-include("dialyzer.hrl").
%%--------------------------------------------------------------------
-type dict_ets() :: ets:tid().
+-type map_ets() :: ets:tid().
-type set_ets() :: ets:tid().
-type types() :: erl_types:type_table().
--type mod_records() :: dict:dict(module(), types()).
+-type mod_records() :: erl_types:mod_records().
--type contracts() :: dict:dict(mfa(),dialyzer_contracts:file_contract()).
+-type contracts() :: #{mfa() => dialyzer_contracts:file_contract()}.
-type mod_contracts() :: dict:dict(module(), contracts()).
%% A property-list of data compiled from -compile and -dialyzer attributes.
@@ -81,16 +87,16 @@
-record(codeserver, {next_core_label = 0 :: label(),
code :: dict_ets(),
- exported_types :: set_ets() | 'undefined', % set(mfa())
- records :: dict_ets() | 'undefined',
- contracts :: dict_ets() | 'undefined',
- callbacks :: dict_ets() | 'undefined',
+ exported_types :: set_ets(), % set(mfa())
+ records :: map_ets(),
+ contracts :: map_ets(),
+ callbacks :: map_ets(),
fun_meta_info :: dict_ets(), % {mfa(), meta_info()}
exports :: 'clean' | set_ets(), % set(mfa())
temp_exported_types :: 'clean' | set_ets(), % set(mfa())
- temp_records :: 'clean' | dict_ets(),
- temp_contracts :: 'clean' | dict_ets(),
- temp_callbacks :: 'clean' | dict_ets()
+ temp_records :: 'clean' | map_ets(),
+ temp_contracts :: 'clean' | map_ets(),
+ temp_callbacks :: 'clean' | map_ets()
}).
-opaque codeserver() :: #codeserver{}.
@@ -104,7 +110,7 @@ ets_dict_find(Key, Table) ->
_:_ -> error
end.
-ets_dict_store(Key, Element, Table) ->
+ets_map_store(Key, Element, Table) ->
true = ets:insert(Table, {Key, Element}),
Table.
@@ -128,9 +134,6 @@ ets_set_to_set(Table) ->
Fold = fun({E}, Set) -> sets:add_element(E, Set) end,
ets:foldl(Fold, sets:new(), Table).
-ets_read_concurrent_table(Name) ->
- ets:new(Name, [{read_concurrency, true}]).
-
%%--------------------------------------------------------------------
-spec new() -> codeserver().
@@ -138,6 +141,13 @@ ets_read_concurrent_table(Name) ->
new() ->
CodeOptions = [compressed, public, {read_concurrency, true}],
Code = ets:new(dialyzer_codeserver_code, CodeOptions),
+ ReadOptions = [compressed, {read_concurrency, true}],
+ [Contracts, Callbacks, Records, ExportedTypes] =
+ [ets:new(Name, ReadOptions) ||
+ Name <- [dialyzer_codeserver_contracts,
+ dialyzer_codeserver_callbacks,
+ dialyzer_codeserver_records,
+ dialyzer_codeserver_exported_types]],
TempOptions = [public, {write_concurrency, true}],
[Exports, FunMetaInfo, TempExportedTypes, TempRecords, TempContracts,
TempCallbacks] =
@@ -150,6 +160,10 @@ new() ->
#codeserver{code = Code,
exports = Exports,
fun_meta_info = FunMetaInfo,
+ exported_types = ExportedTypes,
+ records = Records,
+ contracts = Contracts,
+ callbacks = Callbacks,
temp_exported_types = TempExportedTypes,
temp_records = TempRecords,
temp_contracts = TempContracts,
@@ -170,13 +184,15 @@ insert(Mod, ModCode, CS) ->
Exports = cerl:module_exports(ModCode),
Attrs = cerl:module_attrs(ModCode),
Defs = cerl:module_defs(ModCode),
+ {Files, SmallDefs} = compress_file_anno(Defs),
As = cerl:get_ann(ModCode),
Funs =
[{{Mod, cerl:fname_id(Var), cerl:fname_arity(Var)},
- Val} || Val = {Var, _Fun} <- Defs],
- Keys = [Key || {Key, _Value} <- Funs],
+ Val, {Var, cerl_trees:get_label(Fun)}} || Val = {Var, Fun} <- SmallDefs],
+ Keys = [Key || {Key, _Value, _Label} <- Funs],
ModEntry = {Mod, {Name, Exports, Attrs, Keys, As}},
- true = ets:insert(CS#codeserver.code, [ModEntry|Funs]),
+ ModFileEntry = {{mod, Mod}, Files},
+ true = ets:insert(CS#codeserver.code, [ModEntry, ModFileEntry|Funs]),
CS.
-spec get_temp_exported_types(codeserver()) -> sets:set(mfa()).
@@ -220,12 +236,12 @@ get_exports(#codeserver{exports = Exports}) ->
-spec finalize_exported_types(sets:set(mfa()), codeserver()) -> codeserver().
-finalize_exported_types(Set, CS) ->
- ExportedTypes = ets_read_concurrent_table(dialyzer_codeserver_exported_types),
+finalize_exported_types(Set,
+ #codeserver{exported_types = ExportedTypes,
+ temp_exported_types = TempETypes} = CS) ->
true = ets_set_insert_set(Set, ExportedTypes),
- TempExpTypes = CS#codeserver.temp_exported_types,
- true = ets:delete(TempExpTypes),
- CS#codeserver{exported_types = ExportedTypes, temp_exported_types = clean}.
+ true = ets:delete(TempETypes),
+ CS#codeserver{temp_exported_types = clean}.
-spec lookup_mod_code(atom(), codeserver()) -> cerl:c_module().
@@ -237,6 +253,11 @@ lookup_mod_code(Mod, CS) when is_atom(Mod) ->
lookup_mfa_code({_M, _F, _A} = MFA, CS) ->
table__lookup(CS#codeserver.code, MFA).
+-spec lookup_mfa_var_label(mfa(), codeserver()) -> {cerl:c_var(), label()}.
+
+lookup_mfa_var_label({_M, _F, _A} = MFA, CS) ->
+ ets:lookup_element(CS#codeserver.code, MFA, 3).
+
-spec get_next_core_label(codeserver()) -> label().
get_next_core_label(#codeserver{next_core_label = NCL}) ->
@@ -251,8 +272,8 @@ set_next_core_label(NCL, CS) ->
lookup_mod_records(Mod, #codeserver{records = RecDict}) when is_atom(Mod) ->
case ets_dict_find(Mod, RecDict) of
- error -> dict:new();
- {ok, Dict} -> Dict
+ error -> maps:new();
+ {ok, Map} -> Map
end.
-spec get_records(codeserver()) -> mod_records().
@@ -262,11 +283,11 @@ get_records(#codeserver{records = RecDict}) ->
-spec store_temp_records(module(), types(), codeserver()) -> codeserver().
-store_temp_records(Mod, Dict, #codeserver{temp_records = TempRecDict} = CS)
+store_temp_records(Mod, Map, #codeserver{temp_records = TempRecDict} = CS)
when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
+ case maps:size(Map) =:= 0 of
true -> CS;
- false -> CS#codeserver{temp_records = ets_dict_store(Mod, Dict, TempRecDict)}
+ false -> CS#codeserver{temp_records = ets_map_store(Mod, Map, TempRecDict)}
end.
-spec get_temp_records(codeserver()) -> mod_records().
@@ -284,20 +305,20 @@ set_temp_records(Dict, CS) ->
-spec finalize_records(mod_records(), codeserver()) -> codeserver().
-finalize_records(Dict, CS) ->
- true = ets:delete(CS#codeserver.temp_records),
- Records = ets_read_concurrent_table(dialyzer_codeserver_records),
+finalize_records(Dict, #codeserver{temp_records = TmpRecords,
+ records = Records} = CS) ->
+ true = ets:delete(TmpRecords),
true = ets_dict_store_dict(Dict, Records),
- CS#codeserver{records = Records, temp_records = clean}.
+ CS#codeserver{temp_records = clean}.
-spec lookup_mod_contracts(atom(), codeserver()) -> contracts().
lookup_mod_contracts(Mod, #codeserver{contracts = ContDict})
when is_atom(Mod) ->
case ets_dict_find(Mod, ContDict) of
- error -> dict:new();
+ error -> maps:new();
{ok, Keys} ->
- dict:from_list([get_file_contract(Key, ContDict)|| Key <- Keys])
+ maps:from_list([get_file_contract(Key, ContDict)|| Key <- Keys])
end.
get_file_contract(Key, ContDict) ->
@@ -330,48 +351,69 @@ get_callbacks(#codeserver{callbacks = CallbDict}) ->
-spec store_temp_contracts(module(), contracts(), contracts(), codeserver()) ->
codeserver().
-store_temp_contracts(Mod, SpecDict, CallbackDict,
+store_temp_contracts(Mod, SpecMap, CallbackMap,
#codeserver{temp_contracts = Cn,
temp_callbacks = Cb} = CS)
when is_atom(Mod) ->
- CS1 =
- case dict:size(SpecDict) =:= 0 of
- true -> CS;
- false ->
- CS#codeserver{temp_contracts = ets_dict_store(Mod, SpecDict, Cn)}
- end,
- case dict:size(CallbackDict) =:= 0 of
- true -> CS1;
- false ->
- CS1#codeserver{temp_callbacks = ets_dict_store(Mod, CallbackDict, Cb)}
- end.
-
--spec get_temp_contracts(codeserver()) -> {mod_contracts(), mod_contracts()}.
+ CS1 = CS#codeserver{temp_contracts = ets_map_store(Mod, SpecMap, Cn)},
+ CS1#codeserver{temp_callbacks = ets_map_store(Mod, CallbackMap, Cb)}.
-get_temp_contracts(#codeserver{temp_contracts = TempContDict,
- temp_callbacks = TempCallDict}) ->
- {ets_dict_to_dict(TempContDict), ets_dict_to_dict(TempCallDict)}.
+-spec contracts_modules(codeserver()) -> [module()].
--spec finalize_contracts(mod_contracts(), mod_contracts(), codeserver()) ->
- codeserver().
+contracts_modules(#codeserver{temp_contracts = TempContTable}) ->
+ ets:select(TempContTable, [{{'$1', '$2'}, [], ['$1']}]).
-finalize_contracts(SpecDict, CallbackDict, CS) ->
- Contracts = ets_read_concurrent_table(dialyzer_codeserver_contracts),
- Callbacks = ets_read_concurrent_table(dialyzer_codeserver_callbacks),
- Contracts = dict:fold(fun decompose_spec_dict/3, Contracts, SpecDict),
- Callbacks = dict:fold(fun decompose_cb_dict/3, Callbacks, CallbackDict),
- CS#codeserver{contracts = Contracts, callbacks = Callbacks,
- temp_contracts = clean, temp_callbacks = clean}.
+-spec store_contracts(module(), contracts(), contracts(), codeserver()) ->
+ codeserver().
-decompose_spec_dict(Mod, Dict, Table) ->
- Keys = dict:fetch_keys(Dict),
- true = ets:insert(Table, dict:to_list(Dict)),
- true = ets:insert(Table, {Mod, Keys}),
- Table.
+store_contracts(Mod, SpecMap, CallbackMap, CS) ->
+ #codeserver{contracts = SpecDict, callbacks = CallbackDict} = CS,
+ Keys = maps:keys(SpecMap),
+ true = ets:insert(SpecDict, maps:to_list(SpecMap)),
+ true = ets:insert(SpecDict, {Mod, Keys}),
+ true = ets:insert(CallbackDict, maps:to_list(CallbackMap)),
+ CS.
-decompose_cb_dict(_Mod, Dict, Table) ->
- true = ets:insert(Table, dict:to_list(Dict)),
- Table.
+-spec get_temp_contracts(module(), codeserver()) ->
+ {contracts(), contracts()}.
+
+get_temp_contracts(Mod, #codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict}) ->
+ [{Mod, Contracts}] = ets:lookup(TempContDict, Mod),
+ true = ets:delete(TempContDict, Mod),
+ [{Mod, Callbacks}] = ets:lookup(TempCallDict, Mod),
+ true = ets:delete(TempCallDict, Mod),
+ {Contracts, Callbacks}.
+
+-spec give_away(codeserver(), pid()) -> 'ok'.
+
+give_away(#codeserver{temp_records = TempRecords,
+ temp_contracts = TempContracts,
+ temp_callbacks = TempCallbacks,
+ records = Records,
+ contracts = Contracts,
+ callbacks = Callbacks}, Pid) ->
+ _ = [true = ets:give_away(Table, Pid, any) ||
+ Table <- [TempRecords, TempContracts, TempCallbacks,
+ Records, Contracts, Callbacks],
+ Table =/= clean],
+ ok.
+
+-spec finalize_contracts(codeserver()) -> codeserver().
+
+finalize_contracts(#codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict} = CS) ->
+ true = ets:delete(TempContDict),
+ true = ets:delete(TempCallDict),
+ CS#codeserver{temp_contracts = clean, temp_callbacks = clean}.
+
+-spec translate_fake_file(codeserver(), module(), file:filename()) ->
+ file:filename().
+
+translate_fake_file(#codeserver{code = Code}, Module, FakeFile) ->
+ Files = ets:lookup_element(Code, {mod, Module}, 2),
+ {FakeFile, File} = lists:keyfind(FakeFile, 1, Files),
+ File.
table__lookup(TablePid, M) when is_atom(M) ->
{Name, Exports, Attrs, Keys, As} = ets:lookup_element(TablePid, M, 2),
@@ -379,3 +421,25 @@ table__lookup(TablePid, M) when is_atom(M) ->
cerl:ann_c_module(As, Name, Exports, Attrs, Defs);
table__lookup(TablePid, MFA) ->
ets:lookup_element(TablePid, MFA, 2).
+
+compress_file_anno(Term) ->
+ {Files, SmallTerm} = compress_file_anno(Term, []),
+ {[{FakeFile, File} || {File, {file, FakeFile}} <- Files], SmallTerm}.
+
+compress_file_anno({file, F}, Fs) when is_list(F) ->
+ case lists:keyfind(F, 1, Fs) of
+ false ->
+ I = integer_to_list(length(Fs)),
+ FileI = {file, I},
+ NFs = [{F, FileI}|Fs],
+ {NFs, FileI};
+ {F, FileI} -> {Fs, FileI}
+ end;
+compress_file_anno(T, Fs) when is_tuple(T) ->
+ {NFs, NL} = compress_file_anno(tuple_to_list(T), Fs),
+ {NFs, list_to_tuple(NL)};
+compress_file_anno([E|L], Fs) ->
+ {Fs1, NE} = compress_file_anno(E, Fs),
+ {NFs, NL} = compress_file_anno(L, Fs1),
+ {NFs, [NE|NL]};
+compress_file_anno(T, Fs) -> {Fs, T}.
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index a72368f9f8..f3fba68e84 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -31,7 +31,7 @@
get_contract_return/2,
%% get_contract_signature/1,
is_overloaded/1,
- process_contract_remote_types/1,
+ process_contract_remote_types/2,
store_tmp_contract/5]).
-export_type([file_contract/0, plt_contracts/0]).
@@ -146,14 +146,13 @@ sequence([], _Delimiter) -> "";
sequence([H], _Delimiter) -> H;
sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter).
--spec process_contract_remote_types(dialyzer_codeserver:codeserver()) ->
- dialyzer_codeserver:codeserver().
+-spec process_contract_remote_types(dialyzer_codeserver:codeserver(),
+ erl_types:mod_records()) ->
+ dialyzer_codeserver:codeserver().
-process_contract_remote_types(CodeServer) ->
- {TmpContractDict, TmpCallbackDict} =
- dialyzer_codeserver:get_temp_contracts(CodeServer),
+process_contract_remote_types(CodeServer, RecordDict) ->
+ Mods = dialyzer_codeserver:contracts_modules(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
- RecordDict = dialyzer_codeserver:get_records(CodeServer),
ContractFun =
fun({{_M, _F, _A}=MFA, {File, TmpContract, Xtra}}, C0) ->
#tmp_contract{contract_funs = CFuns, forms = Forms} = TmpContract,
@@ -165,20 +164,21 @@ process_contract_remote_types(CodeServer) ->
{{MFA, {File, Contract, Xtra}}, C2}
end,
ModuleFun =
- fun({ModuleName, ContractDict}, C3) ->
- {NewContractList, C4} =
- lists:mapfoldl(ContractFun, C3, dict:to_list(ContractDict)),
- {{ModuleName, dict:from_list(NewContractList)}, C4}
+ fun(ModuleName) ->
+ Cache = erl_types:cache__new(),
+ {ContractMap, CallbackMap} =
+ dialyzer_codeserver:get_temp_contracts(ModuleName, CodeServer),
+ {NewContractList, Cache1} =
+ lists:mapfoldl(ContractFun, Cache, maps:to_list(ContractMap)),
+ {NewCallbackList, _NewCache} =
+ lists:mapfoldl(ContractFun, Cache1, maps:to_list(CallbackMap)),
+ dialyzer_codeserver:store_contracts(ModuleName,
+ maps:from_list(NewContractList),
+ maps:from_list(NewCallbackList),
+ CodeServer)
end,
- Cache = erl_types:cache__new(),
- {NewContractList, C5} =
- lists:mapfoldl(ModuleFun, Cache, dict:to_list(TmpContractDict)),
- {NewCallbackList, _C6} =
- lists:mapfoldl(ModuleFun, C5, dict:to_list(TmpCallbackDict)),
- NewContractDict = dict:from_list(NewContractList),
- NewCallbackDict = dict:from_list(NewCallbackList),
- dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict,
- CodeServer).
+ lists:foreach(ModuleFun, Mods),
+ dialyzer_codeserver:finalize_contracts(CodeServer).
-type opaques_fun() :: fun((module()) -> [erl_types:erl_type()]).
@@ -232,7 +232,7 @@ check_contract(#contract{contracts = Contracts}, SuccType, Opaques) ->
error ->
{error, {overlapping_contract, []}};
ok ->
- InfList = [erl_types:t_inf(Contract, SuccType, Opaques)
+ InfList = [{Contract, erl_types:t_inf(Contract, SuccType, Opaques)}
|| Contract <- Contracts2],
case check_contract_inf_list(InfList, SuccType, Opaques) of
{error, _} = Invalid -> Invalid;
@@ -256,10 +256,21 @@ check_domains([Dom|Doms]) ->
%% Allow a contract if one of the overloaded contracts is possible.
%% We used to be more strict, e.g., all overloaded contracts had to be
%% possible.
-check_contract_inf_list([FunType|Left], SuccType, Opaques) ->
+check_contract_inf_list(List, SuccType, Opaques) ->
+ case check_contract_inf_list(List, SuccType, Opaques, []) of
+ ok -> ok;
+ {error, []} -> {error, invalid_contract};
+ {error, [{SigRange, ContrRange}|_]} ->
+ case erl_types:t_find_opaque_mismatch(SigRange, ContrRange, Opaques) of
+ error -> {error, invalid_contract};
+ {ok, _T1, T2} -> {error, {opaque_mismatch, T2}}
+ end
+ end.
+
+check_contract_inf_list([{Contract, FunType}|Left], SuccType, Opaques, OM) ->
FunArgs = erl_types:t_fun_args(FunType),
case lists:any(fun erl_types:t_is_none_or_unit/1, FunArgs) of
- true -> check_contract_inf_list(Left, SuccType, Opaques);
+ true -> check_contract_inf_list(Left, SuccType, Opaques, OM);
false ->
STRange = erl_types:t_fun_range(SuccType),
case erl_types:t_is_none_or_unit(STRange) of
@@ -267,13 +278,16 @@ check_contract_inf_list([FunType|Left], SuccType, Opaques) ->
false ->
Range = erl_types:t_fun_range(FunType),
case erl_types:t_is_none(erl_types:t_inf(STRange, Range)) of
- true -> check_contract_inf_list(Left, SuccType, Opaques);
+ true ->
+ CR = erl_types:t_fun_range(Contract),
+ NewOM = [{STRange, CR}|OM],
+ check_contract_inf_list(Left, SuccType, Opaques, NewOM);
false -> ok
end
end
end;
-check_contract_inf_list([], _SuccType, _Opaques) ->
- {error, invalid_contract}.
+check_contract_inf_list([], _SuccType, _Opaques, OM) ->
+ {error, OM}.
check_extraneous([], _SuccType) -> ok;
check_extraneous([C|Cs], SuccType) ->
@@ -383,7 +397,7 @@ solve_constraints(Contract, Call, Constraints) ->
%% ?debug("Inf: ~s\n", [erl_types:t_to_string(Inf)]),
%% erl_types:t_assign_variables_to_subtype(Contract, Inf).
--type contracts() :: dict:dict(mfa(),dialyzer_contracts:file_contract()).
+-type contracts() :: dialyzer_codeserver:contracts().
%% Checks the contracts for functions that are not implemented
-spec contracts_without_fun(contracts(), [_], dialyzer_callgraph:callgraph()) ->
@@ -393,12 +407,12 @@ contracts_without_fun(Contracts, AllFuns0, Callgraph) ->
AllFuns1 = [{dialyzer_callgraph:lookup_name(Label, Callgraph), Arity}
|| {Label, Arity} <- AllFuns0],
AllFuns2 = [{M, F, A} || {{ok, {M, F, _}}, A} <- AllFuns1],
- AllContractMFAs = dict:fetch_keys(Contracts),
+ AllContractMFAs = maps:keys(Contracts),
ErrorContractMFAs = AllContractMFAs -- AllFuns2,
[warn_spec_missing_fun(MFA, Contracts) || MFA <- ErrorContractMFAs].
warn_spec_missing_fun({M, F, A} = MFA, Contracts) ->
- {{File, Line}, _Contract, _Xtra} = dict:fetch(MFA, Contracts),
+ {{File, Line}, _Contract, _Xtra} = maps:get(MFA, Contracts),
WarningInfo = {File, Line, MFA},
{?WARN_CONTRACT_SYNTAX, WarningInfo, {spec_missing_fun, [M, F, A]}}.
@@ -431,11 +445,11 @@ insert_constraints([], Map) -> Map.
-spec store_tmp_contract(mfa(), file_line(), spec_data(), contracts(), types()) ->
contracts().
-store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecDict, RecordsDict) ->
+store_tmp_contract(MFA, FileLine, {TypeSpec, Xtra}, SpecMap, RecordsDict) ->
%% io:format("contract from form: ~p\n", [TypeSpec]),
TmpContract = contract_from_form(TypeSpec, MFA, RecordsDict, FileLine),
%% io:format("contract: ~p\n", [TmpContract]),
- dict:store(MFA, {FileLine, TmpContract, Xtra}, SpecDict).
+ maps:put(MFA, {FileLine, TmpContract, Xtra}, SpecMap).
contract_from_form(Forms, MFA, RecDict, FileLine) ->
{CFuns, Forms1} = contract_from_form(Forms, MFA, RecDict, FileLine, [], []),
@@ -663,7 +677,7 @@ get_invalid_contract_warnings(Modules, CodeServer, Plt, FindOpaques) ->
get_invalid_contract_warnings_modules([Mod|Mods], CodeServer, Plt, FindOpaques, Acc) ->
Contracts1 = dialyzer_codeserver:lookup_mod_contracts(Mod, CodeServer),
- Contracts2 = dict:to_list(Contracts1),
+ Contracts2 = maps:to_list(Contracts1),
Records = dialyzer_codeserver:lookup_mod_records(Mod, CodeServer),
NewAcc = get_invalid_contract_warnings_funs(Contracts2, Plt, Records, FindOpaques, Acc),
get_invalid_contract_warnings_modules(Mods, CodeServer, Plt, FindOpaques, NewAcc);
@@ -687,6 +701,9 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
case check_contract(Contract, Sig, Opaques) of
{error, invalid_contract} ->
[invalid_contract_warning(MFA, WarningInfo, Sig, RecDict)|Acc];
+ {error, {opaque_mismatch, T2}} ->
+ W = contract_opaque_warning(MFA, WarningInfo, T2, Sig, RecDict),
+ [W|Acc];
{error, {overlapping_contract, []}} ->
[overlapping_contract_warning(MFA, WarningInfo)|Acc];
{error, {extra_range, ExtraRanges, STRange}} ->
@@ -740,6 +757,12 @@ invalid_contract_warning({M, F, A}, WarningInfo, SuccType, RecDict) ->
SuccTypeStr = dialyzer_utils:format_sig(SuccType, RecDict),
{?WARN_CONTRACT_TYPES, WarningInfo, {invalid_contract, [M, F, A, SuccTypeStr]}}.
+contract_opaque_warning({M, F, A}, WarningInfo, OpType, SuccType, RecDict) ->
+ OpaqueStr = erl_types:t_to_string(OpType),
+ SuccTypeStr = dialyzer_utils:format_sig(SuccType, RecDict),
+ {?WARN_CONTRACT_TYPES, WarningInfo,
+ {contract_with_opaque, [M, F, A, OpaqueStr, SuccTypeStr]}}.
+
overlapping_contract_warning({M, F, A}, WarningInfo) ->
{?WARN_CONTRACT_TYPES, WarningInfo, {overlapping_contract, [M, F, A]}}.
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 963c953447..ce292e1140 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -529,7 +529,7 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
case is_race_analysis_enabled(State) of
true ->
Ann = cerl:get_ann(Tree),
- File = get_file(Ann),
+ File = get_file(Ann, State),
Line = abs(get_line(Ann)),
dialyzer_races:store_race_call(Fun, ArgTypes, Args,
{File, Line}, State);
@@ -1211,7 +1211,7 @@ handle_tuple(Tree, Map, State) ->
TagVal = cerl:atom_val(Tag),
case state__lookup_record(TagVal, length(Left), State1) of
error -> {State1, Map1, TupleType};
- {ok, RecType} ->
+ {ok, RecType, FieldNames} ->
InfTupleType = t_inf(RecType, TupleType),
case t_is_none(InfTupleType) of
true ->
@@ -1232,10 +1232,13 @@ handle_tuple(Tree, Map, State) ->
Tree, Msg),
{State2, Map1, t_none()};
{error, opaque, ErrorPat, ErrorType, OpaqueType} ->
+ OpaqueStr = format_type(OpaqueType, State1),
+ Name = field_name(Elements, ErrorPat, FieldNames),
Msg = {opaque_match,
- [format_patterns(ErrorPat),
- format_type(ErrorType, State1),
- format_type(OpaqueType, State1)]},
+ ["record field" ++ Name ++
+ " declared to be of type " ++
+ format_type(ErrorType, State1),
+ OpaqueStr, OpaqueStr]},
State2 = state__add_warning(State1, ?WARN_OPAQUE,
Tree, Msg),
{State2, Map1, t_none()};
@@ -1252,6 +1255,15 @@ handle_tuple(Tree, Map, State) ->
end
end.
+field_name(Elements, ErrorPat, FieldNames) ->
+ try
+ [Pat] = ErrorPat,
+ Take = lists:takewhile(fun(X) -> X =/= Pat end, Elements),
+ " " ++ format_atom(lists:nth(length(Take), FieldNames))
+ catch
+ _:_ -> ""
+ end.
+
%%----------------------------------------
%% Clauses
%%
@@ -1632,7 +1644,7 @@ bind_pat_vars([Pat|PatLeft], [Type|TypeLeft], Acc, Map, State, Rev) ->
TagAtom = cerl:atom_val(Tag),
case state__lookup_record(TagAtom, length(Left), State) of
error -> {false, t_tuple(length(Es))};
- {ok, Record} ->
+ {ok, Record, _FieldNames} ->
[_Head|AnyTail] = [t_any() || _ <- Es],
UntypedRecord = t_tuple([t_atom(TagAtom)|AnyTail]),
{not t_is_equal(Record, UntypedRecord), Record}
@@ -2160,7 +2172,7 @@ handle_guard_is_record(Guard, Map, Env, Eval, State) ->
TupleType =
case state__lookup_record(Tag, ArityMin1, State) of
error -> Tuple;
- {ok, Prototype} -> Prototype
+ {ok, Prototype, _FieldNames} -> Prototype
end,
Type = t_inf(TupleType, RecType, State#state.opaques),
case t_is_none(Type) of
@@ -2610,7 +2622,7 @@ bind_guard_case_clauses(Arg, Clauses, Map0, Env, Eval, State) ->
Map = join_maps_begin(Map0),
{GenMap, GenArgType} = bind_guard(Arg, Map, Env, dont_know, State),
bind_guard_case_clauses(GenArgType, GenMap, Arg, Clauses1, Map, Env, Eval,
- t_none(), [], State).
+ t_none(), [], [], State).
filter_fail_clauses([Clause|Left]) ->
case (cerl:clause_pats(Clause) =:= []) of
@@ -2629,7 +2641,7 @@ filter_fail_clauses([]) ->
[].
bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
- Map, Env, Eval, AccType, AccMaps, State) ->
+ Map, Env, Eval, AccType, AccMaps, Throws, State) ->
Pats = cerl:clause_pats(Clause),
{NewMap0, ArgType} =
case Pats of
@@ -2673,9 +2685,9 @@ bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
case (NewMap1 =:= none) orelse t_is_none(GenArgType) of
true ->
bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
- Eval, AccType, AccMaps, State);
+ Eval, AccType, AccMaps, Throws, State);
false ->
- {NewAccType, NewAccMaps} =
+ {NewAccType, NewAccMaps, NewThrows} =
try
{NewMap2, GuardType} = bind_guard(Guard, NewMap1, Env, pos, State),
case t_is_none(t_inf(t_atom(true), GuardType)) of
@@ -2699,17 +2711,26 @@ bind_guard_case_clauses(GenArgType, GenMap, ArgExpr, [Clause|Left],
dont_know ->
ok
end,
- {t_sup(AccType, CType), [NewMap3|AccMaps]}
+ {t_sup(AccType, CType), [NewMap3|AccMaps], Throws}
catch
- throw:{fail, _What} -> {AccType, AccMaps}
+ throw:{fail, Reason} ->
+ Throws1 = case Reason of
+ none -> Throws;
+ _ -> Throws ++ [Reason]
+ end,
+ {AccType, AccMaps, Throws1}
end,
bind_guard_case_clauses(NewGenArgType, GenMap, ArgExpr, Left, Map, Env,
- Eval, NewAccType, NewAccMaps, State)
+ Eval, NewAccType, NewAccMaps, NewThrows, State)
end;
bind_guard_case_clauses(_GenArgType, _GenMap, _ArgExpr, [], Map, _Env, _Eval,
- AccType, AccMaps, _State) ->
+ AccType, AccMaps, Throws, _State) ->
case t_is_none(AccType) of
- true -> throw({fail, none});
+ true ->
+ case Throws of
+ [Throw|_] -> throw({fail, Throw});
+ [] -> throw({fail, none})
+ end;
false -> {join_maps_end(AccMaps, Map), AccType}
end.
@@ -3069,7 +3090,7 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
Ann = cerl:get_ann(Tree),
case Force of
true ->
- WarningInfo = {get_file(Ann),
+ WarningInfo = {get_file(Ann, State),
abs(get_line(Ann)),
State#state.curr_fun},
Warn = {Tag, WarningInfo, Msg},
@@ -3079,7 +3100,9 @@ state__add_warning(#state{warnings = Warnings, warning_mode = true} = State,
case is_compiler_generated(Ann) of
true -> State;
false ->
- WarningInfo = {get_file(Ann), get_line(Ann), State#state.curr_fun},
+ WarningInfo = {get_file(Ann, State),
+ get_line(Ann),
+ State#state.curr_fun},
Warn = {Tag, WarningInfo, Msg},
case Tag of
?WARN_CONTRACT_RANGE -> ok;
@@ -3207,7 +3230,8 @@ state__lookup_record(Tag, Arity, #state{records = Records}) ->
RecType =
t_tuple([t_atom(Tag)|
[FieldType || {_FieldName, _Abstr, FieldType} <- Fields]]),
- {ok, RecType};
+ FieldNames = [FieldName || {FieldName, _Abstr, _FieldType} <- Fields],
+ {ok, RecType, FieldNames};
error ->
error
end.
@@ -3477,6 +3501,12 @@ state__put_races(Races, State) ->
state__records_only(#state{records = Records}) ->
#state{records = Records}.
+-spec state__translate_file(file:filename(), state()) -> file:filename().
+
+state__translate_file(FakeFile, State) ->
+ #state{codeserver = CodeServer, module = Module} = State,
+ dialyzer_codeserver:translate_fake_file(CodeServer, Module, FakeFile).
+
%%% ===========================================================================
%%%
%%% Races
@@ -3548,9 +3578,11 @@ get_line([Line|_]) when is_integer(Line) -> Line;
get_line([_|Tail]) -> get_line(Tail);
get_line([]) -> -1.
-get_file([]) -> [];
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
+get_file([], _State) -> [];
+get_file([{file, FakeFile}|_], State) ->
+ state__translate_file(FakeFile, State);
+get_file([_|Tail], State) ->
+ get_file(Tail, State).
is_compiler_generated(Ann) ->
lists:member(compiler_generated, Ann) orelse (get_line(Ann) < 1).
@@ -3660,6 +3692,9 @@ map_pats(Pats) ->
fold_literals(TreeList) ->
[cerl:fold_literal(Tree) || Tree <- TreeList].
+format_atom(A) ->
+ format_cerl(cerl:c_atom(A)).
+
type(Tree) ->
Folded = cerl:fold_literal(Tree),
case cerl:type(Folded) of
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index 30d2bdeca4..1701aff2f2 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -310,7 +310,7 @@ createWarningsMenu() ->
addCheckedItem(WarningsMenu, ?menuID_WARN_FAIL_FUN_CALLS,
"Failing function calls"),
addCheckedItem(WarningsMenu, ?menuID_WARN_BAD_FUN, "Bad fun applications"),
- addCheckedItem(WarningsMenu, ?menuID_WARN_OPAQUE, "Opaqueness violations"),
+ addCheckedItem(WarningsMenu, ?menuID_WARN_OPAQUE, "Opacity violations"),
addCheckedItem(WarningsMenu, ?menuID_WARN_LIST_CONSTR,
"Improper list constructions"),
addCheckedItem(WarningsMenu, ?menuID_WARN_UNUSED_FUN, "Unused functions"),
@@ -505,8 +505,9 @@ gui_loop(#gui_state{backend_pid = BackendPid, doc_plt = DocPlt,
end,
ExplanationPid = spawn_link(Fun),
gui_loop(State#gui_state{expl_pid = ExplanationPid});
- {BackendPid, done, _NewPlt, NewDocPlt} ->
+ {BackendPid, done, NewMiniPlt, NewDocPlt} ->
message(State, "Analysis done"),
+ dialyzer_plt:delete(NewMiniPlt),
config_gui_stop(State),
gui_loop(State#gui_state{doc_plt = NewDocPlt});
{'EXIT', BackendPid, {error, Reason}} ->
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index add660eae9..e71a0fca9d 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index cf2f0e919e..0eda73a208 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -58,7 +58,9 @@
get_specs/4,
to_file/4,
get_mini_plt/1,
- restore_full_plt/2
+ restore_full_plt/1,
+ delete/1,
+ give_away/2
]).
%% Debug utilities
@@ -82,14 +84,16 @@
%%----------------------------------------------------------------------
-record(plt, {info = table_new() :: dict:dict(),
- types = table_new() :: dict:dict(),
+ types = table_new() :: erl_types:mod_records(),
contracts = table_new() :: dict:dict(),
callbacks = table_new() :: dict:dict(),
exported_types = sets:new() :: sets:set()}).
-record(mini_plt, {info :: ets:tid(),
+ types :: ets:tid(),
contracts :: ets:tid(),
- callbacks :: ets:tid()
+ callbacks :: ets:tid(),
+ exported_types :: ets:tid()
}).
-opaque plt() :: #plt{} | #mini_plt{}.
@@ -130,6 +134,10 @@ delete_module(#plt{info = Info, types = Types,
-spec delete_list(plt(), [mfa() | integer()]) -> plt().
+delete_list(#mini_plt{info = Info,
+ contracts = Contracts}=Plt, List) ->
+ Plt#mini_plt{info = ets_table_delete_list(Info, List),
+ contracts = ets_table_delete_list(Contracts, List)};
delete_list(#plt{info = Info, types = Types,
contracts = Contracts,
callbacks = Callbacks,
@@ -183,7 +191,7 @@ lookup(Plt, Label) when is_integer(Label) ->
lookup_1(#mini_plt{info = Info}, MFAorLabel) ->
ets_table_lookup(Info, MFAorLabel).
--spec insert_types(plt(), dict:dict()) -> plt().
+-spec insert_types(plt(), erl_types:mod_records()) -> plt().
insert_types(PLT, Rec) ->
PLT#plt{types = Rec}.
@@ -193,7 +201,7 @@ insert_types(PLT, Rec) ->
insert_exported_types(PLT, Set) ->
PLT#plt{exported_types = Set}.
--spec get_types(plt()) -> dict:dict().
+-spec get_types(plt()) -> erl_types:mod_records().
get_types(#plt{types = Types}) ->
Types.
@@ -253,8 +261,10 @@ from_file(FileName, ReturnInfo) ->
Msg = io_lib:format("Old PLT file ~s\n", [FileName]),
plt_error(Msg);
ok ->
+ Types = [{Mod, maps:from_list(dict:to_list(Types))} ||
+ {Mod, Types} <- dict:to_list(Rec#file_plt.types)],
Plt = #plt{info = Rec#file_plt.info,
- types = Rec#file_plt.types,
+ types = dict:from_list(Types),
contracts = Rec#file_plt.contracts,
callbacks = Rec#file_plt.callbacks,
exported_types = Rec#file_plt.exported_types},
@@ -371,12 +381,14 @@ to_file(FileName,
end,
OldModDeps, ModDeps),
ImplMd5 = compute_implementation_md5(),
+ FileTypes = dict:from_list([{Mod, dict:from_list(maps:to_list(MTypes))} ||
+ {Mod, MTypes} <- dict:to_list(Types)]),
Record = #file_plt{version = ?VSN,
file_md5_list = MD5,
info = Info,
contracts = Contracts,
callbacks = Callbacks,
- types = Types,
+ types = FileTypes,
exported_types = ExpTypes,
mod_deps = NewModDeps,
implementation_md5 = ImplMd5},
@@ -510,32 +522,100 @@ init_md5_list_1(Md5List, [], Acc) ->
-spec get_mini_plt(plt()) -> plt().
-get_mini_plt(#plt{info = Info, contracts = Contracts, callbacks = Callbacks}) ->
- [ETSInfo, ETSContracts, ETSCallbacks] =
- [ets:new(Name, [public]) || Name <- [plt_info, plt_contracts, plt_callbacks]],
+get_mini_plt(#plt{info = Info,
+ types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
+ exported_types = ExpTypes}) ->
+ [ETSInfo, ETSTypes, ETSContracts, ETSCallbacks, ETSExpTypes] =
+ [ets:new(Name, [public]) ||
+ Name <- [plt_info, plt_types, plt_contracts, plt_callbacks,
+ plt_exported_types]],
CallbackList = dict:to_list(Callbacks),
CallbacksByModule =
[{M, [Cb || {{M1,_,_},_} = Cb <- CallbackList, M1 =:= M]} ||
M <- lists:usort([M || {{M,_,_},_} <- CallbackList])],
- [true, true] =
+ [true, true, true] =
[ets:insert(ETS, dict:to_list(Data)) ||
- {ETS, Data} <- [{ETSInfo, Info}, {ETSContracts, Contracts}]],
+ {ETS, Data} <- [{ETSInfo, Info},
+ {ETSTypes, Types},
+ {ETSContracts, Contracts}]],
true = ets:insert(ETSCallbacks, CallbacksByModule),
- #mini_plt{info = ETSInfo, contracts = ETSContracts, callbacks = ETSCallbacks};
+ true = ets:insert(ETSExpTypes, [{ET} || ET <- sets:to_list(ExpTypes)]),
+ #mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes};
get_mini_plt(undefined) ->
undefined.
--spec restore_full_plt(plt(), plt()) -> plt().
-
-restore_full_plt(#mini_plt{info = ETSInfo, contracts = ETSContracts}, Plt) ->
- Info = dict:from_list(ets:tab2list(ETSInfo)),
- Contracts = dict:from_list(ets:tab2list(ETSContracts)),
- ets:delete(ETSContracts),
- ets:delete(ETSInfo),
- Plt#plt{info = Info, contracts = Contracts};
-restore_full_plt(undefined, undefined) ->
+-spec restore_full_plt(plt()) -> plt().
+
+restore_full_plt(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes} = MiniPlt) ->
+ Info = dict:from_list(tab2list(ETSInfo)),
+ Contracts = dict:from_list(tab2list(ETSContracts)),
+ Types = dict:from_list(tab2list(ETSTypes)),
+ Callbacks =
+ dict:from_list([Cb || {_M, Cbs} <- tab2list(ETSCallbacks), Cb <- Cbs]),
+ ExpTypes = sets:from_list([E || {E} <- tab2list(ETSExpTypes)]),
+ ok = delete(MiniPlt),
+ #plt{info = Info,
+ types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
+ exported_types = ExpTypes};
+restore_full_plt(undefined) ->
undefined.
+-spec delete(plt()) -> 'ok'.
+
+delete(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes}) ->
+ true = ets:delete(ETSContracts),
+ true = ets:delete(ETSTypes),
+ true = ets:delete(ETSInfo),
+ true = ets:delete(ETSCallbacks),
+ true = ets:delete(ETSExpTypes),
+ ok.
+
+-spec give_away(plt(), pid()) -> 'ok'.
+
+give_away(#mini_plt{info = ETSInfo,
+ types = ETSTypes,
+ contracts = ETSContracts,
+ callbacks = ETSCallbacks,
+ exported_types = ETSExpTypes},
+ Pid) ->
+ true = ets:give_away(ETSContracts, Pid, any),
+ true = ets:give_away(ETSTypes, Pid, any),
+ true = ets:give_away(ETSInfo, Pid, any),
+ true = ets:give_away(ETSCallbacks, Pid, any),
+ true = ets:give_away(ETSExpTypes, Pid, any),
+ ok.
+
+%% Somewhat slower than ets:tab2list(), but uses less memory.
+tab2list(T) ->
+ tab2list(ets:first(T), T, []).
+
+tab2list('$end_of_table', T, A) ->
+ case ets:first(T) of % no safe_fixtable()...
+ '$end_of_table' -> A;
+ Key -> tab2list(Key, T, A)
+ end;
+tab2list(Key, T, A) ->
+ Vs = ets:lookup(T, Key),
+ Key1 = ets:next(T, Key),
+ ets:delete(T, Key),
+ tab2list(Key1, T, Vs ++ A).
+
%%---------------------------------------------------------------------------
%% Edoc
@@ -607,6 +687,12 @@ table_delete_module1(Plt, Mod) ->
table_delete_module2(Plt, Mod) ->
dict:filter(fun(M, _Val) -> M =/= Mod end, Plt).
+ets_table_delete_list(Tab, [H|T]) ->
+ ets:delete(Tab, H),
+ ets_table_delete_list(Tab, T);
+ets_table_delete_list(Tab, []) ->
+ Tab.
+
table_delete_list(Plt, [H|T]) ->
table_delete_list(dict:erase(H, Plt), T);
table_delete_list(Plt, []) ->
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index 987da3aecf..0e44a5223f 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -96,7 +96,7 @@ analyze_callgraph(Callgraph, Plt, Codeserver, TimingServer, Solvers, Parent) ->
NewState =
init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
TimingServer, Solvers, Parent),
- dialyzer_plt:restore_full_plt(NewState#st.plt, Plt).
+ NewState#st.plt.
%%--------------------------------------------------------------------
@@ -111,6 +111,7 @@ init_state_and_get_success_typings(Callgraph, Plt, Codeserver,
get_refined_success_typings(SCCs, #st{callgraph = Callgraph,
timing_server = TimingServer} = State) ->
+ erlang:garbage_collect(),
case find_succ_typings(SCCs, State) of
{fixpoint, State1} -> State1;
{not_fixpoint, NotFixpoint1, State1} ->
@@ -155,8 +156,8 @@ get_warnings(Callgraph, Plt, DocPlt, Codeserver,
?timing(TimingServer, "warning",
get_warnings_from_modules(Mods, InitState, MiniDocPlt)),
{postprocess_warnings(CWarns ++ ModWarns, Codeserver),
- dialyzer_plt:restore_full_plt(MiniPlt, Plt),
- dialyzer_plt:restore_full_plt(MiniDocPlt, DocPlt)}.
+ MiniPlt,
+ dialyzer_plt:restore_full_plt(MiniDocPlt)}.
get_warnings_from_modules(Mods, State, DocPlt) ->
#st{callgraph = Callgraph, codeserver = Codeserver,
@@ -174,10 +175,10 @@ collect_warnings(M, {Codeserver, Callgraph, Plt, DocPlt}) ->
%% Check if there are contracts for functions that do not exist
Warnings1 =
dialyzer_contracts:contracts_without_fun(Contracts, AllFuns, Callgraph),
+ Attrs = cerl:module_attrs(ModCode),
{Warnings2, FunTypes} =
dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Codeserver,
Records),
- Attrs = cerl:module_attrs(ModCode),
Warnings3 =
dialyzer_behaviours:check_callbacks(M, Attrs, Records, Plt, Codeserver),
DocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt),
@@ -262,7 +263,7 @@ refine_one_module(M, {CodeServer, Callgraph, Plt, _Solvers}) ->
NewFunTypes =
dialyzer_dataflow:get_fun_types(ModCode, Plt, Callgraph, CodeServer, Records),
Contracts1 = dialyzer_codeserver:lookup_mod_contracts(M, CodeServer),
- Contracts = orddict:from_list(dict:to_list(Contracts1)),
+ Contracts = orddict:from_list(maps:to_list(Contracts1)),
FindOpaques = find_opaques_fun(Records),
DecoratedFunTypes =
decorate_succ_typings(Contracts, Callgraph, NewFunTypes, FindOpaques),
@@ -348,21 +349,25 @@ find_succ_typings(SCCs, #st{codeserver = Codeserver, callgraph = Callgraph,
-spec find_succ_types_for_scc(scc(), typesig_init_data()) -> [mfa_or_funlbl()].
-find_succ_types_for_scc(SCC, {Codeserver, Callgraph, Plt, Solvers}) ->
- SCC_Info = [{MFA,
- dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
- dialyzer_codeserver:lookup_mod_records(M, Codeserver)}
- || {M, _, _} = MFA <- SCC],
+find_succ_types_for_scc(SCC0, {Codeserver, Callgraph, Plt, Solvers}) ->
+ SCC = [MFA || {_, _, _} = MFA <- SCC0],
Contracts1 = [{MFA, dialyzer_codeserver:lookup_mfa_contract(MFA, Codeserver)}
- || {_, _, _} = MFA <- SCC],
+ || MFA <- SCC],
Contracts2 = [{MFA, Contract} || {MFA, {ok, Contract}} <- Contracts1],
Contracts3 = orddict:from_list(Contracts2),
Label = dialyzer_codeserver:get_next_core_label(Codeserver),
- AllFuns = collect_fun_info([Fun || {_MFA, {_Var, Fun}, _Rec} <- SCC_Info]),
+ AllFuns = lists:append(
+ [begin
+ {_Var, Fun} =
+ dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
+ collect_fun_info([Fun])
+ end || MFA <- SCC]),
+ erlang:garbage_collect(),
PropTypes = get_fun_types_from_plt(AllFuns, Callgraph, Plt),
%% Assume that the PLT contains the current propagated types
- FunTypes = dialyzer_typesig:analyze_scc(SCC_Info, Label, Callgraph,
- Plt, PropTypes, Solvers),
+ FunTypes = dialyzer_typesig:analyze_scc(SCC, Label, Callgraph,
+ Codeserver, Plt, PropTypes,
+ Solvers),
AllFunSet = sets:from_list([X || {X, _} <- AllFuns]),
FilteredFunTypes =
dict:filter(fun(X, _) -> sets:is_element(X, AllFunSet) end, FunTypes),
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index 1787b66192..a9ebac6c8b 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -29,7 +29,7 @@
-module(dialyzer_typesig).
--export([analyze_scc/6]).
+-export([analyze_scc/7]).
-export([get_safe_underapprox/2]).
%%-import(helper, %% 'helper' could be any module doing sanity checks...
@@ -101,10 +101,9 @@
-type types() :: erl_types:type_table().
--type typesig_scc() :: [{mfa(), {cerl:c_var(), cerl:c_fun()}, types()}].
-type typesig_funmap() :: #{type_var() => type_var()}.
--type prop_types() :: dict:dict(label(), types()).
+-type prop_types() :: dict:dict(label(), erl_types:erl_type()).
-record(state, {callgraph :: dialyzer_callgraph:callgraph()
| 'undefined',
@@ -121,7 +120,7 @@
plt :: dialyzer_plt:plt()
| 'undefined',
prop_types = dict:new() :: prop_types(),
- records = dict:new() :: types(),
+ records = maps:new() :: types(),
scc = [] :: ordsets:ordset(type_var()),
mfas :: [mfa()],
solvers = [] :: [solver()]
@@ -160,11 +159,10 @@
%%-----------------------------------------------------------------------------
%% Analysis of strongly connected components.
%%
-%% analyze_scc(SCC, NextLabel, CallGraph, PLT, PropTypes, Solvers) -> FunTypes
+%% analyze_scc(SCC, NextLabel, CallGraph, CodeServer,
+%% PLT, PropTypes, Solvers) -> FunTypes
%%
-%% SCC - [{MFA, Def, Records}]
-%% where Def = {Var, Fun} as in the Core Erlang module definitions.
-%% Records = dict(RecName, {Arity, [{FieldName, FieldType}]})
+%% SCC - [{MFA}]
%% NextLabel - An integer that is higher than any label in the code.
%% CallGraph - A callgraph as produced by dialyzer_callgraph.erl
%% Note: The callgraph must have been built with all the
@@ -176,28 +174,27 @@
%% Solvers - User specified solvers.
%%-----------------------------------------------------------------------------
--spec analyze_scc(typesig_scc(), label(),
+-spec analyze_scc([mfa()], label(),
dialyzer_callgraph:callgraph(),
+ dialyzer_codeserver:codeserver(),
dialyzer_plt:plt(), prop_types(), [solver()]) -> prop_types().
-analyze_scc(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers0) ->
+analyze_scc(SCC, NextLabel, CallGraph, CServer, Plt, PropTypes, Solvers0) ->
Solvers = solvers(Solvers0),
- assert_format_of_scc(SCC),
- State1 = new_state(SCC, NextLabel, CallGraph, Plt, PropTypes, Solvers),
- DefSet = add_def_list([Var || {_MFA, {Var, _Fun}, _Rec} <- SCC], sets:new()),
- State2 = traverse_scc(SCC, DefSet, State1),
+ State1 = new_state(SCC, NextLabel, CallGraph, CServer, Plt, PropTypes,
+ Solvers),
+ DefSet = add_def_list(maps:values(State1#state.name_map), sets:new()),
+ ModRecs = [{M, dialyzer_codeserver:lookup_mod_records(M, CServer)} ||
+ M <- lists:usort([M || {M, _, _} <- SCC])],
+ State2 = traverse_scc(SCC, CServer, DefSet, ModRecs, State1),
State3 = state__finalize(State2),
+ erlang:garbage_collect(),
Funs = state__scc(State3),
pp_constrs_scc(Funs, State3),
constraints_to_dot_scc(Funs, State3),
T = solve(Funs, State3),
dict:from_list(maps:to_list(T)).
-assert_format_of_scc([{_MFA, {_Var, _Fun}, _Records}|Left]) ->
- assert_format_of_scc(Left);
-assert_format_of_scc([]) ->
- ok.
-
solvers([]) -> [v2];
solvers(Solvers) -> Solvers.
@@ -207,12 +204,14 @@ solvers(Solvers) -> Solvers.
%%
%% ============================================================================
-traverse_scc([{_MFA, Def, Rec}|Left], DefSet, AccState) ->
+traverse_scc([{M,_,_}=MFA|Left], Codeserver, DefSet, ModRecs, AccState) ->
+ Def = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
+ {M, Rec} = lists:keyfind(M, 1, ModRecs),
TmpState1 = state__set_rec_dict(AccState, Rec),
DummyLetrec = cerl:c_letrec([Def], cerl:c_atom(foo)),
{NewAccState, _} = traverse(DummyLetrec, DefSet, TmpState1),
- traverse_scc(Left, DefSet, NewAccState);
-traverse_scc([], _DefSet, AccState) ->
+ traverse_scc(Left, Codeserver, DefSet, ModRecs, NewAccState);
+traverse_scc([], _Codeserver, _DefSet, _ModRecs, AccState) ->
AccState.
traverse(Tree, DefinedVars, State) ->
@@ -2702,11 +2701,14 @@ pp_map(_S, _Map) ->
%%
%% ============================================================================
-new_state(SCC0, NextLabel, CallGraph, Plt, PropTypes, Solvers) ->
- List = [{MFA, Var} || {MFA, {Var, _Fun}, _Rec} <- SCC0],
+new_state(MFAs, NextLabel, CallGraph, CServer, Plt, PropTypes, Solvers) ->
+ List_SCC =
+ [begin
+ {Var, Label} = dialyzer_codeserver:lookup_mfa_var_label(MFA, CServer),
+ {{MFA, Var}, t_var(Label)}
+ end || MFA <- MFAs],
+ {List, SCC} = lists:unzip(List_SCC),
NameMap = maps:from_list(List),
- MFAs = [MFA || {MFA, _Var} <- List],
- SCC = [mk_var(Fun) || {_MFA, {_Var, Fun}, _Rec} <- SCC0],
SelfRec =
case SCC of
[OneF] ->
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 1f2d3e3aaa..e71a953279 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -202,7 +202,7 @@ get_core_from_abstract_code(AbstrCode, Opts) ->
get_record_and_type_info(AbstractCode) ->
Module = get_module(AbstractCode),
- get_record_and_type_info(AbstractCode, Module, dict:new()).
+ get_record_and_type_info(AbstractCode, Module, maps:new()).
-spec get_record_and_type_info(abstract_code(), module(), type_table()) ->
{'ok', type_table()} | {'error', string()}.
@@ -215,7 +215,7 @@ get_record_and_type_info([{attribute, A, record, {Name, Fields0}}|Left],
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
FN = {File, erl_anno:line(A)},
- NewRecDict = dict:store({record, Name}, {FN, [{Arity,Fields}]}, RecDict),
+ NewRecDict = maps:put({record, Name}, {FN, [{Arity,Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
get_record_and_type_info([{attribute, A, type, {{record, Name}, Fields0, []}}
|Left], Module, RecDict, File) ->
@@ -223,7 +223,7 @@ get_record_and_type_info([{attribute, A, type, {{record, Name}, Fields0, []}}
{ok, Fields} = get_record_fields(Fields0, RecDict),
Arity = length(Fields),
FN = {File, erl_anno:line(A)},
- NewRecDict = dict:store({record, Name}, {FN, [{Arity, Fields}]}, RecDict),
+ NewRecDict = maps:put({record, Name}, {FN, [{Arity, Fields}]}, RecDict),
get_record_and_type_info(Left, Module, NewRecDict, File);
get_record_and_type_info([{attribute, A, Attr, {Name, TypeForm}}|Left],
Module, RecDict, File)
@@ -263,9 +263,9 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, FN,
false ->
try erl_types:t_var_names(ArgForms) of
ArgNames ->
- dict:store({TypeOrOpaque, Name, Arity},
- {{Module, FN, TypeForm, ArgNames},
- erl_types:t_any()}, RecDict)
+ maps:put({TypeOrOpaque, Name, Arity},
+ {{Module, FN, TypeForm, ArgNames},
+ erl_types:t_any()}, RecDict)
catch
_:_ ->
throw({error, flat_format("Type declaration for ~w does not "
@@ -296,19 +296,18 @@ get_record_fields([{record_field, _Line, Name, _Init}|Left], RecDict, Acc) ->
get_record_fields([], _RecDict, Acc) ->
lists:reverse(Acc).
--spec process_record_remote_types(codeserver()) -> codeserver().
+-spec process_record_remote_types(codeserver()) ->
+ {codeserver(), mod_records()}.
%% The field types are cached. Used during analysis when handling records.
process_record_remote_types(CServer) ->
TempRecords = dialyzer_codeserver:get_temp_records(CServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CServer),
- Cache = erl_types:cache__new(),
- {TempRecords1, Cache1} =
- process_opaque_types0(TempRecords, ExpTypes, Cache),
+ TempRecords1 = process_opaque_types0(TempRecords, ExpTypes),
%% A cache (not the field type cache) is used for speeding things up a bit.
VarTable = erl_types:var_table__new(),
ModuleFun =
- fun({Module, Record}, C0) ->
+ fun({Module, Record}) ->
RecordFun =
fun({Key, Value}, C2) ->
case Key of
@@ -334,24 +333,27 @@ process_record_remote_types(CServer) ->
_Other -> {{Key, Value}, C2}
end
end,
- {RecordList, C1} =
- lists:mapfoldl(RecordFun, C0, dict:to_list(Record)),
- {{Module, dict:from_list(RecordList)}, C1}
+ Cache = erl_types:cache__new(),
+ {RecordList, _NewCache} =
+ lists:mapfoldl(RecordFun, Cache, maps:to_list(Record)),
+ {Module, maps:from_list(RecordList)}
end,
- {NewRecordsList, C1} =
- lists:mapfoldl(ModuleFun, Cache1, dict:to_list(TempRecords1)),
+ NewRecordsList = lists:map(ModuleFun, dict:to_list(TempRecords1)),
NewRecords = dict:from_list(NewRecordsList),
- _C8 = check_record_fields(NewRecords, ExpTypes, C1),
- dialyzer_codeserver:finalize_records(NewRecords, CServer).
+ check_record_fields(NewRecords, ExpTypes),
+ {dialyzer_codeserver:finalize_records(NewRecords, CServer), NewRecords}.
%% erl_types:t_from_form() substitutes the declaration of opaque types
%% for the expanded type in some cases. To make sure the initial type,
%% any(), is not used, the expansion is done twice.
%% XXX: Recursive opaque types are not handled well.
-process_opaque_types0(TempRecords0, TempExpTypes, Cache) ->
- {TempRecords1, NewCache} =
+process_opaque_types0(TempRecords0, TempExpTypes) ->
+ Cache = erl_types:cache__new(),
+ {TempRecords1, Cache1} =
process_opaque_types(TempRecords0, TempExpTypes, Cache),
- process_opaque_types(TempRecords1, TempExpTypes, NewCache).
+ {TempRecords, _NewCache} =
+ process_opaque_types(TempRecords1, TempExpTypes, Cache1),
+ TempRecords.
process_opaque_types(TempRecords, TempExpTypes, Cache) ->
VarTable = erl_types:var_table__new(),
@@ -371,8 +373,8 @@ process_opaque_types(TempRecords, TempExpTypes, Cache) ->
end
end,
{RecordList, C1} =
- lists:mapfoldl(RecordFun, C0, dict:to_list(Record)),
- {{Module, dict:from_list(RecordList)}, C1}
+ lists:mapfoldl(RecordFun, C0, maps:to_list(Record)),
+ {{Module, maps:from_list(RecordList)}, C1}
%% dict:map(RecordFun, Record)
end,
{TempRecordList, NewCache} =
@@ -380,7 +382,8 @@ process_opaque_types(TempRecords, TempExpTypes, Cache) ->
{dict:from_list(TempRecordList), NewCache}.
%% dict:map(ModuleFun, TempRecords).
-check_record_fields(Records, TempExpTypes, Cache) ->
+check_record_fields(Records, TempExpTypes) ->
+ Cache = erl_types:cache__new(),
VarTable = erl_types:var_table__new(),
CheckFun =
fun({Module, Element}, C0) ->
@@ -410,9 +413,10 @@ check_record_fields(Records, TempExpTypes, Cache) ->
msg_with_position(Fun, FileLine)
end
end,
- lists:foldl(ElemFun, C0, dict:to_list(Element))
+ lists:foldl(ElemFun, C0, maps:to_list(Element))
end,
- lists:foldl(CheckFun, Cache, dict:to_list(Records)).
+ _NewCache = lists:foldl(CheckFun, Cache, dict:to_list(Records)),
+ ok.
msg_with_position(Fun, FileLine) ->
try Fun()
@@ -435,17 +439,17 @@ merge_records(NewRecords, OldRecords) ->
%%
%% ============================================================================
--type spec_dict() :: dict:dict().
--type callback_dict() :: dict:dict().
+-type spec_map() :: dialyzer_codeserver:contracts().
+-type callback_map() :: dialyzer_codeserver:contracts().
-spec get_spec_info(module(), abstract_code(), type_table()) ->
- {'ok', spec_dict(), callback_dict()} | {'error', string()}.
+ {'ok', spec_map(), callback_map()} | {'error', string()}.
-get_spec_info(ModName, AbstractCode, RecordsDict) ->
+get_spec_info(ModName, AbstractCode, RecordsMap) ->
OptionalCallbacks0 = get_optional_callbacks(AbstractCode, ModName),
OptionalCallbacks = gb_sets:from_list(OptionalCallbacks0),
- get_spec_info(AbstractCode, dict:new(), dict:new(),
- RecordsDict, ModName, OptionalCallbacks, "nofile").
+ get_spec_info(AbstractCode, maps:new(), maps:new(),
+ RecordsMap, ModName, OptionalCallbacks, "nofile").
get_optional_callbacks(Abs, ModName) ->
[{ModName, F, A} || {F, A} <- get_optional_callbacks(Abs)].
@@ -463,7 +467,7 @@ get_optional_callbacks(Abs) ->
%% are erl_types:erl_type()
get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
- SpecDict, CallbackDict, RecordsDict, ModName, OptCb, File)
+ SpecMap, CallbackMap, RecordsMap, ModName, OptCb, File)
when ((Contract =:= 'spec') or (Contract =:= 'callback')),
is_list(TypeSpec) ->
Ln = erl_anno:line(Anno),
@@ -472,24 +476,24 @@ get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
{F, A} -> {ModName, F, A}
end,
Xtra = [optional_callback || gb_sets:is_member(MFA, OptCb)],
- ActiveDict =
+ ActiveMap =
case Contract of
- spec -> SpecDict;
- callback -> CallbackDict
+ spec -> SpecMap;
+ callback -> CallbackMap
end,
- try dict:find(MFA, ActiveDict) of
+ try maps:find(MFA, ActiveMap) of
error ->
SpecData = {TypeSpec, Xtra},
- NewActiveDict =
+ NewActiveMap =
dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, SpecData,
- ActiveDict, RecordsDict),
- {NewSpecDict, NewCallbackDict} =
+ ActiveMap, RecordsMap),
+ {NewSpecMap, NewCallbackMap} =
case Contract of
- spec -> {NewActiveDict, CallbackDict};
- callback -> {SpecDict, NewActiveDict}
+ spec -> {NewActiveMap, CallbackMap};
+ callback -> {SpecMap, NewActiveMap}
end,
- get_spec_info(Left, NewSpecDict, NewCallbackDict,
- RecordsDict, ModName, OptCb, File);
+ get_spec_info(Left, NewSpecMap, NewCallbackMap,
+ RecordsMap, ModName, OptCb, File);
{ok, {{OtherFile, L}, _D}} ->
{Mod, Fun, Arity} = MFA,
Msg = flat_format(" Contract/callback for function ~w:~w/~w "
@@ -502,16 +506,16 @@ get_spec_info([{attribute, Anno, Contract, {Id, TypeSpec}}|Left],
[Ln, Error])}
end;
get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left],
- SpecDict, CallbackDict, RecordsDict, ModName, OptCb, _File) ->
- get_spec_info(Left, SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, IncludeFile);
-get_spec_info([_Other|Left], SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, File) ->
- get_spec_info(Left, SpecDict, CallbackDict,
- RecordsDict, ModName, OptCb, File);
-get_spec_info([], SpecDict, CallbackDict,
- _RecordsDict, _ModName, _OptCb, _File) ->
- {ok, SpecDict, CallbackDict}.
+ SpecMap, CallbackMap, RecordsMap, ModName, OptCb, _File) ->
+ get_spec_info(Left, SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, IncludeFile);
+get_spec_info([_Other|Left], SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, File) ->
+ get_spec_info(Left, SpecMap, CallbackMap,
+ RecordsMap, ModName, OptCb, File);
+get_spec_info([], SpecMap, CallbackMap,
+ _RecordsMap, _ModName, _OptCb, _File) ->
+ {ok, SpecMap, CallbackMap}.
-spec get_fun_meta_info(module(), abstract_code(), [dial_warn_tag()]) ->
dialyzer_codeserver:fun_meta_info() | {'error', string()}.
@@ -707,7 +711,7 @@ format_errors([]) ->
-spec format_sig(erl_types:erl_type()) -> string().
format_sig(Type) ->
- format_sig(Type, dict:new()).
+ format_sig(Type, maps:new()).
-spec format_sig(erl_types:erl_type(), type_table()) -> string().
@@ -959,9 +963,7 @@ label(Tree) ->
-spec parallelism() -> integer().
parallelism() ->
- CPUs = erlang:system_info(logical_processors_available),
- Schedulers = erlang:system_info(schedulers),
- min(CPUs, Schedulers).
+ erlang:system_info(schedulers_online).
-spec family([{K,V}]) -> [{K,[V]}].
diff --git a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2 b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
index f6fb98a863..46e2e8d36c 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
+++ b/lib/dialyzer/test/map_SUITE_data/results/map_in_guard2
@@ -2,11 +2,11 @@
map_in_guard2.erl:10: The call map_in_guard2:assoc_guard_clause('not_a_map') will never return since it differs in the 1st argument from the success typing arguments: (map())
map_in_guard2.erl:12: The pattern 'true' can never match the type 'false'
map_in_guard2.erl:14: The call map_in_guard2:exact_guard_clause(#{}) will never return since it differs in the 1st argument from the success typing arguments: (#{'a':=_, _=>_})
-map_in_guard2.erl:17: Clause guard cannot succeed. The variable M was matched against the type 'not_a_map'
+map_in_guard2.erl:17: Guard test is_map(M::'not_a_map') can never succeed
map_in_guard2.erl:20: Function assoc_update/1 has no local return
map_in_guard2.erl:20: Guard test is_map(M::'not_a_map') can never succeed
-map_in_guard2.erl:22: Clause guard cannot succeed. The variable M was matched against the type 'not_a_map'
map_in_guard2.erl:22: Function assoc_guard_clause/1 has no local return
+map_in_guard2.erl:22: Guard test is_map(M::'not_a_map') can never succeed
map_in_guard2.erl:24: Clause guard cannot succeed. The variable M was matched against the type #{}
map_in_guard2.erl:27: Clause guard cannot succeed. The variable M was matched against the type #{}
map_in_guard2.erl:27: Function exact_guard_clause/1 has no local return
diff --git a/lib/dialyzer/test/map_SUITE_data/results/opaque_key b/lib/dialyzer/test/map_SUITE_data/results/opaque_key
index fb7080cdc5..2ae0e0c5c6 100644
--- a/lib/dialyzer/test/map_SUITE_data/results/opaque_key
+++ b/lib/dialyzer/test/map_SUITE_data/results/opaque_key
@@ -6,10 +6,10 @@ opaque_key_adt.erl:59: Invalid type specification for function opaque_key_adt:sm
opaque_key_use.erl:13: The test opaque_key_use:t() =:= opaque_key_use:t(integer()) can never evaluate to 'true'
opaque_key_use.erl:24: Attempt to test for equality between a term of type opaque_key_adt:t(integer()) and a term of opaque type opaque_key_adt:t()
opaque_key_use.erl:37: Function adt_mm1/0 has no local return
-opaque_key_use.erl:40: The attempt to match a term of type opaque_key_adt:m() against the pattern #{A:=R} breaks the opaqueness of the term
+opaque_key_use.erl:40: The attempt to match a term of type opaque_key_adt:m() against the pattern #{A:=R} breaks the opacity of the term
opaque_key_use.erl:48: Function adt_mu1/0 has no local return
-opaque_key_use.erl:51: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:51: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
opaque_key_use.erl:53: Function adt_mu2/0 has no local return
-opaque_key_use.erl:56: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:56: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
opaque_key_use.erl:58: Function adt_mu3/0 has no local return
-opaque_key_use.erl:60: Guard test is_map(M::opaque_key_adt:m()) breaks the opaqueness of its argument
+opaque_key_use.erl:60: Guard test is_map(M::opaque_key_adt:m()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/array b/lib/dialyzer/test/opaque_SUITE_data/results/array
index 9921b61669..6f1aa1ce3d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/array
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/array
@@ -1,3 +1,3 @@
-array_use.erl:12: The type test is_tuple(array:array(_)) breaks the opaqueness of the term array:array(_)
-array_use.erl:9: The attempt to match a term of type array:array(_) against the pattern {'array', _, _, 'undefined', _} breaks the opaqueness of the term
+array_use.erl:12: The type test is_tuple(array:array(_)) breaks the opacity of the term array:array(_)
+array_use.erl:9: The attempt to match a term of type array:array(_) against the pattern {'array', _, _, 'undefined', _} breaks the opacity of the term
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/dict b/lib/dialyzer/test/opaque_SUITE_data/results/dict
index 42f6663191..3f8242c72d 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/dict
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/dict
@@ -1,15 +1,15 @@
-dict_use.erl:41: The attempt to match a term of type dict:dict(_,_) against the pattern 'gazonk' breaks the opaqueness of the term
-dict_use.erl:45: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opaqueness of the term
-dict_use.erl:46: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opaqueness of the term
-dict_use.erl:51: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opaqueness of the term
-dict_use.erl:52: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opaqueness of the term
+dict_use.erl:41: The attempt to match a term of type dict:dict(_,_) against the pattern 'gazonk' breaks the opacity of the term
+dict_use.erl:45: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opacity of the term
+dict_use.erl:46: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opacity of the term
+dict_use.erl:51: The attempt to match a term of type dict:dict(_,_) against the pattern [] breaks the opacity of the term
+dict_use.erl:52: The attempt to match a term of type dict:dict(_,_) against the pattern 42 breaks the opacity of the term
dict_use.erl:58: Attempt to test for equality between a term of type maybe_improper_list() and a term of opaque type dict:dict(_,_)
dict_use.erl:60: Attempt to test for inequality between a term of type atom() and a term of opaque type dict:dict(_,_)
-dict_use.erl:64: Guard test length(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:65: Guard test is_atom(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:66: Guard test is_list(D::dict:dict(_,_)) breaks the opaqueness of its argument
-dict_use.erl:70: The type test is_list(dict:dict(_,_)) breaks the opaqueness of the term dict:dict(_,_)
+dict_use.erl:64: Guard test length(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:65: Guard test is_atom(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:66: Guard test is_list(D::dict:dict(_,_)) breaks the opacity of its argument
+dict_use.erl:70: The type test is_list(dict:dict(_,_)) breaks the opacity of the term dict:dict(_,_)
dict_use.erl:73: The call dict:fetch('foo',[1 | 2 | 3,...]) does not have an opaque term of type dict:dict(_,_) as 2nd argument
dict_use.erl:76: The call dict:merge(Fun::any(),42,[1 | 2,...]) does not have opaque terms as 2nd and 3rd arguments
dict_use.erl:79: The call dict:store(42,'elli',{'dict',0,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}) does not have an opaque term of type dict:dict(_,_) as 3rd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/ets b/lib/dialyzer/test/opaque_SUITE_data/results/ets
index e11c7a8352..5dde23fb15 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/ets
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/ets
@@ -1,4 +1,4 @@
-ets_use.erl:12: Guard test is_integer(T::atom() | ets:tid()) breaks the opaqueness of its argument
-ets_use.erl:20: The type test is_integer(atom() | ets:tid()) breaks the opaqueness of the term atom() | ets:tid()
-ets_use.erl:7: Guard test is_integer(T::ets:tid()) breaks the opaqueness of its argument
+ets_use.erl:12: Guard test is_integer(T::atom() | ets:tid()) breaks the opacity of its argument
+ets_use.erl:20: The type test is_integer(atom() | ets:tid()) breaks the opacity of the term atom() | ets:tid()
+ets_use.erl:7: Guard test is_integer(T::ets:tid()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/my_queue b/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
index 1f25a6f9c3..67999b0e20 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/my_queue
@@ -1,7 +1,7 @@
my_queue_use.erl:15: The call my_queue_adt:is_empty([]) does not have an opaque term of type my_queue_adt:my_queue() as 1st argument
my_queue_use.erl:19: The call my_queue_adt:add(42,Q0::[]) does not have an opaque term of type my_queue_adt:my_queue() as 2nd argument
-my_queue_use.erl:24: The attempt to match a term of type my_queue_adt:my_queue() against the pattern [42 | Q2] breaks the opaqueness of the term
+my_queue_use.erl:24: The attempt to match a term of type my_queue_adt:my_queue() against the pattern [42 | Q2] breaks the opacity of the term
my_queue_use.erl:30: Attempt to test for equality between a term of type [] and a term of opaque type my_queue_adt:my_queue()
my_queue_use.erl:34: Cons will produce an improper list since its 2nd argument is my_queue_adt:my_queue()
my_queue_use.erl:34: The call my_queue_adt:dequeue(nonempty_maybe_improper_list(42,my_queue_adt:my_queue())) does not have an opaque term of type my_queue_adt:my_queue() as 1st argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/opaque b/lib/dialyzer/test/opaque_SUITE_data/results/opaque
index 5747f9061f..864e0d853c 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/opaque
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/opaque
@@ -1,3 +1,3 @@
opaque_bug3.erl:19: The pattern 'a' can never match the type #c{}
-opaque_bug4.erl:20: The attempt to match a term of type opaque_adt:abc() against the pattern 'a' breaks the opaqueness of the term
+opaque_bug4.erl:20: The attempt to match a term of type opaque_adt:abc() against the pattern 'a' breaks the opacity of the term
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/para b/lib/dialyzer/test/opaque_SUITE_data/results/para
index b23d0cae3a..37b5b7b44e 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/para
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/para
@@ -16,9 +16,9 @@ para2.erl:88: The test para2:circ(integer()) =:= para2:circ(integer(),integer())
para3.erl:28: Invalid type specification for function para3:ot2/0. The success typing is () -> 'foo'
para3.erl:36: The pattern {{{17}}} can never match the type {{{{{{_,_,_,_,_}}}}}}
para3.erl:55: Invalid type specification for function para3:t2/0. The success typing is () -> 'foo'
-para3.erl:65: The attempt to match a term of type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} against the pattern {{{{{17}}}}} breaks the opaqueness of para3_adt:ot1(_,_,_,_,_)
+para3.erl:65: The attempt to match a term of type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}} against the pattern {{{{{17}}}}} breaks the opacity of para3_adt:ot1(_,_,_,_,_)
para3.erl:68: The pattern {{{{17}}}} can never match the type {{{{{para3_adt:ot1(_,_,_,_,_)}}}}}
-para3.erl:74: Invalid type specification for function para3:exp_adt/0. The success typing is () -> 3
+para3.erl:74: The specification for para3:exp_adt/0 has an opaque subtype para3_adt:exp1(para3_adt:exp2()) which is violated by the success typing () -> 3
para4.erl:21: Invalid type specification for function para4:a/1. The success typing is (para4:d_all() | para4:d_atom()) -> [{atom() | integer(),atom() | integer()}]
para4.erl:26: Invalid type specification for function para4:i/1. The success typing is (para4:d_all() | para4:d_integer()) -> [{atom() | integer(),atom() | integer()}]
para4.erl:31: Invalid type specification for function para4:t/1. The success typing is (para4:d_all() | para4:d_tuple()) -> [{atom() | integer(),atom() | integer()}]
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/queue b/lib/dialyzer/test/opaque_SUITE_data/results/queue
index 5b3813c418..9822b7168f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/queue
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/queue
@@ -1,11 +1,11 @@
queue_use.erl:18: The call queue:is_empty({[],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:22: The call queue:in(42,Q0::{[],[]}) does not have an opaque term of type queue:queue(_) as 2nd argument
-queue_use.erl:27: The attempt to match a term of type queue:queue(_) against the pattern {"*", Q2} breaks the opaqueness of the term
+queue_use.erl:27: The attempt to match a term of type queue:queue(_) against the pattern {"*", Q2} breaks the opacity of the term
queue_use.erl:33: Attempt to test for equality between a term of type {[42,...],[]} and a term of opaque type queue:queue(_)
-queue_use.erl:36: The attempt to match a term of type queue:queue(_) against the pattern {F, _R} breaks the opaqueness of the term
+queue_use.erl:36: The attempt to match a term of type queue:queue(_) against the pattern {F, _R} breaks the opacity of the term
queue_use.erl:40: The call queue:out({[42,...],[]}) does not have an opaque term of type queue:queue(_) as 1st argument
queue_use.erl:51: The call queue_use:is_in_queue(E::42,DB::#db{p::[],q::queue:queue(_)}) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue:queue(_)} against the pattern {'db', _, {L1, L2}} breaks the opaqueness of queue:queue(_)
+queue_use.erl:56: The attempt to match a term of type #db{p::[],q::queue:queue(_)} against the pattern {'db', _, {L1, L2}} breaks the opacity of queue:queue(_)
queue_use.erl:62: The call queue_use:tuple_queue({42,'gazonk'}) does not have a term of type {_,queue:queue(_)} (with opaque subterms) as 1st argument
queue_use.erl:65: The call queue:in(F::42,Q::'gazonk') does not have an opaque term of type queue:queue(_) as 2nd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/rec b/lib/dialyzer/test/opaque_SUITE_data/results/rec
index 72736b3b3c..e9b217a93f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/rec
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/rec
@@ -1,6 +1,6 @@
-rec_use.erl:17: The attempt to match a term of type rec_adt:rec() against the pattern {'rec', _, 42} breaks the opaqueness of the term
-rec_use.erl:18: Guard test tuple_size(R::rec_adt:rec()) breaks the opaqueness of its argument
+rec_use.erl:17: The attempt to match a term of type rec_adt:rec() against the pattern {'rec', _, 42} breaks the opacity of the term
+rec_use.erl:18: Guard test tuple_size(R::rec_adt:rec()) breaks the opacity of its argument
rec_use.erl:23: The call rec_adt:get_a(R::tuple()) does not have an opaque term of type rec_adt:rec() as 1st argument
rec_use.erl:27: Attempt to test for equality between a term of type {'rec','gazonk',42} and a term of opaque type rec_adt:rec()
rec_use.erl:30: The call erlang:tuple_size(rec_adt:rec()) contains an opaque term as 1st argument when a structured term of type tuple() is expected
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/simple b/lib/dialyzer/test/opaque_SUITE_data/results/simple
index 391c37664e..5cd8916aee 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/simple
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/simple
@@ -1,29 +1,29 @@
exact_api.erl:17: The call exact_api:set_type(A::#digraph{vtab::'notable',etab::'notable',ntab::'notable',cyclic::'true'}) does not have an opaque term of type digraph:graph() as 1st argument
exact_api.erl:23: The call digraph:delete(G::#digraph{vtab::'notable',etab::'notable',ntab::'notable',cyclic::'true'}) does not have an opaque term of type digraph:graph() as 1st argument
-exact_api.erl:55: The attempt to match a term of type exact_adt:exact_adt() against the pattern {'exact_adt'} breaks the opaqueness of the term
+exact_api.erl:55: The attempt to match a term of type exact_adt:exact_adt() against the pattern {'exact_adt'} breaks the opacity of the term
exact_api.erl:59: The call exact_adt:exact_adt_set_type2(A::#exact_adt{}) does not have an opaque term of type exact_adt:exact_adt() as 1st argument
is_rec.erl:10: The call erlang:is_record(simple1_adt:d1(),'r',2) contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:15: The call erlang:is_record(A::simple1_adt:d1(),'r',I::1 | 2 | 3) contains an opaque term as 1st argument when terms of different types are expected in these positions
-is_rec.erl:19: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opaqueness of its argument
-is_rec.erl:23: Guard test is_record({simple1_adt:d1(),1},'r',2) breaks the opaqueness of its argument
+is_rec.erl:19: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opacity of its argument
+is_rec.erl:23: Guard test is_record({simple1_adt:d1(),1},'r',2) breaks the opacity of its argument
is_rec.erl:41: The call erlang:is_record(A::simple1_adt:d1(),R::'a') contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:45: The call erlang:is_record(A::simple1_adt:d1(),A::simple1_adt:d1(),1) contains an opaque term as 2nd argument when terms of different types are expected in these positions
is_rec.erl:49: The call erlang:is_record(A::simple1_adt:d1(),any(),1) contains an opaque term as 1st argument when terms of different types are expected in these positions
is_rec.erl:53: The call erlang:is_record(A::simple1_adt:d1(),A::simple1_adt:d1(),any()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-is_rec.erl:57: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opaqueness of its argument
+is_rec.erl:57: Guard test is_record(A::simple1_adt:d1(),'r',2) breaks the opacity of its argument
is_rec.erl:61: The record #r{f1::simple1_adt:d1()} violates the declared type for #r{}
is_rec.erl:65: The call erlang:is_record({simple1_adt:d1(),1},'r',2) contains an opaque term as 1st argument when terms of different types are expected in these positions
rec_api.erl:104: Matching of pattern {'r2', 10} tagged with a record name violates the declared type of #r2{f1::10}
-rec_api.erl:113: The attempt to match a term of type #r3{f1::queue:queue(_)} against the pattern {'r3', 'a'} breaks the opaqueness of queue:queue(_)
+rec_api.erl:113: The attempt to match a term of type #r3{f1::queue:queue(_)} against the pattern {'r3', 'a'} breaks the opacity of queue:queue(_)
rec_api.erl:118: Record construction #r3{f1::10} violates the declared type of field f1::queue:queue(_)
-rec_api.erl:123: The attempt to match a term of type #r3{f1::10} against the pattern {'r3', 10} breaks the opaqueness of queue:queue(_)
+rec_api.erl:123: The attempt to match a term of type #r3{f1::10} against the pattern {'r3', 10} breaks the opacity of queue:queue(_)
rec_api.erl:24: Record construction #r1{f1::10} violates the declared type of field f1::rec_api:a()
rec_api.erl:29: Matching of pattern {'r1', 10} tagged with a record name violates the declared type of #r1{f1::10}
-rec_api.erl:33: The attempt to match a term of type rec_adt:r1() against the pattern {'r1', 'a'} breaks the opaqueness of the term
+rec_api.erl:33: The attempt to match a term of type rec_adt:r1() against the pattern {'r1', 'a'} breaks the opacity of the term
rec_api.erl:35: Invalid type specification for function rec_api:adt_t1/1. The success typing is (#r1{f1::'a'}) -> #r1{f1::'a'}
-rec_api.erl:40: Invalid type specification for function rec_api:adt_r1/0. The success typing is () -> #r1{f1::'a'}
-rec_api.erl:85: The attempt to match a term of type rec_api:f() against the variable _ breaks the opaqueness of rec_adt:f()
+rec_api.erl:40: The specification for rec_api:adt_r1/0 has an opaque subtype rec_adt:r1() which is violated by the success typing () -> #r1{f1::'a'}
+rec_api.erl:85: The attempt to match a term of type rec_adt:f() against the record field 'f' declared to be of type rec_api:f() breaks the opacity of the term
rec_api.erl:99: Record construction #r2{f1::10} violates the declared type of field f1::rec_api:a()
simple1_api.erl:113: The test simple1_api:d1() =:= simple1_api:d2() can never evaluate to 'true'
simple1_api.erl:118: Guard test simple1_api:d2() =:= A::simple1_api:d1() can never succeed
@@ -35,20 +35,20 @@ simple1_api.erl:165: Attempt to test for equality between a term of type simple1
simple1_api.erl:181: Guard test A::simple1_adt:d1() =< B::simple1_adt:d2() contains opaque terms as 1st and 2nd arguments
simple1_api.erl:185: Guard test 'a' =< B::simple1_adt:d2() contains an opaque term as 2nd argument
simple1_api.erl:189: Guard test A::simple1_adt:d1() =< 'd' contains an opaque term as 1st argument
-simple1_api.erl:197: The type test is_integer(A::simple1_adt:d1()) breaks the opaqueness of the term A::simple1_adt:d1()
+simple1_api.erl:197: The type test is_integer(A::simple1_adt:d1()) breaks the opacity of the term A::simple1_adt:d1()
simple1_api.erl:221: Guard test A::simple1_api:i1() > 3 can never succeed
simple1_api.erl:225: Guard test A::simple1_adt:i1() > 3 contains an opaque term as 1st argument
simple1_api.erl:233: Guard test A::simple1_adt:i1() < 3 contains an opaque term as 1st argument
simple1_api.erl:239: Guard test A::1 > 3 can never succeed
simple1_api.erl:243: Guard test A::1 > 3 can never succeed
simple1_api.erl:257: Guard test is_function(T::simple1_api:o1()) can never succeed
-simple1_api.erl:265: Guard test is_function(T::simple1_adt:o1()) breaks the opaqueness of its argument
-simple1_api.erl:269: The type test is_function(T::simple1_adt:o1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:265: Guard test is_function(T::simple1_adt:o1()) breaks the opacity of its argument
+simple1_api.erl:269: The type test is_function(T::simple1_adt:o1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:274: Guard test is_function(T::simple1_api:o1(),A::simple1_api:i1()) can never succeed
-simple1_api.erl:284: Guard test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opaqueness of its argument
-simple1_api.erl:289: The type test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:284: Guard test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opacity of its argument
+simple1_api.erl:289: The type test is_function(T::simple1_adt:o1(),A::simple1_adt:i1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:294: The call erlang:is_function(T::simple1_api:o1(),A::simple1_adt:i1()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
-simple1_api.erl:300: The type test is_function(T::simple1_adt:o1(),A::simple1_api:i1()) breaks the opaqueness of the term T::simple1_adt:o1()
+simple1_api.erl:300: The type test is_function(T::simple1_adt:o1(),A::simple1_api:i1()) breaks the opacity of the term T::simple1_adt:o1()
simple1_api.erl:306: Guard test B::simple1_api:b2() =:= 'true' can never succeed
simple1_api.erl:315: Guard test A::simple1_api:b1() =:= 'false' can never succeed
simple1_api.erl:319: Guard test not('and'('true','true')) can never succeed
@@ -60,14 +60,14 @@ simple1_api.erl:365: Clause guard cannot succeed.
simple1_api.erl:368: Invalid type specification for function simple1_api:bool_adt_t8/2. The success typing is (boolean(),boolean()) -> 1
simple1_api.erl:378: Clause guard cannot succeed.
simple1_api.erl:381: Invalid type specification for function simple1_api:bool_adt_t9/2. The success typing is ('false','false') -> 1
-simple1_api.erl:407: The size simple1_adt:i1() breaks the opaqueness of A
-simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opaqueness of simple1_adt:i1()
-simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opaqueness of simple1_adt:i1()
+simple1_api.erl:407: The size simple1_adt:i1() breaks the opacity of A
+simple1_api.erl:418: The attempt to match a term of type non_neg_integer() against the variable A breaks the opacity of simple1_adt:i1()
+simple1_api.erl:425: The attempt to match a term of type non_neg_integer() against the variable B breaks the opacity of simple1_adt:i1()
simple1_api.erl:432: The pattern <<_:B/integer-unit:1>> can never match the type any()
-simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opaqueness of simple1_adt:i1()
-simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opaqueness of the term
-simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opaqueness of the term A :: simple1_adt:a()
-simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opaqueness of the term A :: simple1_adt:a()
+simple1_api.erl:448: The attempt to match a term of type non_neg_integer() against the variable Sz breaks the opacity of simple1_adt:i1()
+simple1_api.erl:460: The attempt to match a term of type simple1_adt:bit1() against the pattern <<_/binary-unit:8>> breaks the opacity of the term
+simple1_api.erl:478: The call 'foo':A(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
+simple1_api.erl:486: The call A:'foo'(A::simple1_adt:a()) breaks the opacity of the term A :: simple1_adt:a()
simple1_api.erl:499: The call 'foo':A(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
simple1_api.erl:503: The call 'foo':A(A::simple1_adt:i()) requires that A is of type atom() not simple1_adt:i()
simple1_api.erl:507: The call A:'foo'(A::simple1_api:i()) requires that A is of type atom() not simple1_api:i()
@@ -79,7 +79,7 @@ simple1_api.erl:538: Guard test A::simple1_adt:d1() =:= 3 contains an opaque ter
simple1_api.erl:548: The call erlang:'<'(A::simple1_adt:d1(),3) contains an opaque term as 1st argument when terms of different types are expected in these positions
simple1_api.erl:558: The call erlang:'=<'(A::simple1_adt:d1(),B::simple1_adt:d2()) contains opaque terms as 1st and 2nd arguments when terms of different types are expected in these positions
simple1_api.erl:565: Guard test {digraph:graph(),3} > {digraph:graph(),atom() | ets:tid()} contains an opaque term as 2nd argument
-simple1_api.erl:91: Invalid type specification for function simple1_api:tup/0. The success typing is () -> {'a','b'}
+simple1_api.erl:91: The specification for simple1_api:tup/0 has an opaque subtype simple1_adt:tuple1() which is violated by the success typing () -> {'a','b'}
simple2_api.erl:100: The call lists:flatten(A::simple1_adt:tuple1()) contains an opaque term as 1st argument when a structured term of type [any()] is expected
simple2_api.erl:116: The call lists:flatten({simple1_adt:tuple1()}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
simple2_api.erl:121: Guard test {simple1_adt:d1(),3} > {simple1_adt:d1(),simple1_adt:tuple1()} contains an opaque term as 2nd argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/timer b/lib/dialyzer/test/opaque_SUITE_data/results/timer
index b1cfcd4e9f..46c5a86307 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/timer
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/timer
@@ -1,4 +1,4 @@
timer_use.erl:16: The pattern 'gazonk' can never match the type {'error',_} | {'ok',timer:tref()}
-timer_use.erl:17: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {'ok', 42} breaks the opaqueness of timer:tref()
-timer_use.erl:18: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {Tag, 'gazonk'} breaks the opaqueness of timer:tref()
+timer_use.erl:17: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {'ok', 42} breaks the opacity of timer:tref()
+timer_use.erl:18: The attempt to match a term of type {'error',_} | {'ok',timer:tref()} against the pattern {Tag, 'gazonk'} breaks the opacity of timer:tref()
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/union b/lib/dialyzer/test/opaque_SUITE_data/results/union
index 98829b424a..8763088bf0 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/union
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/union
@@ -1,5 +1,5 @@
-union_use.erl:12: The attempt to match a term of type union_adt:u() against the pattern 'aaa' breaks the opaqueness of the term
-union_use.erl:16: The type test is_tuple(union_adt:u()) breaks the opaqueness of the term union_adt:u()
-union_use.erl:7: Guard test is_atom(A::union_adt:u()) breaks the opaqueness of its argument
-union_use.erl:8: Guard test is_tuple(T::union_adt:u()) breaks the opaqueness of its argument
+union_use.erl:12: The attempt to match a term of type union_adt:u() against the pattern 'aaa' breaks the opacity of the term
+union_use.erl:16: The type test is_tuple(union_adt:u()) breaks the opacity of the term union_adt:u()
+union_use.erl:7: Guard test is_atom(A::union_adt:u()) breaks the opacity of its argument
+union_use.erl:8: Guard test is_tuple(T::union_adt:u()) breaks the opacity of its argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/wings b/lib/dialyzer/test/opaque_SUITE_data/results/wings
index 511263b70a..391501d86f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/wings
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/wings
@@ -1,11 +1,11 @@
-wings_dissolve.erl:103: Guard test is_list(List::gb_sets:set(_)) breaks the opaqueness of its argument
-wings_dissolve.erl:19: Guard test is_list(Faces::gb_sets:set(_)) breaks the opaqueness of its argument
-wings_dissolve.erl:272: Guard test is_list(Faces::gb_sets:set(_)) breaks the opaqueness of its argument
+wings_dissolve.erl:103: Guard test is_list(List::gb_sets:set(_)) breaks the opacity of its argument
+wings_dissolve.erl:19: Guard test is_list(Faces::gb_sets:set(_)) breaks the opacity of its argument
+wings_dissolve.erl:272: Guard test is_list(Faces::gb_sets:set(_)) breaks the opacity of its argument
wings_dissolve.erl:31: The call gb_sets:is_empty(Faces::[any(),...]) does not have an opaque term of type gb_sets:set(_) as 1st argument
wings_edge.erl:205: The pattern <Edge, 'hard', Htab> can never match the type <_,'soft',_>
wings_edge_cmd.erl:30: The call gb_trees:size(P::gb_sets:set(_)) does not have an opaque term of type gb_trees:tree(_,_) as 1st argument
wings_edge_cmd.erl:32: The pattern [_ | Parts] can never match the type []
wings_edge_cmd.erl:32: The pattern [{_, P} | _] can never match the type []
-wings_io.erl:30: The attempt to match a term of type {'empty',queue:queue(_)} against the pattern {'empty', {In, Out}} breaks the opaqueness of queue:queue(_)
+wings_io.erl:30: The attempt to match a term of type {'empty',queue:queue(_)} against the pattern {'empty', {In, Out}} breaks the opacity of queue:queue(_)
wings_we.erl:155: The call wings_util:gb_trees_largest_key(Etab::gb_trees:tree(_,_)) contains an opaque term as 1st argument when a structured term of type {_,{_,_,_,'nil' | {_,_,_,'nil' | {_,_,_,_}}}} is expected
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl b/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
index a4cec065ab..2527f166f2 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/dict/dict_use.erl
@@ -34,7 +34,7 @@ middle() ->
{w1(), w2()}.
%%---------------------------------------------------------------------
-%% Cases that are problematic w.r.t. opaqueness of types
+%% Cases that are problematic w.r.t. opacity of types
%%---------------------------------------------------------------------
w1() ->
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
index 102215b28d..d8c1f561f7 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/para/para3.erl
@@ -62,7 +62,7 @@ t2() ->
%% Shows that the list TypeNames in t_from_form must include ArgsLen.
t1_adt() ->
- {{{{{17}}}}} = para3_adt:t1(3). % breaks the opaqueness
+ {{{{{17}}}}} = para3_adt:t1(3). % breaks the opacity
t2_adt() ->
{{{{17}}}} = para3_adt:t1(3). % can never match
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl
index ea6a71217c..1139044ec9 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer.hrl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2006-2015. All Rights Reserved.
+%%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl
index bb43d1dcb8..637927c932 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/dialyzer_races.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl
index 7826dada9d..449bf4cbb6 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/recrec/erl_types.erl
@@ -4366,7 +4366,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
string:join(FieldDiffs, " and ").
field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
- %% Don't care about opaqueness for now.
+ %% Don't care about opacity for now.
NewAcc =
case not t_is_none(t_inf(F, DefType)) of
true -> Acc;
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
index c19330eb30..597460ce77 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/exact_api.erl
@@ -52,7 +52,7 @@ exact_api_set_type(#exact_api{}=E) -> E.
-record(exact_adt, {}).
exact_adt_test(X) ->
- #exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opaqueness
+ #exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opacity
exact_adt_new(A) ->
A = #exact_adt{},
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
index 2b157483bc..b906431b44 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/is_rec.erl
@@ -16,11 +16,11 @@ ri11() ->
ri13() ->
A = simple1_adt:d1(),
- if is_record(A, r) -> true end. % breaks the opaqueness
+ if is_record(A, r) -> true end. % breaks the opacity
ri14() ->
A = simple1_adt:d1(),
- if is_record({A, 1}, r) -> true end. % breaks the opaqueness
+ if is_record({A, 1}, r) -> true end. % breaks the opacity
-type '1-3-t'() :: 1..3.
@@ -54,7 +54,7 @@ ri5() ->
ri6() ->
A = simple1_adt:d1(),
- if is_record(A, r) -> true end. % breaks opaqueness
+ if is_record(A, r) -> true end. % breaks opacity
ri7() ->
A = simple1_adt:d1(),
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
index fb6d59d263..59b9e0fec4 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/rec_api.erl
@@ -30,7 +30,7 @@ t3() ->
adt_t1() ->
R = rec_adt:r1(),
- {r1, a} = R. % breaks the opaqueness
+ {r1, a} = R. % breaks the opacity
-spec adt_t1(rec_adt:r1()) -> rec_adt:r1(). % invalid type spec
@@ -82,7 +82,7 @@ f() ->
r_adt() ->
{{r, rec_adt:f(), 2},
- #r{f = rec_adt:f(), o = 2}}. % breaks the opaqueness
+ #r{f = rec_adt:f(), o = 2}}. % breaks the opacity
-record(r2, % like #r1{}, but with initial value
{f1 = a :: a()}).
@@ -110,7 +110,7 @@ u3() ->
v1() ->
A = #r3{f1 = queue:new()},
- {r3, a} = A. % breaks the opaqueness
+ {r3, a} = A. % breaks the opacity
v2() ->
A = {r3, 10},
@@ -120,4 +120,4 @@ v2() ->
v3() ->
A = {r3, 10},
- #r3{f1 = 10} = A. % breaks the opaqueness
+ #r3{f1 = 10} = A. % breaks the opacity
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl b/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
index 7db1100597..d67aa913d8 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/simple/simple1_api.erl
@@ -194,7 +194,7 @@ tt1() ->
tt2() ->
A = simple1_adt:d1(),
- is_integer(A). % breaks the opaqueness
+ is_integer(A). % breaks the opacity
%% Comparison with integers
@@ -262,11 +262,11 @@ f2() ->
adt_f1() ->
T = simple1_adt:n1(),
- if is_function(T) -> ok end. % breaks the opaqueness
+ if is_function(T) -> ok end. % breaks the opacity
adt_f2() ->
T = simple1_adt:n1(),
- is_function(T). % breaks the opaqueness
+ is_function(T). % breaks the opacity
f3() ->
A = i1(),
@@ -281,12 +281,12 @@ f4() ->
adt_f3() ->
A = simple1_adt:i1(),
T = simple1_adt:n1(),
- if is_function(T, A) -> ok end. % breaks the opaqueness
+ if is_function(T, A) -> ok end. % breaks the opacity
adt_f4() ->
A = simple1_adt:i1(),
T = simple1_adt:n1(),
- is_function(T, A). % breaks the opaqueness
+ is_function(T, A). % breaks the opacity
adt_f4_a() ->
A = simple1_adt:i1(),
@@ -297,7 +297,7 @@ adt_f4_a() ->
adt_f4_b() ->
A = i1(),
T = simple1_adt:n1(),
- is_function(T, A). % breaks the opaqueness
+ is_function(T, A). % breaks the opacity
%% A few Boolean examples
@@ -404,7 +404,7 @@ bit_t1() ->
bit_adt_t1() ->
A = simple1_adt:i1(),
- <<100:(A)>>. % breaks the opaqueness
+ <<100:(A)>>. % breaks the opacity
bit_t3(A) ->
B = i1(),
@@ -415,14 +415,14 @@ bit_t3(A) ->
bit_adt_t2() ->
A = simple1_adt:i1(),
case <<"hej">> of
- <<_:A>> -> ok % breaks the opaqueness (but the message is strange)
+ <<_:A>> -> ok % breaks the opacity (but the message is strange)
end.
bit_adt_t3(A) ->
B = simple1_adt:i1(),
case none:none() of
- <<A: % breaks the opaqueness (the message is less than perfect)
+ <<A: % breaks the opacity (the message is less than perfect)
B>> -> 1
end.
@@ -445,7 +445,7 @@ bit_t4(A) ->
bit_adt_t4(A) ->
Sz = simple1_adt:i1(),
case A of
- <<_:Sz>> -> 1 % breaks the opaqueness
+ <<_:Sz>> -> 1 % breaks the opacity
end.
bit_t5() ->
@@ -457,7 +457,7 @@ bit_t5() ->
bit_adt_t5() ->
A = simple1_adt:bit1(),
case A of
- <<_/binary>> -> 1 % breaks the opaqueness
+ <<_/binary>> -> 1 % breaks the opacity
end.
-opaque bit1() :: binary().
@@ -475,7 +475,7 @@ call_f(A) ->
call_f_adt(A) ->
A = simple1_adt:a(),
- foo:A(A). % breaks the opaqueness
+ foo:A(A). % breaks the opacity
call_m(A) ->
A = a(),
@@ -483,7 +483,7 @@ call_m(A) ->
call_m_adt(A) ->
A = simple1_adt:a(),
- A:foo(A). % breaks the opaqueness
+ A:foo(A). % breaks the opacity
-opaque a() :: atom().
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl b/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
index 9c8ea0af1c..ed6810634f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/timer/timer_use.erl
@@ -1,8 +1,8 @@
%%---------------------------------------------------------------------------
%% A test case with:
%% - a genuine matching error -- 1st branch
-%% - a violation of the opaqueness of timer:tref() -- 2nd branch
-%% - a subtle violation of the opaqueness of timer:tref() -- 3rd branch
+%% - a violation of the opacity of timer:tref() -- 2nd branch
+%% - a subtle violation of the opacity of timer:tref() -- 3rd branch
%% The test is supposed to check that these cases are treated properly.
%%---------------------------------------------------------------------------
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl b/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
index ca6bc0ab4a..6b825d85fe 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/wings/wings_util.erl
@@ -14,12 +14,12 @@
rel2fam(Rel) ->
sofs:to_external(sofs:relation_to_family(sofs:relation(Rel))).
-%% a definition that does not violate the opaqueness of gb_trees:tree()
+%% a definition that does not violate the opacity of gb_trees:tree()
gb_trees_smallest_key(Tree) ->
{Key, _V} = gb_trees:smallest(Tree),
Key.
-%% a definition that violates the opaqueness of gb_trees:tree()
+%% a definition that violates the opacity of gb_trees:tree()
gb_trees_largest_key({_, Tree}) ->
largest_key1(Tree).
diff --git a/lib/dialyzer/test/small_SUITE_data/results/chars b/lib/dialyzer/test/small_SUITE_data/results/chars
new file mode 100644
index 0000000000..2c1f8f8d17
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/chars
@@ -0,0 +1,4 @@
+
+chars.erl:29: Invalid type specification for function chars:f/1. The success typing is (#{'b':=50}) -> 'ok'
+chars.erl:32: Function t1/0 has no local return
+chars.erl:32: The call chars:f(#{'b':=50}) breaks the contract (#{'a':=49,'b'=>50,'c'=>51}) -> 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/guards b/lib/dialyzer/test/small_SUITE_data/results/guards
index 824a7cfa24..cd0d3cace0 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/guards
+++ b/lib/dialyzer/test/small_SUITE_data/results/guards
@@ -10,8 +10,8 @@ guards.erl:136: The call guards:t16('a') will never return since it differs in t
guards.erl:136: The call guards:t16('c') will never return since it differs in the 1st argument from the success typing arguments: ('b')
guards.erl:55: Function t5/1 has no local return
guards.erl:55: Guard test is_integer(A::atom()) can never succeed
-guards.erl:59: Clause guard cannot succeed. The variable A was matched against the type any()
guards.erl:59: Function t6/1 has no local return
+guards.erl:59: Guard test is_integer(A::atom()) can never succeed
guards.erl:67: The call guards:t7({42}) will never return since it differs in the 1st argument from the success typing arguments: (atom() | integer())
guards.erl:75: The call guards:t8({42}) will never return since it differs in the 1st argument from the success typing arguments: (atom() | integer())
guards.erl:92: The variable _ can never match since previous clauses completely covered the type {'true','true'}
diff --git a/lib/dialyzer/test/small_SUITE_data/src/anno.erl b/lib/dialyzer/test/small_SUITE_data/src/anno.erl
new file mode 100644
index 0000000000..70f1d42141
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/anno.erl
@@ -0,0 +1,18 @@
+-module(anno).
+
+%% OTP-14131
+
+-export([t1/0, t2/0, t3/0]).
+
+t1() ->
+ A = erl_parse:anno_from_term({attribute, 1, module, my_test}),
+ compile:forms([A], []).
+
+t2() ->
+ A = erl_parse:new_anno({attribute, 1, module, my_test}),
+ compile:forms([A], []).
+
+t3() ->
+ A = erl_parse:new_anno({attribute, 1, module, my_test}),
+ T = erl_parse:anno_to_term(A),
+ {attribute, 1, module, my_test} = T.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/chars.erl b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
new file mode 100644
index 0000000000..1e9c8ab6b9
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/chars.erl
@@ -0,0 +1,32 @@
+-module(chars).
+
+%% ERL-313
+
+-export([t/0]).
+-export([t1/0]).
+
+-record(r, {f :: $A .. $Z}).
+
+-type cs() :: $A..$Z | $a .. $z | $/.
+
+-spec t() -> $0-$0..$9-$0| $?.
+
+t() ->
+ c(#r{f = $z - 3}),
+ c($z - 3),
+ c($B).
+
+-spec c(cs()) -> $3-$0..$9-$0.
+
+c($A + 1) -> 2;
+c(C) ->
+ case C of
+ $z - 3 -> 3;
+ #r{f = $z - 3} -> 7
+ end.
+
+%% Display contract with character in warning:
+-spec f(#{a := $1, b => $2, c => $3}) -> ok. % invalid type spec
+f(_) -> ok.
+
+t1() -> f(#{b => $2}). % breaks the contract
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 6723876208..9830a36e60 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.0.2
+DIALYZER_VSN = 3.0.3
diff --git a/lib/diameter/examples/code/relay.erl b/lib/diameter/examples/code/relay.erl
index cf4ce8848b..806f79915b 100644
--- a/lib/diameter/examples/code/relay.erl
+++ b/lib/diameter/examples/code/relay.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 4007d6b7b1..864d5f0691 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 37c41a1761..869797f11f 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl
index b5e520e642..5353688bf4 100644
--- a/lib/diameter/test/diameter_relay_SUITE.erl
+++ b/lib/diameter/test/diameter_relay_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index e6ad2c683f..4982488335 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.8.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Document the function tags <c>@param</c> and
+ <c>@returns</c>. </p>
+ <p>
+ Own Id: OTP-13930 Aux Id: PR-1175 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/edoc/include/edoc_doclet.hrl b/lib/edoc/include/edoc_doclet.hrl
index ac6763fb33..9893ff3ee0 100644
--- a/lib/edoc/include/edoc_doclet.hrl
+++ b/lib/edoc/include/edoc_doclet.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc.erl b/lib/edoc/src/edoc.erl
index 94013bb5ac..7d61b9e9c5 100644
--- a/lib/edoc/src/edoc.erl
+++ b/lib/edoc/src/edoc.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2007 Richard Carlsson
diff --git a/lib/edoc/src/edoc.hrl b/lib/edoc/src/edoc.hrl
index 5b0fb68cf9..4b28c0b12e 100644
--- a/lib/edoc/src/edoc.hrl
+++ b/lib/edoc/src/edoc.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl
index b797d74a71..86273b8352 100644
--- a/lib/edoc/src/edoc_data.erl
+++ b/lib/edoc/src/edoc_data.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_doclet.erl b/lib/edoc/src/edoc_doclet.erl
index 5961ca8cc0..9128c19a4d 100644
--- a/lib/edoc/src/edoc_doclet.erl
+++ b/lib/edoc/src/edoc_doclet.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2003-2006 Richard Carlsson
diff --git a/lib/edoc/src/edoc_extract.erl b/lib/edoc/src/edoc_extract.erl
index 2d6cb04a6d..5c8c648319 100644
--- a/lib/edoc/src/edoc_extract.erl
+++ b/lib/edoc/src/edoc_extract.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2003 Richard Carlsson
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index ef57b7b084..41a0b193ec 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl
index cc0a8d0b94..8fbc83fa29 100644
--- a/lib/edoc/src/edoc_lib.erl
+++ b/lib/edoc/src/edoc_lib.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2003 Richard Carlsson
diff --git a/lib/edoc/src/edoc_macros.erl b/lib/edoc/src/edoc_macros.erl
index e1a54d5090..7c91cb0f57 100644
--- a/lib/edoc/src/edoc_macros.erl
+++ b/lib/edoc/src/edoc_macros.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
index b9a9391053..9a45d5b0fa 100644
--- a/lib/edoc/src/edoc_refs.erl
+++ b/lib/edoc/src/edoc_refs.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_report.erl b/lib/edoc/src/edoc_report.erl
index dc6320df6d..ce54e71538 100644
--- a/lib/edoc/src/edoc_report.erl
+++ b/lib/edoc/src/edoc_report.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_run.erl b/lib/edoc/src/edoc_run.erl
index 261a649c70..d69bddc999 100644
--- a/lib/edoc/src/edoc_run.erl
+++ b/lib/edoc/src/edoc_run.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2003 Richard Carlsson
diff --git a/lib/edoc/src/edoc_tags.erl b/lib/edoc/src/edoc_tags.erl
index 93f423b906..919159e125 100644
--- a/lib/edoc/src/edoc_tags.erl
+++ b/lib/edoc/src/edoc_tags.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_types.erl b/lib/edoc/src/edoc_types.erl
index 5bb68e79fb..bd4a583b8e 100644
--- a/lib/edoc/src/edoc_types.erl
+++ b/lib/edoc/src/edoc_types.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/edoc_types.hrl b/lib/edoc/src/edoc_types.hrl
index 3e5e91484f..3f502068af 100644
--- a/lib/edoc/src/edoc_types.hrl
+++ b/lib/edoc/src/edoc_types.hrl
@@ -15,7 +15,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Author contact: [email protected]
diff --git a/lib/edoc/src/edoc_wiki.erl b/lib/edoc/src/edoc_wiki.erl
index 5d0d78bf3c..5d15bbcfcc 100644
--- a/lib/edoc/src/edoc_wiki.erl
+++ b/lib/edoc/src/edoc_wiki.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @private
diff --git a/lib/edoc/src/otpsgml_layout.erl b/lib/edoc/src/otpsgml_layout.erl
index 052c75b9d4..8458a52f2d 100644
--- a/lib/edoc/src/otpsgml_layout.erl
+++ b/lib/edoc/src/otpsgml_layout.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index d3cc732e9c..d66802fdac 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.8
+EDOC_VSN = 0.8.1
diff --git a/lib/eldap/test/Makefile b/lib/eldap/test/Makefile
index 21a0da926f..81fa8f187a 100644
--- a/lib/eldap/test/Makefile
+++ b/lib/eldap/test/Makefile
@@ -42,7 +42,7 @@ TARGET_FILES= \
SPEC_FILES = eldap.spec
-# COVER_FILE = eldap.cover
+COVER_FILE = eldap.cover
# ----------------------------------------------------
diff --git a/lib/eldap/test/eldap.cover b/lib/eldap/test/eldap.cover
new file mode 100644
index 0000000000..8c15956e72
--- /dev/null
+++ b/lib/eldap/test/eldap.cover
@@ -0,0 +1,3 @@
+{incl_app,eldap,details}.
+
+{excl_mods, eldap, ['ELDAPv3']}.
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index cf24161d43..4824a755d9 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -31,7 +31,24 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.6</title>
+ <section><title>Erl_Docgen 0.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Docgen would previously emit "utf8" as the default
+ encoding in xml. This has now been remedied by emitting
+ the correct string "UTF-8" instead.</p>
+ <p>
+ Own Id: OTP-13971</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.6</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 6489d26327..d6106a2823 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.6
+ERL_DOCGEN_VSN = 0.6.1
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 4ef5454f44..69ba3cddb8 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,35 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.9.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix <c>ei_connect_init</c> and <c>ei_connect_xinit</c> to
+ adjust the <c>creation</c> argument to be compatible with
+ nodes older than OTP-19.</p>
+ <p>
+ Own Id: OTP-13981</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Editorial documentation changes</p>
+ <p>
+ Own Id: OTP-13980</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.9.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
index d8f0632341..670a5900c9 100644
--- a/lib/erl_interface/src/prog/erl_start.c
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -17,7 +17,6 @@
*
* %CopyrightEnd%
*
-
*/
/* An exception from using eidef.h, use config.h directly */
@@ -45,7 +44,7 @@
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <netinet/tcp.h>
+#include <netinet/tcp.h>
#include <symLib.h>
#include <sysSymTbl.h>
#include <sysLib.h>
@@ -117,9 +116,9 @@ static int unique_id(void);
static unsigned long spawn_erlang_epmd(ei_cnode *ec,
char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl_or_epmd,
- char *args[],
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
int port,
int is_erlang);
#else
@@ -161,10 +160,10 @@ int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
r = ERL_SYS_ERROR;
goto done;
}
-
+
memset(&addr,0,sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) {
@@ -179,12 +178,12 @@ int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
listen(sockd,5);
#if defined(VXWORKS) || defined(__WIN32__)
- if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
+ if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
== 0)
return ERL_SYS_ERROR;
timeout.tv_usec = 0;
timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
- if((r = wait_for_erlang(sockd,unique_id(),&timeout))
+ if((r = wait_for_erlang(sockd,unique_id(),&timeout))
== ERL_TIMEOUT) {
#if defined(VXWORKS)
taskDelete((int) pid);
@@ -262,7 +261,7 @@ done:
static int unique_id(void){
#if defined(VXWORKS)
return taskIdSelf();
-#else
+#else
return (int) GetCurrentThreadId();
#endif
}
@@ -285,7 +284,7 @@ static int enquote_args(char **oargs, char ***qargs){
for(len=0;oargs[len] != NULL; ++len)
;
args = malloc(sizeof(char *) * (len + 1));
-
+
for(i = 0; i < len; ++i){
qwhole = strchr(oargs[i],' ') != NULL;
extra = qwhole * 2;
@@ -337,16 +336,16 @@ static FUNCPTR lookup_function(char *symname){
static unsigned long spawn_erlang_epmd(ei_cnode *ec,
char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl_or_epmd,
- char *args[],
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
int port,
int is_erlang)
{
#if defined(VXWORKS)
FUNCPTR erlfunc;
#else /* Windows */
- STARTUPINFO sinfo;
+ STARTUPINFO sinfo;
SECURITY_ATTRIBUTES sa;
PROCESS_INFORMATION pinfo;
#endif
@@ -364,7 +363,7 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
if(is_erlang){
get_addr(ei_thishostname(ec), &myaddr);
#if defined(VXWORKS)
- inet_ntoa_b(myaddr, iaddrbuf);
+ inet_ntoa_b(myaddr, iaddrbuf);
#else /* Windows */
if((ptr = inet_ntoa(myaddr)) == NULL)
return 0;
@@ -372,7 +371,7 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
strcpy(iaddrbuf,ptr);
#endif
}
- if ((flags & ERL_START_REMOTE) ||
+ if ((flags & ERL_START_REMOTE) ||
(is_erlang && (hisaddr->s_addr != myaddr.s_addr))) {
return 0;
} else {
@@ -382,19 +381,17 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
#if !defined(VXWORKS)
/* On VxWorks, we dont actually run a command,
we call start_erl() */
- if(!erl_or_epmd)
+ if(!erl_or_epmd)
#endif
erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND :
DEF_EPMD_COMMAND;
if(is_erlang){
name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT :
ERL_SNAME_FMT;
- cmdlen +=
+ cmdlen +=
strlen(erl_or_epmd) + (*erl_or_epmd != '\0') +
strlen(name_format) + 1 + strlen(alive) +
- strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) +
- 2 * FORMATTED_INT_LEN +
- 1;
+ strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) + 2 * FORMATTED_INT_LEN + 1;
ptr = cmdbuf = malloc(cmdlen);
if(*erl_or_epmd != '\0')
ptr += sprintf(ptr,"%s ",erl_or_epmd);
@@ -484,11 +481,11 @@ static unsigned long spawn_erlang_epmd(ei_cnode *ec,
* arguments we use here.
*/
static int exec_erlang(ei_cnode *ec,
- char *alive,
+ char *alive,
Erl_IpAddr adr,
- int flags,
- char *erl,
- char *args[],
+ int flags,
+ char *erl,
+ char *args[],
int port)
{
#if !defined(__WIN32__) && !defined(VXWORKS)
@@ -498,8 +495,11 @@ static int exec_erlang(ei_cnode *ec,
char argbuf[BUFSIZ];
struct in_addr myaddr;
struct in_addr *hisaddr = (struct in_addr *)adr;
-
- get_addr(ei_thishostname(ec), &myaddr);
+
+ if (!get_addr(ei_thishostname(ec), &myaddr)) {
+ fprintf(stderr,"erl_call: failed to find hostname\r\n");
+ return ERL_SYS_ERROR;
+ }
/* on this host? */
/* compare ip addresses, unless forced by flag setting to use rsh */
@@ -525,8 +525,8 @@ static int exec_erlang(ei_cnode *ec,
/* *must* be noinput or node (seems to) hang... */
/* long or short names? */
- sprintf(&argbuf[len], "-noinput %s %s ",
- ((flags & ERL_START_LONG) ? "-name" : "-sname"),
+ sprintf(&argbuf[len], "-noinput %s %s ",
+ ((flags & ERL_START_LONG) ? "-name" : "-sname"),
alive);
len = strlen(argbuf);
@@ -572,7 +572,7 @@ static int exec_erlang(ei_cnode *ec,
fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
}
- }
+ }
/* start the system */
execvp(argv[0], argv);
@@ -609,7 +609,7 @@ static void gettimeofday(struct timeval *now, void *dummy){
now->tv_usec = ((ctick - (now->tv_sec * rate))*1000000)/rate;
}
#endif
-
+
/* wait for the remote system to reply */
/*
@@ -648,7 +648,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
"will timeout at %ld.%06ld\n",
now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec);
#endif
-
+
while (1) {
FD_ZERO(&rdset);
FD_SET(sockd,&rdset);
@@ -662,7 +662,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
to.tv_sec--;
}
if (to.tv_sec < 0) return ERL_TIMEOUT;
-
+
#ifdef DEBUG
fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n",
to.tv_sec,to.tv_usec);
@@ -690,7 +690,7 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
if (FD_ISSET(sockd,&rdset)) {
if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0)
return ERL_SYS_ERROR;
-
+
/* now get sign-on message and terminate it */
#if defined(__WIN32__)
if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0;
@@ -703,7 +703,6 @@ static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
fprintf(stderr,"erl_call: debug got %d, expected %d\n",
atoi(buf),magic);
#endif
-
if (atoi(buf) == magic) return 0; /* success */
} /* if FD_SET */
} /* switch */
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 82be43b7df..c7981ed3a5 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.9.1
+EI_VSN = 3.9.2
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index 6ae3c04bc8..8509f44ffc 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -33,6 +33,22 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The address to the FSF in the license header has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14084</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index 8a4cad1e7e..0f7a15f669 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% Copyright (C) 2004-2006 Mickaël Rémond, Richard Carlsson
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index fbfd123c43..1009d76d5b 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2004-2009 Mickaël Rémond, Richard Carlsson
diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl
index 7bb78f5ea8..a3eb64f9c8 100644
--- a/lib/eunit/src/eunit_autoexport.erl
+++ b/lib/eunit/src/eunit_autoexport.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl
index cc002cb449..cea7bcd5c5 100644
--- a/lib/eunit/src/eunit_data.erl
+++ b/lib/eunit/src/eunit_data.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl
index 9dbb4835f8..b19f50b990 100644
--- a/lib/eunit/src/eunit_lib.erl
+++ b/lib/eunit/src/eunit_lib.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2004-2007 Mickaël Rémond, Richard Carlsson
diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl
index 8bdf94c877..c6bb8bdbb3 100644
--- a/lib/eunit/src/eunit_proc.erl
+++ b/lib/eunit/src/eunit_proc.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl
index da76064a53..bbda4400da 100644
--- a/lib/eunit/src/eunit_serial.erl
+++ b/lib/eunit/src/eunit_serial.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl
index 387976eba1..e767822543 100644
--- a/lib/eunit/src/eunit_server.erl
+++ b/lib/eunit/src/eunit_server.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_striptests.erl b/lib/eunit/src/eunit_striptests.erl
index c6ade389ba..ae1a834662 100644
--- a/lib/eunit/src/eunit_striptests.erl
+++ b/lib/eunit/src/eunit_striptests.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 1b468551d8..a70b8bfd4c 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Mickaël Rémond <[email protected]>
diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl
index 62d30b1930..f2b9fa46f2 100644
--- a/lib/eunit/src/eunit_test.erl
+++ b/lib/eunit/src/eunit_test.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl
index 5dee1cb49e..7aadefb29f 100644
--- a/lib/eunit/src/eunit_tests.erl
+++ b/lib/eunit/src/eunit_tests.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl
index f604ca5ba3..1fbc4edd45 100644
--- a/lib/eunit/src/eunit_tty.erl
+++ b/lib/eunit/src/eunit_tty.erl
@@ -10,7 +10,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @author Richard Carlsson <[email protected]>
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 83d826f8b6..7eee75ee10 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.3.1
+EUNIT_VSN = 2.3.2
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 9ef119ba46..7edfbf65df 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -236,7 +236,8 @@
-export([t_is_identifier/1]).
-endif.
--export_type([erl_type/0, opaques/0, type_table/0, var_table/0, cache/0]).
+-export_type([erl_type/0, opaques/0, type_table/0, mod_records/0,
+ var_table/0, cache/0]).
%%-define(DEBUG, true).
@@ -379,8 +380,9 @@
-type type_value() :: {{module(), {file:name(), erl_anno:line()},
erl_parse:abstract_type(), ArgNames :: [atom()]},
erl_type()}.
--type type_table() :: dict:dict(record_key() | type_key(),
- record_value() | type_value()).
+-type type_table() :: #{record_key() | type_key() =>
+ record_value() | type_value()}.
+-type mod_records() :: dict:dict(module(), type_table()).
-opaque var_table() :: #{atom() => erl_type()}.
@@ -749,16 +751,16 @@ decorate_tuples_in_sets([], _L, _Opaques, Acc) ->
-spec t_opaque_from_records(type_table()) -> [erl_type()].
-t_opaque_from_records(RecDict) ->
- OpaqueRecDict =
- dict:filter(fun(Key, _Value) ->
+t_opaque_from_records(RecMap) ->
+ OpaqueRecMap =
+ maps:filter(fun(Key, _Value) ->
case Key of
{opaque, _Name, _Arity} -> true;
_ -> false
end
- end, RecDict),
- OpaqueTypeDict =
- dict:map(fun({opaque, Name, _Arity},
+ end, RecMap),
+ OpaqueTypeMap =
+ maps:map(fun({opaque, Name, _Arity},
{{Module, _FileLine, _Form, ArgNames}, _Type}) ->
%% Args = args_to_types(ArgNames),
%% List = lists:zip(ArgNames, Args),
@@ -767,8 +769,8 @@ t_opaque_from_records(RecDict) ->
Rep = t_any(), % not used for anything right now
Args = [t_any() || _ <- ArgNames],
t_opaque(Module, Name, Args, Rep)
- end, OpaqueRecDict),
- [OpaqueType || {_Key, OpaqueType} <- dict:to_list(OpaqueTypeDict)].
+ end, OpaqueRecMap),
+ [OpaqueType || {_Key, OpaqueType} <- maps:to_list(OpaqueTypeMap)].
%% Decompose opaque instances of type arg2 to structured types, in arg1
%% XXX: Same as t_unopaque
@@ -802,10 +804,6 @@ list_struct_from_opaque(Types, Opaques) ->
[t_struct_from_opaque(Type, Opaques) || Type <- Types].
%%-----------------------------------------------------------------------------
-
--type mod_records() :: dict:dict(module(), type_table()).
-
-%%-----------------------------------------------------------------------------
%% Unit type. Signals non termination.
%%
@@ -3067,88 +3065,91 @@ is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A1, A2) ->
- is_specialization(A1, A2) orelse is_specialization(A2, A1).
-
--spec is_specialization(erl_type(), erl_type()) -> boolean().
-
-%% Returns true if the first argument is a specialization of the
-%% second argument in the sense that every type is a specialization of
-%% any(). For example, {_,_} is a specialization of any(), but not of
-%% tuple(). Does not handle variables, but any() and unions (sort of).
-
-is_specialization(T, T) -> true;
-is_specialization(_, ?any) -> true;
-is_specialization(?any, _) -> false;
-is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
- (is_specialization(Domain1, Domain2) andalso
- is_specialization(Range1, Range2));
-is_specialization(?list(Contents1, Termination1, Size1),
- ?list(Contents2, Termination2, Size2)) ->
+-spec is_compat_arg(erl_type(), erl_type()) -> boolean().
+
+%% The intention is that 'true' is to be returned iff one of the
+%% arguments is a specialization of the other argument in the sense
+%% that every type is a specialization of any(). For example, {_,_} is
+%% a specialization of any(), but not of tuple(). Does not handle
+%% variables, but any() and unions (sort of). However, the
+%% implementation is more relaxed as any() is compatible to anything.
+
+is_compat_arg(T, T) -> true;
+is_compat_arg(_, ?any) -> true;
+is_compat_arg(?any, _) -> true;
+is_compat_arg(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_compat_arg(Domain1, Domain2) andalso
+ is_compat_arg(Range1, Range2));
+is_compat_arg(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
(Size1 =:= Size2 andalso
- is_specialization(Contents1, Contents2) andalso
- is_specialization(Termination1, Termination2));
-is_specialization(?product(Types1), ?product(Types2)) ->
- specialization_list(Types1, Types2);
-is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
-is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(Elements1, Elements2);
-is_specialization(?tuple_set([{Arity, List}]),
- ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
- specialization_list(sup_tuple_elements(List), Elements2);
-is_specialization(?tuple(Elements1, Arity, _),
- ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
- specialization_list(Elements1, sup_tuple_elements(List));
-is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ is_compat_arg(Contents1, Contents2) andalso
+ is_compat_arg(Termination1, Termination2));
+is_compat_arg(?product(Types1), ?product(Types2)) ->
+ is_compat_list(Types1, Types2);
+is_compat_arg(?map(Pairs1, DefK1, DefV1), ?map(Pairs2, DefK2, DefV2)) ->
+ (is_compat_list(Pairs1, Pairs2) andalso
+ is_compat_arg(DefK1, DefK2) andalso
+ is_compat_arg(DefV1, DefV2));
+is_compat_arg(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_compat_arg(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(Elements1, Elements2);
+is_compat_arg(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ is_compat_list(sup_tuple_elements(List), Elements2);
+is_compat_arg(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ is_compat_list(Elements1, sup_tuple_elements(List));
+is_compat_arg(?tuple_set(List1), ?tuple_set(List2)) ->
try
- specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
- [sup_tuple_elements(T) || {_Arity, T} <- List2])
+ is_compat_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
catch _:_ -> false
end;
-is_specialization(?opaque(_) = T1, T2) ->
- is_specialization(t_opaque_structure(T1), T2);
-is_specialization(T1, ?opaque(_) = T2) ->
- is_specialization(T1, t_opaque_structure(T2));
-is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
- case specialization_union2(T1, T2) of
- {yes, Type1, Type2} -> is_specialization(Type1, Type2);
- no -> specialization_list(List1, List2)
+is_compat_arg(?opaque(_) = T1, T2) ->
+ is_compat_arg(t_opaque_structure(T1), T2);
+is_compat_arg(T1, ?opaque(_) = T2) ->
+ is_compat_arg(T1, t_opaque_structure(T2));
+is_compat_arg(?union(List1)=T1, ?union(List2)=T2) ->
+ case is_compat_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_compat_arg(Type1, Type2);
+ no -> is_compat_list(List1, List2)
end;
-is_specialization(?union(List), T2) ->
+is_compat_arg(?union(List), T2) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(Type, T2);
+ {yes, Type} -> is_compat_arg(Type, T2);
no -> false
end;
-is_specialization(T1, ?union(List)) ->
+is_compat_arg(T1, ?union(List)) ->
case unify_union(List) of
- {yes, Type} -> is_specialization(T1, Type);
+ {yes, Type} -> is_compat_arg(T1, Type);
no -> false
end;
-is_specialization(?var(_), _) -> exit(error);
-is_specialization(_, ?var(_)) -> exit(error);
-is_specialization(?none, _) -> false;
-is_specialization(_, ?none) -> false;
-is_specialization(?unit, _) -> false;
-is_specialization(_, ?unit) -> false;
-is_specialization(#c{}, #c{}) -> false.
+is_compat_arg(?var(_), _) -> exit(error);
+is_compat_arg(_, ?var(_)) -> exit(error);
+is_compat_arg(?none, _) -> false;
+is_compat_arg(_, ?none) -> false;
+is_compat_arg(?unit, _) -> false;
+is_compat_arg(_, ?unit) -> false;
+is_compat_arg(#c{}, #c{}) -> false.
-specialization_list_list(LL1, LL2) ->
- length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
+is_compat_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso is_compat_list_list1(LL1, LL2).
-specialization_list_list1([], []) -> true;
-specialization_list_list1([L1|LL1], [L2|LL2]) ->
- specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
+is_compat_list_list1([], []) -> true;
+is_compat_list_list1([L1|LL1], [L2|LL2]) ->
+ is_compat_list(L1, L2) andalso is_compat_list_list1(LL1, LL2).
-specialization_list(L1, L2) ->
- length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
+is_compat_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso is_compat_list1(L1, L2).
-specialization_list1([], []) -> true;
-specialization_list1([T1|L1], [T2|L2]) ->
- is_specialization(T1, T2) andalso specialization_list1(L1, L2).
+is_compat_list1([], []) -> true;
+is_compat_list1([T1|L1], [T2|L2]) ->
+ is_compat_arg(T1, T2) andalso is_compat_list1(L1, L2).
-specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+is_compat_union2(?union(List1)=T1, ?union(List2)=T2) ->
case {unify_union(List1), unify_union(List2)} of
{{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
{{yes, Type1}, no} -> {yes, Type1, T2};
@@ -4181,7 +4182,7 @@ t_map(Fun, T) ->
-spec t_to_string(erl_type()) -> string().
t_to_string(T) ->
- t_to_string(T, dict:new()).
+ t_to_string(T, maps:new()).
-spec t_to_string(erl_type(), type_table()) -> string().
@@ -4377,7 +4378,7 @@ record_field_diffs_to_string(?tuple([_|Fs], Arity, Tag), RecDict) ->
string:join(FieldDiffs, " and ").
field_diffs([F|Fs], [{FName, _Abstr, DefType}|FDefs], RecDict, Acc) ->
- %% Don't care about opaqueness for now.
+ %% Don't care about opacity for now.
NewAcc =
case not t_is_none(t_inf(F, DefType)) of
true -> Acc;
@@ -4542,6 +4543,8 @@ from_form({atom, _L, Atom}, _S, _D, L, C) ->
{t_atom(Atom), L, C};
from_form({integer, _L, Int}, _S, _D, L, C) ->
{t_integer(Int), L, C};
+from_form({char, _L, Char}, _S, _D, L, C) ->
+ {t_integer(Char), L, C};
from_form({op, _L, _Op, _Arg} = Op, _S, _D, L, C) ->
case erl_eval:partial_eval(Op) of
{integer, _, Val} ->
@@ -5056,6 +5059,7 @@ check_record_fields({remote_type, _L, [{atom, _, _}, {atom, _, _}, Args]},
list_check_record_fields(Args, S, C);
check_record_fields({atom, _L, _}, _S, C) -> C;
check_record_fields({integer, _L, _}, _S, C) -> C;
+check_record_fields({char, _L, _}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg}, _S, C) -> C;
check_record_fields({op, _L, _Op, _Arg1, _Arg2}, _S, C) -> C;
check_record_fields({type, _L, tuple, any}, _S, C) -> C;
@@ -5157,6 +5161,7 @@ t_form_to_string({var, _L, Name}) -> atom_to_list(Name);
t_form_to_string({atom, _L, Atom}) ->
io_lib:write_string(atom_to_list(Atom), $'); % To quote or not to quote... '
t_form_to_string({integer, _L, Int}) -> integer_to_list(Int);
+t_form_to_string({char, _L, Char}) -> integer_to_list(Char);
t_form_to_string({op, _L, _Op, _Arg} = Op) ->
case erl_eval:partial_eval(Op) of
{integer, _, _} = Int -> t_form_to_string(Int);
@@ -5239,7 +5244,7 @@ t_form_to_string({type, _L, union, Args}) ->
t_form_to_string({type, _L, Name, []} = T) ->
try
M = mod,
- D0 = dict:new(),
+ D0 = maps:new(),
MR = dict:from_list([{M, D0}]),
Site = {type, {M,Name,0}},
V = var_table__new(),
@@ -5303,8 +5308,8 @@ is_erl_type(_) -> false.
-spec lookup_record(atom(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{_Arity, Fields}]}} ->
{ok, Fields};
{ok, {_FileLine, List}} when is_list(List) ->
@@ -5318,18 +5323,18 @@ lookup_record(Tag, RecDict) when is_atom(Tag) ->
-spec lookup_record(atom(), arity(), type_table()) ->
'error' | {'ok', [{atom(), parse_form(), erl_type()}]}.
-lookup_record(Tag, Arity, RecDict) when is_atom(Tag) ->
- case dict:find({record, Tag}, RecDict) of
+lookup_record(Tag, Arity, Table) when is_atom(Tag) ->
+ case maps:find({record, Tag}, Table) of
{ok, {_FileLine, [{Arity, Fields}]}} -> {ok, Fields};
{ok, {_FileLine, OrdDict}} -> orddict:find(Arity, OrdDict);
error -> error
end.
-spec lookup_type(_, _, _) -> {'type' | 'opaque', type_value()} | 'error'.
-lookup_type(Name, Arity, RecDict) ->
- case dict:find({type, Name, Arity}, RecDict) of
+lookup_type(Name, Arity, Table) ->
+ case maps:find({type, Name, Arity}, Table) of
error ->
- case dict:find({opaque, Name, Arity}, RecDict) of
+ case maps:find({opaque, Name, Arity}, Table) of
error -> error;
{ok, Found} -> {opaque, Found}
end;
@@ -5339,8 +5344,8 @@ lookup_type(Name, Arity, RecDict) ->
-spec type_is_defined('type' | 'opaque', atom(), arity(), type_table()) ->
boolean().
-type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
- dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+type_is_defined(TypeOrOpaque, Name, Arity, Table) ->
+ maps:is_key({TypeOrOpaque, Name, Arity}, Table).
cannot_have_opaque(Type, TypeName, TypeNames) ->
t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index fc529fba61..0bdd60adfd 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,51 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.15.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix flow control bug in hipe compiler that may cause
+ compile time crash.</p>
+ <p>
+ Own Id: OTP-13965 Aux Id: PR-1253 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in native compilation of bitstring pattern
+ matching causing erroneous runtime matching result. The
+ bug only affects code containing constant-valued segments
+ whose size is expressed in bits; it is triggered when the
+ pattern matching against these segments fails (i.e., when
+ the next clause needs to be tried).</p>
+ <p>
+ Own Id: OTP-14005</p>
+ </item>
+ <item>
+ <p>
+ Workaround in HiPE LLVM backend for a bug in LLVM 3.9.
+ The bug could cause LLVM-compiled modules to be rejected
+ during loading with a badarg exception in
+ hipe_bifs:enter_sdecs/1, but also cause corruption or
+ segmentation faults i runtime.</p>
+ <p>
+ Own Id: OTP-14027 Aux Id: ERL-292, PR-1237 </p>
+ </item>
+ <item>
+ <p>
+ Fix a bug in HiPE LLVM backend involving incorrect type
+ tests of atoms sometimes causing incorrect behaviour or
+ even segfaults.</p>
+ <p>
+ Own Id: OTP-14028 Aux Id: PR-1237 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.15.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 78508dff22..13a0bf6141 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/icode/hipe_icode_call_elim.erl b/lib/hipe/icode/hipe_icode_call_elim.erl
index 6a22133962..71c709a7d1 100644
--- a/lib/hipe/icode/hipe_icode_call_elim.erl
+++ b/lib/hipe/icode/hipe_icode_call_elim.erl
@@ -46,7 +46,8 @@ cfg(IcodeSSA) ->
-spec elim_insn(icode_instr()) -> icode_instr().
elim_insn(Insn=#icode_call{'fun'={_,_,_}=MFA, args=Args, type=remote,
dstlist=[Dst=#icode_variable{
- annotation={type_anno, RetType, _}}]}) ->
+ annotation={type_anno, RetType, _}}],
+ continuation=[], fail_label=[]}) ->
Opaques = 'universe',
case erl_types:t_is_singleton(RetType, Opaques) of
true ->
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 6c525dd143..cc0148a80e 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -635,44 +635,51 @@ run_compiler(Name, DisasmFun, IcodeFun, Opts0) ->
Opts = expand_basic_options(Opts0 ++ ?COMPILE_DEFAULTS),
?when_option(verbose, Opts, ?debug_msg("Compiling: ~p\n",[Name])),
?option_start_time("Compile", Opts),
- Res = run_compiler_1(DisasmFun, IcodeFun, Opts),
+ Res = run_compiler_1(Name, DisasmFun, IcodeFun, Opts),
?option_stop_time("Compile", Opts),
Res.
-run_compiler_1(DisasmFun, IcodeFun, Options) ->
+run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
Parent = self(),
{trap_exit,TrapExit} = process_info(Parent, trap_exit),
%% Spawn a compilation process CompProc. In case this process gets
%% killed, the trap_exit flag is restored to that of the Parent process.
process_flag(trap_exit, true),
- CompProc = spawn_link(fun () ->
- %% Compiler process
- set_architecture(Options),
- pre_init(Options),
- %% The full option expansion is not done
- %% until the DisasmFun returns.
- {Code, CompOpts} = DisasmFun(Options),
- Opts0 = expand_options(Options ++ CompOpts,
- get(hipe_target_arch)),
- Opts =
- case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_support_available() of
- true ->
- ?error_msg("No LLVM version 3.4 or greater "
- "found in $PATH; aborting "
- "native code compilation.\n", []),
- ?EXIT(cant_find_required_llvm_version);
- false ->
- Opts0
- end,
- check_options(Opts),
- ?when_option(verbose, Options,
- ?debug_msg("Options: ~p.\n",[Opts])),
- init(Opts),
- {Icode, WholeModule} = IcodeFun(Code, Opts),
- CompRes = compile_finish(Icode, WholeModule, Opts),
- compiler_return(CompRes, Parent)
- end),
+ CompProc =
+ spawn_link(
+ fun () ->
+ try
+ %% Compiler process
+ set_architecture(Options),
+ pre_init(Options),
+ %% The full option expansion is not done
+ %% until the DisasmFun returns.
+ {Code, CompOpts} = DisasmFun(Options),
+ Opts0 = expand_options(Options ++ CompOpts,
+ get(hipe_target_arch)),
+ Opts =
+ case proplists:get_bool(to_llvm, Opts0) andalso
+ not llvm_support_available() of
+ true ->
+ ?error_msg("No LLVM version 3.4 or greater "
+ "found in $PATH; aborting "
+ "native code compilation.\n", []),
+ ?EXIT(cant_find_required_llvm_version);
+ false ->
+ Opts0
+ end,
+ check_options(Opts),
+ ?when_option(verbose, Options,
+ ?debug_msg("Options: ~p.\n",[Opts])),
+ init(Opts),
+ {Icode, WholeModule} = IcodeFun(Code, Opts),
+ CompRes = compile_finish(Icode, WholeModule, Opts),
+ compiler_return(CompRes, Parent)
+ catch error:Error ->
+ print_crash_message(Name, Error),
+ exit(Error)
+ end
+ end),
Timeout = case proplists:get_value(timeout, Options) of
N when is_integer(N), N >= 0 -> N;
undefined -> ?DEFAULT_TIMEOUT;
@@ -691,7 +698,7 @@ run_compiler_1(DisasmFun, IcodeFun, Options) ->
exit(CompProc, kill),
receive {'EXIT', CompProc, _} -> ok end,
flush(),
- ?error_msg("ERROR: Compilation timed out.\n",[]),
+ ?error_msg("ERROR: Compilation of ~w timed out.\n",[Name]),
exit(timed_out)
end,
Result = receive {CompProc, Res} -> Res end,
@@ -844,11 +851,25 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
catch
error:Error ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
- ErrorInfo = {Error, erlang:get_stacktrace()},
- ?error_msg("ERROR: ~p~n", [ErrorInfo]),
- ?EXIT(ErrorInfo)
+ print_crash_message(MFA, Error),
+ exit(Error)
end.
+print_crash_message(What, Error) ->
+ StackFun = fun(_,_,_) -> false end,
+ FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
+ StackTrace = lib:format_stacktrace(1, erlang:get_stacktrace(),
+ StackFun, FormatFun),
+ WhatS = case What of
+ {M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
+ Mod -> io_lib:format("~w", [Mod])
+ end,
+ ?error_msg("INTERNAL ERROR~n"
+ "while compiling ~s~n"
+ "crash reason: ~p~n"
+ "~s~n",
+ [WhatS, Error, StackTrace]).
+
pp_server_start(Opts) ->
set_architecture(Opts),
garbage_collect(),
diff --git a/lib/hipe/main/hipe.hrl.src b/lib/hipe/main/hipe.hrl.src
index 53b59f88f0..b001743038 100644
--- a/lib/hipe/main/hipe.hrl.src
+++ b/lib/hipe/main/hipe.hrl.src
@@ -1,8 +1,8 @@
-%% -*- erlang-indent-level: 2 -*-
+%% -*- mode: erlang; erlang-indent-level: 2 -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -70,20 +70,24 @@
code_server:info_msg(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
code_server:info_msg(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ code_server:error_msg(Msg, Args)).
-else.
-define(msg(Msg, Args),
io:format(?MSGTAG ++ Msg, Args)).
-define(untagged_msg(Msg, Args),
io:format(Msg, Args)).
+-define(untagged_error_msg(Msg, Args),
+ io:format(Msg, Args)).
-endif.
%%
%% Define error and warning messages.
%%
-define(error_msg(Msg, Args),
- code_server:error_msg(?MSGTAG ++
+ ?untagged_error_msg(?MSGTAG ++
"Error: [~s:~w]: " ++ Msg,
- [?MODULE,?LINE|Args])).
+ [?MODULE,?LINE|Args])).
-define(WARNING_MSG(Msg, Args),
?msg("Warning: [~s:~w]: " ++ Msg, [?MODULE,?LINE|Args])).
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index 4b89feb48a..8737560ad5 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
new file mode 100644
index 0000000000..807c4b0d0d
--- /dev/null
+++ b/lib/hipe/test/basic_SUITE_data/basic_num_bif.erl
@@ -0,0 +1,217 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%-------------------------------------------------------------------
+%%% File : basic_num_bif.erl
+%%% Description : Taken from the compiler test suite
+%%%-------------------------------------------------------------------
+-module(basic_num_bif).
+
+-export([test/0]).
+
+%% Tests optimization of the BIFs:
+%% abs/1
+%% float/1
+%% float_to_list/1
+%% integer_to_list/1
+%% list_to_float/1
+%% list_to_integer/1
+%% round/1
+%% trunc/1
+
+test() ->
+ Funs = [fun t_abs/0, fun t_float/0,
+ fun t_float_to_list/0, fun t_integer_to_list/0,
+ fun t_list_to_float_safe/0, fun t_list_to_float_risky/0,
+ fun t_list_to_integer/0, fun t_round/0, fun t_trunc/0],
+ lists:foreach(fun (F) -> ok = F() end, Funs).
+
+t_abs() ->
+ %% Floats.
+ 5.5 = abs(5.5),
+ 0.0 = abs(0.0),
+ 100.0 = abs(-100.0),
+ %% Integers.
+ 5 = abs(5),
+ 0 = abs(0),
+ 100 = abs(-100),
+ %% The largest smallnum. OTP-3190.
+ X = (1 bsl 27) - 1,
+ X = abs(X),
+ X = abs(X-1)+1,
+ X = abs(X+1)-1,
+ X = abs(-X),
+ X = abs(-X-1)-1,
+ X = abs(-X+1)+1,
+ %% Bignums.
+ BigNum = 13984792374983749,
+ BigNum = abs(BigNum),
+ BigNum = abs(-BigNum),
+ ok.
+
+t_float() ->
+ 0.0 = float(0),
+ 2.5 = float(2.5),
+ 0.0 = float(0.0),
+ -100.55 = float(-100.55),
+ 42.0 = float(42),
+ -100.0 = float(-100),
+ %% Bignums.
+ 4294967305.0 = float(4294967305),
+ -4294967305.0 = float(-4294967305),
+ %% Extremely big bignums.
+ Big = list_to_integer(lists:duplicate(2000, $1)),
+ {'EXIT', {badarg, _}} = (catch float(Big)),
+ ok.
+
+%% Tests float_to_list/1.
+
+t_float_to_list() ->
+ test_ftl("0.0e+0", 0.0),
+ test_ftl("2.5e+1", 25.0),
+ test_ftl("2.5e+0", 2.5),
+ test_ftl("2.5e-1", 0.25),
+ test_ftl("-3.5e+17", -350.0e15),
+ ok.
+
+test_ftl(Expect, Float) ->
+ %% No on the next line -- we want the line number from t_float_to_list.
+ Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
+
+%% Removes any non-significant zeros in a floating point number.
+%% Example: 2.500000e+01 -> 2.5e+1
+
+remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$+, $e|Rest], [X|Result]);
+remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
+ remove_zeros([$-, $e|Rest], [X|Result]);
+remove_zeros([$0, $.|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$., $0, $e|Result]);
+remove_zeros([$0|Rest], [$e|Result]) ->
+ remove_zeros(Rest, [$e|Result]);
+remove_zeros([Char|Rest], Result) ->
+ remove_zeros(Rest, [Char|Result]);
+remove_zeros([], Result) ->
+ Result.
+
+%% Tests integer_to_list/1.
+
+t_integer_to_list() ->
+ "0" = integer_to_list(0),
+ "42" = integer_to_list(42),
+ "-42" = integer_to_list(-42),
+ "-42" = integer_to_list(-42),
+ "32768" = integer_to_list(32768),
+ "268435455" = integer_to_list(268435455),
+ "-268435455" = integer_to_list(-268435455),
+ "123456932798748738738" = integer_to_list(123456932798748738738),
+ Big_List = lists:duplicate(2000, $1),
+ Big = list_to_integer(Big_List),
+ Big_List = integer_to_list(Big),
+ ok.
+
+%% Tests list_to_float/1.
+
+t_list_to_float_safe() ->
+ 0.0 = list_to_float("0.0"),
+ 0.0 = list_to_float("-0.0"),
+ 0.5 = list_to_float("0.5"),
+ -0.5 = list_to_float("-0.5"),
+ 100.0 = list_to_float("1.0e2"),
+ 127.5 = list_to_float("127.5"),
+ -199.5 = list_to_float("-199.5"),
+ ok.
+
+%% This might crash the emulator...
+%% (Known to crash the Unix version of Erlang 4.4.1)
+
+t_list_to_float_risky() ->
+ Many_Ones = lists:duplicate(25000, $1),
+ _ = list_to_float("2."++Many_Ones),
+ {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
+ ok.
+
+%% Tests list_to_integer/1.
+
+t_list_to_integer() ->
+ 0 = list_to_integer("0"),
+ 0 = list_to_integer("00"),
+ 0 = list_to_integer("-0"),
+ 1 = list_to_integer("1"),
+ -1 = list_to_integer("-1"),
+ 42 = list_to_integer("42"),
+ -12 = list_to_integer("-12"),
+ 32768 = list_to_integer("32768"),
+ 268435455 = list_to_integer("268435455"),
+ -268435455 = list_to_integer("-268435455"),
+ %% Bignums.
+ 123456932798748738738 = list_to_integer("123456932798748738738"),
+ _ = list_to_integer(lists:duplicate(2000, $1)),
+ ok.
+
+%% Tests round/1.
+
+t_round() ->
+ 0 = round(0.0),
+ 0 = round(0.4),
+ 1 = round(0.5),
+ 0 = round(-0.4),
+ -1 = round(-0.5),
+ 255 = round(255.3),
+ 256 = round(255.6),
+ -1033 = round(-1033.3),
+ -1034 = round(-1033.6),
+ %% OTP-3722:
+ X = (1 bsl 27) - 1,
+ MX = -X,
+ MXm1 = -X-1,
+ MXp1 = -X+1,
+ F = X + 0.0,
+ X = round(F),
+ X = round(F+1)-1,
+ X = round(F-1)+1,
+ MX = round(-F),
+ MXm1 = round(-F-1),
+ MXp1 = round(-F+1),
+ X = round(F+0.1),
+ X = round(F+1+0.1)-1,
+ X = round(F-1+0.1)+1,
+ MX = round(-F+0.1),
+ MXm1 = round(-F-1+0.1),
+ MXp1 = round(-F+1+0.1),
+ X = round(F-0.1),
+ X = round(F+1-0.1)-1,
+ X = round(F-1-0.1)+1,
+ MX = round(-F-0.1),
+ MXm1 = round(-F-1-0.1),
+ MXp1 = round(-F+1-0.1),
+ 0.5 = abs(round(F+0.5)-(F+0.5)),
+ 0.5 = abs(round(F-0.5)-(F-0.5)),
+ 0.5 = abs(round(-F-0.5)-(-F-0.5)),
+ 0.5 = abs(round(-F+0.5)-(-F+0.5)),
+ %% Bignums.
+ 4294967296 = round(4294967296.1),
+ 4294967297 = round(4294967296.9),
+ -4294967296 = -round(4294967296.1),
+ -4294967297 = -round(4294967296.9),
+ ok.
+
+t_trunc() ->
+ 0 = trunc(0.0),
+ 5 = trunc(5.3333),
+ -10 = trunc(-10.978987),
+ %% The largest smallnum, converted to float (OTP-3722):
+ X = (1 bsl 27) - 1,
+ F = X + 0.0,
+ %% io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
+ %% [X, X, binary_to_list(term_to_binary(X)),
+ %% F, F, binary_to_list(term_to_binary(F)),
+ %% trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
+ X = trunc(F),
+ X = trunc(F+1)-1,
+ X = trunc(F-1)+1,
+ X = -trunc(-F),
+ X = -trunc(-F-1)-1,
+ X = -trunc(-F+1)+1,
+ %% Bignums.
+ 4294967305 = trunc(4294967305.7),
+ -4294967305 = trunc(-4294967305.7),
+ ok.
diff --git a/lib/hipe/test/hipe_SUITE.erl b/lib/hipe/test/hipe_SUITE.erl
index a5b3924aa8..b9adb660f2 100644
--- a/lib/hipe/test/hipe_SUITE.erl
+++ b/lib/hipe/test/hipe_SUITE.erl
@@ -16,7 +16,11 @@
%%
-module(hipe_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ app/0, app/1, appup/0, appup/1]).
+
-include_lib("common_test/include/ct.hrl").
all() ->
diff --git a/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
new file mode 100644
index 0000000000..17c3acd6af
--- /dev/null
+++ b/lib/hipe/test/maps_SUITE_data/maps_redundant_branch_is_key.erl
@@ -0,0 +1,14 @@
+-module(maps_redundant_branch_is_key).
+-export([test/0]).
+
+test() ->
+ ok = thingy(#{a => 1}),
+ ok = thingy(#{a => 2}),
+ ok.
+
+thingy(Map) ->
+ try
+ #{a := _} = Map,
+ ok
+ catch _ -> error
+ end.
diff --git a/lib/hipe/test/opt_verify_SUITE.erl b/lib/hipe/test/opt_verify_SUITE.erl
index 61952e81d7..86083fa02b 100644
--- a/lib/hipe/test/opt_verify_SUITE.erl
+++ b/lib/hipe/test/opt_verify_SUITE.erl
@@ -1,6 +1,9 @@
-module(opt_verify_SUITE).
--compile([export_all]).
+-export([all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ call_elim/0, call_elim/1]).
all() ->
[call_elim].
@@ -23,23 +26,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-call_elim_test_file(Config, FileName, Option) ->
- PrivDir = test_server:lookup_config(priv_dir, Config),
- TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
- {ok, TestCase} = compile:file(FileName),
- {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
- {ok, Icode} = file:read_file(TempOut),
- ok = file:delete(TempOut),
- Icode.
-
-substring_count(Icode, Substring) ->
- substring_count(Icode, Substring, 0).
-substring_count(Icode, Substring, N) ->
- case string:str(Icode, Substring) of
- 0 -> N;
- I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
- end.
-
call_elim() ->
[{doc, "Test that the call elimination optimization pass is ok"}].
call_elim(Config) ->
@@ -60,3 +46,20 @@ call_elim(Config) ->
Icode6 = call_elim_test_file(Config, F3, no_icode_call_elim),
3 = substring_count(binary:bin_to_list(Icode6), "is_key"),
ok.
+
+call_elim_test_file(Config, FileName, Option) ->
+ PrivDir = test_server:lookup_config(priv_dir, Config),
+ TempOut = test_server:temp_name(filename:join(PrivDir, "call_elim_out")),
+ {ok, TestCase} = compile:file(FileName),
+ {ok, TestCase} = hipe:c(TestCase, [Option, {pp_range_icode, {file, TempOut}}]),
+ {ok, Icode} = file:read_file(TempOut),
+ ok = file:delete(TempOut),
+ Icode.
+
+substring_count(Icode, Substring) ->
+ substring_count(Icode, Substring, 0).
+substring_count(Icode, Substring, N) ->
+ case string:str(Icode, Substring) of
+ 0 -> N;
+ I -> substring_count(lists:nthtail(I, Icode), Substring, N+1)
+ end.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index f00ff0cf2e..cb4174381a 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.15.2
+HIPE_VSN = 3.15.3
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index 8e0301c520..696b7dfa31 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2012</year><year>2015</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -118,7 +118,7 @@
<v>Option = {ipv6_host_with_brackets, boolean()} |
{scheme_defaults, scheme_defaults()} |
{fragment, boolean()} |
- {schema_validation_fun, fun()}]</v>
+ {scheme_validation_fun, fun()}]</v>
<v>Result = {Scheme, UserInfo, Host, Port, Path, Query} |
{Scheme, UserInfo, Host, Port, Path, Query, Fragment}</v>
<v>UserInfo = user_info()</v>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 705afec022..4217b3c4fb 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -83,7 +83,7 @@
<title>HTTP DATA TYPES</title>
<p>Type definitions related to HTTP:</p>
- <p><c>method() = head | get | put | post | trace | options | delete</c></p>
+ <p><c>method() = head | get | put | post | trace | options | delete | patch</c></p>
<taglist>
<tag><c>request()</c></tag>
<item><p>= <c>{url(), headers()}</c></p>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 0c7604ef65..398fc7e5b6 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,66 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.3.3</title>
+ <section><title>Inets 6.3.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixes a bug that makes the ftp client end up in bad state
+ if there is a multi line response from the server and the
+ response number is in the message being sent.</p>
+ <p>
+ Own Id: OTP-13960 Aux Id: PR1196 </p>
+ </item>
+ <item>
+ <p>
+ The ftp client could stop consuming messages when the
+ multiline response handling was corrected.</p>
+ <p>
+ Own Id: OTP-13967</p>
+ </item>
+ <item>
+ <p>
+ Fix keep-alive https through proxy connections so that
+ all requests, following the first one, will run as
+ expected instead of failing.</p>
+ <p>
+ Own Id: OTP-14041</p>
+ </item>
+ <item>
+ <p>
+ Fix bug from commit
+ fdfda2fab0921d409789174556582db28141448e that could make
+ listing of group members in mod_auth callbacks fail.</p>
+ <p>
+ Own Id: OTP-14082</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update behavior of httpc:request to match RFC-7231</p>
+ <p>
+ Own Id: OTP-13902</p>
+ </item>
+ <item>
+ <p>
+ Fixed dialyzer warnings as well as some white-space
+ issues. Thanks to Kostis.</p>
+ <p>
+ Own Id: OTP-13982 Aux Id: PR-1207 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 91d87289a2..bd5f6df39e 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -147,6 +147,26 @@ request(Method, Request, HttpOptions, Options) ->
request(Method, Request, HttpOptions, Options, default_profile()).
request(Method,
+ {Url, Headers, ContentType, TupleBody},
+ HTTPOptions, Options, Profile)
+ when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
+ andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
+ is_list(ContentType) andalso is_tuple(TupleBody)->
+ case check_body_gen(TupleBody) of
+ ok ->
+ do_request(Method, {Url, Headers, ContentType, TupleBody}, HTTPOptions, Options, Profile);
+ Error ->
+ Error
+ end;
+request(Method,
+ {Url, Headers, ContentType, Body},
+ HTTPOptions, Options, Profile)
+ when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse (Method =:= delete))
+ andalso (is_atom(Profile) orelse is_pid(Profile)) andalso
+ is_list(ContentType) andalso (is_list(Body) orelse is_binary(Body)) ->
+ do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile);
+
+request(Method,
{Url, Headers},
HTTPOptions, Options, Profile)
when (Method =:= options) orelse
@@ -155,12 +175,6 @@ request(Method,
(Method =:= delete) orelse
(Method =:= trace) andalso
(is_atom(Profile) orelse is_pid(Profile)) ->
- ?hcrt("request", [{method, Method},
- {url, Url},
- {headers, Headers},
- {http_options, HTTPOptions},
- {options, Options},
- {profile, Profile}]),
case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
@@ -172,21 +186,9 @@ request(Method,
handle_request(Method, Url, ParsedUrl, Headers, [], [],
HTTPOptions, Options, Profile)
end
- end;
-
-request(Method,
- {Url, Headers, ContentType, Body},
- HTTPOptions, Options, Profile)
- when ((Method =:= post) orelse (Method =:= patch) orelse (Method =:= put) orelse
- (Method =:= delete)) andalso (is_atom(Profile) orelse is_pid(Profile)) ->
- ?hcrt("request", [{method, Method},
- {url, Url},
- {headers, Headers},
- {content_type, ContentType},
- {body, Body},
- {http_options, HTTPOptions},
- {options, Options},
- {profile, Profile}]),
+ end.
+
+do_request(Method, {Url, Headers, ContentType, Body}, HTTPOptions, Options, Profile) ->
case uri_parse(Url, Options) of
{error, Reason} ->
{error, Reason};
@@ -196,7 +198,6 @@ request(Method,
HTTPOptions, Options, Profile)
end.
-
%%--------------------------------------------------------------------------
%% cancel_request(RequestId) -> ok
%% cancel_request(RequestId, Profile) -> ok
@@ -209,7 +210,6 @@ cancel_request(RequestId) ->
cancel_request(RequestId, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("cancel request", [{request_id, RequestId}, {profile, Profile}]),
httpc_manager:cancel_request(RequestId, profile_name(Profile)).
@@ -232,7 +232,6 @@ cancel_request(RequestId, Profile)
set_options(Options) ->
set_options(Options, default_profile()).
set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("set options", [{options, Options}, {profile, Profile}]),
case validate_options(Options) of
{ok, Opts} ->
httpc_manager:set_options(Opts, profile_name(Profile));
@@ -272,7 +271,6 @@ get_options(all = _Options, Profile) ->
get_options(Options, Profile)
when (is_list(Options) andalso
(is_atom(Profile) orelse is_pid(Profile))) ->
- ?hcrt("get options", [{options, Options}, {profile, Profile}]),
case Options -- get_options() of
[] ->
try
@@ -314,9 +312,6 @@ store_cookies(SetCookieHeaders, Url) ->
store_cookies(SetCookieHeaders, Url, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
- ?hcrt("store cookies", [{set_cookie_headers, SetCookieHeaders},
- {url, Url},
- {profile, Profile}]),
try
begin
%% Since the Address part is not actually used
@@ -353,9 +348,6 @@ cookie_header(Url, Opts) when is_list(Opts) ->
cookie_header(Url, Opts, Profile)
when (is_list(Opts) andalso (is_atom(Profile) orelse is_pid(Profile))) ->
- ?hcrt("cookie header", [{url, Url},
- {opts, Opts},
- {profile, Profile}]),
try
begin
httpc_manager:which_cookies(Url, Opts, profile_name(Profile))
@@ -398,7 +390,6 @@ which_sessions() ->
which_sessions(default_profile()).
which_sessions(Profile) ->
- ?hcrt("which sessions", [{profile, Profile}]),
try
begin
httpc_manager:which_sessions(profile_name(Profile))
@@ -419,7 +410,6 @@ info() ->
info(default_profile()).
info(Profile) ->
- ?hcrt("info", [{profile, Profile}]),
try
begin
httpc_manager:info(profile_name(Profile))
@@ -440,7 +430,6 @@ reset_cookies() ->
reset_cookies(default_profile()).
reset_cookies(Profile) ->
- ?hcrt("reset cookies", [{profile, Profile}]),
try
begin
httpc_manager:reset_cookies(profile_name(Profile))
@@ -458,7 +447,6 @@ reset_cookies(Profile) ->
%% same behavior as active once for sockets.
%%-------------------------------------------------------------------------
stream_next(Pid) ->
- ?hcrt("stream next", [{handler, Pid}]),
httpc_handler:stream_next(Pid).
@@ -466,7 +454,6 @@ stream_next(Pid) ->
%%% Behaviour callbacks
%%%========================================================================
start_standalone(PropList) ->
- ?hcrt("start standalone", [{proplist, PropList}]),
case proplists:get_value(profile, PropList) of
undefined ->
{error, no_profile};
@@ -477,14 +464,11 @@ start_standalone(PropList) ->
end.
start_service(Config) ->
- ?hcrt("start service", [{config, Config}]),
httpc_profile_sup:start_child(Config).
stop_service(Profile) when is_atom(Profile) ->
- ?hcrt("stop service", [{profile, Profile}]),
httpc_profile_sup:stop_child(Profile);
stop_service(Pid) when is_pid(Pid) ->
- ?hcrt("stop service", [{pid, Pid}]),
case service_info(Pid) of
{ok, [{profile, Profile}]} ->
stop_service(Profile);
@@ -510,7 +494,6 @@ service_info(Pid) ->
%%%========================================================================
%%% Internal functions
%%%========================================================================
-
handle_request(Method, Url,
{Scheme, UserInfo, Host, Port, Path, Query},
Headers0, ContentType, Body0,
@@ -521,9 +504,6 @@ handle_request(Method, Url,
try
begin
- ?hcrt("begin processing", [{started, Started},
- {new_headers, NewHeaders0}]),
-
{NewHeaders, Body} =
case Body0 of
{chunkify, ProcessBody, Acc}
@@ -575,16 +555,13 @@ handle_request(Method, Url,
{ok, RequestId} ->
handle_answer(RequestId, Sync, Options);
{error, Reason} ->
- ?hcrd("request failed", [{reason, Reason}]),
{error, Reason}
end
end
catch
error:{noproc, _} ->
- ?hcrv("noproc", [{profile, Profile}]),
{error, {not_started, Profile}};
throw:Error ->
- ?hcrv("throw", [{error, Error}]),
Error
end.
@@ -620,15 +597,10 @@ handle_answer(RequestId, false, _) ->
handle_answer(RequestId, true, Options) ->
receive
{http, {RequestId, saved_to_file}} ->
- ?hcrt("received saved-to-file", [{request_id, RequestId}]),
{ok, saved_to_file};
{http, {RequestId, {_,_,_} = Result}} ->
- ?hcrt("received answer", [{request_id, RequestId},
- {result, Result}]),
return_answer(Options, Result);
{http, {RequestId, {error, Reason}}} ->
- ?hcrt("received error", [{request_id, RequestId},
- {reason, Reason}]),
{error, Reason}
end.
@@ -1257,18 +1229,14 @@ child_name(Pid, [{Name, Pid} | _]) ->
child_name(Pid, [_ | Children]) ->
child_name(Pid, Children).
-%% d(F) ->
-%% d(F, []).
-
-%% d(F, A) ->
-%% d(get(dbg), F, A).
-
-%% d(true, F, A) ->
-%% io:format(user, "~w:~w:" ++ F ++ "~n", [self(), ?MODULE | A]);
-%% d(_, _, _) ->
-%% ok.
-
host_address(Host, false) ->
Host;
host_address(Host, true) ->
string:strip(string:strip(Host, right, $]), left, $[).
+
+check_body_gen({Fun, _}) when is_function(Fun) ->
+ ok;
+check_body_gen({chunkify, Fun, _}) when is_function(Fun) ->
+ ok;
+check_body_gen(Gen) ->
+ {error, {bad_body_generator, Gen}}.
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 59cb1299e9..c99200777b 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
%% Internal Application API
-export([
start_link/4,
- %% connect_and_send/2,
send/2,
cancel/2,
stream_next/1,
@@ -165,14 +164,12 @@ info(Pid) ->
%%--------------------------------------------------------------------
%% Request should not be streamed
stream(BodyPart, #request{stream = none} = Request, _) ->
- ?hcrt("stream - none", []),
{false, BodyPart, Request};
%% Stream to caller
stream(BodyPart, #request{stream = Self} = Request, Code)
when ?IS_STREAMED(Code) andalso
((Self =:= self) orelse (Self =:= {self, once})) ->
- ?hcrt("stream - self", [{stream, Self}, {code, Code}]),
httpc_response:send(Request#request.from,
{Request#request.id, stream, BodyPart}),
{true, <<>>, Request};
@@ -182,10 +179,8 @@ stream(BodyPart, #request{stream = Self} = Request, Code)
%% We keep this for backward compatibillity...
stream(BodyPart, #request{stream = Filename} = Request, Code)
when ?IS_STREAMED(Code) andalso is_list(Filename) ->
- ?hcrt("stream - filename", [{stream, Filename}, {code, Code}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
{ok, Fd} ->
- ?hcrt("stream - file open ok", [{fd, Fd}]),
stream(BodyPart, Request#request{stream = Fd}, 200);
{error, Reason} ->
exit({stream_to_file_failed, Reason})
@@ -194,7 +189,6 @@ stream(BodyPart, #request{stream = Filename} = Request, Code)
%% Stream to file
stream(BodyPart, #request{stream = Fd} = Request, Code)
when ?IS_STREAMED(Code) ->
- ?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
ok ->
{true, <<>>, Request};
@@ -203,7 +197,6 @@ stream(BodyPart, #request{stream = Fd} = Request, Code)
end;
stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
- ?hcrt("stream - ignore", [{request, Request}]),
{false, BodyPart, Request}.
@@ -257,22 +250,148 @@ init([Parent, Request, Options, ProfileName]) ->
%% {stop, Reason, State} (terminate/2 is called)
%% Description: Handling call messages
%%--------------------------------------------------------------------
-handle_call(#request{address = Addr} = Request, _,
+handle_call(Request, From, State) ->
+ try do_handle_call(Request, From, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ try do_handle_cast(Msg, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info(Info, State) ->
+ try do_handle_info(Info, State) of
+ Result ->
+ Result
+ catch
+ _:Reason ->
+ {stop, {shutdown, Reason} , State}
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: terminate(Reason, State) -> _ (ignored by gen_server)
+%% Description: Shutdown the httpc_handler
+%%--------------------------------------------------------------------
+
+%% Init error there is no socket to be closed.
+terminate(normal,
+ #state{request = Request,
+ session = {send_failed, _} = Reason} = State) ->
+ maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ ok;
+
+terminate(normal,
+ #state{request = Request,
+ session = {connect_failed, _} = Reason} = State) ->
+ maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ ok;
+
+terminate(normal, #state{session = undefined}) ->
+ ok;
+
+%% Init error sending, no session information has been setup but
+%% there is a socket that needs closing.
+terminate(normal,
+ #state{session = #session{id = undefined} = Session}) ->
+ close_socket(Session);
+
+%% Socket closed remotely
+terminate(normal,
+ #state{session = #session{socket = {remote_close, Socket},
+ socket_type = SocketType,
+ id = Id},
+ profile_name = ProfileName,
+ request = Request,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
+ %% Clobber session
+ (catch httpc_manager:delete_session(Id, ProfileName)),
+
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
+ %% Cancel timers
+ cancel_timers(Timers),
+
+ %% Maybe deliver answers to requests
+ deliver_answer(Request),
+
+ %% And, just in case, close our side (**really** overkill)
+ http_transport:close(SocketType, Socket);
+
+terminate(_Reason, #state{session = #session{id = Id,
+ socket = Socket,
+ socket_type = SocketType},
+ request = undefined,
+ profile_name = ProfileName,
+ timers = Timers,
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
+
+ %% Clobber session
+ (catch httpc_manager:delete_session(Id, ProfileName)),
+
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
+ cancel_timer(Timers#timers.queue_timer, timeout_queue),
+ http_transport:close(SocketType, Socket);
+
+terminate(_Reason, #state{request = undefined}) ->
+ ok;
+
+terminate(Reason, #state{request = Request} = State) ->
+ NewState = maybe_send_answer(Request,
+ httpc_response:error(Request, Reason),
+ State),
+ terminate(Reason, NewState#state{request = undefined}).
+
+%%--------------------------------------------------------------------
+%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
+%% Purpose: Convert process state when code is changed
+%%--------------------------------------------------------------------
+
+code_change(_, State, _) ->
+ {ok, State}.
+
+%%%--------------------------------------------------------------------
+%%% Internal functions
+%%%--------------------------------------------------------------------
+do_handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #session{type = pipeline} = Session,
timers = Timers,
options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State0)
when Status =/= undefined ->
-
- ?hcrv("new request on a pipeline session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status},
- {timers, Timers}]),
-
Address = handle_proxy(Addr, Proxy),
-
case httpc_request:send(Address, Session, Request) of
ok ->
@@ -287,9 +406,8 @@ handle_call(#request{address = Addr} = Request, _,
case State0#state.request of
#request{} = OldRequest -> %% Old request not yet finished
- ?hcrd("old request still not finished", []),
%% Make sure to use the new value of timers in state
- NewTimers = State1#state.timers,
+ NewTimers = State1#state.timers,
NewPipeline = queue:in(Request, State1#state.pipeline),
NewSession =
Session#session{queue_length =
@@ -297,7 +415,6 @@ handle_call(#request{address = Addr} = Request, _,
queue:len(NewPipeline) + 1,
client_close = ClientClose},
insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
{reply, ok, State1#state{
request = OldRequest,
pipeline = NewPipeline,
@@ -306,7 +423,6 @@ handle_call(#request{address = Addr} = Request, _,
undefined ->
%% Note: tcp-message receiving has already been
%% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewSession =
@@ -314,18 +430,16 @@ handle_call(#request{address = Addr} = Request, _,
client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
NewTimers = Timers#timers{queue_timer = undefined},
- ?hcrd("session created", []),
State = init_wait_for_response_state(Request, State1#state{session = NewSession,
timers = NewTimers}),
{reply, ok, State}
end;
{error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
NewPipeline = queue:in(Request, State0#state.pipeline),
- {stop, shutdown, {pipeline_failed, Reason}, State0#state{pipeline = NewPipeline}}
+ {stop, {shutdown, {pipeline_failed, Reason}}, State0#state{pipeline = NewPipeline}}
end;
-handle_call(#request{address = Addr} = Request, _,
+do_handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
session = #session{type = keep_alive} = Session,
timers = Timers,
@@ -333,17 +447,11 @@ handle_call(#request{address = Addr} = Request, _,
profile_name = ProfileName} = State0)
when Status =/= undefined ->
- ?hcrv("new request on a keep-alive session",
- [{request, Request},
- {profile, ProfileName},
- {status, Status}]),
-
ClientClose = httpc_request:is_client_closing(Request#request.headers),
case State0#state.request of
#request{} -> %% Old request not yet finished
%% Make sure to use the new value of timers in state
- ?hcrd("old request still not finished", []),
NewKeepAlive = queue:in(Request, State0#state.keep_alive),
NewSession =
Session#session{queue_length =
@@ -351,13 +459,11 @@ handle_call(#request{address = Addr} = Request, _,
queue:len(NewKeepAlive) + 1,
client_close = ClientClose},
insert_session(NewSession, ProfileName),
- ?hcrd("session updated", []),
{reply, ok, State0#state{keep_alive = NewKeepAlive,
session = NewSession}};
undefined ->
%% Note: tcp-message receiving has already been
%% activated by handle_pipeline/2.
- ?hcrd("no current request", []),
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewTimers = Timers#timers{queue_timer = undefined},
@@ -365,8 +471,6 @@ handle_call(#request{address = Addr} = Request, _,
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcrd("request sent", []),
-
%% Activate the request time out for the new request
State2 =
activate_request_timeout(State1#state{request = Request}),
@@ -377,22 +481,13 @@ handle_call(#request{address = Addr} = Request, _,
State = init_wait_for_response_state(Request, State2#state{session = NewSession}),
{reply, ok, State};
{error, Reason} ->
- ?hcri("failed sending request", [{reason, Reason}]),
- {stop, shutdown, {keepalive_failed, Reason}, State1}
+ {stop, {shutdown, {keepalive_failed, Reason}}, State1}
end
end;
-
-handle_call(info, _, State) ->
+do_handle_call(info, _, State) ->
Info = handler_info(State),
{reply, Info, State}.
-%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%% Description: Handling cast messages
-%%--------------------------------------------------------------------
-
%% When the request in process has been canceled the handler process is
%% stopped and the pipelined requests will be reissued or remaining
%% requests will be sent on a new connection. This is is
@@ -405,145 +500,102 @@ handle_call(info, _, State) ->
%% handle_keep_alive_queue/2 on the other hand will just skip the
%% request as if it was never issued as in this case the request will
%% not have been sent.
-handle_cast({cancel, RequestId},
+do_handle_cast({cancel, RequestId},
#state{request = #request{id = RequestId} = Request,
- profile_name = ProfileName,
canceled = Canceled} = State) ->
- ?hcrv("cancel current request", [{request_id, RequestId},
- {profile, ProfileName},
- {canceled, Canceled}]),
{stop, normal,
State#state{canceled = [RequestId | Canceled],
request = Request#request{from = answer_sent}}};
-handle_cast({cancel, RequestId},
- #state{profile_name = ProfileName,
- request = #request{id = CurrId},
- canceled = Canceled} = State) ->
- ?hcrv("cancel", [{request_id, RequestId},
- {curr_req_id, CurrId},
- {profile, ProfileName},
- {canceled, Canceled}]),
+do_handle_cast({cancel, RequestId},
+ #state{request = #request{},
+ canceled = Canceled} = State) ->
{noreply, State#state{canceled = [RequestId | Canceled]}};
-handle_cast({cancel, RequestId},
- #state{profile_name = ProfileName,
- request = undefined,
- canceled = Canceled} = State) ->
- ?hcrv("cancel", [{request_id, RequestId},
- {curr_req_id, undefined},
- {profile, ProfileName},
- {canceled, Canceled}]),
+do_handle_cast({cancel, _},
+ #state{request = undefined} = State) ->
{noreply, State};
-
-handle_cast(stream_next, #state{session = Session} = State) ->
+do_handle_cast(stream_next, #state{session = Session} = State) ->
activate_once(Session),
%% Inactivate the #state.once here because we don't want
%% next_body_chunk/1 to activate the socket twice.
{noreply, State#state{once = inactive}}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
-handle_info({Proto, _Socket, Data},
+do_handle_info({Proto, _Socket, Data},
#state{mfa = {Module, Function, Args},
- request = #request{method = Method,
- stream = Stream} = Request,
+ request = #request{method = Method} = Request,
session = Session,
status_line = StatusLine} = State)
when (Proto =:= tcp) orelse
(Proto =:= ssl) orelse
(Proto =:= httpc_handler) ->
- ?hcri("received data", [{proto, Proto},
- {module, Module},
- {function, Function},
- {method, Method},
- {stream, Stream},
- {session, Session},
- {status_line, StatusLine}]),
-
- FinalResult =
- try Module:Function([Data | Args]) of
- {ok, Result} ->
- ?hcrd("data processed - ok", []),
- handle_http_msg(Result, State);
- {_, whole_body, _} when Method =:= head ->
- ?hcrd("data processed - whole body", []),
- handle_response(State#state{body = <<>>});
- {Module, whole_body, [Body, Length]} ->
- ?hcrd("data processed - whole body", [{length, Length}]),
- {_, Code, _} = StatusLine,
- {Streamed, NewBody, NewRequest} = stream(Body, Request, Code),
- %% When we stream we will not keep the already
- %% streamed data, that would be a waste of memory.
- NewLength =
- case Streamed of
- false ->
- Length;
- true ->
- Length - size(Body)
- end,
-
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, whole_body, [NewBody, NewLength]},
- {noreply, NewState#state{mfa = NewMFA,
- request = NewRequest}};
- {Module, decode_size,
- [TotalChunk, HexList,
+ try Module:Function([Data | Args]) of
+ {ok, Result} ->
+ handle_http_msg(Result, State);
+ {_, whole_body, _} when Method =:= head ->
+ handle_response(State#state{body = <<>>});
+ {Module, whole_body, [Body, Length]} ->
+ {_, Code, _} = StatusLine,
+ {Streamed, NewBody, NewRequest} = stream(Body, Request, Code),
+ %% When we stream we will not keep the already
+ %% streamed data, that would be a waste of memory.
+ NewLength =
+ case Streamed of
+ false ->
+ Length;
+ true ->
+ Length - size(Body)
+ end,
+
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, whole_body, [NewBody, NewLength]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ {Module, decode_size,
+ [TotalChunk, HexList, AccHeaderSize,
{MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
- when BodySoFar =/= <<>> ->
- ?hcrd("data processed - decode_size", []),
- %% The response body is chunk-encoded. Steal decoded
- %% chunks as much as possible to stream.
- {_, Code, _} = StatusLine,
- {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code),
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, decode_size,
- [TotalChunk, HexList,
+ when BodySoFar =/= <<>> ->
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ {_, Code, _} = StatusLine,
+ {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code),
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, decode_size,
+ [TotalChunk, HexList, AccHeaderSize,
{MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ {Module, decode_data,
+ [ChunkSize, TotalChunk,
+ {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
+ when TotalChunk =/= <<>> orelse BodySoFar =/= <<>> ->
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ ChunkSizeToSteal = min(ChunkSize, byte_size(TotalChunk)),
+ <<StolenChunk:ChunkSizeToSteal/binary, NewTotalChunk/binary>> = TotalChunk,
+ StolenBody = <<BodySoFar/binary, StolenChunk/binary>>,
+ NewChunkSize = ChunkSize - ChunkSizeToSteal,
+ {_, Code, _} = StatusLine,
+
+ {_, NewBody, NewRequest} = stream(StolenBody, Request, Code),
+ NewState = next_body_chunk(State, Code),
+ NewMFA = {Module, decode_data,
+ [NewChunkSize, NewTotalChunk,
+ {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
{noreply, NewState#state{mfa = NewMFA,
request = NewRequest}};
- {Module, decode_data,
- [ChunkSize, TotalChunk,
- {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
- when TotalChunk =/= <<>> orelse BodySoFar =/= <<>> ->
- ?hcrd("data processed - decode_data", []),
- %% The response body is chunk-encoded. Steal decoded
- %% chunks as much as possible to stream.
- ChunkSizeToSteal = min(ChunkSize, byte_size(TotalChunk)),
- <<StolenChunk:ChunkSizeToSteal/binary, NewTotalChunk/binary>> = TotalChunk,
- StolenBody = <<BodySoFar/binary, StolenChunk/binary>>,
- NewChunkSize = ChunkSize - ChunkSizeToSteal,
- {_, Code, _} = StatusLine,
-
- {_, NewBody, NewRequest} = stream(StolenBody, Request, Code),
- NewState = next_body_chunk(State, Code),
- NewMFA = {Module, decode_data,
- [NewChunkSize, NewTotalChunk,
- {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
- {noreply, NewState#state{mfa = NewMFA,
- request = NewRequest}};
- NewMFA ->
- ?hcrd("data processed - new mfa", []),
- activate_once(Session),
- {noreply, State#state{mfa = NewMFA}}
- catch
- _:_Reason ->
- ?hcrd("data processing exit", [{exit, _Reason}]),
- ClientReason = {could_not_parse_as_http, Data},
- ClientErrMsg = httpc_response:error(Request, ClientReason),
- NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState}
- end,
- ?hcri("data processed", [{final_result, FinalResult}]),
- FinalResult;
-
+ NewMFA ->
+ activate_once(Session),
+ {noreply, State#state{mfa = NewMFA}}
+ catch
+ _:Reason ->
+ ClientReason = {could_not_parse_as_http, Data},
+ ClientErrMsg = httpc_response:error(Request, ClientReason),
+ NewState = answer_request(Request, ClientErrMsg, State),
+ {stop, {shutdown, Reason}, NewState}
+ end;
-handle_info({Proto, Socket, Data},
+do_handle_info({Proto, Socket, Data},
#state{mfa = MFA,
request = Request,
session = Session,
@@ -568,200 +620,107 @@ handle_info({Proto, Socket, Data},
{noreply, State};
-
%% The Server may close the connection to indicate that the
%% whole body is now sent instead of sending an length
%% indicator.
-handle_info({tcp_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
+do_handle_info({tcp_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
handle_response(State#state{body = hd(Args)});
-handle_info({ssl_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
+do_handle_info({ssl_closed, _}, State = #state{mfa = {_, whole_body, Args}}) ->
handle_response(State#state{body = hd(Args)});
%%% Server closes idle pipeline
-handle_info({tcp_closed, _}, State = #state{request = undefined}) ->
+do_handle_info({tcp_closed, _}, State = #state{request = undefined}) ->
{stop, normal, State};
-handle_info({ssl_closed, _}, State = #state{request = undefined}) ->
+do_handle_info({ssl_closed, _}, State = #state{request = undefined}) ->
{stop, normal, State};
%%% Error cases
-handle_info({tcp_closed, _}, #state{session = Session0} = State) ->
+do_handle_info({tcp_closed, _}, #state{session = Session0} = State) ->
Socket = Session0#session.socket,
Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
-handle_info({ssl_closed, _}, #state{session = Session0} = State) ->
+do_handle_info({ssl_closed, _}, #state{session = Session0} = State) ->
Socket = Session0#session.socket,
Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
-handle_info({tcp_error, _, _} = Reason, State) ->
+do_handle_info({tcp_error, _, _} = Reason, State) ->
{stop, Reason, State};
-handle_info({ssl_error, _, _} = Reason, State) ->
+do_handle_info({ssl_error, _, _} = Reason, State) ->
{stop, Reason, State};
%% Timeouts
%% Internally, to a request handling process, a request timeout is
%% seen as a canceled request.
-handle_info({timeout, RequestId},
+do_handle_info({timeout, RequestId},
#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},
+do_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
httpc_response:send(From,
httpc_response:error(Request, timeout)),
httpc_manager:request_done(RequestId, ProfileName),
- ?hcrv("response (timeout) sent", []),
[Request#request{from = answer_sent}];
(_) ->
true
end,
case State#state.status of
pipeline ->
- ?hcrd("pipeline", []),
Pipeline = queue:filter(Filter, State#state.pipeline),
{noreply, State#state{canceled = [RequestId | Canceled],
pipeline = Pipeline}};
keep_alive ->
- ?hcrd("keep_alive", []),
KeepAlive = queue:filter(Filter, State#state.keep_alive),
{noreply, State#state{canceled = [RequestId | Canceled],
keep_alive = KeepAlive}}
end;
-handle_info(timeout_queue, State = #state{request = undefined}) ->
+do_handle_info(timeout_queue, State = #state{request = undefined}) ->
{stop, normal, State};
%% Timing was such as the queue_timeout was not canceled!
-handle_info(timeout_queue, #state{timers = Timers} = State) ->
+do_handle_info(timeout_queue, #state{timers = Timers} = State) ->
{noreply, State#state{timers =
Timers#timers{queue_timer = undefined}}};
%% Setting up the connection to the server somehow failed.
-handle_info({init_error, Tag, ClientErrMsg},
+do_handle_info({init_error, Reason, ClientErrMsg},
State = #state{request = Request}) ->
- ?hcrv("init error", [{tag, Tag}, {client_error, ClientErrMsg}]),
NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState};
-
+ {stop, {shutdown, Reason}, NewState};
%%% httpc_manager process dies.
-handle_info({'EXIT', _, _}, State = #state{request = undefined}) ->
+do_handle_info({'EXIT', _, _}, State = #state{request = undefined}) ->
{stop, normal, State};
%%Try to finish the current request anyway,
%% there is a fairly high probability that it can be done successfully.
%% Then close the connection, hopefully a new manager is started that
%% can retry requests in the pipeline.
-handle_info({'EXIT', _, _}, State) ->
+do_handle_info({'EXIT', _, _}, State) ->
{noreply, State#state{status = close}}.
-%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> _ (ignored by gen_server)
-%% Description: Shutdown the httpc_handler
-%%--------------------------------------------------------------------
-
-%% Init error there is no socket to be closed.
-terminate(normal,
- #state{request = Request,
- session = {send_failed, AReason} = Reason} = State) ->
- ?hcrd("terminate", [{send_reason, AReason}, {request, Request}]),
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
-terminate(normal,
- #state{request = Request,
- session = {connect_failed, AReason} = Reason} = State) ->
- ?hcrd("terminate", [{connect_reason, AReason}, {request, Request}]),
- maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- ok;
-
-terminate(normal, #state{session = undefined}) ->
- ok;
-
-%% Init error sending, no session information has been setup but
-%% there is a socket that needs closing.
-terminate(normal,
- #state{session = #session{id = undefined} = Session}) ->
- close_socket(Session);
-
-%% Socket closed remotely
-terminate(normal,
- #state{session = #session{socket = {remote_close, Socket},
- socket_type = SocketType,
- id = Id},
- profile_name = ProfileName,
- request = Request,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
- ?hcrt("terminate(normal) - remote close",
- [{id, Id}, {profile, ProfileName}]),
-
- %% Clobber session
- (catch httpc_manager:delete_session(Id, ProfileName)),
-
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
-
- %% Cancel timers
- cancel_timers(Timers),
-
- %% Maybe deliver answers to requests
- deliver_answer(Request),
-
- %% And, just in case, close our side (**really** overkill)
- http_transport:close(SocketType, Socket);
-
-terminate(Reason, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
- request = undefined,
- profile_name = ProfileName,
- timers = Timers,
- pipeline = Pipeline,
- keep_alive = KeepAlive} = State) ->
- ?hcrt("terminate",
- [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
-
- %% Clobber session
- (catch httpc_manager:delete_session(Id, ProfileName)),
-
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
-
- cancel_timer(Timers#timers.queue_timer, timeout_queue),
- http_transport:close(SocketType, Socket);
+call(Msg, Pid) ->
+ call(Msg, Pid, infinity).
-terminate(Reason, #state{request = undefined}) ->
- ?hcrt("terminate", [{reason, Reason}]),
- ok;
+call(Msg, Pid, Timeout) ->
+ gen_server:call(Pid, Msg, Timeout).
-terminate(Reason, #state{request = Request} = State) ->
- ?hcrd("terminate", [{reason, Reason}, {request, Request}]),
- NewState = maybe_send_answer(Request,
- httpc_response:error(Request, Reason),
- State),
- terminate(Reason, NewState#state{request = undefined}).
+cast(Msg, Pid) ->
+ gen_server:cast(Pid, Msg).
maybe_retry_queue(Q, State) ->
case queue:is_empty(Q) of
@@ -776,45 +735,13 @@ maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
maybe_send_answer(Request, Answer, State) ->
answer_request(Request, Answer, State).
-deliver_answer(#request{id = Id, from = From} = Request)
+deliver_answer(#request{from = From} = Request)
when is_pid(From) ->
Response = httpc_response:error(Request, socket_closed_remotely),
- ?hcrd("deliver answer", [{id, Id}, {from, From}, {response, Response}]),
httpc_response:send(From, Response);
-deliver_answer(Request) ->
- ?hcrd("skip deliver answer", [{request, Request}]),
+deliver_answer(_Request) ->
ok.
-
-%%--------------------------------------------------------------------
-%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
-%% Purpose: Convert process state when code is changed
-%%--------------------------------------------------------------------
-
-code_change(_, State, _) ->
- {ok, State}.
-
-
-%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
-%% Auth, Relaxed}) ->
-%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
-%% Auth, Relaxed}.
-
-%% old_http_options({http_options, _, TimeOut, AutoRedirect,
-%% SslOpts, Auth, Relaxed}) ->
-%% {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
-
-%% new_queue(Queue, Fun) ->
-%% List = queue:to_list(Queue),
-%% NewList =
-%% lists:map(fun(Request) ->
-%% Settings =
-%% Fun(Request#request.settings),
-%% Request#request{settings = Settings}
-%% end, List),
-%% queue:from_list(NewList).
-
-
%%%--------------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
@@ -872,26 +799,21 @@ connect(SocketType, ToAddress,
connect_and_send_first_request(Address, Request, #state{options = Options} = State) ->
SocketType = socket_type(Request),
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
- ?hcri("connect",
- [{address, Address}, {request, Request}, {options, Options}]),
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
ClientClose =
- httpc_request:is_client_closing(
- Request#request.headers),
+ httpc_request:is_client_closing(
+ Request#request.headers),
SessionType = httpc_manager:session_type(Options),
SocketType = socket_type(Request),
Session = #session{id = {Request#request.address, self()},
scheme = Request#request.scheme,
socket = Socket,
- socket_type = SocketType,
- client_close = ClientClose,
- type = SessionType},
- ?hcri("connected - now send first request", [{socket, Socket}]),
-
+ socket_type = SocketType,
+ client_close = ClientClose,
+ type = SessionType},
case httpc_request:send(Address, Session, Request) of
ok ->
- ?hcri("first request sent", []),
TmpState = State#state{request = Request,
session = Session,
mfa = init_mfa(Request, State),
@@ -949,12 +871,6 @@ handler_info(#state{request = Request,
options = _Options,
timers = _Timers} = _State) ->
- ?hcrt("handler info", [{request, Request},
- {session, Session},
- {pipeline, Pipeline},
- {keep_alive, KeepAlive},
- {status, Status}]),
-
%% Info about the current request
RequestInfo =
case Request of
@@ -965,8 +881,6 @@ handler_info(#state{request = Request,
[{id, Id}, {started, ReqStarted}]
end,
- ?hcrt("handler info", [{request_info, RequestInfo}]),
-
%% Info about the current session/socket
SessionType = Session#session.type,
QueueLen = case SessionType of
@@ -979,22 +893,12 @@ handler_info(#state{request = Request,
Socket = Session#session.socket,
SocketType = Session#session.socket_type,
- ?hcrt("handler info", [{session_type, SessionType},
- {queue_length, QueueLen},
- {scheme, Scheme},
- {socket, Socket}]),
-
SocketOpts = http_transport:getopts(SocketType, Socket),
SocketStats = http_transport:getstat(SocketType, Socket),
Remote = http_transport:peername(SocketType, Socket),
Local = http_transport:sockname(SocketType, Socket),
- ?hcrt("handler info", [{remote, Remote},
- {local, Local},
- {socket_opts, SocketOpts},
- {socket_stats, SocketStats}]),
-
SocketInfo = [{remote, Remote},
{local, Local},
{socket_opts, SocketOpts},
@@ -1014,7 +918,6 @@ handler_info(#state{request = Request,
handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
State = #state{request = Request}) ->
- ?hcrt("handle_http_msg", [{headers, Headers}]),
case Headers#http_response_h.'content-type' of
"multipart/byteranges" ++ _Param ->
exit({not_yet_implemented, multypart_byteranges});
@@ -1028,15 +931,12 @@ handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
end;
handle_http_msg({ChunkedHeaders, Body},
#state{status_line = {_, Code, _}, headers = Headers} = State) ->
- ?hcrt("handle_http_msg",
- [{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
{_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{headers = NewHeaders,
body = NewBody,
request = NewRequest});
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
- ?hcrt("handle_http_msg", [{code, Code}]),
{_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{body = NewBody, request = NewRequest}).
@@ -1051,41 +951,28 @@ handle_http_body(_, #state{status = {ssl_tunnel, Request},
{stop, normal, NewState};
handle_http_body(<<>>, #state{status_line = {_,304, _}} = State) ->
- ?hcrt("handle_http_body - 304", []),
handle_response(State#state{body = <<>>});
handle_http_body(<<>>, #state{status_line = {_,204, _}} = State) ->
- ?hcrt("handle_http_body - 204", []),
handle_response(State#state{body = <<>>});
handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
- ?hcrt("handle_http_body - head", []),
handle_response(State#state{body = <<>>});
handle_http_body(Body, #state{headers = Headers,
max_body_size = MaxBodySize,
status_line = {_,Code, _},
request = Request} = State) ->
- ?hcrt("handle_http_body",
- [{max_body_size, MaxBodySize}, {headers, Headers}, {code, Code}]),
TransferEnc = Headers#http_response_h.'transfer-encoding',
case case_insensitive_header(TransferEnc) of
"chunked" ->
- ?hcrt("handle_http_body - chunked", []),
try http_chunk:decode(Body, State#state.max_body_size,
State#state.max_header_size) of
{Module, Function, Args} ->
- ?hcrt("handle_http_body - new mfa",
- [{module, Module},
- {function, Function},
- {args, Args}]),
NewState = next_body_chunk(State, Code),
{noreply, NewState#state{mfa =
{Module, Function, Args}}};
{ok, {ChunkedHeaders, NewBody}} ->
- ?hcrt("handle_http_body - new body",
- [{chunked_headers, ChunkedHeaders},
- {new_body, NewBody}]),
NewHeaders = http_chunk:handle_headers(Headers,
ChunkedHeaders),
case Body of
@@ -1107,7 +994,6 @@ handle_http_body(Body, #state{headers = Headers,
{stop, normal, NewState}
end;
Enc when Enc =:= "identity"; Enc =:= undefined ->
- ?hcrt("handle_http_body - identity", []),
Length =
list_to_integer(Headers#http_response_h.'content-length'),
case ((Length =< MaxBodySize) orelse (MaxBodySize =:= nolimit)) of
@@ -1131,7 +1017,6 @@ handle_http_body(Body, #state{headers = Headers,
{stop, normal, NewState}
end;
Encoding when is_list(Encoding) ->
- ?hcrt("handle_http_body - other", [{encoding, Encoding}]),
NewState = answer_request(Request,
httpc_response:error(Request,
unknown_encoding),
@@ -1152,18 +1037,10 @@ handle_response(#state{request = Request,
options = Options,
profile_name = ProfileName} = State)
when Status =/= new ->
-
- ?hcrd("handle response", [{profile, ProfileName},
- {status, Status},
- {request, Request},
- {session, Session},
- {status_line, StatusLine}]),
-
handle_cookies(Headers, Request, Options, ProfileName),
case httpc_response:result({StatusLine, Headers, Body}, Request) of
%% 100-continue
continue ->
- ?hcrd("handle response - continue", []),
%% Send request body
{_, RequestBody} = Request#request.content,
send_raw(Session, RequestBody),
@@ -1180,7 +1057,6 @@ handle_response(#state{request = Request,
%% Ignore unexpected 100-continue response and receive the
%% actual response that the server will send right away.
{ignore, Data} ->
- ?hcrd("handle response - ignore", [{data, Data}]),
Relaxed = (Request#request.settings)#http_options.relaxed,
MFA = {httpc_response, parse,
[State#state.max_header_size, Relaxed]},
@@ -1194,23 +1070,17 @@ handle_response(#state{request = Request,
%% obsolete and the manager will create a new request
%% with the same id as the current.
{redirect, NewRequest, Data} ->
- ?hcrt("handle response - redirect",
- [{new_request, NewRequest}, {data, Data}]),
ok = httpc_manager:redirect_request(NewRequest, ProfileName),
handle_queue(State#state{request = undefined}, Data);
{retry, TimeNewRequest, Data} ->
- ?hcrt("handle response - retry",
- [{time_new_request, TimeNewRequest}, {data, Data}]),
ok = httpc_manager:retry_request(TimeNewRequest, ProfileName),
handle_queue(State#state{request = undefined}, Data);
{ok, Msg, Data} ->
- ?hcrd("handle response - ok", []),
stream_remaining_body(Body, Request, StatusLine),
end_stream(StatusLine, Request),
NewState = maybe_send_answer(Request, Msg, State),
handle_queue(NewState, Data);
{stop, Msg} ->
- ?hcrd("handle response - stop", [{msg, Msg}]),
end_stream(StatusLine, Request),
NewState = maybe_send_answer(Request, Msg, State),
{stop, normal, NewState}
@@ -1245,28 +1115,19 @@ handle_pipeline(#state{status = pipeline,
profile_name = ProfileName,
options = #options{pipeline_timeout = TimeOut}} = State,
Data) ->
-
- ?hcrd("handle pipeline", [{profile, ProfileName},
- {session, Session},
- {timeout, TimeOut}]),
-
case queue:out(State#state.pipeline) of
{empty, _} ->
- ?hcrd("pipeline queue empty", []),
handle_empty_queue(Session, ProfileName, TimeOut, State);
{{value, NextRequest}, Pipeline} ->
- ?hcrd("pipeline queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
- ?hcrv("next request had been cancelled", []),
%% See comment for handle_cast({cancel, RequestId})
{stop, normal,
State#state{request =
NextRequest#request{from = answer_sent},
pipeline = Pipeline}};
false ->
- ?hcrv("next request", [{request, NextRequest}]),
NewSession =
Session#session{queue_length =
%% Queue + current
@@ -1283,25 +1144,16 @@ handle_keep_alive_queue(#state{status = keep_alive,
options = #options{keep_alive_timeout = TimeOut,
proxy = Proxy}} = State,
Data) ->
-
- ?hcrd("handle keep_alive", [{profile, ProfileName},
- {session, Session},
- {timeout, TimeOut}]),
-
case queue:out(State#state.keep_alive) of
{empty, _} ->
- ?hcrd("keep_alive queue empty", []),
handle_empty_queue(Session, ProfileName, TimeOut, State);
{{value, NextRequest}, KeepAlive} ->
- ?hcrd("keep_alive queue non-empty", []),
case lists:member(NextRequest#request.id,
State#state.canceled) of
true ->
- ?hcrv("next request has already been canceled", []),
handle_keep_alive_queue(
State#state{keep_alive = KeepAlive}, Data);
false ->
- ?hcrv("next request", [{request, NextRequest}]),
#request{address = Addr} = NextRequest,
Address = handle_proxy(Addr, Proxy),
case httpc_request:send(Address, Session, NextRequest) of
@@ -1314,7 +1166,6 @@ handle_keep_alive_queue(#state{status = keep_alive,
end
end
end.
-
handle_empty_queue(Session, ProfileName, TimeOut, State) ->
%% The server may choose too terminate an idle pipline| keep_alive session
%% in this case we want to receive the close message
@@ -1350,7 +1201,6 @@ init_wait_for_response_state(Request, State) ->
status_line = undefined,
headers = undefined,
body = undefined}.
-
gather_data(<<>>, Session, State) ->
activate_once(Session),
{noreply, State};
@@ -1381,10 +1231,6 @@ activate_request_timeout(
State;
_ ->
ReqId = Request#request.id,
- ?hcrt("activate request timer",
- [{request_id, ReqId},
- {time_consumed, t() - Request#request.started},
- {timeout, Timeout}]),
Msg = {timeout, ReqId},
Ref = erlang:send_after(Timeout, self(), Msg),
Request2 = Request#request{timer = Ref},
@@ -1427,10 +1273,6 @@ try_to_enable_pipeline_or_keep_alive(
status_line = {Version, _, _},
headers = Headers,
profile_name = ProfileName} = State) ->
- ?hcrd("try to enable pipeline or keep-alive",
- [{version, Version},
- {headers, Headers},
- {session, Session}]),
case is_keep_alive_enabled_server(Version, Headers) andalso
is_keep_alive_connection(Headers, Session) of
true ->
@@ -1455,7 +1297,6 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
#state{session = Session,
timers = Timers,
profile_name = ProfileName} = State) ->
- ?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
RequestTimers = Timers#timers.request_timers,
TimerRef =
@@ -1602,42 +1443,32 @@ socket_type(#request{scheme = http}) ->
ip_comm;
socket_type(#request{scheme = https, settings = Settings}) ->
Settings#http_options.ssl.
-%% socket_type(http) ->
-%% ip_comm;
-%% socket_type(https) ->
-%% {ssl1, []}. %% Dummy value ok for ex setopts that does not use this value
start_stream({_Version, _Code, _ReasonPhrase}, _Headers,
#request{stream = none} = Request) ->
- ?hcrt("start stream - none", []),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, Headers,
#request{stream = self} = Request)
when ?IS_STREAMED(Code) ->
- ?hcrt("start stream - self", [{code, Code}]),
Msg = httpc_response:stream_start(Headers, Request, ignore),
httpc_response:send(Request#request.from, Msg),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, Headers,
#request{stream = {self, once}} = Request)
when ?IS_STREAMED(Code) ->
- ?hcrt("start stream - self:once", [{code, Code}]),
Msg = httpc_response:stream_start(Headers, Request, self()),
httpc_response:send(Request#request.from, Msg),
{ok, Request};
start_stream({_Version, Code, _ReasonPhrase}, _Headers,
#request{stream = Filename} = Request)
when ?IS_STREAMED(Code) andalso is_list(Filename) ->
- ?hcrt("start stream", [{code, Code}, {filename, Filename}]),
case file:open(Filename, [write, raw, append, delayed_write]) of
{ok, Fd} ->
- ?hcri("start stream - file open ok", [{fd, Fd}]),
{ok, Request#request{stream = Fd}};
{error, Reason} ->
exit({stream_to_file_failed, Reason})
end;
start_stream(_StatusLine, _Headers, Request) ->
- ?hcrt("start stream - no op", []),
{ok, Request}.
stream_remaining_body(<<>>, _, _) ->
@@ -1648,16 +1479,12 @@ stream_remaining_body(Body, Request, {_, Code, _}) ->
%% Note the end stream message is handled by httpc_response and will
%% be sent by answer_request
end_stream(_, #request{stream = none}) ->
- ?hcrt("end stream - none", []),
ok;
end_stream(_, #request{stream = self}) ->
- ?hcrt("end stream - self", []),
ok;
end_stream(_, #request{stream = {self, once}}) ->
- ?hcrt("end stream - self:once", []),
ok;
end_stream({_,200,_}, #request{stream = Fd}) ->
- ?hcrt("end stream - 200", [{stream, Fd}]),
case file:close(Fd) of
ok ->
ok;
@@ -1665,15 +1492,13 @@ end_stream({_,200,_}, #request{stream = Fd}) ->
file:close(Fd)
end;
end_stream({_,206,_}, #request{stream = Fd}) ->
- ?hcrt("end stream - 206", [{stream, Fd}]),
case file:close(Fd) of
ok ->
ok;
{error, enospc} -> % Could be due to delayed_write
file:close(Fd)
end;
-end_stream(SL, R) ->
- ?hcrt("end stream", [{status_line, SL}, {request, R}]),
+end_stream(_, _) ->
ok.
@@ -1702,11 +1527,8 @@ handle_verbose(trace) ->
handle_verbose(_) ->
ok.
-
-
send_raw(#session{socket = Socket, socket_type = SocketType},
{ProcessBody, Acc}) when is_function(ProcessBody, 1) ->
- ?hcrt("send raw", [{acc, Acc}]),
send_raw(SocketType, Socket, ProcessBody, Acc);
send_raw(#session{socket = Socket, socket_type = SocketType}, Body) ->
http_transport:send(SocketType, Socket, Body).
@@ -1717,7 +1539,6 @@ send_raw(SocketType, Socket, ProcessBody, Acc) ->
ok;
{ok, Data, NewAcc} ->
DataBin = iolist_to_binary(Data),
- ?hcrd("send", [{data, DataBin}]),
case http_transport:send(SocketType, Socket, DataBin) of
ok ->
send_raw(SocketType, Socket, ProcessBody, NewAcc);
@@ -1749,14 +1570,16 @@ tls_tunnel(Address, Request, #state{session = #session{socket = Socket,
tls_tunnel_request(#request{headers = Headers,
settings = Options,
+ id = RequestId,
+ from = From,
address = {Host, Port}= Adress,
ipv6_host_with_brackets = IPV6}) ->
URI = Host ++":" ++ integer_to_list(Port),
#request{
- id = make_ref(),
- from = self(),
+ id = RequestId,
+ from = From,
scheme = http, %% Use tcp-first and then upgrade!
address = Adress,
path = URI,
@@ -1881,16 +1704,3 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
end.
-%% ---------------------------------------------------------------------
-
-call(Msg, Pid) ->
- call(Msg, Pid, infinity).
-
-call(Msg, Pid, Timeout) ->
- gen_server:call(Pid, Msg, Timeout).
-
-cast(Msg, Pid) ->
- gen_server:cast(Pid, Msg).
-
-t() ->
- http_util:timestamp().
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index e8d020c165..89872a3831 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -88,9 +88,11 @@ send(SendAddr, Socket, SocketType,
case Address of
SendAddr ->
{TmpHdrs2, Path ++ Query};
- _Proxy ->
+ _Proxy when SocketType == ip_comm ->
TmpHdrs3 = handle_proxy(HttpOptions, TmpHdrs2),
- {TmpHdrs3, AbsUri}
+ {TmpHdrs3, AbsUri};
+ _ ->
+ {TmpHdrs2, Path ++ Query}
end,
FinalHeaders =
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index d8bdac24e3..0fd5faa466 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -363,7 +363,7 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
%% Automatic redirection
{ok, {Scheme, _, Host, Port, Path, Query}} ->
NewHeaders =
- (Request#request.headers)#http_request_h{host = Host},
+ (Request#request.headers)#http_request_h{host = Host++":"++integer_to_list(Port)},
NewRequest =
Request#request{redircount =
Request#request.redircount+1,
diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl
index 991417cb36..ca1dad07cd 100644
--- a/lib/inets/src/http_lib/http_internal.hrl
+++ b/lib/inets/src/http_lib/http_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 1374b7e85e..effa273e92 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_auth_server.erl b/lib/inets/src/http_server/mod_auth_server.erl
index 93d8145821..90d9ee34b1 100644
--- a/lib/inets/src/http_server/mod_auth_server.erl
+++ b/lib/inets/src/http_server/mod_auth_server.erl
@@ -128,7 +128,7 @@ list_group_members(Addr, Port, Dir, Group, Password) ->
list_group_members(Addr, Port, ?DEFAULT_PROFILE, Dir, Group, Password).
list_group_members(Addr, Port, Profile, Dir, Group, Password) ->
Name = make_name(Addr, Port, Profile),
- Req = {list_group_members, Addr, Port, Dir, Group, Password},
+ Req = {list_group_members, Addr, Port, Profile, Dir, Group, Password},
call(Name, Req).
delete_group(Addr, Port, Dir, GroupName, Password) ->
diff --git a/lib/inets/src/inets_app/inets_lib.erl b/lib/inets/src/inets_app/inets_lib.erl
index 8993be29e4..3fae376a9f 100644
--- a/lib/inets/src/inets_app/inets_lib.erl
+++ b/lib/inets/src/inets_app/inets_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index a2b463e98c..4e10a97f58 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 57da82c6ad..8aea38037d 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -88,7 +88,8 @@ real_requests()->
stream_through_mfa,
streaming_error,
inet_opts,
- invalid_headers
+ invalid_headers,
+ invalid_body
].
only_simulated() ->
@@ -125,7 +126,9 @@ only_simulated() ->
redirect_see_other,
redirect_temporary_redirect,
port_in_host_header,
- relaxed
+ redirect_port_in_host_header,
+ relaxed,
+ multipart_chunks
].
misc() ->
@@ -1000,10 +1003,25 @@ invalid_headers(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), [{"cookie", undefined}]},
{error, _} = httpc:request(get, Request, [], []).
+%%-------------------------------------------------------------------------
+
+invalid_body(Config) ->
+ URL = url(group_name(Config), "/dummy.html", Config),
+ try
+ httpc:request(post, {URL, [], <<"text/plain">>, "foobar"},
+ [], []),
+ ct:fail(accepted_invalid_input)
+ catch
+ error:function_clause ->
+ ok
+ end.
+
+%%-------------------------------------------------------------------------
remote_socket_close(Config) when is_list(Config) ->
URL = url(group_name(Config), "/just_close.html", Config),
{error, socket_closed_remotely} = httpc:request(URL).
+
%%-------------------------------------------------------------------------
remote_socket_close_async(Config) when is_list(Config) ->
@@ -1102,7 +1120,20 @@ port_in_host_header(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/ensure_host_header_with_port.html", Config), []},
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
inets_test_lib:check_body(Body).
+%%-------------------------------------------------------------------------
+redirect_port_in_host_header(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/redirect_ensure_host_header_with_port.html", Config), []},
+ {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []),
+ inets_test_lib:check_body(Body).
+
+%%-------------------------------------------------------------------------
+multipart_chunks(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/multipart_chunks.html", Config), []},
+ {ok, Ref} = httpc:request(get, Request, [], [{sync, false}, {stream, self}]),
+ ok = receive_stream_n(Ref, 10),
+ httpc:cancel_request(Ref).
+
%%-------------------------------------------------------------------------
timeout_memory_leak() ->
[{doc, "Check OTP-8739"}].
@@ -1398,7 +1429,7 @@ dummy_server(Caller, SocketType, Inet, Extra) ->
end.
dummy_server_init(Caller, ip_comm, Inet, _) ->
- BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {active, false}],
+ BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {keepalive, true}, {active, false}],
{ok, ListenSocket} = gen_tcp:listen(0, [Inet | BaseOpts]),
{ok, Port} = inet:port(ListenSocket),
Caller ! {port, Port},
@@ -1680,6 +1711,12 @@ handle_uri(_,"/ensure_host_header_with_port.html",_,Headers,_,_) ->
"HTTP/1.1 500 Internal Server Error\r\n" ++
"Content-Length:" ++ Len ++ "\r\n\r\n" ++ B
end;
+handle_uri(_,"/redirect_ensure_host_header_with_port.html",Port,_,Socket,_) ->
+ NewUri = url_start(Socket) ++
+ integer_to_list(Port) ++ "/ensure_host_header_with_port.html",
+ "HTTP/1.1 302 Found \r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:0\r\n\r\n";
handle_uri(_,"/300.html",Port,_,Socket,_) ->
NewUri = url_start(Socket) ++
@@ -1968,6 +2005,16 @@ handle_uri(_,"/missing_CR.html",_,_,_,_) ->
"Content-Length:32\r\n\n" ++
"<HTML><BODY>foobar</BODY></HTML>";
+handle_uri(_,"/multipart_chunks.html",_,_,Socket,_) ->
+ Head = "HTTP/1.1 200 ok\r\n" ++
+ "Transfer-Encoding:chunked\r\n" ++
+ "Date: " ++ httpd_util:rfc1123_date() ++ "\r\n"
+ "Connection: Keep-Alive\r\n" ++
+ "Content-Type: multipart/x-mixed-replace; boundary=chunk_boundary\r\n" ++
+ "\r\n",
+ send(Socket, Head),
+ send_multipart_chunks(Socket),
+ http_chunk:encode_last();
handle_uri("HEAD",_,_,_,_,_) ->
"HTTP/1.1 200 ok\r\n" ++
"Content-Length:0\r\n\r\n";
@@ -2264,3 +2311,21 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) ->
Error ->
exit(Error)
end.
+
+send_multipart_chunks(Socket) ->
+ send(Socket, http_chunk:encode("--chunk_boundary\r\n")),
+ send(Socket, http_chunk:encode("Content-Type: text/plain\r\nContent-Length: 4\r\n\r\n")),
+ send(Socket, http_chunk:encode("test\r\n")),
+ ct:sleep(500),
+ send_multipart_chunks(Socket).
+
+receive_stream_n(_, 0) ->
+ ok;
+receive_stream_n(Ref, N) ->
+ receive
+ {http, {Ref, stream_start, _}} ->
+ receive_stream_n(Ref, N);
+ {http, {Ref,stream, Data}} ->
+ ct:pal("Data: ~p", [Data]),
+ receive_stream_n(Ref, N-1)
+ end.
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 28e77151f2..aae4ce5256 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -521,6 +521,9 @@ do_auth_api(AuthPrefix, Config) ->
"two", "group1"),
add_group_member(Node, ServerRoot, Port, AuthPrefix,
"secret", "Aladdin", "group2"),
+ {ok, Members} = list_group_members(Node, ServerRoot, Port, AuthPrefix, "secret", "group1"),
+ true = lists:member("one", Members),
+ true = lists:member("two", Members),
ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
"one", "onePassword", Version, Host),
Config, [{statuscode, 200}]),
@@ -2155,6 +2158,10 @@ add_group_member(Node, Root, Port, AuthPrefix, Dir, User, Group) ->
Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port,
Directory]).
+list_group_members(Node, Root, Port, AuthPrefix, Dir, Group) ->
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, list_group_members, [Group, [{port, Port}, {dir, Directory}]]).
+
getaddr() ->
{ok,HostName} = inet:gethostname(),
{ok,{A1,A2,A3,A4}} = inet:getaddr(HostName,inet),
diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl
index 18df995215..7ea7e08ed1 100644
--- a/lib/inets/test/inets_socketwrap_SUITE.erl
+++ b/lib/inets/test/inets_socketwrap_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index f668ef106c..eef5abd610 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.3.3
+INETS_VSN = 6.3.4
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 59a046bf4d..5b5b71e521 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -37,10 +37,7 @@
the <c>heart</c> port program is to check that the Erlang runtime system
it is supervising is still running. If the port program has not
received any heartbeats within <c>HEART_BEAT_TIMEOUT</c> seconds
- (defaults to 60 seconds), the system can be rebooted. Also, if
- the system is equipped with a hardware watchdog timer and is
- running Solaris, the watchdog can be used to supervise the entire
- system.</p>
+ (defaults to 60 seconds), the system can be rebooted.</p>
<p>An Erlang runtime system to be monitored by a heart program
is to be started with command-line flag <c>-heart</c> (see
also <seealso marker="erts:erl"><c>erl(1)</c></seealso>).
@@ -51,17 +48,13 @@
or a terminated Erlang runtime system, environment variable
<c>HEART_COMMAND</c> must be set before the system is started.
If this variable is not set, a warning text is printed but
- the system does not reboot. However, if the hardware watchdog is
- used, it still triggers a reboot <c>HEART_BEAT_BOOT_DELAY</c>
- seconds later (defaults to 60 seconds).</p>
+ the system does not reboot.</p>
<p>To reboot on Windows, <c>HEART_COMMAND</c> can be
set to <c>heart -shutdown</c> (included in the Erlang delivery)
or to any other suitable program that can activate a reboot.</p>
- <p>The hardware watchdog is not started under Solaris if
- environment variable <c>HW_WD_DISABLE</c> is set.</p>
- <p>The environment variables <c>HEART_BEAT_TIMEOUT</c> and
- <c>HEART_BEAT_BOOT_DELAY</c> can be used to configure the heart
- time-outs; they can be set in the operating system shell before Erlang
+ <p>The environment variable <c>HEART_BEAT_TIMEOUT</c>
+ can be used to configure the heart
+ time-outs; it can be set in the operating system shell before Erlang
is started or be specified at the command line:</p>
<pre>
% <input>erl -heart -env HEART_BEAT_TIMEOUT 30 ...</input></pre>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index d907cef7d3..4c4a5c39cb 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -987,11 +987,6 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
<p>Sets the line delimiting character for line-oriented protocols
(<c>line</c>). Defaults to <c>$\n</c>.</p>
</item>
- <tag><c>{priority, Priority}</c></tag>
- <item>
- <p>Sets the protocol-defined priority for all packets to be sent
- on this socket.</p>
- </item>
<tag><c>{raw, Protocol, OptionNum, ValueBin}</c></tag>
<item>
<p>See below.</p>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 5bcc0b7c09..9277c2d353 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,39 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 5.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>code:add_pathsa/1</c> and command line option
+ <c>-pa</c> both revert the given list of directories when
+ adding it at the beginning of the code path. This is now
+ documented.</p>
+ <p>
+ Own Id: OTP-13920 Aux Id: ERL-267 </p>
+ </item>
+ <item>
+ <p>
+ Add lost runtime dependency to erts-8.1. This should have
+ been done in kernel-5.1 (OTP-19.1) as it cannot run
+ without at least erts-8.1 (OTP-19.1).</p>
+ <p>
+ Own Id: OTP-14003</p>
+ </item>
+ <item>
+ <p>
+ Type and doc for gen_{tcp,udp,sctp}:controlling_process/2
+ has been improved.</p>
+ <p>
+ Own Id: OTP-14022 Aux Id: PR-1208 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index 5944e9321a..adec2d9520 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -88,6 +88,12 @@
to retrieve the value of evaluating <c>apply(<anno>Module</anno>,
<anno>Function</anno>, <anno>Args</anno>)</c> on node
<c><anno>Node</anno></c>.</p>
+ <note>
+ <p><seealso marker="#yield/1"><c>yield/1</c></seealso> and
+ <seealso marker="#nb_yield/1"><c>nb_yield/1,2</c></seealso>
+ must be called by the same process from which this function
+ was made otherwise they will never yield correctly.</p>
+ </note>
</desc>
</func>
@@ -299,6 +305,11 @@
the tuple <c>{value, <anno>Val</anno>}</c> when the computation is
finished, or <c>timeout</c> when <c><anno>Timeout</anno></c>
milliseconds has elapsed.</p>
+ <note>
+ <p>This function must be called by the same process from which
+ <seealso marker="#async_call/4"><c>async_call/4</c></seealso>
+ was made otherwise it will only return <c>timeout</c>.</p>
+ </note>
</desc>
</func>
@@ -407,6 +418,11 @@
If the answer is available, it is
returned immediately. Otherwise, the calling process is
suspended until the answer arrives from <c>Node</c>.</p>
+ <note>
+ <p>This function must be called by the same process from which
+ <seealso marker="#async_call/4"><c>async_call/4</c></seealso>
+ was made otherwise it will never return.</p>
+ </note>
</desc>
</func>
</funcs>
diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl
index 8ac0bd9551..f5ead2a4c5 100644
--- a/lib/kernel/src/global_group.erl
+++ b/lib/kernel/src/global_group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl
index eea78aabdf..8fa48d56fb 100644
--- a/lib/kernel/src/heart.erl
+++ b/lib/kernel/src/heart.erl
@@ -198,16 +198,11 @@ start_portprogram() ->
end.
get_heart_timeouts() ->
- HeartOpts = case os:getenv("HEART_BEAT_TIMEOUT") of
- false -> "";
- H when is_list(H) ->
- "-ht " ++ H
- end,
- HeartOpts ++ case os:getenv("HEART_BEAT_BOOT_DELAY") of
- false -> "";
- W when is_list(W) ->
- " -wt " ++ W
- end.
+ case os:getenv("HEART_BEAT_TIMEOUT") of
+ false -> "";
+ H when is_list(H) ->
+ "-ht " ++ H
+ end.
check_start_heart() ->
case init:get_argument(heart) of
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index 3084bd599a..8c8fe86811 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index d3b2d18ae5..8d2517e680 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 5.1
+KERNEL_VSN = 5.1.1
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 46da79cfe3..9c73ab8072 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/megaco/test/megaco_app_test.erl b/lib/megaco/test/megaco_app_test.erl
index 346a123c66..981d93f5dd 100644
--- a/lib/megaco/test/megaco_app_test.erl
+++ b/lib/megaco/test/megaco_app_test.erl
@@ -17,8 +17,6 @@
%%
%% %CopyrightEnd%
%%
-
-%%
%%----------------------------------------------------------------------
%% Purpose: Verify the application specifics of the Megaco application
%%----------------------------------------------------------------------
@@ -26,296 +24,26 @@
-compile(export_all).
--include("megaco_test_lib.hrl").
-
-
-t() -> megaco_test_lib:t(?MODULE).
-t(Case) -> megaco_test_lib:t({?MODULE, Case}).
-
-
-%% Test server callbacks
-init_per_testcase(undef_funcs = Case, Config) ->
- NewConfig = [{tc_timeout, ?MINUTES(10)} | Config],
- megaco_test_lib:init_per_testcase(Case, NewConfig);
-init_per_testcase(Case, Config) ->
- megaco_test_lib:init_per_testcase(Case, Config).
-
-end_per_testcase(Case, Config) ->
- megaco_test_lib:end_per_testcase(Case, Config).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-include_lib("common_test/include/ct.hrl").
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
all() ->
[
- fields,
- modules,
- exportall,
- app_depend,
- undef_funcs
+ app,
+ appup
].
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_per_suite(suite) -> [];
-init_per_suite(doc) -> [];
-init_per_suite(Config) when is_list(Config) ->
- case is_app(megaco) of
- {ok, AppFile} ->
- io:format("AppFile: ~n~p~n", [AppFile]),
- case megaco_flex_scanner:is_enabled() of
- true ->
- case megaco_flex_scanner:is_reentrant_enabled() of
- true ->
- io:format("~nMegaco reentrant flex scanner enabled~n~n", []);
- false ->
- io:format("~nMegaco non-reentrant flex scanner enabled~n~n", [])
- end;
- false ->
- io:format("~nMegaco flex scanner disabled~n~n", [])
- end,
- megaco:print_version_info(),
- [{app_file, AppFile}|Config];
- {error, Reason} ->
- fail(Reason)
- end.
-
-is_app(App) ->
- LibDir = code:lib_dir(App),
- File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
- case file:consult(File) of
- {ok, [{application, App, AppFile}]} ->
- {ok, AppFile};
- {error, {LineNo, Mod, Code}} ->
- IoList = lists:concat([File, ":", LineNo, ": ",
- Mod:format_error(Code)]),
- {error, list_to_atom(lists:flatten(IoList))};
- Error ->
- {error, {invalid_format, Error}}
- end.
-
-
-end_per_suite(suite) -> [];
-end_per_suite(doc) -> [];
-end_per_suite(Config) when is_list(Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fields(suite) ->
- [];
-fields(doc) ->
- [];
-fields(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Fields = [vsn, description, modules, registered, applications],
- case check_fields(Fields, AppFile, []) of
- [] ->
- ok;
- Missing ->
- fail({missing_fields, Missing})
- end.
-
-check_fields([], _AppFile, Missing) ->
- Missing;
-check_fields([Field|Fields], AppFile, Missing) ->
- check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
-
-check_field(Name, AppFile, Missing) ->
- io:format("checking field: ~p~n", [Name]),
- case lists:keymember(Name, 1, AppFile) of
- true ->
- Missing;
- false ->
- [Name|Missing]
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-modules(suite) ->
- [];
-modules(doc) ->
- [];
-modules(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- EbinList = get_ebin_mods(megaco),
- case missing_modules(Mods, EbinList, []) of
- [] ->
- ok;
- Missing ->
- throw({error, {missing_modules, Missing}})
- end,
- case extra_modules(Mods, EbinList, []) of
- [] ->
- ok;
- Extra ->
- throw({error, {extra_modules, Extra}})
- end,
- {ok, Mods}.
-
-get_ebin_mods(App) ->
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- {ok, Files0} = file:list_dir(EbinDir),
- Files1 = [lists:reverse(File) || File <- Files0],
- [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
-
-
-missing_modules([], _Ebins, Missing) ->
- Missing;
-missing_modules([Mod|Mods], Ebins, Missing) ->
- case lists:member(Mod, Ebins) of
- true ->
- missing_modules(Mods, Ebins, Missing);
- false ->
- io:format("missing module: ~p~n", [Mod]),
- missing_modules(Mods, Ebins, [Mod|Missing])
- end.
-
-
-extra_modules(_Mods, [], Extra) ->
- Extra;
-extra_modules(Mods, [Mod|Ebins], Extra) ->
- case lists:member(Mod, Mods) of
- true ->
- extra_modules(Mods, Ebins, Extra);
- false ->
- io:format("supefluous module: ~p~n", [Mod]),
- extra_modules(Mods, Ebins, [Mod|Extra])
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-exportall(suite) ->
- [];
-exportall(doc) ->
- [];
-exportall(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- check_export_all(Mods).
-
-
-check_export_all([]) ->
- ok;
-check_export_all([Mod|Mods]) ->
- case (catch apply(Mod, module_info, [compile])) of
- {'EXIT', {undef, _}} ->
- check_export_all(Mods);
- O ->
- case lists:keysearch(options, 1, O) of
- false ->
- check_export_all(Mods);
- {value, {options, List}} ->
- case lists:member(export_all, List) of
- true ->
- throw({error, {export_all, Mod}});
- false ->
- check_export_all(Mods)
- end
- end
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-app_depend(suite) ->
- [];
-app_depend(doc) ->
- [];
-app_depend(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Apps = key1search(applications, AppFile),
- check_apps(Apps).
-
-
-check_apps([]) ->
- ok;
-check_apps([App|Apps]) ->
- case is_app(App) of
- {ok, _} ->
- check_apps(Apps);
- Error ->
- throw({error, {missing_app, {App, Error}}})
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-undef_funcs(suite) ->
- [];
-undef_funcs(doc) ->
- [];
-undef_funcs(Config) when is_list(Config) ->
- App = megaco,
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
- Root = code:root_dir(),
- LibDir = code:lib_dir(App),
- EbinDir = filename:join([LibDir,"ebin"]),
- XRefTestName = undef_funcs_make_name(App, xref_test_name),
- {ok, XRef} = xref:start(XRefTestName),
- ok = xref:set_default(XRef,
- [{verbose,false},{warnings,false}]),
- XRefName = undef_funcs_make_name(App, xref_name),
- {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
- {ok, App} = xref:replace_application(XRef, App, EbinDir),
- {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
- xref:stop(XRef),
- analyze_undefined_function_calls(Undefs, Mods, []).
-
-analyze_undefined_function_calls([], _, []) ->
- ok;
-analyze_undefined_function_calls([], _, AppUndefs) ->
- exit({suite_failed, {undefined_function_calls, AppUndefs}});
-analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
- AppModules, AppUndefs) ->
- %% Check that this module is our's
- case lists:member(Mod,AppModules) of
- true ->
- {Calling,Called} = AppUndef,
- {Mod1,Func1,Ar1} = Calling,
- {Mod2,Func2,Ar2} = Called,
- io:format("undefined function call: "
- "~n ~w:~w/~w calls ~w:~w/~w~n",
- [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
- analyze_undefined_function_calls(Undefs, AppModules,
- [AppUndef|AppUndefs]);
- false ->
- io:format("dropping ~p~n", [Mod]),
- analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
- end.
-
-%% This function is used simply to avoid cut-and-paste errors later...
-undef_funcs_make_name(App, PostFix) ->
- list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
-
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the megaco app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = test_server:app_test(megaco).
+%%--------------------------------------------------------------------
+appup() ->
+ [{doc, "Test that the megaco appup file is ok"}].
+appup(Config) when is_list(Config) ->
+ ok = test_server:appup_test(megaco).
diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl
index 325e7a6096..8dc3ad51a0 100644
--- a/lib/megaco/test/megaco_appup_test.erl
+++ b/lib/megaco/test/megaco_appup_test.erl
@@ -17,8 +17,6 @@
%%
%% %CopyrightEnd%
%%
-
-%%
%%----------------------------------------------------------------------
%% Purpose: Verify the application specifics of the Megaco application
%%----------------------------------------------------------------------
@@ -27,26 +25,18 @@
-compile(export_all).
-compile({no_auto_import,[error/1]}).
+-include_lib("common_test/include/ct.hrl").
-include("megaco_test_lib.hrl").
--define(APPLICATION, megaco).
-
-t() -> megaco_test_lib:t(?MODULE).
-t(Case) -> megaco_test_lib:t({?MODULE, Case}).
-
-
-%% Test server callbacks
-init_per_testcase(Case, Config) ->
- megaco_test_lib:init_per_testcase(Case, Config).
-
-end_per_testcase(Case, Config) ->
- megaco_test_lib:end_per_testcase(Case, Config).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
all() ->
- [appup].
+ Cases =
+ [
+ appup_file
+ ],
+ Cases.
groups() ->
[].
@@ -64,16 +54,9 @@ end_per_group(_GroupName, Config) ->
init_per_suite(suite) -> [];
init_per_suite(doc) -> [];
init_per_suite(Config) when is_list(Config) ->
- AppFile = file_name(?APPLICATION, ".app"),
- AppupFile = file_name(?APPLICATION, ".appup"),
- [{app_file, AppFile}, {appup_file, AppupFile}|Config].
+ Config.
-file_name(App, Ext) ->
- LibDir = code:lib_dir(App),
- filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]).
-
-
end_per_suite(suite) -> [];
end_per_suite(doc) -> [];
end_per_suite(Config) when is_list(Config) ->
@@ -82,468 +65,17 @@ end_per_suite(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-appup(suite) ->
- [];
-appup(doc) ->
- "perform a simple check of the appup file";
-appup(Config) when is_list(Config) ->
- AppupFile = key1search(appup_file, Config),
- AppFile = key1search(app_file, Config),
- Modules = modules(AppFile),
- check_appup(AppupFile, Modules).
-
-modules(File) ->
- case file:consult(File) of
- {ok, [{application,megaco,Info}]} ->
- case lists:keysearch(modules,1,Info) of
- {value, {modules, Modules}} ->
- Modules;
- false ->
- fail({bad_appinfo, Info})
- end;
- Error ->
- fail({bad_appfile, Error})
- end.
-
-
-check_appup(AppupFile, Modules) ->
- case file:consult(AppupFile) of
- {ok, [{V, UpFrom, DownTo}]} ->
- check_appup(V, UpFrom, DownTo, Modules);
- Else ->
- fail({bad_appupfile, Else})
- end.
-
-
-check_appup(V, UpFrom, DownTo, Modules) ->
- check_version(V),
- check_depends(up, UpFrom, Modules),
- check_depends(down, DownTo, Modules),
- check_module_subset(UpFrom),
- check_module_subset(DownTo),
- ok.
-
-
-check_depends(_, [], _) ->
- ok;
-check_depends(UpDown, [Dep|Deps], Modules) ->
- check_depend(UpDown, Dep, Modules),
- check_depends(UpDown, Deps, Modules).
-
-
-check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instruction: ~p"
- "~n Modules: ~p", [UpDown, Instr, Modules]),
- ok;
-check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr,
- Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instruction: ~p"
- "~n Modules: ~p", [UpDown, Instr, Modules]),
- ok;
-check_depend(UpDown, {V, Instructions}, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n V: ~p"
- "~n Modules: ~p", [UpDown, V, Modules]),
- check_version(V),
- case check_instructions(UpDown,
- Instructions, Instructions, [], [], Modules) of
- {_Good, []} ->
- ok;
- {_, Bad} ->
- fail({bad_instructions, Bad, UpDown})
- end.
-
-
-check_instructions(_, [], _, Good, Bad, _) ->
- {lists:reverse(Good), lists:reverse(Bad)};
-check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) ->
- d("check_instructions(~w) -> entry with"
- "~n Instr: ~p", [UpDown,Instr]),
- case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of
- ok ->
- check_instructions(UpDown, Instrs, AllInstr,
- [Instr|Good], Bad, Modules);
- {error, Reason} ->
- d("check_instructions(~w) -> bad instruction: "
- "~n Reason: ~p", [UpDown,Reason]),
- check_instructions(UpDown, Instrs, AllInstr, Good,
- [{Instr, Reason}|Bad], Modules)
- end.
-
-%% A new module is added
-check_instruction(up, {add_module, Module}, _, Modules)
- when is_atom(Module) ->
- d("check_instruction -> entry when up-add_module instruction with"
- "~n Module: ~p", [Module]),
- check_module(Module, Modules);
-
-%% An old module is re-added
-check_instruction(down, {add_module, Module}, _, Modules)
- when is_atom(Module) ->
- d("check_instruction -> entry when down-add_module instruction with"
- "~n Module: ~p", [Module]),
- case (catch check_module(Module, Modules)) of
- {error, {unknown_module, Module, Modules}} ->
- ok;
- ok ->
- error({existing_readded_module, Module})
- end;
-
-%% Removing a module on upgrade:
-%% - the module has been removed from the app-file.
-%% - check that no module depends on this (removed) module
-check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
- d("check_instruction -> entry when up-remove instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p", [Module, Pre, Post]),
- case (catch check_module(Module, Modules)) of
- {error, {unknown_module, Module, Modules}} ->
- check_purge(Pre),
- check_purge(Post);
- ok ->
- error({existing_removed_module, Module})
- end;
-
-%% Removing a module on downgrade: the module exist
-%% in the app-file.
-check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) ->
- d("check_instruction -> entry when down-remove instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p", [Module, Pre, Post]),
- case (catch check_module(Module, Modules)) of
- ok ->
- check_purge(Pre),
- check_purge(Post),
- check_no_remove_depends(Module, AllInstr);
- {error, {unknown_module, Module, Modules}} ->
- error({nonexisting_removed_module, Module})
- end;
-
-check_instruction(_, {load_module, Module, Pre, Post, Depend},
- AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
- d("check_instruction -> entry when load_module instruction with"
- "~n Module: ~p"
- "~n Pre: ~p"
- "~n Post: ~p"
- "~n Depend: ~p", [Module, Pre, Post, Depend]),
- check_module(Module, Modules),
- check_module_depend(Module, Depend, Modules),
- check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
- check_purge(Pre),
- check_purge(Post);
-
-check_instruction(_, {update, Module, Change, Pre, Post, Depend},
- AllInstr, Modules)
- when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) ->
- d("check_instruction -> entry when update instruction with"
- "~n Module: ~p"
- "~n Change: ~p"
- "~n Pre: ~p"
- "~n Post: ~p"
- "~n Depend: ~p", [Module, Change, Pre, Post, Depend]),
- check_module(Module, Modules),
- check_module_depend(Module, Depend, Modules),
- check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
- check_change(Change),
- check_purge(Pre),
- check_purge(Post);
-
-check_instruction(_, {update, Module, supervisor}, _, Modules)
- when is_atom(Module) ->
- check_module(Module, Modules);
-
-check_instruction(_, {apply, {Module, Function, Args}}, _, Modules)
- when is_atom(Module) andalso is_atom(Function) andalso is_list(Args) ->
- d("check_instruction -> entry when down-apply instruction with"
- "~n Module: ~p"
- "~n Function: ~p"
- "~n Args: ~p", [Module, Function, Args]),
- check_module(Module, Modules),
- check_apply(Module, Function, Args);
-
-check_instruction(_, {restart_application, ?APPLICATION}, _AllInstr, _Modules) ->
- ok;
-
-check_instruction(_, Instr, _AllInstr, _Modules) ->
- d("check_instruction -> entry when unknown instruction with"
- "~n Instr: ~p", [Instr]),
- error({error, {unknown_instruction, Instr}}).
-
-
-%% If Module X depends on Module Y, then module Y must have an update
-%% instruction of some sort (otherwise the depend is faulty).
-updated_modules([], Modules) ->
- d("update_modules -> entry when done with"
- "~n Modules: ~p", [Modules]),
- Modules;
-updated_modules([Instr|Instrs], Modules) ->
- d("update_modules -> entry with"
- "~n Instr: ~p"
- "~n Modules: ~p", [Instr,Modules]),
- Module = instruction_module(Instr),
- d("update_modules -> Module: ~p", [Module]),
- updated_modules(Instrs, [Module|Modules]).
-
-instruction_module({add_module, Module}) ->
- Module;
-instruction_module({remove, {Module, _, _}}) ->
- Module;
-instruction_module({load_module, Module, _, _, _}) ->
- Module;
-instruction_module({update, Module, _, _, _, _}) ->
- Module;
-instruction_module({apply, {Module, _, _}}) ->
- Module;
-instruction_module(Instr) ->
- d("instruction_module -> entry when unknown instruction with"
- "~n Instr: ~p", [Instr]),
- error({error, {unknown_instruction, Instr}}).
-
-
-%% Check that the modules handled in an instruction set for version X
-%% is a subset of the instruction set for version X-1.
-check_module_subset(Instructions) ->
- %% io:format("check_module_subset -> "
- %% "~n Instructions: ~p"
- %% "~n", [Instructions]),
- do_check_module_subset(modules_of(Instructions)).
-
-do_check_module_subset([]) ->
- ok;
-do_check_module_subset([_]) ->
- ok;
-do_check_module_subset([{_V1, Mods1}|T]) ->
- %% io:format("do_check_module_subset -> "
- %% "~n V1: ~p"
- %% "~n Mods1: ~p"
- %% "~n T: ~p"
- %% "~n", [_V1, Mods1, T]),
- {V2, Mods2} = hd(T),
- %% Check that the modules in V1 is a subset of V2
- case do_check_module_subset2(Mods1, Mods2) of
- ok ->
- do_check_module_subset(T);
- {error, Modules} ->
- fail({subset_missing_instructions, V2, Modules})
- end.
-
-do_check_module_subset2(Mods1, Mods2) ->
- do_check_module_subset2(Mods1, Mods2, []).
-
-do_check_module_subset2([], _, []) ->
- ok;
-do_check_module_subset2([], _, Acc) ->
- {error, lists:reverse(Acc)};
-do_check_module_subset2([Mod|Mods], Mods2, Acc) ->
- case lists:member(Mod, Mods2) of
- true ->
- do_check_module_subset2(Mods, Mods2, Acc);
- false ->
- do_check_module_subset2(Mods, Mods2, [Mod|Acc])
- end.
-
-
-modules_of(Instructions) ->
- modules_of(Instructions, []).
-
-modules_of([], Acc) ->
- lists:reverse(Acc);
-modules_of([{V,Instructions}|T], Acc) ->
- %% io:format("modules_of -> "
- %% "~n V: ~p"
- %% "~n Instructions: ~p"
- %% "~n", [V, Instructions]),
- case modules_of2(Instructions, []) of
- Mods when is_list(Mods) ->
- %% io:format("modules_of -> "
- %% "~n Mods: ~p"
- %% "~n", [Mods]),
- modules_of(T, [{V, Mods}|Acc]);
- skip ->
- %% io:format("modules_of -> skip"
- %% "~n", []),
- modules_of(T, Acc)
- end.
-
-modules_of2([], Acc) ->
- lists:reverse(Acc);
-modules_of2([Instr|Instructions], Acc) ->
- case module_of(Instr) of
- {value, Mod} ->
- modules_of2(Instructions, [Mod|Acc]);
- skip ->
- skip;
- false ->
- modules_of2(Instructions, Acc)
- end.
-
-module_of({add_module, Module}) ->
- {value, Module};
-module_of({remove, {Module, _Pre, _Post}}) ->
- {value, Module};
-module_of({load_module, Module, _Pre, _Post, _Depend}) ->
- {value, Module};
-module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
- {value, Module};
-module_of({restart_application, _App}) ->
- skip;
-module_of(_) ->
- false.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% The version is a string consting of numbers separated by dots: "."
-%% Example: "3.3.3"
-%%
-check_version(V) when is_list(V) ->
- case do_check_version(string:tokens(V, [$.])) of
- ok ->
- ok;
- {error, BadVersionPart} ->
- throw({error, {bad_version, V, BadVersionPart}})
- end;
-check_version(V) ->
- error({bad_version, V}).
-
-do_check_version([]) ->
- ok;
-do_check_version([H|T]) ->
- case (catch list_to_integer(H)) of
- I when is_integer(I) ->
- do_check_version(T);
- _ ->
- {error, H}
- end.
-
-check_module(M, Modules) when is_atom(M) ->
- case lists:member(M,Modules) of
- true ->
- ok;
- false ->
- error({unknown_module, M, Modules})
- end;
-check_module(M, _) ->
- error({bad_module, M}).
-
-
-check_module_depend(M, [], _) when is_atom(M) ->
- d("check_module_depend -> entry with"
- "~n M: ~p", [M]),
- ok;
-check_module_depend(M, Deps, Modules) when is_atom(M) andalso is_list(Deps) ->
- d("check_module_depend -> entry with"
- "~n M: ~p"
- "~n Deps: ~p"
- "~n Modules: ~p", [M, Deps, Modules]),
- case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of
- [] ->
- ok;
- Unknown ->
- error({unknown_depend_modules, Unknown})
- end;
-check_module_depend(_M, D, _Modules) ->
- d("check_module_depend -> entry when bad depend with"
- "~n D: ~p", [D]),
- error({bad_depend, D}).
-
-
-check_no_remove_depends(_Module, []) ->
- ok;
-check_no_remove_depends(Module, [Instr|Instrs]) ->
- check_no_remove_depend(Module, Instr),
- check_no_remove_depends(Module, Instrs).
-
-check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) ->
- case lists:member(Module, Depend) of
- true ->
- error({removed_module_in_depend, load_module, Mod, Module});
- false ->
- ok
- end;
-check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) ->
- case lists:member(Module, Depend) of
- true ->
- error({removed_module_in_depend, update, Mod, Module});
- false ->
- ok
- end;
-check_no_remove_depend(_, _) ->
- ok.
-
-
-check_change(soft) ->
- ok;
-check_change({advanced, _Something}) ->
- ok;
-check_change(Change) ->
- error({bad_change, Change}).
-
-
-check_purge(soft_purge) ->
- ok;
-check_purge(brutal_purge) ->
- ok;
-check_purge(Purge) ->
- error({bad_purge, Purge}).
-
-
-check_apply(Module, Function, Args) ->
- case (catch Module:module_info()) of
- Info when is_list(Info) ->
- check_exported(Function, Args, Info);
- {'EXIT', {undef, _}} ->
- error({not_existing_module, Module})
- end.
-
-check_exported(Function, Args, Info) ->
- case lists:keysearch(exports, 1, Info) of
- {value, {exports, FuncList}} ->
- Arity = length(Args),
- Arities = [A || {F, A} <- FuncList, F == Function],
- case lists:member(Arity, Arities) of
- true ->
- ok;
- false ->
- error({not_exported_function, Function, Arity})
- end;
- _ ->
- error({bad_export, Info})
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-error(Reason) ->
- throw({error, Reason}).
-
-fail(Reason) ->
- exit({suite_failed, Reason}).
+%% Test server callbacks
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
- fail({not_found, Key, L});
- {value, {Key, Value}} ->
- Value
- end.
+end_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-d(F, A) ->
- d(false, F, A).
+%% Perform a simple check of the appup file
+appup_file(Config) when is_list(Config) ->
+ ok = ?t:appup_test(megaco).
-d(true, F, A) ->
- io:format(F ++ "~n", A);
-d(_, _, _) ->
- ok.
-
-
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index b95cd66a81..0d40f863b2 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2015. All Rights Reserved.
+# Copyright Ericsson AB 1997-2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index e621bd593c..51c98d0d3e 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -39,7 +39,39 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.14.1</title>
+ <section><title>Mnesia 4.14.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A continuation returned by mnesia:select/[14] should be
+ reusable in different, non-transactional activities.</p>
+ <p>
+ Own Id: OTP-13944 Aux Id: PR-1184 </p>
+ </item>
+ <item>
+ <p>
+ Fixed crash when calling block_table multiple times.
+ Could happen when having locks for a long time and
+ restarting mnesia.</p>
+ <p>
+ Own Id: OTP-13970 Aux Id: Seq-13198 </p>
+ </item>
+ <item>
+ <p>
+ Change mnesia_tm process to have off-heap messages since
+ mnesia_tm can be the receiver of many non-synchronized
+ message from other nodes.</p>
+ <p>
+ Own Id: OTP-14074</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.14.1</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 5bf2fc2dc3..34efeca4fa 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -1882,9 +1882,10 @@ any_table_info(Tab, Item) when is_atom(Tab) ->
[] ->
abort({no_exists, Tab, Item});
Props ->
- lists:map(fun({setorbag, Type}) -> {type, Type};
- (Prop) -> Prop end,
- Props)
+ Rename = fun ({setorbag, Type}) -> {type, Type};
+ (Prop) -> Prop
+ end,
+ lists:sort(lists:map(Rename, Props))
end;
name ->
Tab;
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 388b42cf15..305bf14bcf 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -80,6 +80,7 @@ start() ->
init(Parent) ->
register(?MODULE, self()),
process_flag(trap_exit, true),
+ process_flag(message_queue_data, off_heap),
%% Initialize the schema
IgnoreFallback = mnesia_monitor:get_env(ignore_fallback_at_startup),
diff --git a/lib/mnesia/test/ext_test.erl b/lib/mnesia/test/ext_test.erl
index 45ddb148bc..3d1cc40c09 100644
--- a/lib/mnesia/test/ext_test.erl
+++ b/lib/mnesia/test/ext_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index f08e364276..439b21e58c 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.14.1
+MNESIA_VSN = 4.14.2
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 659eb28292..8f3ebcb4de 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -32,6 +32,60 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The shell script (priv/bin/cdv) and bat file
+ (priv/bin/cdv.bat) which can be used for starting
+ crashdump_viewer both started a distributed erlang node.
+ This would cause any attempt at starting a second
+ instance of the crashdump_viewer to fail. To solve this
+ problem, cdv and cdv.bat now use non-distributed nodes
+ when starting the crashdump_viewer.</p>
+ <p>
+ Own Id: OTP-14010</p>
+ </item>
+ <item>
+ <p>
+ A bug caused the number of buckets to be shown in the
+ 'Objects' column, and the number of objects to be shown
+ in the 'Memory' column for ets table in crashdump_viewer.
+ This is now corrected.</p>
+ <p>
+ Own Id: OTP-14064</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add option <c>queue_size</c> to ttb:tracer/2. This sets
+ the maximum queue size for the IP trace driver which is
+ used when tracing to shell and/or <c>{local,File}</c>.</p>
+ <p>
+ The default value for <c>queue_size</c> is specified by
+ <c>dbg</c>, and it is now changed from 50 to 200.</p>
+ <p>
+ Own Id: OTP-13829 Aux Id: seq13171 </p>
+ </item>
+ <item>
+ <p>
+ The port information page is updated to show more
+ information per port.</p>
+ <p>
+ Own Id: OTP-13948 Aux Id: ERL-272 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/priv/bin/cdv b/lib/observer/priv/bin/cdv
index 1c44785ac2..d14fd47e41 100755
--- a/lib/observer/priv/bin/cdv
+++ b/lib/observer/priv/bin/cdv
@@ -1,4 +1,4 @@
#!/bin/sh
-erl -sname cdv -noinput -s crashdump_viewer script_start $@
+erl -noinput -s crashdump_viewer script_start $@
diff --git a/lib/observer/priv/bin/cdv.bat b/lib/observer/priv/bin/cdv.bat
index efa8bf8687..18136a30d6 100644
--- a/lib/observer/priv/bin/cdv.bat
+++ b/lib/observer/priv/bin/cdv.bat
@@ -1,2 +1,2 @@
@ECHO OFF
-CALL werl -sname cdv -s crashdump_viewer script_start %*
+CALL werl -s crashdump_viewer script_start %*
diff --git a/lib/observer/priv/crashdump_viewer.tool b/lib/observer/priv/crashdump_viewer.tool
deleted file mode 100644
index b6bd6bbdef..0000000000
--- a/lib/observer/priv/crashdump_viewer.tool
+++ /dev/null
@@ -1,2 +0,0 @@
-{version,"1.2"}.
-[{config_func,{crashdump_viewer,configData,[]}}].
diff --git a/lib/observer/priv/crashdump_viewer/collapsd.gif b/lib/observer/priv/crashdump_viewer/collapsd.gif
deleted file mode 100644
index 0b90c08a9a..0000000000
--- a/lib/observer/priv/crashdump_viewer/collapsd.gif
+++ /dev/null
Binary files differ
diff --git a/lib/observer/priv/crashdump_viewer/exploded.gif b/lib/observer/priv/crashdump_viewer/exploded.gif
deleted file mode 100644
index e3ab5ca2e9..0000000000
--- a/lib/observer/priv/crashdump_viewer/exploded.gif
+++ /dev/null
Binary files differ
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index dd7831fa2b..ff2bcbdb99 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -92,7 +92,7 @@ EXAMPLE_FILES= multitrace.erl
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
PRIVDIR= ../priv
-WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool $(PRIVDIR)/erlang_observer.png
+PNGFILES= $(PRIVDIR)/erlang_observer.png
BINDIR= $(PRIVDIR)/bin
ifeq ($(findstring win32,$(TARGET)),win32)
WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/cdv.bat
@@ -103,10 +103,6 @@ EXECUTABLES= \
$(BINDIR)/etop \
$(BINDIR)/cdv \
$(WIN32_EXECUTABLES)
-CDVDIR= $(PRIVDIR)/crashdump_viewer
-GIF_FILES= \
- $(CDVDIR)/collapsd.gif \
- $(CDVDIR)/exploded.gif
APP_FILE= observer.app
@@ -163,9 +159,7 @@ release_spec: opt
$(INSTALL_DATA) $(TARGET_FILES) "$(RELSYSDIR)/ebin"
$(INSTALL_DIR) "$(RELSYSDIR)/priv/bin"
$(INSTALL_SCRIPT) $(EXECUTABLES) "$(RELSYSDIR)/priv/bin"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/crashdump_viewer"
- $(INSTALL_DATA) $(WEBTOOLFILES) "$(RELSYSDIR)/priv"
- $(INSTALL_DATA) $(GIF_FILES) "$(RELSYSDIR)/priv/crashdump_viewer"
+ $(INSTALL_DATA) $(PNGFILES) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/observer/src/cdv_ets_cb.erl b/lib/observer/src/cdv_ets_cb.erl
index 52a90b093b..ddd2d42df6 100644
--- a/lib/observer/src/cdv_ets_cb.erl
+++ b/lib/observer/src/cdv_ets_cb.erl
@@ -34,10 +34,8 @@
-define(COL_NAME, ?COL_ID+1).
-define(COL_SLOT, ?COL_NAME+1).
-define(COL_OWNER, ?COL_SLOT+1).
--define(COL_BUCK, ?COL_OWNER+1).
--define(COL_OBJ, ?COL_BUCK+1).
+-define(COL_OBJ, ?COL_OWNER+1).
-define(COL_MEM, ?COL_OBJ+1).
--define(COL_TYPE, ?COL_MEM+1).
%% Callbacks for cdv_virtual_list_wx
col_to_elem(id) -> col_to_elem(?COL_ID);
@@ -45,8 +43,6 @@ col_to_elem(?COL_ID) -> #ets_table.id;
col_to_elem(?COL_NAME) -> #ets_table.name;
col_to_elem(?COL_SLOT) -> #ets_table.slot;
col_to_elem(?COL_OWNER) -> #ets_table.pid;
-col_to_elem(?COL_TYPE) -> #ets_table.data_type;
-col_to_elem(?COL_BUCK) -> #ets_table.buckets;
col_to_elem(?COL_OBJ) -> #ets_table.size;
col_to_elem(?COL_MEM) -> #ets_table.memory.
@@ -57,7 +53,6 @@ col_spec() ->
{"Owner", ?wxLIST_FORMAT_CENTRE, 120},
{"Objects", ?wxLIST_FORMAT_RIGHT, 80},
{"Memory", ?wxLIST_FORMAT_RIGHT, 80}
-% {"Type", ?wxLIST_FORMAT_LEFT, 50}
].
get_info(Owner) ->
diff --git a/lib/observer/src/cdv_mem_cb.erl b/lib/observer/src/cdv_mem_cb.erl
index ba972d6963..abeddc7335 100644
--- a/lib/observer/src/cdv_mem_cb.erl
+++ b/lib/observer/src/cdv_mem_cb.erl
@@ -77,6 +77,10 @@ fix_alloc([{Title,Columns,Data}|Tables]) ->
fix_alloc(Tables)];
fix_alloc([{Title,[{_,V}|_]=Data}|Tables]) ->
fix_alloc([{Title,lists:duplicate(length(V),[]),Data}|Tables]);
+fix_alloc([{"",[]}|Tables]) -> % no name and no data, probably truncated dump
+ fix_alloc(Tables);
+fix_alloc([{Title,[]=Data}|Tables]) -> % no data, probably truncated dump
+ fix_alloc([{Title,[],Data}|Tables]);
fix_alloc([]) ->
[].
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index 9268dac180..13e73f027d 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -90,6 +90,7 @@
%% All possible tags - use macros in order to avoid misspelling in the code
+-define(abort,abort).
-define(allocated_areas,allocated_areas).
-define(allocator,allocator).
-define(atoms,atoms).
@@ -321,8 +322,16 @@ handle_call(general_info,_From,State=#state{file=File}) ->
NumAtoms = GenInfo#general_info.num_atoms,
WS = parse_vsn_str(GenInfo#general_info.system_vsn,4),
TW = case get(truncated) of
- true -> ["WARNING: The crash dump is truncated. "
- "Some information might be missing."];
+ true ->
+ case get(truncated_reason) of
+ undefined ->
+ ["WARNING: The crash dump is truncated. "
+ "Some information might be missing."];
+ Reason ->
+ ["WARNING: The crash dump is truncated "
+ "("++Reason++"). "
+ "Some information might be missing."]
+ end;
false -> []
end,
ets:insert(cdv_reg_proc_table,
@@ -515,8 +524,15 @@ truncated_warning([Tag|Tags]) ->
false -> truncated_warning(Tags)
end.
truncated_warning() ->
- ["WARNING: The crash dump is truncated here. "
- "Some information might be missing."].
+ case get(truncated_reason) of
+ undefined ->
+ ["WARNING: The crash dump is truncated here. "
+ "Some information might be missing."];
+ Reason ->
+ ["WARNING: The crash dump is truncated here "
+ "("++Reason++"). "
+ "Some information might be missing."]
+ end.
truncated_here(Tag) ->
case get(truncated) of
@@ -692,6 +708,7 @@ val(Fd, NoExist) ->
{eof,[]} -> NoExist;
[] -> NoExist;
{eof,Val} -> Val;
+ "=abort:"++_ -> NoExist;
Val -> Val
end.
@@ -787,7 +804,7 @@ do_read_file(File) ->
?erl_crash_dump ->
reset_index_table(),
insert_index(Tag,Id,N1+1),
- put(last_tag,{Tag,""}),
+ put_last_tag(Tag,""),
indexify(Fd,Rest,N1),
end_progress(),
check_if_truncated(),
@@ -831,7 +848,7 @@ indexify(Fd,Bin,N) ->
<<_:Pos/binary,TagAndRest/binary>> = Bin,
{Tag,Id,Rest,N1} = tag(Fd,TagAndRest,N+Pos),
insert_index(Tag,Id,N1+1), % +1 to get past newline
- put(last_tag,{Tag,Id}),
+ put_last_tag(Tag,Id),
indexify(Fd,Rest,N1);
nomatch ->
case progress_read(Fd) of
@@ -911,7 +928,10 @@ general_info(File) ->
WholeLine -> WholeLine
end,
- GI = get_general_info(Fd,#general_info{created=Created}),
+ {Slogan,SysVsn} = get_slogan_and_sysvsn(Fd,[]),
+ GI = get_general_info(Fd,#general_info{created=Created,
+ slogan=Slogan,
+ system_vsn=SysVsn}),
{MemTot,MemMax} =
case lookup_index(?memory) of
@@ -965,12 +985,20 @@ general_info(File) ->
mem_max=MemMax,
instr_info=InstrInfo}.
+get_slogan_and_sysvsn(Fd,Acc) ->
+ case val(Fd,eof) of
+ "Slogan: " ++ SloganPart when Acc==[] ->
+ get_slogan_and_sysvsn(Fd,[SloganPart]);
+ "System version: " ++ SystemVsn ->
+ {lists:append(lists:reverse(Acc)),SystemVsn};
+ eof ->
+ {lists:append(lists:reverse(Acc)),"-1"};
+ SloganPart ->
+ get_slogan_and_sysvsn(Fd,[[$\n|SloganPart]|Acc])
+ end.
+
get_general_info(Fd,GenInfo) ->
case line_head(Fd) of
- "Slogan" ->
- get_general_info(Fd,GenInfo#general_info{slogan=val(Fd)});
- "System version" ->
- get_general_info(Fd,GenInfo#general_info{system_vsn=val(Fd)});
"Compiled" ->
get_general_info(Fd,GenInfo#general_info{compile_time=val(Fd)});
"Taints" ->
@@ -1174,7 +1202,11 @@ parse_link_list("{from,"++Str,Links,Monitors,MonitoredBy) ->
parse_link_list(", "++Rest,Links,Monitors,MonitoredBy) ->
parse_link_list(Rest,Links,Monitors,MonitoredBy);
parse_link_list([],Links,Monitors,MonitoredBy) ->
- {lists:reverse(Links),lists:reverse(Monitors),lists:reverse(MonitoredBy)}.
+ {lists:reverse(Links),lists:reverse(Monitors),lists:reverse(MonitoredBy)};
+parse_link_list(Unexpected,Links,Monitors,MonitoredBy) ->
+ io:format("WARNING: found unexpected data in link list:~n~s~n",[Unexpected]),
+ parse_link_list([],Links,Monitors,MonitoredBy).
+
parse_port(Str) ->
{Port,Rest} = parse_link(Str,[]),
@@ -1813,16 +1845,16 @@ main_modinfo(_Fd,LM,_LineHead) ->
all_modinfo(Fd,LM,LineHead) ->
case LineHead of
"Current attributes" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{current_attrib=Str};
"Current compilation info" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{current_comp_info=Str};
"Old attributes" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{old_attrib=Str};
"Old compilation info" ->
- Str = hex_to_str(val(Fd)),
+ Str = hex_to_str(val(Fd,"")),
LM#loaded_mod{old_comp_info=Str};
Other ->
unexpected(Fd,Other,"loaded modules info"),
@@ -1848,7 +1880,12 @@ hex_to_term([],Acc) ->
Bin};
Term ->
Term
- end.
+ end;
+hex_to_term(Rest,Acc) ->
+ {"WARNING: The term is probably truncated!",
+ "I can not convert hex to term.",
+ Rest,list_to_binary(lists:reverse(Acc))}.
+
hex_to_dec("F") -> 15;
hex_to_dec("E") -> 14;
@@ -2159,7 +2196,8 @@ sort_allocator_types([{Name,Data}|Allocators],Acc,DoTotal) ->
Type =
case string:tokens(Name,"[]") of
[T,_Id] -> T;
- [Name] -> Name
+ [Name] -> Name;
+ Other -> Other
end,
TypeData = proplists:get_value(Type,Acc,[]),
{NewTypeData,NewDoTotal} = sort_type_data(Type,Data,TypeData,DoTotal),
@@ -2686,6 +2724,7 @@ count_index(Tag) ->
%%-----------------------------------------------------------------
%% Convert tags read from crashdump to atoms used as first part of key
%% in cdv_dump_index_table
+tag_to_atom("abort") -> ?abort;
tag_to_atom("allocated_areas") -> ?allocated_areas;
tag_to_atom("allocator") -> ?allocator;
tag_to_atom("atoms") -> ?atoms;
@@ -2720,6 +2759,14 @@ tag_to_atom(UnknownTag) ->
list_to_atom(UnknownTag).
%%%-----------------------------------------------------------------
+%%% Store last tag for use when truncated, and reason if aborted
+put_last_tag(?abort,Reason) ->
+ %% Don't overwrite the real last tag
+ put(truncated_reason,Reason);
+put_last_tag(Tag,Id) ->
+ put(last_tag,{Tag,Id}).
+
+%%%-----------------------------------------------------------------
%%% Fetch next chunk from crashdump file
lookup_and_parse_index(File,What,ParseFun,Str) when is_list(File) ->
Indices = lookup_index(What),
@@ -2815,7 +2862,16 @@ collect(Pids,Acc) ->
update_progress(),
collect(Pids,Acc);
{'DOWN', _Ref, process, Pid, {pmap_done,Result}} ->
- collect(lists:delete(Pid,Pids),[Result|Acc])
+ collect(lists:delete(Pid,Pids),[Result|Acc]);
+ {'DOWN', _Ref, process, Pid, _Error} ->
+ Warning =
+ "WARNING: an error occured while parsing data.\n" ++
+ case get(truncated) of
+ true -> "This might be because the dump is truncated.\n";
+ false -> ""
+ end,
+ io:format(Warning),
+ collect(lists:delete(Pid,Pids),Acc)
end.
%%%-----------------------------------------------------------------
diff --git a/lib/observer/src/etop.erl b/lib/observer/src/etop.erl
index fcb900960b..925f4456bb 100644
--- a/lib/observer/src/etop.erl
+++ b/lib/observer/src/etop.erl
@@ -23,7 +23,7 @@
-export([start/0, start/1, config/2, stop/0, dump/1, help/0]).
%% Internal
-export([update/1]).
--export([loadinfo/1, meminfo/2, getopt/2]).
+-export([loadinfo/2, meminfo/2, getopt/2]).
-include("etop.hrl").
-include("etop_defs.hrl").
@@ -319,18 +319,18 @@ output(graphical) -> exit({deprecated, "Use observer instead"});
output(text) -> etop_txt.
-loadinfo(SysI) ->
+loadinfo(SysI,Prev) ->
#etop_info{n_procs = Procs,
run_queue = RQ,
now = Now,
wall_clock = WC,
runtime = RT} = SysI,
- Cpu = calculate_cpu_utilization(WC,RT),
+ Cpu = calculate_cpu_utilization(WC,RT,Prev#etop_info.runtime),
Clock = io_lib:format("~2.2.0w:~2.2.0w:~2.2.0w",
tuple_to_list(element(2,calendar:now_to_datetime(Now)))),
{Cpu,Procs,RQ,Clock}.
-calculate_cpu_utilization({_,WC},{_,RT}) ->
+calculate_cpu_utilization({_,WC},{_,RT},_) ->
%% Old version of observer_backend, using statistics(wall_clock)
%% and statistics(runtime)
case {WC,RT} of
@@ -341,15 +341,23 @@ calculate_cpu_utilization({_,WC},{_,RT}) ->
_ ->
round(100*RT/WC)
end;
-calculate_cpu_utilization(_,undefined) ->
+calculate_cpu_utilization(_,undefined,_) ->
%% First time collecting - no cpu utilization has been measured
%% since scheduler_wall_time flag is not yet on
0;
-calculate_cpu_utilization(_,RTInfo) ->
+calculate_cpu_utilization(WC,RTInfo,undefined) ->
+ %% Second time collecting - RTInfo shows scheduler_wall_time since
+ %% flag was set to true. Faking previous values by setting
+ %% everything to zero.
+ ZeroRT = [{Id,0,0} || {Id,_,_} <- RTInfo],
+ calculate_cpu_utilization(WC,RTInfo,ZeroRT);
+calculate_cpu_utilization(_,RTInfo,PrevRTInfo) ->
%% New version of observer_backend, using statistics(scheduler_wall_time)
- Sum = lists:foldl(fun({_,A,T},{AAcc,TAcc}) -> {A+AAcc,T+TAcc} end,
+ Sum = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}},{AAcc,TAcc}) ->
+ {(A1 - A0)+AAcc,(T1 - T0)+TAcc}
+ end,
{0,0},
- RTInfo),
+ lists:zip(PrevRTInfo,RTInfo)),
case Sum of
{0,0} ->
0;
diff --git a/lib/observer/src/etop_txt.erl b/lib/observer/src/etop_txt.erl
index 3b4c176478..6b8f9df24f 100644
--- a/lib/observer/src/etop_txt.erl
+++ b/lib/observer/src/etop_txt.erl
@@ -22,35 +22,35 @@
%%-compile(export_all).
-export([init/1,stop/1]).
--export([do_update/3]).
+-export([do_update/4]).
-include("etop.hrl").
-include("etop_defs.hrl").
--import(etop,[loadinfo/1,meminfo/2]).
+-import(etop,[loadinfo/2,meminfo/2]).
-define(PROCFORM,"~-15w~-20s~8w~8w~8w~8w ~-20s~n").
stop(Pid) -> Pid ! stop.
init(Config) ->
- loop(Config).
+ loop(#etop_info{},Config).
-loop(Config) ->
- Info = do_update(Config),
+loop(Prev,Config) ->
+ Info = do_update(Prev,Config),
receive
stop -> stopped;
- {dump,Fd} -> do_update(Fd,Info,Config), loop(Config);
- {config,_,Config1} -> loop(Config1)
- after Config#opts.intv -> loop(Config)
+ {dump,Fd} -> do_update(Fd,Info,Prev,Config), loop(Info,Config);
+ {config,_,Config1} -> loop(Info,Config1)
+ after Config#opts.intv -> loop(Info,Config)
end.
-do_update(Config) ->
+do_update(Prev,Config) ->
Info = etop:update(Config),
- do_update(standard_io,Info,Config).
+ do_update(standard_io,Info,Prev,Config).
-do_update(Fd,Info,Config) ->
- {Cpu,NProcs,RQ,Clock} = loadinfo(Info),
+do_update(Fd,Info,Prev,Config) ->
+ {Cpu,NProcs,RQ,Clock} = loadinfo(Info,Prev),
io:nl(Fd),
writedoubleline(Fd),
case Info#etop_info.memi of
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index 77609b11ce..ca54080e15 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 7c1337025f..1eaba31a3a 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -25,7 +25,7 @@
wait_for_progress/0, report_progress/1,
user_term/3, user_term_multiline/3,
interval_dialog/4, start_timer/1, stop_timer/1,
- display_info/2, fill_info/2, update_info/2, to_str/1,
+ display_info/2, display_info/3, fill_info/2, update_info/2, to_str/1,
create_menus/3, create_menu_item/3,
create_attrs/0,
set_listctrl_col_size/2,
@@ -124,6 +124,11 @@ display_info(Frame, Info) ->
Panel = wxPanel:new(Frame),
wxWindow:setBackgroundStyle(Panel, ?wxBG_STYLE_SYSTEM),
Sizer = wxBoxSizer:new(?wxVERTICAL),
+ InfoFs = display_info(Panel, Sizer, Info),
+ wxWindow:setSizerAndFit(Panel, Sizer),
+ {Panel, Sizer, InfoFs}.
+
+display_info(Panel, Sizer, Info) ->
wxSizer:addSpacer(Sizer, 5),
Add = fun(BoxInfo) ->
case create_box(Panel, BoxInfo) of
@@ -136,9 +141,7 @@ display_info(Frame, Info) ->
[]
end
end,
- InfoFs = [Add(I) || I <- Info],
- wxWindow:setSizerAndFit(Panel, Sizer),
- {Panel, Sizer, InfoFs}.
+ [Add(I) || I <- Info].
fill_info([{dynamic, Key}|Rest], Data)
when is_atom(Key); is_function(Key) ->
@@ -254,6 +257,11 @@ to_str({func, {F,A}}) when is_atom(F), is_integer(A) ->
lists:concat([F, "/", A]);
to_str({func, {F,'_'}}) when is_atom(F) ->
atom_to_list(F);
+to_str({inet, Addr}) ->
+ case inet:ntoa(Addr) of
+ {error,einval} -> to_str(Addr);
+ AddrStr -> AddrStr
+ end;
to_str({{format,Fun},Value}) when is_function(Fun) ->
Fun(Value);
to_str({A, B}) when is_atom(A), is_atom(B) ->
@@ -453,14 +461,16 @@ create_box(Parent, Data) ->
link_entry(Panel,Value);
_ ->
Value = to_str(Value0),
- case length(Value) > 100 of
- true ->
- Shown = lists:sublist(Value, 80),
+ case string:sub_word(lists:sublist(Value, 80),1,$\n) of
+ Value ->
+ %% Short string, no newlines - show all
+ wxStaticText:new(Panel, ?wxID_ANY, Value);
+ Shown ->
+ %% Long or with newlines,
+ %% use tooltip to show all
TCtrl = wxStaticText:new(Panel, ?wxID_ANY, [Shown,"..."]),
wxWindow:setToolTip(TCtrl,wxToolTip:new(Value)),
- TCtrl;
- false ->
- wxStaticText:new(Panel, ?wxID_ANY, Value)
+ TCtrl
end
end,
wxSizer:add(Line, 10, 0), % space of size 10 horisontally
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index 6a1aac92c7..b0ead42e3f 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -383,8 +383,8 @@ lmax(MState, Values, State) ->
init_data(runq, {stats, _, T0, _, _}) -> {mk_max(),lists:sort(T0)};
init_data(io, {stats, _, _, {{_,In0}, {_,Out0}}, _}) -> {mk_max(), {In0,Out0}};
init_data(memory, _) -> {mk_max(), info(memory, undefined)};
-init_data(alloc, _) -> {mk_max(), ok};
-init_data(utilz, _) -> {mk_max(), ok}.
+init_data(alloc, _) -> {mk_max(), unused};
+init_data(utilz, _) -> {mk_max(), unused}.
info(runq, {stats, _, T0, _, _}) -> lists:seq(1, length(T0));
info(memory, _) -> [total, processes, atom, binary, code, ets];
@@ -410,11 +410,11 @@ collect_data(memory, {stats, _, _, _, MemInfo}, {Max, MemTypes}) ->
collect_data(alloc, MemInfo, Max) ->
Vs = [Carrier || {_Type,_Block,Carrier} <- MemInfo],
Sample = list_to_tuple(Vs),
- {Sample, lmax(Max, Vs, Sample)};
+ {Sample, {lmax(Max, Vs, Sample),unused}};
collect_data(utilz, MemInfo, Max) ->
Vs = [round(100*Block/Carrier) || {_Type,Block,Carrier} <- MemInfo],
Sample = list_to_tuple(Vs),
- {Sample, lmax(Max,Vs,Sample)}.
+ {Sample, {lmax(Max,Vs,Sample),unused}}.
calc_delta([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) ->
[100*(WN-WP) div (TN-TP)|calc_delta(Ss, Ps)];
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index 3b788642cc..53ba3fa607 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,7 +52,13 @@
slot,
id_str,
links,
- monitors}).
+ monitors,
+ monitored_by,
+ parallelism,
+ locking,
+ queue_size,
+ memory,
+ inet}).
-record(opt, {sort_key=2,
sort_incr=true
@@ -358,7 +364,13 @@ list_to_portrec(PL) ->
links = proplists:get_value(links, PL, []),
name = proplists:get_value(registered_name, PL, []),
monitors = proplists:get_value(monitors, PL, []),
- controls = proplists:get_value(name, PL)}.
+ monitored_by = proplists:get_value(monitored_by, PL, []),
+ controls = proplists:get_value(name, PL),
+ parallelism = proplists:get_value(parallelism, PL),
+ locking = proplists:get_value(locking, PL),
+ queue_size = proplists:get_value(queue_size, PL, 0),
+ memory = proplists:get_value(memory, PL, 0),
+ inet = proplists:get_value(inet, PL, [])}.
portrec_to_list(#port{id = Id,
slot = Slot,
@@ -366,14 +378,26 @@ portrec_to_list(#port{id = Id,
links = Links,
name = Name,
monitors = Monitors,
- controls = Controls}) ->
+ monitored_by = MonitoredBy,
+ controls = Controls,
+ parallelism = Parallelism,
+ locking = Locking,
+ queue_size = QueueSize,
+ memory = Memory,
+ inet = Inet}) ->
[{id,Id},
{slot,Slot},
{connected,Connected},
{links,Links},
{name,Name},
{monitors,Monitors},
- {controls,Controls}].
+ {monitored_by,MonitoredBy},
+ {controls,Controls},
+ {parallelism,Parallelism},
+ {locking,Locking},
+ {queue_size,QueueSize},
+ {memory,Memory} |
+ Inet].
display_port_info(Parent, PortRec, Opened) ->
PortIdStr = PortRec#port.id_str,
@@ -391,29 +415,86 @@ do_display_port_info(Parent0, PortRec) ->
Title = "Port Info: " ++ PortRec#port.id_str,
Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title,
[{style, ?wxSYSTEM_MENU bor ?wxCAPTION
- bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}]),
-
+ bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER},
+ {size,{600,400}}]),
+ ScrolledWin = wxScrolledWindow:new(Frame,[{style,?wxHSCROLL bor ?wxVSCROLL}]),
+ wxScrolledWindow:enableScrolling(ScrolledWin,true,true),
+ wxScrolledWindow:setScrollbars(ScrolledWin,20,20,0,0),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxWindow:setSizer(ScrolledWin,Sizer),
Port = portrec_to_list(PortRec),
Fields0 = port_info_fields(Port),
- {_FPanel, _Sizer, _UpFields} = observer_lib:display_info(Frame, Fields0),
+ _UpFields = observer_lib:display_info(ScrolledWin, Sizer, Fields0),
wxFrame:center(Frame),
wxFrame:connect(Frame, close_window, [{skip, true}]),
wxFrame:show(Frame),
Frame.
-port_info_fields(Port) ->
+
+port_info_fields(Port0) ->
+ {InetStruct,Port} = inet_extra_fields(Port0),
Struct =
[{"Overview",
- [{"Name", name},
+ [{"Registered Name", name},
{"Connected", {click,connected}},
{"Slot", slot},
- {"Controls", controls}]},
+ {"Controls", controls},
+ {"Parallelism", parallelism},
+ {"Locking", locking},
+ {"Queue Size", {bytes,queue_size}},
+ {"Memory", {bytes,memory}}]},
{scroll_boxes,
[{"Links",1,{click,links}},
- {"Monitors",1,{click,filter_monitor_info()}}]}],
+ {"Monitors",1,{click,filter_monitor_info()}},
+ {"Monitored by",1,{click,monitored_by}}]} | InetStruct],
observer_lib:fill_info(Struct, Port).
+inet_extra_fields(Port) ->
+ Statistics = proplists:get_value(statistics,Port,[]),
+ Options = proplists:get_value(options,Port,[]),
+ Struct =
+ case proplists:get_value(controls,Port) of
+ Inet when Inet=="tcp_inet"; Inet=="udp_inet"; Inet=="sctp_inet" ->
+ [{"Inet",
+ [{"Local Address", {inet,local_address}},
+ {"Local Port Number", local_port},
+ {"Remote Address", {inet,remote_address}},
+ {"Remote Port Number", remote_port}]},
+ {"Statistics",
+ [stat_name_and_unit(Key) || {Key,_} <- Statistics]},
+ {"Options",
+ [{atom_to_list(Key),Key} || {Key,_} <- Options]}];
+ _ ->
+ []
+ end,
+ Port1 = lists:keydelete(statistics,1,Port),
+ Port2 = lists:keydelete(options,1,Port1),
+ {Struct,Port2 ++ Statistics ++ Options}.
+
+stat_name_and_unit(recv_avg) ->
+ {"Average package size received", {bytes,recv_avg}};
+stat_name_and_unit(recv_cnt) ->
+ {"Number of packets received", recv_cnt};
+stat_name_and_unit(recv_dvi) ->
+ {"Average packet size deviation received", {bytes,recv_dvi}};
+stat_name_and_unit(recv_max) ->
+ {"Largest packet received", {bytes,recv_max}};
+stat_name_and_unit(recv_oct) ->
+ {"Total received", {bytes,recv_oct}};
+stat_name_and_unit(send_avg) ->
+ {"Average packet size sent", {bytes, send_avg}};
+stat_name_and_unit(send_cnt) ->
+ {"Number of packets sent", send_cnt};
+stat_name_and_unit(send_max) ->
+ {"Largest packet sent", {bytes, send_max}};
+stat_name_and_unit(send_oct) ->
+ {"Total sent", {bytes, send_oct}};
+stat_name_and_unit(send_pend) ->
+ {"Data waiting to be sent from driver", {bytes,send_pend}};
+stat_name_and_unit(Key) ->
+ {atom_to_list(Key), Key}.
+
filter_monitor_info() ->
fun(Data) ->
Ms = proplists:get_value(monitors, Data),
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index ee6829b847..f07b9e295a 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -511,7 +511,13 @@ table_holder(#holder{info=Info, attrs=Attrs,
table_holder(S0);
{dump, Fd} ->
EtopInfo = (S0#holder.etop)#etop_info{procinfo=array:to_list(Info)},
- etop_txt:do_update(Fd, EtopInfo, #opts{node=Node}),
+ %% The empty #etop_info{} below is a dummy previous info
+ %% value. It is used by etop to calculate the scheduler
+ %% utilization since last update. When dumping to file,
+ %% there is no previous measurement to use, so we just add
+ %% a dummy here, and the value shown will be since the
+ %% tool was started.
+ etop_txt:do_update(Fd, EtopInfo, #etop_info{}, #opts{node=Node}),
file:close(Fd),
table_holder(S0);
stop ->
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 620979dcc9..c13b164ff9 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -434,7 +434,7 @@ get_gc_info(Arg) ->
filter_monitor_info() ->
fun(Data) ->
Ms = proplists:get_value(monitors, Data),
- [Pid || {process, Pid} <- Ms]
+ [Id || {_Type, Id} <- Ms] % Type is process or port
end.
stringify_bins(Data) ->
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 73ed890802..8df69c6624 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -420,6 +420,10 @@ special(File,Procs) ->
%% ".trunc" ->
%% %% ????
%% ok;
+ ".trunc.bytes" ->
+ {ok,_,[TW]} = crashdump_viewer:general_info(),
+ {match,_} = re:run(TW,"CRASH DUMP SIZE LIMIT REACHED"),
+ ok;
_ ->
ok
end,
@@ -481,7 +485,11 @@ do_create_dumps(DataDir,Rel) ->
current ->
CD3 = dump_with_args(DataDir,Rel,"instr","+Mim true"),
CD4 = dump_with_strange_module_name(DataDir,Rel,"strangemodname"),
- {[CD1,CD2,CD3,CD4], DosDump};
+ Bytes = rand:uniform(300000) + 100,
+ CD5 = dump_with_args(DataDir,Rel,"trunc.bytes",
+ "-env ERL_CRASH_DUMP_BYTES " ++
+ integer_to_list(Bytes)),
+ {[CD1,CD2,CD3,CD4,CD5], DosDump};
_ ->
{[CD1,CD2], DosDump}
end.
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index 444089151e..dd23b08484 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.2.2
+OBSERVER_VSN = 2.3
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index d26daa5eda..2dec6e5abf 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -65,7 +65,7 @@ dnl ---------------------------------------------------------------------
dnl Special windows stuff regarding CFLAGS and details in the environment...
dnl ---------------------------------------------------------------------
LM_WINDOWS_ENVIRONMENT
-
+
AC_PROG_MAKE_SET
AC_CHECK_PROGS(LD, ld.sh)
@@ -136,8 +136,8 @@ AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_addr], [], [],
dnl Checks for library functions.
AC_CHECK_FUNCS([memset socket])
-
-# ODBC
+
+# ODBC
$RM -f "$ERL_TOP/lib/odbc/SKIP"
LM_CHECK_THR_LIB
@@ -146,24 +146,24 @@ AC_SUBST(THR_LIBS)
odbc_lib_link_success=no
AC_SUBST(TARGET_FLAGS)
- case $host_os in
- darwin1[[0-5]].*|darwin[[0-9]].*)
+ case $host_os in
+ darwin1[[0-9]].*)
TARGET_FLAGS="-DUNIX"
if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then
- ODBC_LIB= -L"/usr/lib"
- ODBC_INCLUDE="-I/usr/lib/include"
+ ODBC_LIB= -L"/usr/local/lib"
+ ODBC_INCLUDE="-I/usr/local/include"
else
ODBC_LIB=-L"$with_odbc/lib"
ODBC_INCLUDE="-I$with_odbc/include"
fi
-
- AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -liodbc"; odbc_lib_link_success=yes])
+
+ AC_CHECK_LIB(iodbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
;;
win32|cygwin)
TARGET_FLAGS="-DWIN32"
AC_CHECK_LIB(ws2_32, main)
if test ! -d "$with_odbc" || test "$with_odbc" = "yes"; then
- ODBC_LIB=""
+ ODBC_LIB=""
ODBC_INCLUDE=""
else
ODBC_LIB=-L"$with_odbc/lib"
@@ -196,7 +196,7 @@ AC_SUBST(TARGET_FLAGS)
elif test -d "${libdir}/64/."; then
libdir="${libdir}/64"
fi
- fi
+ fi
ODBC_LIB="-L$libdir"
ODBC_INCLUDE="-I$erl_xcomp_isysroot$rdir/include"
break
@@ -207,7 +207,7 @@ AC_SUBST(TARGET_FLAGS)
echo "No odbc library found" > "$ERL_TOP/lib/odbc/SKIP"
else
AC_MSG_RESULT($ODBC_LIB)
- AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
+ AC_CHECK_LIB(odbc, SQLAllocHandle,[ODBC_LIB="$ODBC_LIB -lodbc"; odbc_lib_link_success=yes])
fi
;;
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index 7fb19a072e..cc25a21c74 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -32,7 +32,28 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.11.3</title>
+ <section><title>ODBC 2.12</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Change configure to skip odbc for old MACs, the change in
+ PR-1227 is not backwards compatible with old MACs, and we
+ do not see a need to continue support for such old
+ versions. However it is still possible to make it work on
+ such machines using the --with-odbc configure option.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14083</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.11.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index a7c8f8079b..2e313570e1 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.11.3
+ODBC_VSN = 2.12
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index 30a9374e81..5a16445577 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -31,6 +31,26 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.1.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Correct counting of newlines when rules with newlines
+ are used in Leex. </p>
+ <p>
+ Own Id: OTP-13916 Aux Id: ERL-263 </p>
+ </item>
+ <item>
+ <p> Correct handling of Unicode in Leex. </p>
+ <p>
+ Own Id: OTP-13919</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.1.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index 07cd959c98..d102c63730 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1.3
+PARSETOOLS_VSN = 2.1.4
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index c4d930c01f..74d1a57936 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,23 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function
+ <c>public_key:ssh_hostkey_fingerprint/1,2</c> to
+ calculate the SSH host key fingerprint string.</p>
+ <p>
+ Own Id: OTP-13888 Aux Id: OTP-13887 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 385604677c..c503230d70 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2016</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -822,6 +822,36 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
+ <name>ssh_hostkey_fingerprint(HostKey) -> string()</name>
+ <name>ssh_hostkey_fingerprint(DigestType, HostKey) -> string()</name>
+ <fsummary>Calculates a ssh fingerprint for a hostkey.</fsummary>
+ <type>
+ <v>Key = public_key()</v>
+ <v>DigestType = digest_type()</v>
+ </type>
+ <desc>
+ <p>Calculates a ssh fingerprint from a public host key as openssh does.</p>
+ <p>The algorithm in <c>ssh_hostkey_fingerprint/1</c> is md5 to be compatible with older
+ ssh-keygen commands. The string from the second variant is prepended by the algorithm name
+ in uppercase as in newer ssh-keygen commands.</p>
+ <p>Examples:</p>
+ <code>
+ 2> public_key:ssh_hostkey_fingerprint(Key).
+ "f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
+
+ 3> public_key:ssh_hostkey_fingerprint(md5,Key).
+ "MD5:f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
+
+ 4> public_key:ssh_hostkey_fingerprint(sha,Key).
+ "SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY"
+
+ 5> public_key:ssh_hostkey_fingerprint(sha256,Key).
+ "SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"
+ </code>
+ </desc>
+ </func>
+
+ <func>
<name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
<fsummary>Verifies a digital signature.</fsummary>
<type>
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index d23abfe256..05c09f8996 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@
pkix_normalize_name/1,
pkix_path_validation/3,
ssh_decode/2, ssh_encode/2,
+ ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2,
ssh_curvename2oid/1, oid2ssh_curvename/1,
pkix_crls_validate/3,
pkix_dist_point/1,
@@ -91,7 +92,8 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
--type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
+-type digest_type() :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type().
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -819,6 +821,41 @@ oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>;
oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
%%--------------------------------------------------------------------
+-spec ssh_hostkey_fingerprint(public_key()) -> string().
+-spec ssh_hostkey_fingerprint(digest_type(), public_key()) -> string().
+
+ssh_hostkey_fingerprint(Key) ->
+ sshfp_string(md5, Key).
+
+ssh_hostkey_fingerprint(HashAlg, Key) ->
+ lists:concat([sshfp_alg_name(HashAlg),
+ [$: | sshfp_string(HashAlg, Key)]
+ ]).
+
+sshfp_string(HashAlg, Key) ->
+ %% Other HashAlgs than md5 will be printed with
+ %% other formats than hextstr by
+ %% ssh-keygen -E <alg> -lf <file>
+ fp_fmt(sshfp_fmt(HashAlg), crypto:hash(HashAlg, public_key:ssh_encode(Key,ssh2_pubkey))).
+
+sshfp_alg_name(sha) -> "SHA1";
+sshfp_alg_name(Alg) -> string:to_upper(atom_to_list(Alg)).
+
+sshfp_fmt(md5) -> hexstr;
+sshfp_fmt(_) -> b64.
+
+fp_fmt(hexstr, Bin) ->
+ lists:flatten(string:join([io_lib:format("~2.16.0b",[C1]) || <<C1>> <= Bin], ":"));
+fp_fmt(b64, Bin) ->
+ %% This function clause *seems* to be
+ %% [C || C<-base64:encode_to_string(Bin), C =/= $=]
+ %% but I am not sure. Must be checked.
+ B64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+ BitsInLast = 8*size(Bin) rem 6,
+ Padding = (6-BitsInLast) rem 6, % Want BitsInLast = [1:5] to map to padding [5:1] and 0 -> 0
+ [lists:nth(C+1,B64Chars) || <<C:6>> <= <<Bin/binary,0:Padding>> ].
+
+%%--------------------------------------------------------------------
-spec short_name_hash({rdnSequence, [#'AttributeTypeAndValue'{}]}) ->
string().
diff --git a/lib/public_key/test/public_key.cover b/lib/public_key/test/public_key.cover
index ec00814578..6c46492bec 100644
--- a/lib/public_key/test/public_key.cover
+++ b/lib/public_key/test/public_key.cover
@@ -1,4 +1,4 @@
{incl_app,public_key,details}.
-{excl_mods, public_key, ['OTP-PUB-KEY']}.
+{excl_mods, public_key, ['OTP-PUB-KEY', 'PKCS-FRAME']}.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index b22b69a0f2..cd24819899 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -45,7 +45,14 @@ all() ->
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name,
- short_cert_issuer_hash, short_crl_issuer_hash].
+ short_cert_issuer_hash, short_crl_issuer_hash,
+ ssh_hostkey_fingerprint_md5_implicit,
+ ssh_hostkey_fingerprint_md5,
+ ssh_hostkey_fingerprint_sha,
+ ssh_hostkey_fingerprint_sha256,
+ ssh_hostkey_fingerprint_sha384,
+ ssh_hostkey_fingerprint_sha512
+ ].
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
@@ -81,7 +88,25 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
%%-------------------------------------------------------------------
-init_per_testcase(_TestCase, Config0) ->
+init_per_testcase(TestCase, Config) ->
+ case TestCase of
+ ssh_hostkey_fingerprint_md5_implicit -> init_fingerprint_testcase(md5, Config);
+ ssh_hostkey_fingerprint_md5 -> init_fingerprint_testcase(md5, Config);
+ ssh_hostkey_fingerprint_sha -> init_fingerprint_testcase(sha, Config);
+ ssh_hostkey_fingerprint_sha256 -> init_fingerprint_testcase(sha256, Config);
+ ssh_hostkey_fingerprint_sha384 -> init_fingerprint_testcase(sha384, Config);
+ ssh_hostkey_fingerprint_sha512 -> init_fingerprint_testcase(sha512, Config);
+ _ -> init_common_per_testcase(Config)
+ end.
+
+init_fingerprint_testcase(Alg, Config) ->
+ CryptoSupports = lists:member(Alg, proplists:get_value(hashs, crypto:supports())),
+ case CryptoSupports of
+ false -> {skip,{Alg,not_supported}};
+ true -> init_common_per_testcase(Config)
+ end.
+
+init_common_per_testcase(Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -89,6 +114,7 @@ init_per_testcase(_TestCase, Config0) ->
end_per_testcase(_TestCase, _Config) ->
ok.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -529,6 +555,48 @@ ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5_implicit(_Config) ->
+ Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5(_Config) ->
+ Expected = "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(md5, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead. The Expected is generated with:
+%% $ openssh-7.3p1/ssh-keygen -E sha1 -lf <file>
+%% 2048 SHA1:Soammnaqg06jrm2jivMSnzQGlmk [email protected] (RSA)
+ssh_hostkey_fingerprint_sha(_Config) ->
+ Expected = "SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
+ Expected = public_key:ssh_hostkey_fingerprint(sha, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha256(_Config) ->
+ Expected = "SHA256:T7F1BahkJWR7iJO8+rpzWOPbp7LZP4MlNrDExdNYOvY",
+ Expected = public_key:ssh_hostkey_fingerprint(sha256, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha384(_Config) ->
+ Expected = "SHA384:QhkLoGNI4KXdPvC//HxxSCP3uTQVADqxdajbgm+Gkx9zqz8N94HyP1JmH8C4/aEl",
+ Expected = public_key:ssh_hostkey_fingerprint(sha384, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha512(_Config) ->
+ Expected = "SHA512:ezUismvm3ADQQb6Nm0c1DwQ6ydInlJNfsnSQejFkXNmABg1Aenk9oi45CXeBOoTnlfTsGG8nFDm0smP10PBEeA",
+ Expected = public_key:ssh_hostkey_fingerprint(sha512, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
encrypt_decrypt() ->
[{doc, "Test public_key:encrypt_private and public_key:decrypt_public"}].
encrypt_decrypt(Config) when is_list(Config) ->
@@ -929,3 +997,13 @@ incorrect_countryname_pkix_cert() ->
incorrect_emailaddress_pkix_cert() ->
<<48,130,3,74,48,130,2,50,2,9,0,133,49,203,25,198,156,252,230,48,13,6,9,42,134, 72,134,247,13,1,1,5,5,0,48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17, 6,3,85,4,8,12,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10, 12,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116, 121,32,76,116,100,49,32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110, 118,97,108,105,100,64,101,109,97,105,108,46,99,111,109,48,30,23,13,49,51,49, 49,48,55,50,48,53,54,49,56,90,23,13,49,52,49,49,48,55,50,48,53,54,49,56,90, 48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,12,10,83,111, 109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,12,24,73,110,116,101, 114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,49, 32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110,118,97,108,105,100,64, 101,109,97,105,108,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13, 1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,190,243,49,213,219,60,232,105, 1,127,126,9,130,15,60,190,78,100,148,235,246,223,21,91,238,200,251,84,55,212, 78,32,120,61,85,172,0,144,248,5,165,29,143,79,64,178,51,153,203,76,115,238, 192,49,173,37,121,203,89,62,157,13,181,166,30,112,154,40,202,140,104,211,157, 73,244,9,78,236,70,153,195,158,233,141,42,238,2,143,160,225,249,27,30,140, 151,176,43,211,87,114,164,108,69,47,39,195,123,185,179,219,28,218,122,53,83, 77,48,81,184,14,91,243,12,62,146,86,210,248,228,171,146,225,87,51,146,155, 116,112,238,212,36,111,58,41,67,27,6,61,61,3,84,150,126,214,121,57,38,12,87, 121,67,244,37,45,145,234,131,115,134,58,194,5,36,166,52,59,229,32,47,152,80, 237,190,58,182,248,98,7,165,198,211,5,31,231,152,116,31,108,71,218,64,188, 178,143,27,167,79,15,112,196,103,116,212,65,197,94,37,4,132,103,91,217,73, 223,207,185,7,153,221,240,232,31,44,102,108,82,83,56,242,210,214,74,71,246, 177,217,148,227,220,230,4,176,226,74,194,37,2,3,1,0,1,48,13,6,9,42,134,72, 134,247,13,1,1,5,5,0,3,130,1,1,0,89,247,141,154,173,123,123,203,143,85,28,79, 73,37,164,6,17,89,171,224,149,22,134,17,198,146,158,192,241,41,253,58,230, 133,71,189,43,66,123,88,15,242,119,227,249,99,137,61,200,54,161,0,177,167, 169,114,80,148,90,22,97,78,162,181,75,93,209,116,245,46,81,232,64,157,93,136, 52,57,229,113,197,218,113,93,42,161,213,104,205,137,30,144,183,58,10,98,47, 227,177,96,40,233,98,150,209,217,68,22,221,133,27,161,152,237,46,36,179,59, 172,97,134,194,205,101,137,71,192,57,153,20,114,27,173,233,166,45,56,0,61, 205,45,202,139,7,132,103,248,193,157,184,123,43,62,172,236,110,49,62,209,78, 249,83,219,133,1,213,143,73,174,16,113,143,189,41,84,60,128,222,30,177,104, 134,220,52,239,171,76,59,176,36,113,176,214,118,16,44,235,21,167,199,216,200, 76,219,142,248,13,70,145,205,216,230,226,148,97,223,216,179,68,209,222,63, 140,137,24,164,192,149,194,79,119,247,75,159,49,116,70,241,70,116,11,40,119, 176,157,36,160,102,140,255,34,248,25,231,136,59>>.
+
+
+
+ssh_hostkey(rsa) ->
+ [{PKdecoded,_}] =
+ public_key:ssh_decode(
+ <<"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYXcYmsyJBstl4EfFYzfQJmSiUE162zvSGSoMYybShYOI6rnnyvvihfw8Aml+2gZ716F2tqG48FQ/yPZEGWNPMrCejPpJctaPWhpNdNMJ8KFXSEgr5bY2mEpa19DHmuDeXKzeJJ+X7s3fVdYc4FMk5731KIW6Huf019ZnTxbx0VKG6b1KAJBg3vpNsDxEMwQ4LFMB0JHVklOTzbxmpaeULuIxvl65A+eGeFVeo2Q+YI9UnwY1vSgmc9Azwy8Ie9Z0HpQBN5I7Uc5xnknT8V6xDhgNfXEfzsgsRdDfZLECt1WO/1gP9wkosvAGZWt5oG8pbNQWiQdFq536ck8WQD9WD [email protected]">>,
+ public_key),
+ PKdecoded.
+
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 84f6a659b5..2f541d8d84 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.2
+PUBLIC_KEY_VSN = 1.3
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 89b5f3a997..3b1e868757 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 0b830593b4..4c79a560ec 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -32,6 +32,33 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.11</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add option <c>queue_size</c> to ttb:tracer/2. This sets
+ the maximum queue size for the IP trace driver which is
+ used when tracing to shell and/or <c>{local,File}</c>.</p>
+ <p>
+ The default value for <c>queue_size</c> is specified by
+ <c>dbg</c>, and it is now changed from 50 to 200.</p>
+ <p>
+ Own Id: OTP-13829 Aux Id: seq13171 </p>
+ </item>
+ <item>
+ <p>
+ The port information page is updated to show more
+ information per port.</p>
+ <p>
+ Own Id: OTP-13948 Aux Id: ERL-272 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.10.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/runtime_tools/src/msacc.erl b/lib/runtime_tools/src/msacc.erl
index 4db5dbec91..0d9b2690e5 100644
--- a/lib/runtime_tools/src/msacc.erl
+++ b/lib/runtime_tools/src/msacc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index cedb677178..b27bc63d15 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -141,14 +141,59 @@ get_mnesia_loop(Parent, {Match, Cont}) ->
get_mnesia_loop(Parent, mnesia:select(Cont)).
get_port_list() ->
+ ExtraItems = [monitors,monitored_by,parallelism,locking,queue_size,memory],
[begin
[{port_id,P}|erlang:port_info(P)] ++
- case erlang:port_info(P,monitors) of
- undefined -> [];
- Monitors -> [Monitors]
- end
+ port_info(P,ExtraItems) ++
+ inet_port_extra(erlang:port_info(P, name), P)
end || P <- erlang:ports()].
+port_info(P,[Item|Items]) ->
+ case erlang:port_info(P,Item) of
+ undefined -> port_info(P,Items);
+ Value -> [Value|port_info(P,Items)]
+ end;
+port_info(_,[]) ->
+ [].
+
+inet_port_extra({_,Type},Port) when Type =:= "udp_inet";
+ Type =:= "tcp_inet";
+ Type =:= "sctp_inet" ->
+ Data =
+ case inet:getstat(Port) of
+ {ok, Stats} -> [{statistics, Stats}];
+ _ -> []
+ end ++
+ case inet:peername(Port) of
+ {ok, {RAddr,RPort}} when is_tuple(RAddr), is_integer(RPort) ->
+ [{remote_address,RAddr},{remote_port,RPort}];
+ {ok, RAddr} ->
+ [{remote_address,RAddr}];
+ {error, _} -> []
+ end ++
+ case inet:sockname(Port) of
+ {ok, {LAddr,LPort}} when is_tuple(LAddr), is_integer(LPort) ->
+ [{local_address,LAddr},{local_port,LPort}];
+ {ok, LAddr} ->
+ [{local_address,LAddr}];
+ {error, _} -> []
+ end ++
+ case inet:getopts(Port,
+ [active, broadcast, buffer, delay_send,
+ deliver, dontroute, exit_on_close,
+ header, high_msgq_watermark, high_watermark,
+ ipv6_v6only, keepalive, linger, low_msgq_watermark,
+ low_watermark, mode, netns, nodelay, packet,
+ packet_size, priority, read_packets, recbuf,
+ reuseaddr, send_timeout, send_timeout_close,
+ show_econnreset, sndbuf, tos, tclass]) of
+ {ok, Opts} -> [{options, Opts}];
+ {error, _} -> []
+ end,
+ [{inet,Data}];
+inet_port_extra(_,_) ->
+ [].
+
get_table_list(ets, Opts) ->
HideUnread = proplists:get_value(unread_hidden, Opts, true),
HideSys = proplists:get_value(sys_hidden, Opts, true),
@@ -269,13 +314,12 @@ etop_collect(Collector) ->
case SchedulerWallTime of
undefined ->
- spawn(fun() -> flag_holder_proc(Collector) end),
+ erlang:system_flag(scheduler_wall_time,true),
+ spawn(fun() -> flag_holder_proc(Collector) end),
ok;
_ ->
ok
- end,
-
- erlang:system_flag(scheduler_wall_time,true).
+ end.
flag_holder_proc(Collector) ->
Ref = erlang:monitor(process,Collector),
diff --git a/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c b/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
index ecdee7e3a2..ec00c68049 100644
--- a/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
+++ b/lib/runtime_tools/test/dbg_SUITE_data/dbg_SUITE.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2016. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 0fc86e42f7..53fc51c198 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.10.1
+RUNTIME_TOOLS_VSN = 1.11
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index 055d433524..190b937f03 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -31,6 +31,24 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>code:add_pathsa/1</c> and command line option
+ <c>-pa</c> both revert the given list of directories when
+ adding it at the beginning of the code path. This is now
+ documented.</p>
+ <p>
+ Own Id: OTP-13920 Aux Id: ERL-267 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.0.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 10d2539b7f..7093158502 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/test/release_handler_SUITE_data/start b/lib/sasl/test/release_handler_SUITE_data/start
index 87275045b1..eab2b77aed 100755
--- a/lib/sasl/test/release_handler_SUITE_data/start
+++ b/lib/sasl/test/release_handler_SUITE_data/start
@@ -21,8 +21,7 @@ then
fi
HEART_COMMAND=$ROOTDIR/bin/start
-HW_WD_DISABLE=true
-export HW_WD_DISABLE HEART_COMMAND
+export HEART_COMMAND
START_ERL_DATA=${1:-$RELDIR/start_erl.data}
diff --git a/lib/sasl/test/release_handler_SUITE_data/start_client b/lib/sasl/test/release_handler_SUITE_data/start_client
index 5ea94d6f7c..05d744f06e 100755
--- a/lib/sasl/test/release_handler_SUITE_data/start_client
+++ b/lib/sasl/test/release_handler_SUITE_data/start_client
@@ -24,8 +24,7 @@ RELDIR=$CLIENTDIR/releases
# Note that this scripts is modified an copied to $CLIENTDIR/bin/start
# in release_handler_SUITE:copy_client - therefore HEART_COMMAND is as follows:
HEART_COMMAND=$CLIENTDIR/bin/start
-HW_WD_DISABLE=true
-export HW_WD_DISABLE HEART_COMMAND
+export HEART_COMMAND
START_ERL_DATA=${1:-$RELDIR/start_erl.data}
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index a7d7c09cde..e35a0c2977 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.0.1
+SASL_VSN = 3.0.2
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index d25f66f44a..d4bf0de61a 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index d86692aaf6..416353508e 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
index ca84528f3d..b7a73e2597 100644
--- a/lib/ssh/doc/src/introduction.xml
+++ b/lib/ssh/doc/src/introduction.xml
@@ -195,8 +195,6 @@
Transport Layer Protocol</item>
<item><url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> -
Connection Protocol</item>
- <item><url href="http://www.ietf.org/rfc/rfc4255.txt">RFC 4255</url> -
- Key Fingerprints</item>
<item><url href="http://www.ietf.org/rfc/rfc4344.txt">RFC 4344</url> -
Transport Layer Encryption Modes</item>
<item><url href="http://www.ietf.org/rfc/rfc4716.txt">RFC 4716</url> -
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index f5a67bc00e..1837350284 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,50 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A file read with an sftp client could loose data if the
+ packet_size is set to larger than 64k. This is corrected
+ now in such a way that the packet_size is silently
+ lowered if there is a risk for data loss.</p>
+ <p>
+ Own Id: OTP-13857 Aux Id: ERL-238, OTP-13858 </p>
+ </item>
+ <item>
+ <p>
+ When user defined SSH shell REPL process exits with
+ reason normal, the SSH channel callback module should
+ report successful exit status to the SSH client. This
+ provides simple way for SSH clients to check for
+ successful completion of executed commands. (Thanks to
+ isvilen)</p>
+ <p>
+ Own Id: OTP-13905 Aux Id: PR-1173 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Extended the option <c>silently_accept_hosts</c> for
+ <c>ssh:connect</c> to make it possible for the client to
+ check the SSH host key fingerprint string. Se the
+ reference manual for SSH.</p>
+ <p>
+ Own Id: OTP-13887 Aux Id: OTP-13888 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.3.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index ef9f7cbd9b..6b49f89449 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -175,11 +175,21 @@
supplied with this option.
</p>
</item>
- <tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag>
+ <tag><c><![CDATA[{silently_accept_hosts, boolean() | accept_fun() | {crypto:digest_type(), accept_fun()} }]]></c>
+ <br/>
+ <c><![CDATA[accept_fun() :: fun(PeerName::string(), FingerPrint::string()) -> boolean()]]></c>
+ </tag>
<item>
<p>When <c>true</c>, hosts are added to the
file <c><![CDATA[known_hosts]]></c> without asking the user.
- Defaults to <c>false</c>.
+ Defaults to <c>false</c> which will give a user question on stdio of whether to accept or reject a previously
+ unseen host.</p>
+ <p>If the option value is has an <c>accept_fun()</c>, that fun will called with the arguments
+ <c>(PeerName, PeerHostKeyFingerPrint)</c>. The fingerprint is calculated on the Peer's Host Key with
+ <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-1">public_key:ssh_hostkey_fingerprint/1</seealso>.
+ </p>
+ <p>If the <c>crypto:digest_type()</c> is present, the fingerprint is calculated with that digest type by the function
+ <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-2">public_key:ssh_hostkey_fingerprint/2</seealso>.
</p>
</item>
<tag><c><![CDATA[{user_interaction, boolean()}]]></c></tag>
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index 7288266cf7..a0032ab449 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2013</year><year>2013</year>
+ <year>2013</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -138,8 +138,6 @@
Transport Layer Protocol.</item>
<item><url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url> -
Connection Protocol.</item>
- <item><url href="http://www.ietf.org/rfc/rfc4255.txt">RFC 4255</url> -
- Key Fingerprints.</item>
<item><url href="http://www.ietf.org/rfc/rfc4344.txt">RFC 4344</url> -
Transport Layer Encryption Modes.</item>
<item><url href="http://www.ietf.org/rfc/rfc4716.txt">RFC 4716</url> -
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 69d5a47f83..7ab6f22424 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -96,7 +96,7 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl ssh_dbg.hrl
# ----------------------------------------------------
# FLAGS
diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src
index 4cda8fee95..2540720c41 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 1d7be3547b..31e343e81b 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -617,6 +617,15 @@ handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) ->
Opt;
handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) ->
Opt;
+handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) ->
+ Opt;
+handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) ->
+ case lists:member(DigestAlg, [md5, sha, sha224, sha256, sha384, sha512]) of
+ true ->
+ Opt;
+ false ->
+ throw({error, {eoptions, Opt}})
+ end;
handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({preferred_algorithms,[_|_]} = Opt) ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 9f3e60bd62..13c9d9af4a 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index ac35b70209..9b54ecb2dd 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -406,7 +406,11 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{num_responses = 1,
kb_tries_left = KbTriesLeft,
user = User,
userauth_supported_methods = Methods} = Ssh) ->
- SendOneEmpty = proplists:get_value(tstflg, Opts) == one_empty,
+ SendOneEmpty =
+ (proplists:get_value(tstflg,Opts) == one_empty)
+ orelse
+ proplists:get_value(one_empty, proplists:get_value(tstflg,Opts,[]), false),
+
case check_password(User, unicode:characters_to_list(Password), Opts, Ssh) of
{true,Ssh1} when SendOneEmpty==true ->
Msg = #ssh_msg_userauth_info_request{name = "",
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index d0f2d54c06..c7a2c92670 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -287,6 +287,9 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
ssh_channel:cache_update(Cache, Channel#channel{
remote_id = RemoteId,
+ recv_packet_size = max(32768, % rfc4254/5.2
+ min(PacketSz, Channel#channel.recv_packet_size)
+ ),
send_window_size = WindowSz,
send_packet_size = PacketSz}),
{Reply, Connection} = reply_msg(Channel, Connection0, {open, ChannelId}),
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index dd414894d4..7451c9e6d0 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -928,6 +928,7 @@ handle_event(internal, Msg=#ssh_msg_channel_request{}, StateName, D) -
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_success{}, StateName, D) ->
+ update_inet_buffers(D#data.socket),
handle_connection_msg(Msg, StateName, D);
handle_event(internal, Msg=#ssh_msg_channel_failure{}, StateName, D) ->
@@ -1007,6 +1008,7 @@ handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
+ update_inet_buffers(D#data.socket),
{keep_state, send_msg(Msg,D)};
undefined ->
@@ -1194,12 +1196,12 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D))
of
Msg = #ssh_msg_kexinit{} ->
- {keep_state, D, [{next_event, internal, {Msg,DecryptedBytes}},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, {Msg,DecryptedBytes}}
]};
Msg ->
- {keep_state, D, [{next_event, internal, Msg},
- {next_event, internal, prepare_next_packet}
+ {keep_state, D, [{next_event, internal, prepare_next_packet},
+ {next_event, internal, Msg}
]}
catch
_C:_E ->
@@ -1738,6 +1740,11 @@ send_replies(Repls, State) ->
Repls).
get_repl({connection_reply,Msg}, {CallRepls,S}) ->
+ if is_record(Msg, ssh_msg_channel_success) ->
+ update_inet_buffers(S#data.socket);
+ true ->
+ ok
+ end,
{CallRepls, send_msg(Msg,S)};
get_repl({channel_data,undefined,_Data}, Acc) ->
Acc;
@@ -1926,3 +1933,13 @@ handshake(Pid, Ref, Timeout) ->
{error, timeout}
end.
+update_inet_buffers(Socket) ->
+ {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
+ MinVal = 655360,
+ case
+ [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
+ Val < MinVal]
+ of
+ [] -> ok;
+ NewOpts -> inet:setopts(Socket, NewOpts)
+ end.
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index ce5596e0f9..dff2bae9f2 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -28,6 +28,9 @@
stop/0
]).
+-export([shrink_bin/1,
+ wr_record/3]).
+
-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_connect.hrl").
diff --git a/lib/ssh/src/ssh_dbg.hrl b/lib/ssh/src/ssh_dbg.hrl
new file mode 100644
index 0000000000..e94664737b
--- /dev/null
+++ b/lib/ssh/src/ssh_dbg.hrl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-ifndef(SSH_DBG_HRL).
+-define(SSH_DBG_HRL, 1).
+
+-define(formatrec(RecName,R),
+ ssh_dbg:wr_record(R, record_info(fields,RecName), [])).
+
+-endif. % SSH_DBG_HRL defined
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index 0c24c09887..d464def6fa 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index dca018f20f..b739955836 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftpd_file_api.erl b/lib/ssh/src/ssh_sftpd_file_api.erl
index 78f452df67..e444e52ac0 100644
--- a/lib/ssh/src/ssh_sftpd_file_api.erl
+++ b/lib/ssh/src/ssh_sftpd_file_api.erl
@@ -36,7 +36,7 @@
-callback list_dir(file:name(), State::term()) ->
{{ok, Filenames::term()}, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_dir(Dir::term(), State::term()) ->
- {{ok, State::term()},State::term()} | {{error, Reason::term()}, State::term()}.
+ {ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback make_symlink(Path2::term(), Path::term(), State::term()) ->
{ok, State::term()} | {{error, Reason::term()}, State::term()}.
-callback open(Path::term(), Flags::term(), State::term()) ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 15b80de30a..21ba34506a 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -734,12 +734,16 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
-accepted_host(Ssh, PeerName, Opts) ->
+accepted_host(Ssh, PeerName, Public, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
+ F when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public)));
+ {DigestAlg,F} when is_function(F,2) ->
+ true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public)));
true ->
- yes;
+ true;
false ->
- yes_no(Ssh, "New host " ++ PeerName ++ " accept")
+ yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept")
end.
known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
@@ -749,10 +753,10 @@ known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh,
true ->
ok;
false ->
- case accepted_host(Ssh, PeerName, Opts) of
- yes ->
+ case accepted_host(Ssh, PeerName, Public, Opts) of
+ true ->
Mod:add_host_key(PeerName, Public, Opts);
- no ->
+ false ->
{error, rejected}
end
end.
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index dc3b7dc7e6..0f8a838f97 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -54,15 +54,18 @@
-endif.
-endif.
+%% Public key records:
+-include_lib("public_key/include/public_key.hrl").
%%% Properties:
prop_ssh_decode() ->
- ?FORALL(Msg, ssh_msg(),
- try ssh_message:decode(Msg)
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ try ssh_message:decode(decode_state(Msg,KexFam))
of
_ -> true
catch
+
C:E -> io:format('~p:~p~n',[C,E]),
false
end
@@ -71,122 +74,101 @@ prop_ssh_decode() ->
%%% This fails because ssh_message is not symmetric in encode and decode regarding data types
prop_ssh_decode_encode() ->
- ?FORALL(Msg, ssh_msg(),
- Msg == ssh_message:encode(ssh_message:decode(Msg))
+ ?FORALL({Msg,KexFam}, ?LET(KF, kex_family(), {ssh_msg(KF),KF} ),
+ Msg == ssh_message:encode(
+ fix_asym(
+ ssh_message:decode(decode_state(Msg,KexFam))))
).
%%%================================================================
%%%
-%%% Scripts to generate message generators
-%%%
-
-%% awk '/^( |\t)+byte( |\t)+SSH/,/^( |\t)*$/{print}' rfc425?.txt | sed 's/^\( \|\\t\)*//' > msgs.txt
-
-%% awk '/^byte( |\t)+SSH/{print $2","}' < msgs.txt
-
-%% awk 'BEGIN{print "%%%---- BEGIN GENERATED";prev=0} END{print " >>.\n%%%---- END GENERATED"} /^byte( |\t)+SSH/{if (prev==1) print " >>.\n"; prev=1; printf "%c%s%c",39,$2,39; print "()->\n <<?"$2;next} /^string( |\t)+\"/{print " ,"$2;next} /^string( |\t)+.*address/{print " ,(ssh_string_address())/binary %%",$2,$3,$4,$5,$6;next}/^string( |\t)+.*US-ASCII/{print " ,(ssh_string_US_ASCII())/binary %%",$2,$3,$4,$5,$6;next} /^string( |\t)+.*UTF-8/{print " ,(ssh_string_UTF_8())/binary %% ",$2,$3,$4,$5,$6;next} /^[a-z0-9]+( |\t)/{print " ,(ssh_"$1"())/binary %%",$2,$3,$4,$5,$6;next} /^byte\[16\]( |\t)+/{print" ,(ssh_byte_16())/binary %%",$2,$3,$4,$5,$6;next} /^name-list( |\t)+/{print" ,(ssh_name_list())/binary %%",$2,$3,$4,$5,$6;next} /./{print "?? %%",$0}' < msgs.txt > gen.txt
-
-%%%================================================================
-%%%
%%% Generators
%%%
-ssh_msg() -> ?LET(M,oneof(
-[[msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
-%%Assym [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
- [msg_code('SSH_MSG_IGNORE'),gen_string( )],
- %% [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()],
- %% [msg_code('SSH_MSG_KEXDH_REPLY'),gen_string( ),gen_mpint(),gen_string( )],
- %% [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
- [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()],
- [msg_code('SSH_MSG_NEWKEYS')],
- [msg_code('SSH_MSG_REQUEST_FAILURE')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS')],
- [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
- [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
- [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
- [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
- [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
- [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
- [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
-]
-
-), list_to_binary(M)).
-
-
-%%%================================================================
-%%%
-%%% Generator
-%%%
-
-do() ->
- io_lib:format('[~s~n]',
- [write_gen(
- files(["rfc4254.txt",
- "rfc4253.txt",
- "rfc4419.txt",
- "rfc4252.txt",
- "rfc4256.txt"]))]).
-
-
-write_gen(L) when is_list(L) ->
- string:join(lists:map(fun write_gen/1, L), ",\n ");
-write_gen({MsgName,Args}) ->
- lists:flatten(["[",generate_args([MsgName|Args]),"]"]).
-
-generate_args(As) -> string:join([generate_arg(A) || A <- As], ",").
-
-generate_arg({<<"string">>, <<"\"",B/binary>>}) ->
- S = get_string($",B),
- ["gen_string(\"",S,"\")"];
-generate_arg({<<"string">>, _}) -> "gen_string( )";
-generate_arg({<<"byte[",B/binary>>, _}) ->
- io_lib:format("gen_byte(~p)",[list_to_integer(get_string($],B))]);
-generate_arg({<<"byte">> ,_}) -> "gen_byte()";
-generate_arg({<<"uint16">>,_}) -> "gen_uint16()";
-generate_arg({<<"uint32">>,_}) -> "gen_uint32()";
-generate_arg({<<"uint64">>,_}) -> "gen_uint64()";
-generate_arg({<<"mpint">>,_}) -> "gen_mpint()";
-generate_arg({<<"name-list">>,_}) -> "gen_name_list()";
-generate_arg({<<"boolean">>,<<"FALSE">>}) -> "0";
-generate_arg({<<"boolean">>,<<"TRUE">>}) -> "1";
-generate_arg({<<"boolean">>,_}) -> "gen_boolean()";
-generate_arg({<<"....">>,_}) -> ""; %% FIXME
-generate_arg(Name) when is_binary(Name) ->
- lists:flatten(["msg_code('",binary_to_list(Name),"')"]).
-
+ssh_msg(<<"dh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEXDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEXDH_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ssh_msg(<<"dh_gex">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST_OLD'),gen_uint32()], % 30
+ [msg_code('SSH_MSG_KEX_DH_GEX_GROUP'),gen_mpint(),gen_mpint()] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M));
+
+ ssh_msg(<<"ecdh">>) ->
+ ?LET(M,oneof(
+ [
+ [msg_code('SSH_MSG_KEX_ECDH_INIT'),gen_mpint()], % 30
+ [msg_code('SSH_MSG_KEX_ECDH_REPLY'),gen_pubkey_string(ecdsa),gen_mpint(),gen_signature_string(ecdsa)] % 31
+ | rest_ssh_msgs()
+ ]),
+ list_to_binary(M)).
+
+
+rest_ssh_msgs() ->
+ [%% SSH_MSG_USERAUTH_INFO_RESPONSE
+ %% hard args SSH_MSG_USERAUTH_INFO_REQUEST
+ %% rfc4252 p12 error SSH_MSG_USERAUTH_REQUEST
+ [msg_code('SSH_MSG_KEX_DH_GEX_REQUEST'),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_INIT'),gen_mpint()],
+ [msg_code('SSH_MSG_KEX_DH_GEX_REPLY'),gen_pubkey_string(rsa),gen_mpint(),gen_signature_string(rsa)],
+ [msg_code('SSH_MSG_CHANNEL_CLOSE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_DATA'),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_EOF'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_EXTENDED_DATA'),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_FAILURE'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("direct-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("forwarded-tcpip"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("session"),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string("x11"),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN'),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_CONFIRMATION'),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_OPEN_FAILURE'),gen_uint32(),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("env"),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exec"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-signal"),0,gen_string( ),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("exit-status"),0,gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("pty-req"),gen_boolean(),gen_string( ),gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("shell"),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("signal"),0,gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("subsystem"),gen_boolean(),gen_string( )],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("window-change"),0,gen_uint32(),gen_uint32(),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("x11-req"),gen_boolean(),gen_boolean(),gen_string( ),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string("xon-xoff"),0,gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_REQUEST'),gen_uint32(),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_CHANNEL_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_CHANNEL_WINDOW_ADJUST'),gen_uint32(),gen_uint32()],
+ [msg_code('SSH_MSG_DEBUG'),gen_boolean(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_DISCONNECT'),gen_uint32(),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("cancel-tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string("tcpip-forward"),gen_boolean(),gen_string( ),gen_uint32()],
+ [msg_code('SSH_MSG_GLOBAL_REQUEST'),gen_string( ),gen_boolean()],
+ [msg_code('SSH_MSG_IGNORE'),gen_string( )],
+ [msg_code('SSH_MSG_KEXINIT'),gen_byte(16),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_name_list(),gen_boolean(),gen_uint32()],
+ [msg_code('SSH_MSG_NEWKEYS')],
+ [msg_code('SSH_MSG_REQUEST_FAILURE')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS')],
+ [msg_code('SSH_MSG_REQUEST_SUCCESS'),gen_uint32()],
+ [msg_code('SSH_MSG_SERVICE_ACCEPT'),gen_string( )],
+ [msg_code('SSH_MSG_SERVICE_REQUEST'),gen_string( )],
+ [msg_code('SSH_MSG_UNIMPLEMENTED'),gen_uint32()],
+ [msg_code('SSH_MSG_USERAUTH_BANNER'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_FAILURE'),gen_name_list(),gen_boolean()],
+ [msg_code('SSH_MSG_USERAUTH_PASSWD_CHANGEREQ'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_PK_OK'),gen_string( ),gen_string( )],
+ [msg_code('SSH_MSG_USERAUTH_SUCCESS')]
+ ].
+
+kex_family() -> oneof([<<"dh">>, <<"dh_gex">>, <<"ecdh">>]).
gen_boolean() -> choose(0,1).
@@ -230,13 +212,22 @@ gen_name() -> gen_string().
uint32_to_list(I) -> binary_to_list(<<I:32/unsigned-big-integer>>).
-%%%----
-get_string(Delim, B) ->
- binary_to_list( element(1, split_binary(B, count_string_chars(Delim,B,0))) ).
-
-count_string_chars(Delim, <<Delim,_/binary>>, Acc) -> Acc;
-count_string_chars(Delim, <<_,B/binary>>, Acc) -> count_string_chars(Delim, B, Acc+1).
+gen_pubkey_string(Type) ->
+ PubKey = case Type of
+ rsa -> #'RSAPublicKey'{modulus = 12345,publicExponent = 2};
+ ecdsa -> {#'ECPoint'{point=[1,2,3,4,5]},
+ {namedCurve,{1,2,840,10045,3,1,7}}} % 'secp256r1' nistp256
+ end,
+ gen_string(public_key:ssh_encode(PubKey, ssh2_pubkey)).
+
+gen_signature_string(Type) ->
+ Signature = <<"hejhopp">>,
+ Id = case Type of
+ rsa -> "ssh-rsa";
+ ecdsa -> "ecdsa-sha2-nistp256"
+ end,
+ gen_string(gen_string(Id) ++ gen_string(Signature)).
-define(MSG_CODE(Name,Num),
msg_code(Name) -> Num;
@@ -273,124 +264,34 @@ msg_code(Num) -> Name
?MSG_CODE('SSH_MSG_CHANNEL_FAILURE', 100);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_REQUEST', 60);
?MSG_CODE('SSH_MSG_USERAUTH_INFO_RESPONSE', 61);
+?MSG_CODE('SSH_MSG_KEXDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEXDH_REPLY', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST_OLD', 30);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_REQUEST', 34);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_GROUP', 31);
?MSG_CODE('SSH_MSG_KEX_DH_GEX_INIT', 32);
-?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33).
-
-%%%=============================================================================
-%%%=============================================================================
-%%%=============================================================================
-
-files(Fs) ->
- Defs = lists:usort(lists:flatten(lists:map(fun file/1, Fs))),
- DefinedIDs = lists:usort([binary_to_list(element(1,D)) || D <- Defs]),
- WantedIDs = lists:usort(wanted_messages()),
- Missing = WantedIDs -- DefinedIDs,
- case Missing of
- [] -> ok;
- _ -> io:format('%% Warning: missing ~p~n', [Missing])
- end,
- Defs.
-
-
-file(F) ->
- {ok,B} = file:read_file(F),
- hunt_msg_def(B).
-
-
-hunt_msg_def(<<"\n",B/binary>>) -> some_hope(skip_blanks(B));
-hunt_msg_def(<<_, B/binary>>) -> hunt_msg_def(B);
-hunt_msg_def(<<>>) -> [].
-
-some_hope(<<"byte ", B/binary>>) -> try_message(skip_blanks(B));
-some_hope(B) -> hunt_msg_def(B).
-
-try_message(B = <<"SSH_MSG_",_/binary>>) ->
- {ID,Rest} = get_id(B),
- case lists:member(binary_to_list(ID), wanted_messages()) of
- true ->
- {Lines,More} = get_def_lines(skip_blanks(Rest), []),
- [{ID,lists:reverse(Lines)} | hunt_msg_def(More)];
- false ->
- hunt_msg_def(Rest)
- end;
-try_message(B) -> hunt_msg_def(B).
-
-
-skip_blanks(<<32, B/binary>>) -> skip_blanks(B);
-skip_blanks(<< 9, B/binary>>) -> skip_blanks(B);
-skip_blanks(B) -> B.
-
-get_def_lines(B0 = <<"\n",B/binary>>, Acc) ->
- {ID,Rest} = get_id(skip_blanks(B)),
- case {size(ID), skip_blanks(Rest)} of
- {0,<<"....",More/binary>>} ->
- {Text,LineEnd} = get_to_eol(skip_blanks(More)),
- get_def_lines(LineEnd, [{<<"....">>,Text}|Acc]);
- {0,_} ->
- {Acc,B0};
- {_,Rest1} ->
- {Text,LineEnd} = get_to_eol(Rest1),
- get_def_lines(LineEnd, [{ID,Text}|Acc])
- end;
-get_def_lines(B, Acc) ->
- {Acc,B}.
-
-
-get_to_eol(B) -> split_binary(B, count_to_eol(B,0)).
-
-count_to_eol(<<"\n",_/binary>>, Acc) -> Acc;
-count_to_eol(<<>>, Acc) -> Acc;
-count_to_eol(<<_,B/binary>>, Acc) -> count_to_eol(B,Acc+1).
-
-
-get_id(B) -> split_binary(B, count_id_chars(B,0)).
-
-count_id_chars(<<C,B/binary>>, Acc) when $A=<C,C=<$Z -> count_id_chars(B,Acc+1);
-count_id_chars(<<C,B/binary>>, Acc) when $a=<C,C=<$z -> count_id_chars(B,Acc+1);
-count_id_chars(<<C,B/binary>>, Acc) when $0=<C,C=<$9 -> count_id_chars(B,Acc+1);
-count_id_chars(<<"_",B/binary>>, Acc) -> count_id_chars(B,Acc+1);
-count_id_chars(<<"-",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g name-list
-count_id_chars(<<"[",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(<<"]",B/binary>>, Acc) -> count_id_chars(B,Acc+1); %% e.g byte[16]
-count_id_chars(_, Acc) -> Acc.
-
-wanted_messages() ->
- ["SSH_MSG_CHANNEL_CLOSE",
- "SSH_MSG_CHANNEL_DATA",
- "SSH_MSG_CHANNEL_EOF",
- "SSH_MSG_CHANNEL_EXTENDED_DATA",
- "SSH_MSG_CHANNEL_FAILURE",
- "SSH_MSG_CHANNEL_OPEN",
- "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
- "SSH_MSG_CHANNEL_OPEN_FAILURE",
- "SSH_MSG_CHANNEL_REQUEST",
- "SSH_MSG_CHANNEL_SUCCESS",
- "SSH_MSG_CHANNEL_WINDOW_ADJUST",
- "SSH_MSG_DEBUG",
- "SSH_MSG_DISCONNECT",
- "SSH_MSG_GLOBAL_REQUEST",
- "SSH_MSG_IGNORE",
- "SSH_MSG_KEXDH_INIT",
- "SSH_MSG_KEXDH_REPLY",
- "SSH_MSG_KEXINIT",
- "SSH_MSG_KEX_DH_GEX_GROUP",
- "SSH_MSG_KEX_DH_GEX_REQUEST",
- "SSH_MSG_KEX_DH_GEX_REQUEST_OLD",
- "SSH_MSG_NEWKEYS",
- "SSH_MSG_REQUEST_FAILURE",
- "SSH_MSG_REQUEST_SUCCESS",
- "SSH_MSG_SERVICE_ACCEPT",
- "SSH_MSG_SERVICE_REQUEST",
- "SSH_MSG_UNIMPLEMENTED",
- "SSH_MSG_USERAUTH_BANNER",
- "SSH_MSG_USERAUTH_FAILURE",
-%% hard args "SSH_MSG_USERAUTH_INFO_REQUEST",
-%% "SSH_MSG_USERAUTH_INFO_RESPONSE",
- "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ",
- "SSH_MSG_USERAUTH_PK_OK",
-%%rfc4252 p12 error "SSH_MSG_USERAUTH_REQUEST",
- "SSH_MSG_USERAUTH_SUCCESS"].
+?MSG_CODE('SSH_MSG_KEX_DH_GEX_REPLY', 33);
+?MSG_CODE('SSH_MSG_KEX_ECDH_INIT', 30);
+?MSG_CODE('SSH_MSG_KEX_ECDH_REPLY', 31).
+
+%%%====================================================
+%%%=== WARNING: Knowledge of the test object ahead! ===
+%%%====================================================
+
+%% SSH message records:
+-include_lib("ssh/src/ssh_connect.hrl").
+-include_lib("ssh/src/ssh_transport.hrl").
+
+%%% Encoding and decodeing is asymetric so out=binary in=string. Sometimes. :(
+fix_asym(#ssh_msg_global_request{name=N} = M) -> M#ssh_msg_global_request{name = binary_to_list(N)};
+fix_asym(#ssh_msg_debug{message=D,language=L} = M) -> M#ssh_msg_debug{message = binary_to_list(D),
+ language = binary_to_list(L)};
+fix_asym(#ssh_msg_kexinit{cookie=C} = M) -> M#ssh_msg_kexinit{cookie = <<C:128>>};
+fix_asym(M) -> M.
+
+%%% Message codes 30 and 31 are overloaded depending on kex family so arrange the decoder
+%%% input as the test object does
+decode_state(<<30,_/binary>>=Msg, KexFam) -> <<KexFam/binary, Msg/binary>>;
+decode_state(<<31,_/binary>>=Msg, KexFam) -> <<KexFam/binary, Msg/binary>>;
+decode_state(Msg, _) -> Msg.
diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover
index a4221fbbbe..69d2a1c4f8 100644
--- a/lib/ssh/test/ssh.cover
+++ b/lib/ssh/test/ssh.cover
@@ -1,2 +1,3 @@
{incl_app,ssh,details}.
+{excl_mods, ssh, [ssh_dbg, ssh_info, ssh_server_key_api, ssh_sftpd_file_api]}. \ No newline at end of file
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 8b2db0e1a8..14605ee44f 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -198,7 +198,7 @@ try_exec_simple_group(Group, Config) ->
%%--------------------------------------------------------------------
%% Testing all default groups
-simple_exec_groups() -> [{timetrap,{minutes,5}}].
+simple_exec_groups() -> [{timetrap,{minutes,8}}].
simple_exec_groups(Config) ->
Sizes = interpolate( public_key:dh_gex_group_sizes() ),
@@ -206,10 +206,8 @@ simple_exec_groups(Config) ->
fun(Sz) ->
ct:log("Try size ~p",[Sz]),
ct:comment(Sz),
- case simple_exec_group(Sz, Config) of
- expected -> ct:log("Size ~p ok",[Sz]);
- _ -> ct:log("Size ~p not ok",[Sz])
- end
+ simple_exec_group(Sz, Config),
+ ct:log("Size ~p ok",[Sz])
end, Sizes),
ct:comment("~p",[lists:map(fun({_,I,_}) -> I;
(I) -> I
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index bcf3b01824..2819a4dbd9 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -381,13 +381,13 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
{password, "morot"},
{subsystems, [{"echo_n",EchoSS_spec}]}]),
- ct:log("connect", []),
+ ct:log("~p:~p connect", [?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
{user, "foo"},
{password, "morot"},
{user_interaction, false},
{user_dir, UserDir}]),
- ct:log("connected", []),
+ ct:log("~p:~p connected", [?MODULE,?LINE]),
%% build big binary
Data = << <<X:32>> || X <- lists:seq(1,SendSize div 4)>>,
@@ -399,58 +399,80 @@ do_interrupted_send(Config, SendSize, EchoSize) ->
Parent = self(),
ResultPid = spawn(
fun() ->
- ct:log("open channel",[]),
+ ct:log("~p:~p open channel",[?MODULE,?LINE]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- ct:log("start subsystem", []),
+ ct:log("~p:~p start subsystem", [?MODULE,?LINE]),
case ssh_connection:subsystem(ConnectionRef, ChannelId, "echo_n", infinity) of
success ->
Parent ! {self(), channelId, ChannelId},
Result =
- try collect_data(ConnectionRef, ChannelId)
+ try collect_data(ConnectionRef, ChannelId, EchoSize)
of
ExpectedData ->
+ ct:log("~p:~p got expected data",[?MODULE,?LINE]),
ok;
- _ ->
- {fail,"unexpected result"}
+ Other ->
+ ct:log("~p:~p unexpect: ~p", [?MODULE,?LINE,Other]),
+ {fail,"unexpected result in listener"}
catch
Class:Exception ->
- {fail, io_lib:format("Exception ~p:~p",[Class,Exception])}
+ {fail, io_lib:format("Listener exception ~p:~p",[Class,Exception])}
end,
- Parent ! {self(), Result};
+ Parent ! {self(), result, Result};
Other ->
Parent ! {self(), channelId, error, Other}
end
end),
receive
+ {ResultPid, channelId, error, Other} ->
+ ct:log("~p:~p channelId error ~p", [?MODULE,?LINE,Other]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ {fail, "ssh_connection:subsystem"};
+
{ResultPid, channelId, ChannelId} ->
- %% pre-adjust receive window so the other end doesn't block
- ct:log("adjust window", []),
- ssh_connection:adjust_window(ConnectionRef, ChannelId, size(ExpectedData) + 1),
-
- ct:log("going to send ~p bytes", [size(Data)]),
- case ssh_connection:send(ConnectionRef, ChannelId, Data, 30000) of
- {error, closed} ->
- ct:log("{error,closed} - That's what we expect :)", []),
- ok;
- Msg ->
- ct:log("Got ~p - that's bad, very bad indeed",[Msg]),
- ct:fail({expected,{error,closed}, got, Msg})
- end,
- ct:log("going to check the result (if it is available)", []),
+ ct:log("~p:~p ~p going to send ~p bytes", [?MODULE,?LINE,self(),size(Data)]),
+ SenderPid = spawn(fun() ->
+ Parent ! {self(), ssh_connection:send(ConnectionRef, ChannelId, Data, 30000)}
+ end),
receive
- {ResultPid, Result} ->
- ct:log("Got result: ~p", [Result]),
+ {ResultPid, result, {fail, Fail}} ->
+ ct:log("~p:~p Listener failed: ~p", [?MODULE,?LINE,Fail]),
+ {fail, Fail};
+
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Got result: ~p", [?MODULE,?LINE,Result]),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid),
- Result
- end;
+ ct:log("~p:~p Check sender", [?MODULE,?LINE]),
+ receive
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect :)",[?MODULE,?LINE]),
+ ok;
+ Msg ->
+ ct:log("~p:~p Not expected send result: ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Not expected msg"}
+ end;
+
+ {SenderPid, {error, closed}} ->
+ ct:log("~p:~p {error,closed} - That's what we expect, but client channel handler has not reported yet",[?MODULE,?LINE]),
+ receive
+ {ResultPid, result, Result} ->
+ ct:log("~p:~p Now got the result: ~p", [?MODULE,?LINE,Result]),
+ ssh:close(ConnectionRef),
+ ssh:stop_daemon(Pid),
+ ok;
+ Msg ->
+ ct:log("~p:~p Got an unexpected msg ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Un-expected msg"}
+ end;
- {ResultPid, channelId, error, Other} ->
- ssh:close(ConnectionRef),
- ssh:stop_daemon(Pid),
- {fail, io_lib:format("ssh_connection:subsystem: ~p",[Other])}
+ Msg ->
+ ct:log("~p:~p Got unexpected ~p",[?MODULE,?LINE,Msg]),
+ {fail, "Unexpected msg"}
+ end
end.
%%--------------------------------------------------------------------
@@ -909,36 +931,46 @@ big_cat_rx(ConnectionRef, ChannelId, Acc) ->
timeout
end.
-collect_data(ConnectionRef, ChannelId) ->
- ct:log("Listener ~p running! ConnectionRef=~p, ChannelId=~p",[self(),ConnectionRef,ChannelId]),
- collect_data(ConnectionRef, ChannelId, [], 0).
+collect_data(ConnectionRef, ChannelId, EchoSize) ->
+ ct:log("~p:~p Listener ~p running! ConnectionRef=~p, ChannelId=~p",[?MODULE,?LINE,self(),ConnectionRef,ChannelId]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, [], 0).
-collect_data(ConnectionRef, ChannelId, Acc, Sum) ->
+collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum) ->
TO = 5000,
receive
{ssh_cm, ConnectionRef, {data, ChannelId, 0, Data}} when is_binary(Data) ->
- ct:log("collect_data: received ~p bytes. total ~p bytes",[size(Data),Sum+size(Data)]),
- collect_data(ConnectionRef, ChannelId, [Data | Acc], Sum+size(Data));
- {ssh_cm, ConnectionRef, {eof, ChannelId}} ->
- try
- iolist_to_binary(lists:reverse(Acc))
- of
- Bin ->
- ct:log("collect_data: received eof.~nGot in total ~p bytes",[size(Bin)]),
- Bin
- catch
- C:E ->
- ct:log("collect_data: received eof.~nAcc is strange...~nException=~p:~p~nAcc=~p",
- [C,E,Acc]),
- {error,{C,E}}
- end;
+ ct:log("~p:~p collect_data: received ~p bytes. total ~p bytes, want ~p more",
+ [?MODULE,?LINE,size(Data),Sum+size(Data),EchoSize-Sum]),
+ ssh_connection:adjust_window(ConnectionRef, ChannelId, size(Data)),
+ collect_data(ConnectionRef, ChannelId, EchoSize, [Data | Acc], Sum+size(Data));
+ {ssh_cm, ConnectionRef, Msg={eof, ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
+ {ssh_cm, ConnectionRef, Msg={closed,ChannelId}} ->
+ collect_data_report_end(Acc, Msg, EchoSize);
+
Msg ->
- ct:log("collect_data: ***** unexpected message *****~n~p",[Msg]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ ct:log("~p:~p collect_data: ***** unexpected message *****~n~p",[?MODULE,?LINE,Msg]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
after TO ->
- ct:log("collect_data: ----- Nothing received for ~p seconds -----~n",[]),
- collect_data(ConnectionRef, ChannelId, Acc, Sum)
+ ct:log("~p:~p collect_data: ----- Nothing received for ~p seconds -----~n",[?MODULE,?LINE,TO]),
+ collect_data(ConnectionRef, ChannelId, EchoSize, Acc, Sum)
+ end.
+
+collect_data_report_end(Acc, Msg, EchoSize) ->
+ try
+ iolist_to_binary(lists:reverse(Acc))
+ of
+ Bin ->
+ ct:log("~p:~p collect_data: received ~p.~nGot in total ~p bytes, want ~p more",
+ [?MODULE,?LINE,Msg,size(Bin),EchoSize,size(Bin)]),
+ Bin
+ catch
+ C:E ->
+ ct:log("~p:~p collect_data: received ~p.~nAcc is strange...~nException=~p:~p~nAcc=~p",
+ [?MODULE,?LINE,Msg,C,E,Acc]),
+ {error,{C,E}}
end.
%%%-------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 4cc12cbcbe..86f5cb1746 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -61,7 +61,13 @@
unexpectedfun_option_client/1,
unexpectedfun_option_server/1,
user_dir_option/1,
- connectfun_disconnectfun_server/1
+ connectfun_disconnectfun_server/1,
+ hostkey_fingerprint_check/1,
+ hostkey_fingerprint_check_md5/1,
+ hostkey_fingerprint_check_sha/1,
+ hostkey_fingerprint_check_sha256/1,
+ hostkey_fingerprint_check_sha384/1,
+ hostkey_fingerprint_check_sha512/1
]).
%%% Common test callbacks
@@ -100,6 +106,12 @@ all() ->
disconnectfun_option_client,
unexpectedfun_option_server,
unexpectedfun_option_client,
+ hostkey_fingerprint_check,
+ hostkey_fingerprint_check_md5,
+ hostkey_fingerprint_check_sha,
+ hostkey_fingerprint_check_sha256,
+ hostkey_fingerprint_check_sha384,
+ hostkey_fingerprint_check_sha512,
id_string_no_opt_client,
id_string_own_string_client,
id_string_random_client,
@@ -782,6 +794,96 @@ unexpectedfun_option_client(Config) ->
end.
%%--------------------------------------------------------------------
+hostkey_fingerprint_check(Config) ->
+ do_hostkey_fingerprint_check(Config, old).
+
+hostkey_fingerprint_check_md5(Config) ->
+ do_hostkey_fingerprint_check(Config, md5).
+
+hostkey_fingerprint_check_sha(Config) ->
+ do_hostkey_fingerprint_check(Config, sha).
+
+hostkey_fingerprint_check_sha256(Config) ->
+ do_hostkey_fingerprint_check(Config, sha256).
+
+hostkey_fingerprint_check_sha384(Config) ->
+ do_hostkey_fingerprint_check(Config, sha384).
+
+hostkey_fingerprint_check_sha512(Config) ->
+ do_hostkey_fingerprint_check(Config, sha512).
+
+
+%%%----
+do_hostkey_fingerprint_check(Config, HashAlg) ->
+ case supported_hash(HashAlg) of
+ true ->
+ really_do_hostkey_fingerprint_check(Config, HashAlg);
+ false ->
+ {skip,{unsupported_hash,HashAlg}}
+ end.
+
+supported_hash(old) -> true;
+supported_hash(HashAlg) ->
+ proplists:get_value(HashAlg,
+ proplists:get_value(hashs, crypto:supports(), []),
+ false).
+
+
+really_do_hostkey_fingerprint_check(Config, HashAlg) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ UserDirServer = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
+ file:make_dir(UserDirServer),
+ SysDir = proplists:get_value(data_dir, Config),
+
+ UserDirClient =
+ ssh_test_lib:create_random_dir(Config), % Ensure no 'known_hosts' disturbs
+
+ %% All host key fingerprints. Trust that public_key has checked the ssh_hostkey_fingerprint
+ %% function since that function is used by the ssh client...
+ FPs = [case HashAlg of
+ old -> public_key:ssh_hostkey_fingerprint(Key);
+ _ -> public_key:ssh_hostkey_fingerprint(HashAlg, Key)
+ end
+ || FileCandidate <- begin
+ {ok,KeyFileCands} = file:list_dir(SysDir),
+ KeyFileCands
+ end,
+ nomatch =/= re:run(FileCandidate, ".*\\.pub", []),
+ {Key,_Cmnts} <- begin
+ {ok,Bin} = file:read_file(filename:join(SysDir, FileCandidate)),
+ try public_key:ssh_decode(Bin, public_key)
+ catch
+ _:_ -> []
+ end
+ end],
+ ct:log("Fingerprints(~p) = ~p",[HashAlg,FPs]),
+
+ %% Start daemon with the public keys that we got fingerprints from
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, UserDirServer},
+ {password, "morot"}]),
+
+ FP_check_fun = fun(PeerName, FP) ->
+ ct:pal("PeerName = ~p, FP = ~p",[PeerName,FP]),
+ HostCheck = (Host == PeerName),
+ FPCheck = lists:member(FP, FPs),
+ ct:log("check ~p == ~p (~p) and ~n~p in ~p (~p)~n",
+ [PeerName,Host,HostCheck,FP,FPs,FPCheck]),
+ HostCheck and FPCheck
+ end,
+
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts,
+ case HashAlg of
+ old -> FP_check_fun;
+ _ -> {HashAlg, FP_check_fun}
+ end},
+ {user, "foo"},
+ {password, "morot"},
+ {user_dir, UserDirClient},
+ {user_interaction, false}]),
+ ssh:stop_daemon(Pid).
+
+%%--------------------------------------------------------------------
%%% Test connect_timeout option in ssh:connect/4
ssh_connect_timeout(_Config) ->
ConnTimeout = 2000,
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 7ba2732a88..9b2a84d8e4 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -68,9 +68,6 @@ init_per_group(_, Config) ->
end_per_group(_, Config) ->
Config.
-%%% Always skip the testcase that is not quite in phase with the
-%%% ssh_message.erl code
-init_per_testcase(decode_encode, _) -> {skip, "Fails - testcase is not ok"};
init_per_testcase(_TestCase, Config) -> Config.
end_per_testcase(_TestCase, Config) -> Config.
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index 19ad81e7da..acf76157a2 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -60,12 +60,16 @@ end_per_suite(_onfig) ->
groups() ->
[{not_unicode, [], [{group,erlang_server},
{group,openssh_server},
+ {group,big_recvpkt_size},
sftp_nonexistent_subsystem]},
{unicode, [], [{group,erlang_server},
{group,openssh_server},
sftp_nonexistent_subsystem]},
+ {big_recvpkt_size, [], [{group,erlang_server},
+ {group,openssh_server}]},
+
{erlang_server, [], [{group,write_read_tests},
version_option,
{group,remote_tar}]},
@@ -149,6 +153,9 @@ init_per_group(unicode, Config) ->
{skip, "Not unicode file encoding"}
end;
+init_per_group(big_recvpkt_size, Config) ->
+ [{pkt_sz,123456} | Config];
+
init_per_group(erlang_server, Config) ->
ct:comment("Begin ~p",[grps(Config)]),
PrivDir = proplists:get_value(priv_dir, Config),
@@ -257,7 +264,10 @@ init_per_testcase(Case, Config00) ->
Dog = ct:timetrap(2 * ?default_timeout),
User = proplists:get_value(user, Config0),
Passwd = proplists:get_value(passwd, Config0),
-
+ PktSzOpt = case proplists:get_value(pkt_sz, Config0) of
+ undefined -> [];
+ Sz -> [{packet_size,Sz}]
+ end,
Config =
case proplists:get_value(group,Config2) of
erlang_server ->
@@ -267,7 +277,9 @@ init_per_testcase(Case, Config00) ->
[{user, User},
{password, Passwd},
{user_interaction, false},
- {silently_accept_hosts, true}]
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]
),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2];
@@ -278,7 +290,9 @@ init_per_testcase(Case, Config00) ->
{ok, ChannelPid, Connection} =
ssh_sftp:start_channel(Host,
[{user_interaction, false},
- {silently_accept_hosts, true}]),
+ {silently_accept_hosts, true}
+ | PktSzOpt
+ ]),
Sftp = {ChannelPid, Connection},
[{sftp, Sftp}, {watchdog, Dog} | Config2]
end,
@@ -1024,7 +1038,7 @@ oldprep(Config) ->
prepare(Config0) ->
PrivDir = proplists:get_value(priv_dir, Config0),
- Dir = filename:join(PrivDir, random_chars(10)),
+ Dir = filename:join(PrivDir, ssh_test_lib:random_chars(10)),
file:make_dir(Dir),
Keys = [filename,
testfile,
@@ -1044,8 +1058,6 @@ prepare(Config0) ->
[{sftp_priv_dir,Dir} | Config2].
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
-
foldl_keydelete(Keys, L) ->
lists:foldl(fun(K,E) -> lists:keydelete(K,1,E) end,
L,
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index f93237f3e7..286ac6e882 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -113,19 +113,27 @@ std_simple_exec(Host, Port, Config) ->
std_simple_exec(Host, Port, Config, []).
std_simple_exec(Host, Port, Config, Opts) ->
+ ct:log("~p:~p std_simple_exec",[?MODULE,?LINE]),
ConnectionRef = ssh_test_lib:std_connect(Config, Host, Port, Opts),
+ ct:log("~p:~p connected! ~p",[?MODULE,?LINE,ConnectionRef]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
- Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"42\n">>}},
- case ssh_test_lib:receive_exec_result(Data) of
- expected ->
- ok;
- Other ->
- ct:fail(Other)
- end,
- ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
- ssh:close(ConnectionRef).
-
+ ct:log("~p:~p session_channel ok ~p",[?MODULE,?LINE,ChannelId]),
+ ExecResult = ssh_connection:exec(ConnectionRef, ChannelId, "23+21-2.", infinity),
+ ct:log("~p:~p exec ~p",[?MODULE,?LINE,ExecResult]),
+ case ExecResult of
+ success ->
+ Expected = {ssh_cm, ConnectionRef, {data,ChannelId,0,<<"42\n">>}},
+ case receive_exec_result(Expected) of
+ expected ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end,
+ receive_exec_end(ConnectionRef, ChannelId),
+ ssh:close(ConnectionRef);
+ _ ->
+ ct:fail(ExecResult)
+ end.
start_shell(Port, IOServer) ->
start_shell(Port, IOServer, []).
@@ -834,3 +842,20 @@ get_kex_init(Conn, Ref, TRef) ->
end
end.
+%%%----------------------------------------------------------------
+%%% Return a string with N random characters
+%%%
+random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+
+
+create_random_dir(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Name = filename:join(PrivDir, random_chars(15)),
+ case file:make_dir(Name) of
+ ok ->
+ Name;
+ {error,eexist} ->
+ %% The Name already denotes an existing file system object, try again.
+ %% The likelyhood of always generating an existing file name is low
+ create_random_dir(Config)
+ end.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 2c7fe7898f..86c3d5de26 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -404,8 +404,6 @@ erlang_server_openssh_client_renegotiate(Config) ->
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{public_key_alg, PubKeyAlg},
{failfun, fun ssh_test_lib:failfun/2}]),
-
-%% catch ssh_dbg:messages(fun(String,_D) -> ct:log(String) end),
ct:sleep(500),
RenegLimitK = 3,
@@ -431,13 +429,24 @@ erlang_server_openssh_client_renegotiate(Config) ->
catch
_:_ -> false
end;
+
+ ({exit_status,E}) when E=/=0 ->
+ ct:log("exit_status ~p",[E]),
+ throw({skip,"exit status"});
+
(_) ->
false
end,
-
- ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT),
- %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
- ssh:stop_daemon(Pid).
+
+ try
+ ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT)
+ of
+ _ ->
+ %% Unfortunatly we can't check that there has been a renegotiation, just trust OpenSSH.
+ ssh:stop_daemon(Pid)
+ catch
+ throw:{skip,R} -> {skip,R}
+ end.
%%--------------------------------------------------------------------
erlang_client_openssh_server_renegotiate(_Config) ->
@@ -447,7 +456,6 @@ erlang_client_openssh_server_renegotiate(_Config) ->
Ref = make_ref(),
Parent = self(),
- catch ssh_dbg:messages(fun(X,_) -> ct:log(X) end),
Shell =
spawn_link(
fun() ->
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index e34071af99..bc86000d81 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index b5b27c369a..7b9b109fa1 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -199,6 +199,4 @@ close(#state{server = Server,
connection = undefined}.
-random_contents() -> list_to_binary( random_chars(3) ).
-
-random_chars(N) -> [crypto:rand_uniform($a,$z) || _<-lists:duplicate(N,x)].
+random_contents() -> list_to_binary( ssh_test_lib:random_chars(3) ).
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c023429056..c6a5990f41 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.3.6
+SSH_VSN = 4.4
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index c7f50777a8..29b8e8ff67 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -28,6 +28,42 @@
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ List of possible anonymous suites, never supported by
+ default, where incorrect for some TLS versions.</p>
+ <p>
+ Own Id: OTP-13926</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Experimental version of DTLS. It is runnable but not
+ complete and cannot be considered reliable for production
+ usage.</p>
+ <p>
+ Own Id: OTP-12982</p>
+ </item>
+ <item>
+ <p>
+ Add API options to handle ECC curve selection.</p>
+ <p>
+ Own Id: OTP-13959</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index edc7e0d8b2..916b41742e 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -424,6 +424,14 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
</taglist>
</item>
+
+ <tag><c>max_handshake_size</c></tag>
+ <item>
+ <p>Integer (24 bits unsigned). Used to limit the size of
+ valid TLS handshake packets to avoid DoS attacks.
+ Defaults to 256*1024.</p>
+ </item>
+
</taglist>
</item>
diff --git a/lib/ssl/doc/src/ssl_crl_cache_api.xml b/lib/ssl/doc/src/ssl_crl_cache_api.xml
index 7440b6ef04..c6774b4df6 100644
--- a/lib/ssl/doc/src/ssl_crl_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache_api.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year><year>2015</year>
+ <year>2015</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index b625db0656..3dda1a3316 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2015. All Rights Reserved.
+# Copyright Ericsson AB 1999-2016. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -50,6 +50,7 @@ MODULES= \
ssl_app \
ssl_dist_sup\
ssl_sup \
+ dtls_udp_sup \
inet_tls_dist \
inet6_tls_dist \
ssl_certificate\
@@ -71,7 +72,9 @@ MODULES= \
ssl_crl\
ssl_crl_cache \
ssl_crl_hash_dir \
- ssl_socket \
+ tls_socket \
+ dtls_socket \
+ dtls_udp_listener\
ssl_listen_tracker_sup \
tls_record \
dtls_record \
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 4f1f050e4b..070a90d481 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,12 +48,12 @@
select_sni_extension/1]).
%% Alert and close handling
--export([send_alert/2, close/5]).
+-export([encode_alert/3,send_alert/2, close/5]).
%% Data handling
--export([passive_receive/2, next_record_if_active/1, handle_common_event/4
- ]).
+-export([encode_data/3, passive_receive/2, next_record_if_active/1, handle_common_event/4,
+ send/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
@@ -93,61 +93,120 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} =
Error
end.
-send_handshake(Handshake, State) ->
- send_handshake_flight(queue_handshake(Handshake, State)).
+send_handshake(Handshake, #state{connection_states = ConnectionStates} = States) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ send_handshake_flight(queue_handshake(Handshake, States), Epoch).
+
+queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
+ negotiated_version = Version,
+ flight_buffer = #{handshakes := HsBuffer0,
+ change_cipher_spec := undefined,
+ next_sequence := Seq} = Flight0} = State) ->
+ Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
+ Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ State#state{flight_buffer = Flight0#{handshakes => [Handshake | HsBuffer0],
+ next_sequence => Seq +1},
+ tls_handshake_history = Hist};
+
+queue_handshake(Handshake0, #state{tls_handshake_history = Hist0,
+ negotiated_version = Version,
+ flight_buffer = #{handshakes_after_change_cipher_spec := Buffer0,
+ next_sequence := Seq} = Flight0} = State) ->
+ Handshake = dtls_handshake:encode_handshake(Handshake0, Version, Seq),
+ Hist = update_handshake_history(Handshake0, Handshake, Hist0),
+ State#state{flight_buffer = Flight0#{handshakes_after_change_cipher_spec => [Handshake | Buffer0],
+ next_sequence => Seq +1},
+ tls_handshake_history = Hist}.
-queue_flight_buffer(Msg, #state{negotiated_version = Version,
- connection_states = ConnectionStates,
- flight_buffer = Flight} = State) ->
- ConnectionState =
- ssl_record:current_connection_state(ConnectionStates, write),
- Epoch = maps:get(epoch, ConnectionState),
- State#state{flight_buffer = Flight ++ [{Version, Epoch, Msg}]}.
-
-queue_handshake(Handshake, #state{negotiated_version = Version,
- tls_handshake_history = Hist0,
- connection_states = ConnectionStates0} = State0) ->
- {Frag, ConnectionStates, Hist} =
- encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
- queue_flight_buffer(Frag, State0#state{connection_states = ConnectionStates,
- tls_handshake_history = Hist}).
send_handshake_flight(#state{socket = Socket,
transport_cb = Transport,
- flight_buffer = Flight,
- connection_states = ConnectionStates0} = State0) ->
-
+ flight_buffer = #{handshakes := Flight,
+ change_cipher_spec := undefined},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ %% TODO remove hardcoded Max size
{Encoded, ConnectionStates} =
- encode_handshake_flight(Flight, ConnectionStates0),
+ encode_handshake_flight(lists:reverse(Flight), Version, 1400, Epoch, ConnectionStates0),
+ send(Transport, Socket, Encoded),
+ start_flight(State0#state{connection_states = ConnectionStates});
+
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [_|_] = Flight0,
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := []},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {HsBefore, ConnectionStates1} =
+ encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch, ConnectionStates0),
+ {EncChangeCipher, ConnectionStates} = encode_change_cipher(ChangeCipher, Version, Epoch, ConnectionStates1),
+
+ send(Transport, Socket, [HsBefore, EncChangeCipher]),
+ start_flight(State0#state{connection_states = ConnectionStates});
- Transport:send(Socket, Encoded),
- State0#state{flight_buffer = [], connection_states = ConnectionStates}.
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [_|_] = Flight0,
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := Flight1},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {HsBefore, ConnectionStates1} =
+ encode_handshake_flight(lists:reverse(Flight0), Version, 1400, Epoch-1, ConnectionStates0),
+ {EncChangeCipher, ConnectionStates2} =
+ encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates1),
+ {HsAfter, ConnectionStates} =
+ encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates2),
+ send(Transport, Socket, [HsBefore, EncChangeCipher, HsAfter]),
+ start_flight(State0#state{connection_states = ConnectionStates});
-queue_change_cipher(Msg, State) ->
- queue_flight_buffer(Msg, State).
+send_handshake_flight(#state{socket = Socket,
+ transport_cb = Transport,
+ flight_buffer = #{handshakes := [],
+ change_cipher_spec := ChangeCipher,
+ handshakes_after_change_cipher_spec := Flight1},
+ negotiated_version = Version,
+ connection_states = ConnectionStates0} = State0, Epoch) ->
+ {EncChangeCipher, ConnectionStates1} =
+ encode_change_cipher(ChangeCipher, Version, Epoch-1, ConnectionStates0),
+ {HsAfter, ConnectionStates} =
+ encode_handshake_flight(lists:reverse(Flight1), Version, 1400, Epoch, ConnectionStates1),
+ send(Transport, Socket, [EncChangeCipher, HsAfter]),
+ start_flight(State0#state{connection_states = ConnectionStates}).
+
+queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
+ connection_states = ConnectionStates0} = State) ->
+ ConnectionStates =
+ dtls_record:next_epoch(ConnectionStates0, write),
+ State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
+ connection_states = ConnectionStates}.
send_alert(Alert, #state{negotiated_version = Version,
socket = Socket,
transport_cb = Transport,
connection_states = ConnectionStates0} = State0) ->
{BinMsg, ConnectionStates} =
- ssl_alert:encode(Alert, Version, ConnectionStates0),
- Transport:send(Socket, BinMsg),
+ encode_alert(Alert, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State0#state{connection_states = ConnectionStates}.
close(downgrade, _,_,_,_) ->
ok;
%% Other
close(_, Socket, Transport, _,_) ->
- Transport:close(Socket).
+ dtls_socket:close(Transport,Socket).
reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_history = ssl_handshake:init_handshake_history(),
protocol_buffers =
- Buffers#protocol_buffers{dtls_fragment_state =
- dtls_handshake:dtls_handshake_new_flight(0)}}.
+ Buffers#protocol_buffers{
+ dtls_handshake_next_seq = 0,
+ dtls_handshake_next_fragments = [],
+ dtls_handshake_later_fragments = []
+ }}.
select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
HelloExtensions#hello_extensions.sni;
@@ -160,7 +219,7 @@ select_sni_extension(_) ->
%%--------------------------------------------------------------------
-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
- {ok, pid()} | ignore | {error, reason()}.
+ {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
@@ -191,7 +250,6 @@ init({call, From}, {start, Timeout},
#state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
session = #session{own_certificate = Cert} = Session0,
- transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
session_cache = Cache,
@@ -199,23 +257,26 @@ init({call, From}, {start, Timeout},
} = State0) ->
Timer = ssl_connection:start_or_recv_cancel_timer(Timeout, From),
Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
- Cache, CacheCb, Renegotiation, Cert),
-
+ Cache, CacheCb, Renegotiation, Cert),
+
Version = Hello#client_hello.client_version,
HelloVersion = dtls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
- Handshake0 = ssl_handshake:init_handshake_history(),
- {BinMsg, ConnectionStates, Handshake} =
- encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0),
- Transport:send(Socket, BinMsg),
- State1 = State0#state{connection_states = ConnectionStates,
- negotiated_version = Version, %% Requested version
+ State1 = prepare_flight(State0#state{negotiated_version = Version}),
+ State2 = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
+ State3 = State2#state{negotiated_version = Version, %% Requested version
session =
Session0#session{session_id = Hello#client_hello.session_id},
- tls_handshake_history = Handshake,
start_or_recv_from = From,
timer = Timer},
- {Record, State} = next_record(State1),
+ {Record, State} = next_record(State3),
next_event(hello, Record, State);
+init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
+ ssl_connection:init(Type, Event,
+ State#state{flight_state = {waiting, undefined, ?INITIAL_RETRANSMIT_TIMEOUT}},
+ ?MODULE);
+init({call, _} = Type, Event, #state{role = server} = State) ->
+ %% I.E. DTLS over sctp
+ ssl_connection:init(Type, Event, State#state{flight_state = reliable}, ?MODULE);
init(Type, Event, State) ->
ssl_connection:init(Type, Event, State, ?MODULE).
@@ -232,34 +293,53 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-hello(internal, #client_hello{client_version = ClientVersion} = Hello,
- State = #state{connection_states = ConnectionStates0,
- port = Port, session = #session{own_certificate = Cert} = Session0,
- renegotiation = {Renegotiation, _},
- session_cache = Cache,
- session_cache_cb = CacheCb,
- negotiated_protocol = CurrentProtocol,
- key_algorithm = KeyExAlg,
- ssl_options = SslOpts}) ->
-
- case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
- ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State);
- {Version, {Type, Session},
- ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
- Protocol = case Protocol0 of
- undefined -> CurrentProtocol;
- _ -> Protocol0
- end,
-
- ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
- State#state{connection_states = ConnectionStates,
- negotiated_version = Version,
- hashsign_algorithm = HashSign,
- session = Session,
- negotiated_protocol = Protocol}, ?MODULE)
+hello(internal, #client_hello{cookie = <<>>,
+ client_version = Version} = Hello, #state{role = server,
+ transport_cb = Transport,
+ socket = Socket} = State0) ->
+ %% TODO: not hard code key
+ {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
+ Cookie = dtls_handshake:cookie(<<"secret">>, IP, Port, Hello),
+ VerifyRequest = dtls_handshake:hello_verify_request(Cookie, Version),
+ State1 = prepare_flight(State0#state{negotiated_version = Version}),
+ State2 = send_handshake(VerifyRequest, State1),
+ {Record, State} = next_record(State2),
+ next_event(hello, Record, State#state{tls_handshake_history = ssl_handshake:init_handshake_history()});
+hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
+ transport_cb = Transport,
+ socket = Socket} = State0) ->
+ {ok, {IP, Port}} = dtls_socket:peername(Transport, Socket),
+ %% TODO: not hard code key
+ case dtls_handshake:cookie(<<"secret">>, IP, Port, Hello) of
+ Cookie ->
+ handle_client_hello(Hello, State0);
+ _ ->
+ %% Handle bad cookie as new cookie request RFC 6347 4.1.2
+ hello(internal, Hello#client_hello{cookie = <<>>}, State0)
end;
+hello(internal, #hello_verify_request{cookie = Cookie}, #state{role = client,
+ host = Host, port = Port,
+ ssl_options = SslOpts,
+ session = #session{own_certificate = OwnCert}
+ = Session0,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb
+ } = State0) ->
+ State1 = prepare_flight(State0#state{tls_handshake_history = ssl_handshake:init_handshake_history()}),
+ Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0,
+ SslOpts,
+ Cache, CacheCb, Renegotiation, OwnCert),
+ Version = Hello#client_hello.client_version,
+ HelloVersion = dtls_record:lowest_protocol_version(SslOpts#ssl_options.versions),
+ State2 = send_handshake(Hello, State1#state{negotiated_version = HelloVersion}),
+ State3 = State2#state{negotiated_version = Version, %% Requested version
+ session =
+ Session0#session{session_id =
+ Hello#client_hello.session_id}},
+ {Record, State} = next_record(State3),
+ next_event(hello, Record, State);
hello(internal, #server_hello{} = Hello,
#state{connection_states = ConnectionStates0,
negotiated_version = ReqVersion,
@@ -273,24 +353,49 @@ hello(internal, #server_hello{} = Hello,
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
end;
+hello(internal, {handshake, {#client_hello{cookie = <<>>} = Handshake, _}}, State) ->
+ %% Initial hello should not be in handshake history
+ {next_state, hello, State, [{next_event, internal, Handshake}]};
+
+hello(internal, {handshake, {#hello_verify_request{} = Handshake, _}}, State) ->
+ %% hello_verify should not be in handshake history
+ {next_state, hello, State, [{next_event, internal, Handshake}]};
+
hello(info, Event, State) ->
handle_info(Event, hello, State);
-
hello(Type, Event, State) ->
ssl_connection:hello(Type, Event, State, ?MODULE).
abbreviated(info, Event, State) ->
handle_info(Event, abbreviated, State);
+abbreviated(internal = Type,
+ #change_cipher_spec{type = <<1>>} = Event,
+ #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
+ ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
+ ssl_connection:abbreviated(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+abbreviated(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+ ssl_connection:cipher(Type, Event, prepare_flight(State#state{connection_states = ConnectionStates}), ?MODULE);
abbreviated(Type, Event, State) ->
ssl_connection:abbreviated(Type, Event, State, ?MODULE).
certify(info, Event, State) ->
handle_info(Event, certify, State);
+certify(internal = Type, #server_hello_done{} = Event, State) ->
+ ssl_connection:certify(Type, Event, prepare_flight(State), ?MODULE);
certify(Type, Event, State) ->
ssl_connection:certify(Type, Event, State, ?MODULE).
cipher(info, Event, State) ->
handle_info(Event, cipher, State);
+cipher(internal = Type, #change_cipher_spec{type = <<1>>} = Event,
+ #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = dtls_record:save_current_connection_state(ConnectionStates0, read),
+ ConnectionStates = dtls_record:next_epoch(ConnectionStates1, read),
+ ssl_connection:cipher(Type, Event, State#state{connection_states = ConnectionStates}, ?MODULE);
+cipher(internal = Type, #finished{} = Event, #state{connection_states = ConnectionStates} = State) ->
+ ssl_connection:cipher(Type, Event,
+ prepare_flight(State#state{connection_states = ConnectionStates}), ?MODULE);
cipher(Type, Event, State) ->
ssl_connection:cipher(Type, Event, State, ?MODULE).
@@ -310,7 +415,6 @@ connection(internal, #hello_request{}, #state{host = Host, port = Port,
State1#state{session = Session0#session{session_id
= Hello#client_hello.session_id}}),
next_event(hello, Record, State);
-
connection(internal, #client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
%% Mitigate Computational DoS attack
%% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
@@ -319,14 +423,11 @@ connection(internal, #client_hello{} = Hello, #state{role = server, allow_renego
%% renegotiations immediately after each other.
erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
{next_state, hello, State#state{allow_renegotiate = false}, [{next_event, internal, Hello}]};
-
-
connection(internal, #client_hello{}, #state{role = server, allow_renegotiate = false} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
next_event(connection, Record, State);
-
connection(Type, Event, State) ->
ssl_connection:connection(Type, Event, State, ?MODULE).
@@ -341,15 +442,25 @@ downgrade(Type, Event, State) ->
%%--------------------------------------------------------------------
%% raw data from socket, unpack records
-handle_info({Protocol, _, Data}, StateName,
+handle_info({_,flight_retransmission_timeout}, connection, _) ->
+ {next_state, keep_state_and_data};
+handle_info({Ref, flight_retransmission_timeout}, StateName,
+ #state{flight_state = {waiting, Ref, NextTimeout}} = State0) ->
+ State1 = send_handshake_flight(State0#state{flight_state = {retransmit_timer, NextTimeout}},
+ retransmit_epoch(StateName, State0)),
+ {Record, State} = next_record(State1),
+ next_event(StateName, Record, State);
+handle_info({_, flight_retransmission_timeout}, _, _) ->
+ {next_state, keep_state_and_data};
+handle_info({Protocol, _, _, _, Data}, StateName,
#state{data_tag = Protocol} = State0) ->
- case next_tls_record(Data, State0) of
+ case next_dtls_record(Data, State0) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
{stop, {shutdown, own_alert}}
- end;
+ end;
handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
negotiated_version = Version} = State) ->
@@ -380,23 +491,26 @@ handle_common_event(internal, #alert{} = Alert, StateName,
ssl_connection:handle_own_alert(Alert, Version, StateName, State);
%%% DTLS record protocol level handshake messages
-handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE} = Record,
+handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE,
+ fragment = Data},
StateName,
- #state{protocol_buffers =
- #protocol_buffers{dtls_packets = Packets0,
- dtls_fragment_state = HsState0} = Buffers,
+ #state{protocol_buffers = Buffers0,
negotiated_version = Version} = State0) ->
try
- {Packets1, HsState} = dtls_handshake:get_dtls_handshake(Record, HsState0),
- State =
- State0#state{protocol_buffers =
- Buffers#protocol_buffers{dtls_fragment_state = HsState}},
- Events = dtls_handshake_events(Packets0 ++ Packets1),
- case StateName of
- connection ->
- ssl_connection:hibernate_after(StateName, State, Events);
- _ ->
- {next_state, StateName, State, Events}
+ case dtls_handshake:get_dtls_handshake(Version, Data, Buffers0) of
+ {more_data, Buffers} ->
+ {Record, State} = next_record(State0#state{protocol_buffers = Buffers}),
+ next_event(StateName, Record, State);
+ {Packets, Buffers} ->
+ State = State0#state{protocol_buffers = Buffers},
+ Events = dtls_handshake_events(Packets),
+ case StateName of
+ connection ->
+ ssl_connection:hibernate_after(StateName, State, Events);
+ _ ->
+ {next_state, StateName,
+ State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ end
end
catch throw:#alert{} = Alert ->
ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
@@ -420,6 +534,10 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta
handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
{next_state, StateName, State}.
+send(Transport, {_, {{_,_}, _} = Socket}, Data) ->
+ send(Transport, Socket, Data);
+send(Transport, Socket, Data) ->
+ dtls_socket:send(Transport, Socket, Data).
%%--------------------------------------------------------------------
%% 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
@@ -442,96 +560,56 @@ format_status(Type, Data) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
+ #state{connection_states = ConnectionStates0,
+ port = Port, session = #session{own_certificate = Cert} = Session0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb,
+ negotiated_protocol = CurrentProtocol,
+ key_algorithm = KeyExAlg,
+ ssl_options = SslOpts} = State0) ->
+
+ case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State0);
+ {Version, {Type, Session},
+ ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
+ Protocol = case Protocol0 of
+ undefined -> CurrentProtocol;
+ _ -> Protocol0
+ end,
-dtls_handshake_events([]) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake));
-dtls_handshake_events(Packets) ->
- lists:map(fun(Packet) ->
- {next_event, internal, {handshake, Packet}}
- end, Packets).
-
-
-encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
- {Seq, ConnectionStates} = sequence(ConnectionStates0),
- {EncHandshake, Frag} = dtls_handshake:encode_handshake(Handshake, Version, Seq),
- %% DTLS does not have an equivalent version to SSLv2. So v2 hello compatibility
- %% will always be false
- Hist = ssl_handshake:update_handshake_history(Hist0, EncHandshake, false),
- {Frag, ConnectionStates, Hist}.
-
-encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- dtls_record:encode_change_cipher_spec(Version, ConnectionStates).
+ State = prepare_flight(State0#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ hashsign_algorithm = HashSign,
+ session = Session,
+ negotiated_protocol = Protocol}),
+
+ ssl_connection:hello(internal, {common_client_hello, Type, ServerHelloExt},
+ State, ?MODULE)
+ end.
-encode_handshake_flight(Flight, ConnectionStates) ->
- MSS = 1400,
- encode_handshake_records(Flight, ConnectionStates, MSS, init_pack_records()).
+encode_handshake_flight(Flight, Version, MaxFragmentSize, Epoch, ConnectionStates) ->
+ Fragments = lists:map(fun(Handshake) ->
+ dtls_handshake:fragment_handshake(Handshake, MaxFragmentSize)
+ end, Flight),
+ dtls_record:encode_handshake(Fragments, Version, Epoch, ConnectionStates).
-encode_handshake_records([], CS, _MSS, Recs) ->
- {finish_pack_records(Recs), CS};
+encode_change_cipher(#change_cipher_spec{}, Version, Epoch, ConnectionStates) ->
+ dtls_record:encode_change_cipher_spec(Version, Epoch, ConnectionStates).
-encode_handshake_records([{Version, _Epoch, Frag = #change_cipher_spec{}}|Tail], ConnectionStates0, MSS, Recs0) ->
- {Encoded, ConnectionStates} =
- encode_change_cipher(Frag, Version, ConnectionStates0),
- Recs = append_pack_records([Encoded], MSS, Recs0),
- encode_handshake_records(Tail, ConnectionStates, MSS, Recs);
-
-encode_handshake_records([{Version, Epoch, {MsgType, MsgSeq, Bin}}|Tail], CS0, MSS, Recs0 = {Buf0, _}) ->
- Space = MSS - iolist_size(Buf0),
- Len = byte_size(Bin),
- {Encoded, CS} =
- encode_handshake_record(Version, Epoch, Space, MsgType, MsgSeq, Len, Bin, 0, MSS, [], CS0),
- Recs = append_pack_records(Encoded, MSS, Recs0),
- encode_handshake_records(Tail, CS, MSS, Recs).
-
-%% TODO: move to dtls_handshake????
-encode_handshake_record(_Version, _Epoch, _Space, _MsgType, _MsgSeq, _Len, <<>>, _Offset, _MRS, Encoded, CS)
- when length(Encoded) > 0 ->
- %% make sure we encode at least one segment (for empty messages like Server Hello Done
- {lists:reverse(Encoded), CS};
-
-encode_handshake_record(Version, Epoch, Space, MsgType, MsgSeq, Len, Bin,
- Offset, MRS, Encoded0, CS0) ->
- MaxFragmentLen = Space - 25,
- {BinFragment, Rest} =
- case Bin of
- <<BinFragment0:MaxFragmentLen/bytes, Rest0/binary>> ->
- {BinFragment0, Rest0};
- _ ->
- {Bin, <<>>}
- end,
- FragLength = byte_size(BinFragment),
- Frag = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragLength), BinFragment],
- %% TODO Real solution, now avoid dialyzer error {Encoded, CS} = ssl_record:encode_handshake({Epoch, Frag}, Version, CS0),
- {Encoded, CS} = ssl_record:encode_handshake(Frag, Version, CS0),
- encode_handshake_record(Version, Epoch, MRS, MsgType, MsgSeq, Len, Rest, Offset + FragLength, MRS, [Encoded|Encoded0], CS).
-
-init_pack_records() ->
- {[], []}.
-
-append_pack_records([], MSS, Recs = {Buf0, Acc0}) ->
- Remaining = MSS - iolist_size(Buf0),
- if Remaining < 12 ->
- {[], [lists:reverse(Buf0)|Acc0]};
- true ->
- Recs
- end;
-append_pack_records([Head|Tail], MSS, {Buf0, Acc0}) ->
- TotLen = iolist_size(Buf0) + iolist_size(Head),
- if TotLen > MSS ->
- append_pack_records(Tail, MSS, {[Head], [lists:reverse(Buf0)|Acc0]});
- true ->
- append_pack_records(Tail, MSS, {[Head|Buf0], Acc0})
- end.
+encode_data(Data, Version, ConnectionStates0)->
+ dtls_record:encode_data(Data, Version, ConnectionStates0).
-finish_pack_records({[], Acc}) ->
- lists:reverse(Acc);
-finish_pack_records({Buf, Acc}) ->
- lists:reverse([lists:reverse(Buf)|Acc]).
+encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
+ dtls_record:encode_alert_record(Alert, Version, ConnectionStates).
decode_alerts(Bin) ->
ssl_alert:decode(Bin).
-initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
+initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, _}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
#ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
ConnectionStates = dtls_record:init_connection_states(Role, BeastMitigation),
@@ -566,10 +644,11 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
renegotiation = {false, first},
allow_renegotiate = SSLOptions#ssl_options.client_renegotiation,
start_or_recv_from = undefined,
- protocol_cb = ?MODULE
+ protocol_cb = ?MODULE,
+ flight_buffer = new_flight()
}.
-next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{
+next_dtls_record(Data, #state{protocol_buffers = #protocol_buffers{
dtls_record_buffer = Buf0,
dtls_cipher_texts = CT0} = Buffers} = State0) ->
case dtls_record:get_dtls_records(Data, Buf0) of
@@ -578,14 +657,15 @@ next_tls_record(Data, #state{protocol_buffers = #protocol_buffers{
next_record(State0#state{protocol_buffers =
Buffers#protocol_buffers{dtls_record_buffer = Buf1,
dtls_cipher_texts = CT1}});
-
#alert{} = Alert ->
Alert
- end.
+ end.
-next_record(#state{%%flight = #flight{state = finished},
- protocol_buffers =
- #protocol_buffers{dtls_packets = [], dtls_cipher_texts = [CT | Rest]}
+next_record(#state{unprocessed_handshake_events = N} = State) when N > 0 ->
+ {no_record, State#state{unprocessed_handshake_events = N-1}};
+
+next_record(#state{protocol_buffers =
+ #protocol_buffers{dtls_cipher_texts = [CT | Rest]}
= Buffers,
connection_states = ConnStates0} = State) ->
case dtls_record:decode_cipher_text(CT, ConnStates0) of
@@ -596,9 +676,15 @@ next_record(#state{%%flight = #flight{state = finished},
#alert{} = Alert ->
{Alert, State}
end;
-next_record(#state{socket = Socket,
- transport_cb = Transport} = State) -> %% when FlightState =/= finished
- ssl_socket:setopts(Transport, Socket, [{active,once}]),
+next_record(#state{role = server,
+ socket = {Listener, {Client, _}},
+ transport_cb = gen_udp} = State) ->
+ dtls_udp_listener:active_once(Listener, Client, self()),
+ {no_record, State};
+next_record(#state{role = client,
+ socket = {_Server, Socket},
+ transport_cb = Transport} = State) ->
+ dtls_socket:setopts(Transport, Socket, [{active,once}]),
{no_record, State};
next_record(State) ->
{no_record, State}.
@@ -624,75 +710,89 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
-next_event(connection = StateName, no_record, State0, Actions) ->
+next_event(connection = StateName, no_record,
+ #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
case next_record_if_active(State0) of
{no_record, State} ->
ssl_connection:hibernate_after(StateName, State, Actions);
- {#ssl_tls{} = Record, State} ->
+ {#ssl_tls{epoch = CurrentEpoch} = Record, State} ->
{next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
+ {#ssl_tls{epoch = Epoch,
+ type = ?HANDSHAKE,
+ version = _Version}, State1} = _Record when Epoch == CurrentEpoch-1 ->
+ State = send_handshake_flight(State1, Epoch),
+ {next_state, StateName, State, Actions};
+ {#ssl_tls{epoch = _Epoch,
+ version = _Version}, State} ->
+ %% TODO maybe buffer later epoch
+ {next_state, StateName, State, Actions};
{#alert{} = Alert, State} ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end;
-next_event(StateName, Record, State, Actions) ->
+next_event(StateName, Record,
+ #state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State, Actions) ->
case Record of
no_record ->
{next_state, StateName, State, Actions};
- #ssl_tls{} = Record ->
- {next_state, StateName, State, [{next_event, internal, {protocol_record, Record}} | Actions]};
+ #ssl_tls{epoch = CurrentEpoch,
+ version = Version} = Record ->
+ {next_state, StateName,
+ dtls_version(StateName, Version, State),
+ [{next_event, internal, {protocol_record, Record}} | Actions]};
+ #ssl_tls{epoch = _Epoch,
+ version = _Version} = _Record ->
+ %% TODO maybe buffer later epoch
+ {next_state, StateName, State, Actions};
#alert{} = Alert ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end.
-%% TODO This generates dialyzer warnings, has to be handled differently.
-%% handle_packet(Address, Port, Packet) ->
-%% try dtls_record:get_dtls_records(Packet, <<>>) of
-%% %% expect client hello
-%% {[#ssl_tls{type = ?HANDSHAKE, version = {254, _}} = Record], <<>>} ->
-%% handle_dtls_client_hello(Address, Port, Record);
-%% _Other ->
-%% {error, not_dtls}
-%% catch
-%% _Class:_Error ->
-%% {error, not_dtls}
-%% end.
-
-%% handle_dtls_client_hello(Address, Port,
-%% #ssl_tls{epoch = Epoch, sequence_number = Seq,
-%% version = Version} = Record) ->
-%% {[{Hello, _}], _} =
-%% dtls_handshake:get_dtls_handshake(Record,
-%% dtls_handshake:dtls_handshake_new_flight(undefined)),
-%% #client_hello{client_version = {Major, Minor},
-%% random = Random,
-%% session_id = SessionId,
-%% cipher_suites = CipherSuites,
-%% compression_methods = CompressionMethods} = Hello,
-%% CookieData = [address_to_bin(Address, Port),
-%% <<?BYTE(Major), ?BYTE(Minor)>>,
-%% Random, SessionId, CipherSuites, CompressionMethods],
-%% Cookie = crypto:hmac(sha, <<"secret">>, CookieData),
-
-%% case Hello of
-%% #client_hello{cookie = Cookie} ->
-%% accept;
-
-%% _ ->
-%% %% generate HelloVerifyRequest
-%% {RequestFragment, _} = dtls_handshake:encode_handshake(
-%% dtls_handshake:hello_verify_request(Cookie),
-%% Version, 0),
-%% HelloVerifyRequest =
-%% dtls_record:encode_tls_cipher_text(?HANDSHAKE, Version, Epoch, Seq, RequestFragment),
-%% {reply, HelloVerifyRequest}
-%% end.
-
-%% address_to_bin({A,B,C,D}, Port) ->
-%% <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
-%% address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
-%% <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
-
-sequence(#{write_msg_seq := Seq} = ConnectionState) ->
- {Seq, ConnectionState#{write_msg_seq => Seq + 1}}.
+dtls_version(hello, Version, #state{role = server} = State) ->
+ State#state{negotiated_version = Version}; %%Inital version
+dtls_version(_,_, State) ->
+ State.
+
+prepare_flight(#state{flight_buffer = Flight,
+ connection_states = ConnectionStates0,
+ protocol_buffers =
+ #protocol_buffers{} = Buffers} = State) ->
+ ConnectionStates = dtls_record:save_current_connection_state(ConnectionStates0, write),
+ State#state{flight_buffer = next_flight(Flight),
+ connection_states = ConnectionStates,
+ protocol_buffers = Buffers#protocol_buffers{
+ dtls_handshake_next_fragments = [],
+ dtls_handshake_later_fragments = []}}.
+new_flight() ->
+ #{next_sequence => 0,
+ handshakes => [],
+ change_cipher_spec => undefined,
+ handshakes_after_change_cipher_spec => []}.
+
+next_flight(Flight) ->
+ Flight#{handshakes => [],
+ change_cipher_spec => undefined,
+ handshakes_after_change_cipher_spec => []}.
+
+
+start_flight(#state{transport_cb = gen_udp,
+ flight_state = {retransmit_timer, Timeout}} = State) ->
+ Ref = erlang:make_ref(),
+ _ = erlang:send_after(Timeout, self(), {Ref, flight_retransmission_timeout}),
+ State#state{flight_state = {waiting, Ref, new_timeout(Timeout)}};
+
+start_flight(State) ->
+ %% No retransmision needed i.e DTLS over SCTP
+ State#state{flight_state = reliable}.
+
+new_timeout(N) when N =< 30 ->
+ N * 2;
+new_timeout(_) ->
+ 60.
+
+dtls_handshake_events(Packets) ->
+ lists:map(fun(Packet) ->
+ {next_event, internal, {handshake, Packet}}
+ end, Packets).
renegotiate(#state{role = client} = State, Actions) ->
%% Handle same way as if server requested
@@ -722,3 +822,27 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State));
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
+
+retransmit_epoch(StateName, #state{connection_states = ConnectionStates}) ->
+ #{epoch := Epoch} =
+ ssl_record:current_connection_state(ConnectionStates, write),
+ case StateName of
+ connection ->
+ Epoch-1;
+ _ ->
+ Epoch
+ end.
+
+update_handshake_history(#hello_verify_request{}, _, Hist) ->
+ Hist;
+update_handshake_history(_, Handshake, Hist) ->
+ %% DTLS never needs option "v2_hello_compatible" to be true
+ ssl_handshake:update_handshake_history(Hist, iolist_to_binary(Handshake), false).
+
+unprocessed_events(Events) ->
+ %% The first handshake event will be processed immediately
+ %% as it is entered first in the event queue and
+ %% when it is processed there will be length(Events)-1
+ %% handshake events left to process before we should
+ %% process more TLS-records received on the socket.
+ erlang:length(Events)-1.
diff --git a/lib/ssl/src/dtls_connection.hrl b/lib/ssl/src/dtls_connection.hrl
index ee3daa3c14..3dd78235d0 100644
--- a/lib/ssl/src/dtls_connection.hrl
+++ b/lib/ssl/src/dtls_connection.hrl
@@ -29,20 +29,14 @@
-include("ssl_connection.hrl").
-record(protocol_buffers, {
- dtls_packets = [], %%::[binary()], % Not yet handled decode ssl/tls packets.
- dtls_record_buffer = <<>>, %%:: binary(), % Buffer of incomplete records
- dtls_fragment_state, %%:: [], % DTLS fragments
- dtls_handshake_buffer = <<>>, %%:: binary(), % Buffer of incomplete handshakes
- dtls_cipher_texts = [], %%:: [binary()],
- dtls_cipher_texts_next %%:: [binary()] % Received for Epoch not yet active
+ dtls_record_buffer = <<>>, %% Buffer of incomplete records
+ dtls_handshake_next_seq = 0,
+ dtls_flight_last,
+ dtls_handshake_next_fragments = [], %% Fragments of the next handshake message
+ dtls_handshake_later_fragments = [], %% Fragments of handsake messages come after the one in next buffer
+ dtls_cipher_texts = [] %%:: [binary()],
}).
--record(flight, {
- last_retransmit,
- last_read_seq,
- msl_timer,
- state,
- buffer % buffer of not yet ACKed TLS records
- }).
+-define(INITIAL_RETRANSMIT_TIMEOUT, 1000). %1 sec
-endif. % -ifdef(dtls_connection).
diff --git a/lib/ssl/src/dtls_connection_sup.erl b/lib/ssl/src/dtls_connection_sup.erl
index dc7601a684..7d7be5743d 100644
--- a/lib/ssl/src/dtls_connection_sup.erl
+++ b/lib/ssl/src/dtls_connection_sup.erl
@@ -60,7 +60,7 @@ init(_O) ->
StartFunc = {dtls_connection, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [dtls_connection],
+ Modules = [dtls_connection, ssl_connection],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index c6535d5928..af3708ddb7 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -18,15 +18,15 @@
%% %CopyrightEnd%
-module(dtls_handshake).
+-include("dtls_connection.hrl").
-include("dtls_handshake.hrl").
-include("dtls_record.hrl").
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
--export([client_hello/8, client_hello/9, hello/4,
- hello_verify_request/1, get_dtls_handshake/2,
- dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
- encode_handshake/3]).
+-export([client_hello/8, client_hello/9, cookie/4, hello/4,
+ hello_verify_request/2, get_dtls_handshake/3, fragment_handshake/2,
+ handshake_bin/2, encode_handshake/3]).
-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |
ssl_handshake:ssl_handshake().
@@ -62,9 +62,10 @@ client_hello(Host, Port, Cookie, ConnectionStates,
Version = dtls_record:highest_protocol_version(Versions),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = maps:get(security_parameters, Pending),
- CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ CipherSuites = ssl_handshake:available_suites(UserSuites, TLSVersion),
- Extensions = ssl_handshake:client_hello_extensions(Host, dtls_v1:corresponding_tls_version(Version), CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, TLSVersion, CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -96,72 +97,51 @@ hello(#client_hello{client_version = ClientVersion} = Hello,
#ssl_options{versions = Versions} = SslOpts,
Info, Renegotiation) ->
Version = ssl_handshake:select_version(dtls_record, ClientVersion, Versions),
- %%
- %% TODO: handle Cipher Fallback
- %%
handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation).
--spec hello_verify_request(binary()) -> #hello_verify_request{}.
+cookie(Key, Address, Port, #client_hello{client_version = {Major, Minor},
+ random = Random,
+ session_id = SessionId,
+ cipher_suites = CipherSuites,
+ compression_methods = CompressionMethods}) ->
+ CookieData = [address_to_bin(Address, Port),
+ <<?BYTE(Major), ?BYTE(Minor)>>,
+ Random, SessionId, CipherSuites, CompressionMethods],
+ crypto:hmac(sha, Key, CookieData).
+
+-spec hello_verify_request(binary(), dtls_record:dtls_version()) -> #hello_verify_request{}.
%%
%% Description: Creates a hello verify request message sent by server to
%% verify client
%%--------------------------------------------------------------------
-hello_verify_request(Cookie) ->
- %% TODO: DTLS Versions?????
- #hello_verify_request{protocol_version = {254, 255}, cookie = Cookie}.
+hello_verify_request(Cookie, Version) ->
+ #hello_verify_request{protocol_version = Version, cookie = Cookie}.
%%--------------------------------------------------------------------
-%% %%--------------------------------------------------------------------
-encode_handshake(Handshake, Version, MsgSeq) ->
+encode_handshake(Handshake, Version, Seq) ->
{MsgType, Bin} = enc_handshake(Handshake, Version),
Len = byte_size(Bin),
- Enc = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
- Frag = {MsgType, MsgSeq, Bin},
- {Enc, Frag}.
+ [MsgType, ?uint24(Len), ?uint16(Seq), ?uint24(0), ?uint24(Len), Bin].
-%%--------------------------------------------------------------------
--spec get_dtls_handshake(#ssl_tls{}, #dtls_hs_state{} | undefined) ->
- {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}.
-%%
-%% Description: Given a DTLS state and new data from ssl_record, collects
-%% and returns it as a list of handshake messages, also returns a new
-%% DTLS state
-%%--------------------------------------------------------------------
-get_dtls_handshake(Records, undefined) ->
- HsState = #dtls_hs_state{highest_record_seq = 0,
- starting_read_seq = 0,
- fragments = gb_trees:empty(),
- completed = []},
- get_dtls_handshake(Records, HsState);
-get_dtls_handshake(Records, HsState0) when is_list(Records) ->
- HsState1 = lists:foldr(fun get_dtls_handshake_aux/2, HsState0, Records),
- get_dtls_handshake_completed(HsState1);
-get_dtls_handshake(Record, HsState0) when is_record(Record, ssl_tls) ->
- HsState1 = get_dtls_handshake_aux(Record, HsState0),
- get_dtls_handshake_completed(HsState1).
+fragment_handshake(Bin, _) when is_binary(Bin)->
+ %% This is the change_cipher_spec not a "real handshake" but part of the flight
+ Bin;
+fragment_handshake([MsgType, Len, Seq, _, Len, Bin], Size) ->
+ Bins = bin_fragments(Bin, Size),
+ handshake_fragments(MsgType, Seq, Len, Bins, []).
+handshake_bin([Type, Length, Data], Seq) ->
+ handshake_bin(Type, Length, Seq, Data).
+
%%--------------------------------------------------------------------
--spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
+-spec get_dtls_handshake(dtls_record:dtls_version(), binary(), #protocol_buffers{}) ->
+ {[{dtls_handshake(), binary()}], #protocol_buffers{}} | {more_data, #protocol_buffers{}}.
%%
-%% Description: Reset the DTLS decoder state for a new Epoch
+%% Description: ...
%%--------------------------------------------------------------------
-%% dtls_handshake_new_epoch(<<>>) ->
-%% dtls_hs_state_init();
-dtls_handshake_new_epoch(HsState) ->
- HsState#dtls_hs_state{highest_record_seq = 0,
- starting_read_seq = HsState#dtls_hs_state.current_read_seq,
- fragments = gb_trees:empty(), completed = []}.
-
-%--------------------------------------------------------------------
--spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}.
-%
-% Description: Init the DTLS decoder state for a new Flight
-dtls_handshake_new_flight(ExpectedReadReq) ->
- #dtls_hs_state{current_read_seq = ExpectedReadReq,
- highest_record_seq = 0,
- starting_read_seq = 0,
- fragments = gb_trees:empty(), completed = []}.
+get_dtls_handshake(Version, Fragment, ProtocolBuffers) ->
+ handle_fragments(Version, Fragment, ProtocolBuffers, []).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -170,27 +150,29 @@ handle_client_hello(Version, #client_hello{session_id = SugesstedId,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions = #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns} = HelloExt},
+ extensions =
+ #hello_extensions{elliptic_curves = Curves,
+ signature_algs = ClientHashSigns} = HelloExt},
#ssl_options{versions = Versions,
signature_algs = SupportedHashSigns} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert, _}, Renegotiation) ->
case dtls_record:is_acceptable_version(Version, Versions) of
true ->
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
AvailableHashSigns = ssl_handshake:available_signature_algs(
- ClientHashSigns, SupportedHashSigns, Cert,
- dtls_v1:corresponding_tls_version(Version)),
- ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)),
+ ClientHashSigns, SupportedHashSigns, Cert,TLSVersion),
+ ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(TLSVersion)),
{Type, #session{cipher_suite = CipherSuite} = Session1}
= ssl_handshake:select_session(SugesstedId, CipherSuites, AvailableHashSigns, Compressions,
- Port, Session0#session{ecc = ECCCurve}, Version,
+ Port, Session0#session{ecc = ECCCurve}, TLSVersion,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
{KeyExAlg,_,_,_} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg, SupportedHashSigns, Version) of
+ case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
+ SupportedHashSigns, TLSVersion) of
#alert{} = Alert ->
Alert;
HashSign ->
@@ -228,214 +210,15 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
end.
-get_dtls_handshake_completed(HsState = #dtls_hs_state{completed = Completed}) ->
- {lists:reverse(Completed), HsState#dtls_hs_state{completed = []}}.
-
-get_dtls_handshake_aux(#ssl_tls{version = Version,
- sequence_number = SeqNo,
- fragment = Data}, HsState) ->
- get_dtls_handshake_aux(Version, SeqNo, Data, HsState).
-
-get_dtls_handshake_aux(Version, SeqNo,
- <<?BYTE(Type), ?UINT24(Length),
- ?UINT16(MessageSeq),
- ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
- Body:FragmentLength/binary, Rest/binary>>,
- HsState0) ->
- case reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState0) of
- {HsState1, HighestSeqNo, MsgBody} ->
- HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1),
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3);
-
- HsState2 ->
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3)
- end;
-
-get_dtls_handshake_aux(_Version, _SeqNo, <<>>, HsState) ->
- HsState.
-
-dec_dtls_fragment(Version, SeqNo, Type, Length, MessageSeq, MsgBody,
- HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->
- Raw = <<?BYTE(Type), ?UINT24(Length), ?UINT16(MessageSeq), ?UINT24(0), ?UINT24(Length), MsgBody/binary>>,
- H = decode_handshake(Version, Type, MsgBody),
- HsState#dtls_hs_state{completed = [{H,Raw}|Acc], highest_record_seq = erlang:max(HighestSeqNo, SeqNo)}.
-
-process_dtls_fragments(Version,
- HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
- case gb_trees:is_empty(Fragments0) of
- true ->
- HsState0;
- _ ->
- case gb_trees:smallest(Fragments0) of
- {CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} ->
- HsState1 = dtls_hs_state_process_seq(HsState0),
- HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1),
- process_dtls_fragments(Version, HsState2);
- _ ->
- HsState0
- end
- end.
-
-dtls_hs_state_process_seq(HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
- Fragments1 = gb_trees:delete_any(CurrentReadSeq, Fragments0),
- HsState0#dtls_hs_state{current_read_seq = CurrentReadSeq + 1,
- fragments = Fragments1}.
-
-dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState0 = #dtls_hs_state{fragments = Fragments0}) ->
- Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
- HsState0#dtls_hs_state{fragments = Fragments1}.
-
-reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})
- when Type == ?CLIENT_HELLO;
- Type == ?SERVER_HELLO;
- Type == ?HELLO_VERIFY_REQUEST ->
- %% First message, should be client hello
- %% return the current message and set the next expected Sequence
- %%
- %% Note: this could (should?) be restricted further, ClientHello and
- %% HelloVerifyRequest have to have message_seq = 0, ServerHello
- %% can have a message_seq of 0 or 1
- %%
- {HsState0#dtls_hs_state{current_read_seq = MessageSeq + 1}, SeqNo, Body};
-
-reassemble_dtls_fragment(_SeqNo, _Type, Length, _MessageSeq, _, Length,
- _Body, HsState = #dtls_hs_state{current_read_seq = undefined}) ->
- %% not what we expected, drop it
- HsState;
-
-reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 =
- #dtls_hs_state{starting_read_seq = StartingReadSeq})
- when MessageSeq < StartingReadSeq ->
- %% this has to be the start of a new flight, let it through
- %%
- %% Note: this could (should?) be restricted further, the first message of a
- %% new flight has to have message_seq = 0
- %%
- HsState = dtls_hs_state_process_seq(HsState0),
- {HsState, SeqNo, Body};
-
-reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
- when MessageSeq < CurrentReadSeq ->
- HsState;
-
-reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->
- %% Message fully contained and it's the current seq
- HsState1 = dtls_hs_state_process_seq(HsState0),
- {HsState1, SeqNo, Body};
-
-reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState) ->
- %% Message fully contained and it's the NOT the current seq -> buffer
- Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, 0, Length, Body)},
- dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState);
-
-reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, FragmentOffset, FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
- when FragmentOffset + FragmentLength == Length andalso MessageSeq == (CurrentReadSeq - 1) ->
- {retransmit, HsState};
-
-reassemble_dtls_fragment(_SeqNo, _Type, _Length, MessageSeq, _FragmentOffset, _FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
- when MessageSeq < CurrentReadSeq ->
- HsState;
-
-reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
- case gb_trees:lookup(MessageSeq, Fragments0) of
- {value, Fragment} ->
- dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, Fragment, HsState);
- none ->
- dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState)
- end.
-dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->
- Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)},
- Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),
- HsState#dtls_hs_state{fragments = Fragments1}.
-
-dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body,
- {LastSeqNo, Type, Length, MessageSeq, FragBuffer0},
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
- FragBuffer1 = dtls_fragment_add(FragBuffer0, FragmentOffset, FragmentLength, Body),
- Fragment = {erlang:max(SeqNo, LastSeqNo), Type, Length, MessageSeq, FragBuffer1},
- Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
- HsState#dtls_hs_state{fragments = Fragments1};
-
-%% Type, Length or Seq mismatch, drop everything...
-%% Note: the RFC is not clear on how to handle this...
-dtls_fragment_reassemble(_SeqNo, _Type, _Length, MessageSeq,
- _FragmentOffset, _FragmentLength, _Body, _Fragment,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
- Fragments1 = gb_trees:delete_any(MessageSeq, Fragments0),
- HsState#dtls_hs_state{fragments = Fragments1}.
-
-dtls_fragment_add({Length, FragmentList0, Bin0}, FragmentOffset, FragmentLength, Body) ->
- Bin1 = dtls_fragment_bin_add(FragmentOffset, FragmentLength, Body, Bin0),
- FragmentList1 = add_fragment(FragmentList0, {FragmentOffset, FragmentLength}),
- {Length, FragmentList1, Bin1}.
-
-dtls_fragment_init(Length, 0, Length, Body) ->
- {Length, [{0, Length}], Body};
-dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body) ->
- Bin = dtls_fragment_bin_add(FragmentOffset, FragmentLength, Body, <<0:(Length*8)>>),
- {Length, [{FragmentOffset, FragmentOffset + FragmentLength}], Bin}.
-
-dtls_fragment_bin_add(FragmentOffset, FragmentLength, Add, Buffer) ->
- <<First:FragmentOffset/bytes, _:FragmentLength/bytes, Rest/binary>> = Buffer,
- <<First/binary, Add/binary, Rest/binary>>.
-
-merge_fragment_list([], Fragment, Acc) ->
- lists:reverse([Fragment|Acc]);
-
-merge_fragment_list([H = {_, HEnd}|Rest], Frag = {FStart, _}, Acc)
- when FStart > HEnd ->
- merge_fragment_list(Rest, Frag, [H|Acc]);
-
-merge_fragment_list(Rest = [{HStart, _HEnd}|_], Frag = {_FStart, FEnd}, Acc)
- when FEnd < HStart ->
- lists:reverse(Acc) ++ [Frag|Rest];
-
-merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
- when
- FStart =< HEnd orelse FEnd >= HStart ->
- Start = erlang:min(HStart, FStart),
- End = erlang:max(HEnd, FEnd),
- NewFrag = {Start, End},
- merge_fragment_list(Rest, NewFrag, Acc).
-
-add_fragment(List, {FragmentOffset, FragmentLength}) ->
- merge_fragment_list(List, {FragmentOffset, FragmentOffset + FragmentLength}, []).
+%%%%%%% Encodeing %%%%%%%%%%%%%
enc_handshake(#hello_verify_request{protocol_version = {Major, Minor},
cookie = Cookie}, _Version) ->
- CookieLength = byte_size(Cookie),
+ CookieLength = byte_size(Cookie),
{?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
?BYTE(CookieLength),
- Cookie/binary>>};
+ Cookie:CookieLength/binary>>};
enc_handshake(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
@@ -459,38 +242,246 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
?BYTE(CookieLength), Cookie/binary,
?UINT16(CsLength), BinCipherSuites/binary,
?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
+
+enc_handshake(#server_hello{} = HandshakeMsg, Version) ->
+ {Type, <<?BYTE(Major), ?BYTE(Minor), Rest/binary>>} =
+ ssl_handshake:encode_handshake(HandshakeMsg, Version),
+ {DTLSMajor, DTLSMinor} = dtls_v1:corresponding_dtls_version({Major, Minor}),
+ {Type, <<?BYTE(DTLSMajor), ?BYTE(DTLSMinor), Rest/binary>>};
+
enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
-decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+bin_fragments(Bin, Size) ->
+ bin_fragments(Bin, size(Bin), Size, 0, []).
+
+bin_fragments(Bin, BinSize, FragSize, Offset, Fragments) ->
+ case (BinSize - Offset - FragSize) > 0 of
+ true ->
+ Frag = binary:part(Bin, {Offset, FragSize}),
+ bin_fragments(Bin, BinSize, FragSize, Offset + FragSize, [{Frag, Offset} | Fragments]);
+ false ->
+ Frag = binary:part(Bin, {Offset, BinSize-Offset}),
+ lists:reverse([{Frag, Offset} | Fragments])
+ end.
+
+handshake_fragments(_, _, _, [], Acc) ->
+ lists:reverse(Acc);
+handshake_fragments(MsgType, Seq, Len, [{Bin, Offset} | Bins], Acc) ->
+ FragLen = size(Bin),
+ handshake_fragments(MsgType, Seq, Len, Bins,
+ [<<?BYTE(MsgType), Len/binary, Seq/binary, ?UINT24(Offset),
+ ?UINT24(FragLen), Bin/binary>> | Acc]).
+
+address_to_bin({A,B,C,D}, Port) ->
+ <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
+address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
+ <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
+
+%%%%%%% Decodeing %%%%%%%%%%%%%
+
+handle_fragments(Version, FragmentData, Buffers0, Acc) ->
+ Fragments = decode_handshake_fragments(FragmentData),
+ do_handle_fragments(Version, Fragments, Buffers0, Acc).
+
+do_handle_fragments(_, [], Buffers, Acc) ->
+ {lists:reverse(Acc), Buffers};
+do_handle_fragments(Version, [Fragment | Fragments], Buffers0, Acc) ->
+ case reassemble(Version, Fragment, Buffers0) of
+ {more_data, _} = More when Acc == []->
+ More;
+ {more_data, Buffers} when Fragments == [] ->
+ {lists:reverse(Acc), Buffers};
+ {more_data, Buffers} ->
+ do_handle_fragments(Version, Fragments, Buffers, Acc);
+ {HsPacket, Buffers} ->
+ do_handle_fragments(Version, Fragments, Buffers, [HsPacket | Acc])
+ end.
+
+decode_handshake(Version, <<?BYTE(Type), Bin/binary>>) ->
+ decode_handshake(Version, Type, Bin).
+
+decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
+ #hello_request{};
+decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_),
+ ?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
- ?BYTE(Cookie_length), Cookie:Cookie_length/binary,
+ ?BYTE(CookieLength), Cookie:CookieLength/binary,
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
Extensions/binary>>) ->
- DecodedExtensions = ssl_handshake:decode_hello_extensions(Extensions),
-
+ DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
+
#client_hello{
client_version = {Major,Minor},
random = Random,
- session_id = Session_ID,
cookie = Cookie,
+ session_id = Session_ID,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
compression_methods = Comp_methods,
extensions = DecodedExtensions
- };
+ };
+
+decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_),
+ ?BYTE(Major), ?BYTE(Minor),
+ ?BYTE(CookieLength),
+ Cookie:CookieLength/binary>>) ->
+ #hello_verify_request{protocol_version = {Major, Minor},
+ cookie = Cookie};
+
+decode_handshake(Version, Tag, <<?UINT24(_), ?UINT16(_),
+ ?UINT24(_), ?UINT24(_), Msg/binary>>) ->
+ %% DTLS specifics stripped
+ decode_tls_thandshake(Version, Tag, Msg).
+
+decode_tls_thandshake(Version, Tag, Msg) ->
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ ssl_handshake:decode_handshake(TLSVersion, Tag, Msg).
+
+decode_handshake_fragments(<<>>) ->
+ [<<>>];
+decode_handshake_fragments(<<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(MessageSeq),
+ ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
+ Fragment:FragmentLength/binary, Rest/binary>>) ->
+ [#handshake_fragment{type = Type,
+ length = Length,
+ message_seq = MessageSeq,
+ fragment_offset = FragmentOffset,
+ fragment_length = FragmentLength,
+ fragment = Fragment} | decode_handshake_fragments(Rest)].
+
+reassemble(Version, #handshake_fragment{message_seq = Seq} = Fragment,
+ #protocol_buffers{dtls_handshake_next_seq = Seq,
+ dtls_handshake_next_fragments = Fragments0,
+ dtls_handshake_later_fragments = LaterFragments0} =
+ Buffers0)->
+ case reassemble_fragments(Fragment, Fragments0) of
+ {more_data, Fragments} ->
+ {more_data, Buffers0#protocol_buffers{dtls_handshake_next_fragments = Fragments}};
+ {raw, RawHandshake} ->
+ Handshake = decode_handshake(Version, RawHandshake),
+ {NextFragments, LaterFragments} = next_fragments(LaterFragments0),
+ {{Handshake, RawHandshake}, Buffers0#protocol_buffers{dtls_handshake_next_seq = Seq + 1,
+ dtls_handshake_next_fragments = NextFragments,
+ dtls_handshake_later_fragments = LaterFragments}}
+ end;
+reassemble(_, #handshake_fragment{message_seq = FragSeq} = Fragment,
+ #protocol_buffers{dtls_handshake_next_seq = Seq,
+ dtls_handshake_later_fragments = LaterFragments} = Buffers0) when FragSeq > Seq->
+ {more_data,
+ Buffers0#protocol_buffers{dtls_handshake_later_fragments = [Fragment | LaterFragments]}};
+reassemble(_, _, Buffers) ->
+ %% Disregard fragments FragSeq < Seq
+ {more_data, Buffers}.
+
+reassemble_fragments(Current, Fragments0) ->
+ [Frag1 | Frags] = lists:keysort(#handshake_fragment.fragment_offset, [Current | Fragments0]),
+ [Fragment | _] = Fragments = merge_fragment(Frag1, Frags),
+ case is_complete_handshake(Fragment) of
+ true ->
+ {raw, handshake_bin(Fragment)};
+ false ->
+ {more_data, Fragments}
+ end.
-decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
+merge_fragment(Frag0, []) ->
+ [Frag0];
+merge_fragment(Frag0, [Frag1 | Rest]) ->
+ case merge_fragments(Frag0, Frag1) of
+ [_|_] = Frags ->
+ Frags ++ Rest;
+ Frag ->
+ merge_fragment(Frag, Rest)
+ end.
- #hello_verify_request{
- protocol_version = {Major,Minor},
- cookie = Cookie};
-decode_handshake(Version, Tag, Msg) ->
- ssl_handshake:decode_handshake(Version, Tag, Msg).
+is_complete_handshake(#handshake_fragment{length = Length, fragment_length = Length}) ->
+ true;
+is_complete_handshake(_) ->
+ false.
+
+next_fragments(LaterFragments) ->
+ case lists:keysort(#handshake_fragment.message_seq, LaterFragments) of
+ [] ->
+ {[], []};
+ [#handshake_fragment{message_seq = Seq} | _] = Fragments ->
+ split_frags(Fragments, Seq, [])
+ end.
-%% address_to_bin({A,B,C,D}, Port) ->
-%% <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
-%% address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
-%% <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
+split_frags([#handshake_fragment{message_seq = Seq} = Frag | Rest], Seq, Acc) ->
+ split_frags(Rest, Seq, [Frag | Acc]);
+split_frags(Frags, _, Acc) ->
+ {lists:reverse(Acc), Frags}.
+
+
+%% Duplicate
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData}) ->
+ Previous;
+
+%% Lager fragment save new data
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = CurrentLen,
+ fragment = CurrentData}) when CurrentLen > PreviousLen ->
+ NewLength = CurrentLen - PreviousLen,
+ <<_:PreviousLen/binary, NewData/binary>> = CurrentData,
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + NewLength,
+ fragment = <<PreviousData/binary, NewData/binary>>
+ };
+
+%% Smaller fragment
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = CurrentLen}) when CurrentLen < PreviousLen ->
+ Previous;
+%% Next fragment
+merge_fragments(#handshake_fragment{
+ fragment_offset = PreviousOffSet,
+ fragment_length = PreviousLen,
+ fragment = PreviousData
+ } = Previous,
+ #handshake_fragment{
+ fragment_offset = CurrentOffSet,
+ fragment_length = CurrentLen,
+ fragment = CurrentData}) when PreviousOffSet + PreviousLen == CurrentOffSet->
+ Previous#handshake_fragment{
+ fragment_length = PreviousLen + CurrentLen,
+ fragment = <<PreviousData/binary, CurrentData/binary>>};
+%% No merge there is a gap
+merge_fragments(Previous, Current) ->
+ [Previous, Current].
+
+handshake_bin(#handshake_fragment{
+ type = Type,
+ length = Len,
+ message_seq = Seq,
+ fragment_length = Len,
+ fragment_offset = 0,
+ fragment = Fragment}) ->
+ handshake_bin(Type, Len, Seq, Fragment).
+
+handshake_bin(Type, Length, Seq, FragmentData) ->
+ <<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(Seq), ?UINT24(0), ?UINT24(Length),
+ FragmentData:Length/binary>>.
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 0298fd3105..0a980c5f31 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -46,12 +46,13 @@
cookie
}).
--record(dtls_hs_state,
- {current_read_seq,
- starting_read_seq,
- highest_record_seq,
- fragments,
- completed
- }).
+-record(handshake_fragment, {
+ type,
+ length,
+ message_seq,
+ fragment_offset,
+ fragment_length,
+ fragment
+ }).
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 8a6e2d315c..f447897d59 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,9 @@
-export([decode_cipher_text/2]).
%% Encoding
--export([encode_plain_text/4, encode_tls_cipher_text/5, encode_change_cipher_spec/2]).
+-export([encode_handshake/4, encode_alert_record/3,
+ encode_change_cipher_spec/3, encode_data/3]).
+-export([encode_plain_text/5]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
@@ -44,9 +46,9 @@
is_higher/2, supported_protocol_versions/0,
is_acceptable_version/2]).
-%% DTLS Epoch handling
--export([init_connection_state_seq/2, current_connection_state_epoch/2,
- set_connection_state_by_epoch/3, connection_state_by_epoch/3]).
+-export([save_current_connection_state/2, next_epoch/2]).
+
+-export([init_connection_state_seq/2, current_connection_state_epoch/2]).
-export_type([dtls_version/0, dtls_atom_version/0]).
@@ -68,16 +70,64 @@
%%--------------------------------------------------------------------
init_connection_states(Role, BeastMitigation) ->
ConnectionEnd = ssl_record:record_protocol_role(Role),
- Current = initial_connection_state(ConnectionEnd, BeastMitigation),
- Pending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
- #{write_msg_seq => 0,
- prvious_read => undefined,
+ Initial = initial_connection_state(ConnectionEnd, BeastMitigation),
+ Current = Initial#{epoch := 0},
+ InitialPending = ssl_record:empty_connection_state(ConnectionEnd, BeastMitigation),
+ Pending = InitialPending#{epoch => undefined},
+ #{saved_read => Current,
current_read => Current,
pending_read => Pending,
- prvious_write => undefined,
+ saved_write => Current,
current_write => Current,
pending_write => Pending}.
-
+
+%%--------------------------------------------------------------------
+-spec save_current_connection_state(ssl_record:connection_states(), read | write) ->
+ ssl_record:connection_states().
+%%
+%% Description: Returns the instance of the connection_state map
+%% where the current read|write state has been copied to the save state.
+%%--------------------------------------------------------------------
+save_current_connection_state(#{current_read := Current} = States, read) ->
+ States#{saved_read := Current};
+
+save_current_connection_state(#{current_write := Current} = States, write) ->
+ States#{saved_write := Current}.
+
+next_epoch(#{pending_read := Pending,
+ current_read := #{epoch := Epoch}} = States, read) ->
+ States#{pending_read := Pending#{epoch := Epoch + 1}};
+
+next_epoch(#{pending_write := Pending,
+ current_write := #{epoch := Epoch}} = States, write) ->
+ States#{pending_write := Pending#{epoch := Epoch + 1}}.
+
+get_connection_state_by_epoch(Epoch, #{current_write := #{epoch := Epoch} = Current},
+ write) ->
+ Current;
+get_connection_state_by_epoch(Epoch, #{saved_write := #{epoch := Epoch} = Saved},
+ write) ->
+ Saved;
+get_connection_state_by_epoch(Epoch, #{current_read := #{epoch := Epoch} = Current},
+ read) ->
+ Current;
+get_connection_state_by_epoch(Epoch, #{saved_read := #{epoch := Epoch} = Saved},
+ read) ->
+ Saved.
+
+set_connection_state_by_epoch(WriteState, Epoch, #{current_write := #{epoch := Epoch}} = States,
+ write) ->
+ States#{current_write := WriteState};
+set_connection_state_by_epoch(WriteState, Epoch, #{saved_write := #{epoch := Epoch}} = States,
+ write) ->
+ States#{saved_write := WriteState};
+set_connection_state_by_epoch(ReadState, Epoch, #{current_read := #{epoch := Epoch}} = States,
+ read) ->
+ States#{current_read := ReadState};
+set_connection_state_by_epoch(ReadState, Epoch, #{saved_read := #{epoch := Epoch}} = States,
+ read) ->
+ States#{saved_read := ReadState}.
+
%%--------------------------------------------------------------------
-spec get_dtls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}.
%%
@@ -140,98 +190,57 @@ get_dtls_records_aux(Data, Acc) ->
?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
end.
-encode_plain_text(Type, Version, Data,
- #{current_write :=
- #{epoch := Epoch,
- sequence_number := Seq,
- compression_state := CompS0,
- security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm = CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- AAD = calc_aad(Type, Version, Epoch, Seq),
- {CipherFragment, WriteState} = ssl_record:cipher_aead(dtls_v1:corresponding_tls_version(Version),
- Comp, WriteState1, AAD),
- CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment),
- {CipherText, ConnectionStates#{current_write => WriteState#{sequence_number => Seq +1}}};
-
-encode_plain_text(Type, Version, Data,
- #{current_write :=
- #{epoch := Epoch,
- sequence_number := Seq,
- compression_state := CompS0,
- security_parameters :=
- #security_parameters{compression_algorithm = CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- MacHash = calc_mac_hash(WriteState1, Type, Version, Epoch, Seq, Comp),
- {CipherFragment, WriteState} = ssl_record:cipher(dtls_v1:corresponding_tls_version(Version),
- Comp, WriteState1, MacHash),
- CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment),
- {CipherText, ConnectionStates#{current_write => WriteState#{sequence_number => Seq +1}}}.
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), dtls_version(), integer(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version, Epoch, ConnectionStates) ->
+ encode_plain_text(?HANDSHAKE, Version, Epoch, Frag, ConnectionStates).
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- epoch = Epoch,
- sequence_number = Seq,
- fragment = CipherFragment} = CipherText,
- #{current_read :=
- #{compression_state := CompressionS0,
- security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm = CompAlg}
- } = ReadState0} = ConnnectionStates0) ->
- AAD = calc_aad(Type, Version, Epoch, Seq),
- case ssl_record:decipher_aead(dtls_v1:corresponding_tls_version(Version),
- CipherFragment, ReadState0, AAD) of
- {PlainFragment, ReadState1} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
- current_read => ReadState1#{
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- #alert{} = Alert ->
- Alert
- end;
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- epoch = Epoch,
- sequence_number = Seq,
- fragment = CipherFragment} = CipherText,
- #{current_read :=
- #{compression_state := CompressionS0,
- security_parameters :=
- #security_parameters{
- compression_algorithm = CompAlg}
- } = ReadState0}= ConnnectionStates0) ->
- {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
- CipherFragment, ReadState0, true),
- MacHash = calc_mac_hash(ReadState1, Type, Version, Epoch, Seq, PlainFragment),
- case ssl_record:is_correct_mac(Mac, MacHash) of
- true ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
- current_read => ReadState1#{
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end.
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, dtls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ Version, ConnectionStates) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ encode_plain_text(?ALERT, Version, Epoch, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(dtls_version(), ssl_record:connection_states()) ->
+-spec encode_change_cipher_spec(dtls_version(), integer(), ssl_record:connection_states()) ->
{iolist(), ssl_record:connection_states()}.
%%
%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
%%--------------------------------------------------------------------
-encode_change_cipher_spec(Version, ConnectionStates) ->
- encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
+encode_change_cipher_spec(Version, Epoch, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, Epoch, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_data(binary(), dtls_version(), ssl_record:connection_states()) ->
+ {iolist(),ssl_record:connection_states()}.
+%%
+%% Description: Encodes data to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_data(Data, Version, ConnectionStates) ->
+ #{epoch := Epoch} = ssl_record:current_connection_state(ConnectionStates, write),
+ encode_plain_text(?APPLICATION_DATA, Version, Epoch, Data, ConnectionStates).
+
+encode_plain_text(Type, Version, Epoch, Data, ConnectionStates) ->
+ Write0 = get_connection_state_by_epoch(Epoch, ConnectionStates, write),
+ {CipherFragment, Write1} = encode_plain_text(Type, Version, Data, Write0),
+ {CipherText, Write} = encode_dtls_cipher_text(Type, Version, CipherFragment, Write1),
+ {CipherText, set_connection_state_by_epoch(Write, Epoch, ConnectionStates, write)}.
+
+
+decode_cipher_text(#ssl_tls{epoch = Epoch} = CipherText, ConnnectionStates0) ->
+ ReadState = get_connection_state_by_epoch(Epoch, ConnnectionStates0, read),
+ decode_cipher_text(CipherText, ReadState, ConnnectionStates0).
%%--------------------------------------------------------------------
-spec protocol_version(dtls_atom_version() | dtls_version()) ->
@@ -373,12 +382,11 @@ is_acceptable_version(Version, Versions) ->
%% This is only valid for DTLS in the first client_hello
%%--------------------------------------------------------------------
init_connection_state_seq({254, _},
- #{current_read := #{epoch := 0} = Read,
- current_write := #{epoch := 0} = Write} = CS0) ->
- Seq = maps:get(sequence_number, Read),
- CS0#{current_write => Write#{sequence_number => Seq}};
-init_connection_state_seq(_, CS) ->
- CS.
+ #{current_read := #{epoch := 0, sequence_number := Seq},
+ current_write := #{epoch := 0} = Write} = ConnnectionStates0) ->
+ ConnnectionStates0#{current_write => Write#{sequence_number => Seq}};
+init_connection_state_seq(_, ConnnectionStates) ->
+ ConnnectionStates.
%%--------------------------------------------------------
-spec current_connection_state_epoch(ssl_record:connection_states(), read | write) ->
@@ -387,49 +395,12 @@ init_connection_state_seq(_, CS) ->
%% Description: Returns the epoch the connection_state record
%% that is currently defined as the current conection state.
%%--------------------------------------------------------------------
-current_connection_state_epoch(#{current_read := Current},
+current_connection_state_epoch(#{current_read := #{epoch := Epoch}},
read) ->
- maps:get(epoch, Current);
-current_connection_state_epoch(#{current_write := Current},
+ Epoch;
+current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
write) ->
- maps:get(epoch, Current).
-
-%%--------------------------------------------------------------------
-
--spec connection_state_by_epoch(ssl_record:connection_states(), integer(), read | write) ->
- ssl_record:connection_state().
-%%
-%% Description: Returns the instance of the connection_state record
-%% that is defined by the Epoch.
-%%--------------------------------------------------------------------
-connection_state_by_epoch(#{current_read := #{epoch := Epoch}} = CS, Epoch, read) ->
- CS;
-connection_state_by_epoch(#{pending_read := #{epoch := Epoch}} = CS, Epoch, read) ->
- CS;
-connection_state_by_epoch(#{current_write := #{epoch := Epoch}} = CS, Epoch, write) ->
- CS;
-connection_state_by_epoch(#{pending_write := #{epoch := Epoch}} = CS, Epoch, write) ->
- CS.
-%%--------------------------------------------------------------------
--spec set_connection_state_by_epoch(ssl_record:connection_states(),
- ssl_record:connection_state(), read | write)
- -> ssl_record:connection_states().
-%%
-%% Description: Returns the instance of the connection_state record
-%% that is defined by the Epoch.
-%%--------------------------------------------------------------------
-set_connection_state_by_epoch(#{current_read := #{epoch := Epoch}} = ConnectionStates0,
- NewCS = #{epoch := Epoch}, read) ->
- ConnectionStates0#{current_read => NewCS};
-set_connection_state_by_epoch(#{pending_read := #{epoch := Epoch}} = ConnectionStates0,
- NewCS = #{epoch := Epoch}, read) ->
- ConnectionStates0#{pending_read => NewCS};
-set_connection_state_by_epoch(#{current_write := #{epoch := Epoch}} = ConnectionStates0,
- NewCS = #{epoch := Epoch}, write) ->
- ConnectionStates0#{current_write => NewCS};
-set_connection_state_by_epoch(#{pending_write := #{epoch := Epoch}} = ConnectionStates0,
-NewCS = #{epoch := Epoch}, write) ->
- ConnectionStates0#{pending_write => NewCS}.
+ Epoch.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -437,8 +408,8 @@ NewCS = #{epoch := Epoch}, write) ->
initial_connection_state(ConnectionEnd, BeastMitigation) ->
#{security_parameters =>
ssl_record:initial_security_params(ConnectionEnd),
- epoch => 0,
- sequence_number => 1,
+ epoch => undefined,
+ sequence_number => 0,
beast_mitigation => BeastMitigation,
compression_state => undefined,
cipher_state => undefined,
@@ -458,14 +429,85 @@ highest_list_protocol_version(Ver, []) ->
highest_list_protocol_version(Ver1, [Ver2 | Rest]) ->
highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
-encode_tls_cipher_text(Type, {MajVer, MinVer}, Epoch, Seq, Fragment) ->
+encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
+ #{epoch := Epoch, sequence_number := Seq} = WriteState) ->
Length = erlang:iolist_size(Fragment),
- [<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
- ?UINT48(Seq), ?UINT16(Length)>>, Fragment].
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Epoch),
+ ?UINT48(Seq), ?UINT16(Length)>>, Fragment],
+ WriteState#{sequence_number => Seq + 1}}.
+
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ epoch := Epoch,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ AAD = calc_aad(Type, Version, Epoch, Seq),
+ ssl_record:cipher_aead(dtls_v1:corresponding_tls_version(Version), Comp, WriteState1, AAD);
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ epoch := Epoch,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ }= WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ MacHash = calc_mac_hash(Type, Version, WriteState1, Epoch, Seq, Comp),
+ ssl_record:cipher(dtls_v1:corresponding_tls_version(Version), Comp, WriteState1, MacHash).
+
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ epoch = Epoch,
+ sequence_number = Seq,
+ fragment = CipherFragment} = CipherText,
+ #{compression_state := CompressionS0,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}} = ReadState0,
+ ConnnectionStates0) ->
+ AAD = calc_aad(Type, Version, Epoch, Seq),
+ case ssl_record:decipher_aead(dtls_v1:corresponding_tls_version(Version),
+ CipherFragment, ReadState0, AAD) of
+ {PlainFragment, ReadState1} ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ReadState = ReadState1#{compression_state => CompressionS1},
+ ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end;
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ epoch = Epoch,
+ sequence_number = Seq,
+ fragment = CipherFragment} = CipherText,
+ #{compression_state := CompressionS0,
+ security_parameters :=
+ #security_parameters{
+ compression_algorithm = CompAlg}} = ReadState0,
+ ConnnectionStates0) ->
+ {PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
+ CipherFragment, ReadState0, true),
+ MacHash = calc_mac_hash(Type, Version, ReadState1, Epoch, Seq, PlainFragment),
+ case ssl_record:is_correct_mac(Mac, MacHash) of
+ true ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+
+ ReadState = ReadState1#{compression_state => CompressionS1},
+ ConnnectionStates = set_connection_state_by_epoch(ReadState, Epoch, ConnnectionStates0, read),
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end.
-calc_mac_hash(#{mac_secret := MacSecret,
- security_parameters := #security_parameters{mac_algorithm = MacAlg}},
- Type, Version, Epoch, SeqNo, Fragment) ->
+calc_mac_hash(Type, Version, #{mac_secret := MacSecret,
+ security_parameters := #security_parameters{mac_algorithm = MacAlg}},
+ Epoch, SeqNo, Fragment) ->
Length = erlang:iolist_size(Fragment),
NewSeq = (Epoch bsl 48) + SeqNo,
mac_hash(Version, MacAlg, MacSecret, NewSeq, Type,
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
index b9f84cbe7f..373481c3f8 100644
--- a/lib/ssl/src/dtls_record.hrl
+++ b/lib/ssl/src/dtls_record.hrl
@@ -34,11 +34,10 @@
-record(ssl_tls, {
type,
version,
- epoch,
- sequence_number,
- offset,
- length,
- fragment
+ %%length,
+ fragment,
+ epoch,
+ sequence_number
}).
-endif. % -ifdef(dtls_record).
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
new file mode 100644
index 0000000000..570b3ae83a
--- /dev/null
+++ b/lib/ssl/src/dtls_socket.erl
@@ -0,0 +1,148 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dtls_socket).
+
+-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
+
+-export([send/3, listen/3, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
+ peername/2, sockname/2, port/2, close/2]).
+-export([emulated_options/0, internal_inet_values/0, default_inet_values/0, default_cb_info/0]).
+
+send(Transport, {{IP,Port},Socket}, Data) ->
+ Transport:send(Socket, IP, Port, Data).
+
+listen(gen_udp = Transport, Port, #config{transport_info = {Transport, _, _, _},
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_user = Options} = Config) ->
+
+
+ case dtls_udp_sup:start_child([Port, emulated_socket_options(EmOpts, #socket_options{}),
+ Options ++ internal_inet_values(), SslOpts]) of
+ {ok, Pid} ->
+ {ok, #sslsocket{pid = {udp, Config#config{udp_handler = {Pid, Port}}}}};
+ Err = {error, _} ->
+ Err
+ end.
+
+accept(udp, #config{transport_info = {Transport = gen_udp,_,_,_},
+ connection_cb = ConnectionCb,
+ udp_handler = {Listner, _}}, _Timeout) ->
+ case dtls_udp_listener:accept(Listner, self()) of
+ {ok, Pid, Socket} ->
+ {ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
+ connection_cb = ConnectionCb,
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_ssl = SocketOpts}, Timeout) ->
+ case Transport:open(0, SocketOpts ++ internal_inet_values()) of
+ {ok, Socket} ->
+ ssl_connection:connect(ConnectionCb, Address, Port, {{Address, Port},Socket},
+ {SslOpts,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, _} = Error->
+ Error
+ end.
+
+close(gen_udp, {_Client, _Socket}) ->
+ ok.
+
+socket(Pid, Transport, Socket, ConnectionCb) ->
+ #sslsocket{pid = Pid,
+ %% "The name "fd" is keept for backwards compatibility
+ fd = {Transport, Socket, ConnectionCb}}.
+
+%% Vad göra med emulerade
+setopts(gen_udp, #sslsocket{pid = {Socket, _}}, Options) ->
+ {SockOpts, _} = tls_socket:split_options(Options),
+ inet:setopts(Socket, SockOpts);
+setopts(_, #sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}, Options) ->
+ {SockOpts, _} = tls_socket:split_options(Options),
+ Transport:setopts(ListenSocket, SockOpts);
+%%% Following clauses will not be called for emulated options, they are handled in the connection process
+setopts(gen_udp, Socket, Options) ->
+ inet:setopts(Socket, Options);
+setopts(Transport, Socket, Options) ->
+ Transport:setopts(Socket, Options).
+
+getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) ->
+ {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
+ EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
+ SocketOpts = tls_socket:get_socket_opts(Socket, SockOptNames, inet),
+ {ok, EmulatedOpts ++ SocketOpts};
+getopts(Transport, #sslsocket{pid = {ListenSocket, #config{emulated = EmOpts}}}, Options) ->
+ {SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
+ EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
+ SocketOpts = tls_socket:get_socket_opts(ListenSocket, SockOptNames, Transport),
+ {ok, EmulatedOpts ++ SocketOpts};
+%%% Following clauses will not be called for emulated options, they are handled in the connection process
+getopts(gen_udp, {_,Socket}, Options) ->
+ inet:getopts(Socket, Options);
+getopts(Transport, Socket, Options) ->
+ Transport:getopts(Socket, Options).
+getstat(gen_udp, {_,Socket}, Options) ->
+ inet:getstat(Socket, Options);
+getstat(Transport, Socket, Options) ->
+ Transport:getstat(Socket, Options).
+peername(gen_udp, {_, {Client, _Socket}}) ->
+ {ok, Client};
+peername(Transport, Socket) ->
+ Transport:peername(Socket).
+sockname(gen_udp, {_,Socket}) ->
+ inet:sockname(Socket);
+sockname(Transport, Socket) ->
+ Transport:sockname(Socket).
+
+port(gen_udp, {_,Socket}) ->
+ inet:port(Socket);
+port(Transport, Socket) ->
+ Transport:port(Socket).
+
+emulated_options() ->
+ [mode, active, packet, packet_size].
+
+internal_inet_values() ->
+ [{active, false}, {mode,binary}].
+
+default_inet_values() ->
+ [{active, true}, {mode, list}].
+
+default_cb_info() ->
+ {gen_udp, udp, udp_closed, udp_error}.
+
+get_emulated_opts(EmOpts, EmOptNames) ->
+ lists:map(fun(Name) -> {value, Value} = lists:keysearch(Name, 1, EmOpts),
+ Value end,
+ EmOptNames).
+
+emulated_socket_options(InetValues, #socket_options{
+ mode = Mode,
+ active = Active}) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, Mode),
+ active = proplists:get_value(active, InetValues, Active)
+ }.
diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_udp_listener.erl
new file mode 100644
index 0000000000..b7f115582e
--- /dev/null
+++ b/lib/ssl/src/dtls_udp_listener.erl
@@ -0,0 +1,205 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% 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(dtls_udp_listener).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/4, active_once/3, accept/2, sockname/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-record(state,
+ {port,
+ listner,
+ dtls_options,
+ emulated_options,
+ dtls_msq_queues = kv_new(),
+ clients = set_new(),
+ dtls_processes = kv_new(),
+ accepters = queue:new(),
+ first
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+start_link(Port, EmOpts, InetOptions, DTLSOptions) ->
+ gen_server:start_link(?MODULE, [Port, EmOpts, InetOptions, DTLSOptions], []).
+
+active_once(UDPConnection, Client, Pid) ->
+ gen_server:cast(UDPConnection, {active_once, Client, Pid}).
+
+accept(UDPConnection, Accepter) ->
+ gen_server:call(UDPConnection, {accept, Accepter}, infinity).
+
+sockname(UDPConnection) ->
+ gen_server:call(UDPConnection, sockname, infinity).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+init([Port, EmOpts, InetOptions, DTLSOptions]) ->
+ try
+ {ok, Socket} = gen_udp:open(Port, InetOptions),
+ {ok, #state{port = Port,
+ first = true,
+ dtls_options = DTLSOptions,
+ emulated_options = EmOpts,
+ listner = Socket}}
+ catch _:_ ->
+ {error, closed}
+ end.
+
+handle_call({accept, Accepter}, From, #state{first = true,
+ accepters = Accepters,
+ listner = Socket} = State0) ->
+ next_datagram(Socket),
+ State = State0#state{first = false,
+ accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+
+handle_call({accept, Accepter}, From, #state{accepters = Accepters} = State0) ->
+ State = State0#state{accepters = queue:in({Accepter, From}, Accepters)},
+ {noreply, State};
+handle_call(sockname, _, #state{listner = Socket} = State) ->
+ Reply = inet:sockname(Socket),
+ {reply, Reply, State}.
+
+handle_cast({active_once, Client, Pid}, State0) ->
+ State = handle_active_once(Client, Pid, State0),
+ {noreply, State}.
+
+handle_info({udp, Socket, IP, InPortNo, _} = Msg, #state{listner = Socket} = State0) ->
+ State = handle_datagram({IP, InPortNo}, Msg, State0),
+ next_datagram(Socket),
+ {noreply, State};
+
+handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
+ dtls_processes = Processes0} = State) ->
+ Client = kv_get(Pid, Processes0),
+ Processes = kv_delete(Pid, Processes0),
+ {noreply, State#state{clients = set_delete(Client, Clients),
+ dtls_processes = Processes}}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+handle_datagram(Client, Msg, #state{clients = Clients,
+ accepters = AcceptorsQueue0} = State) ->
+ case set_is_member(Client, Clients) of
+ false ->
+ case queue:out(AcceptorsQueue0) of
+ {{value, {UserPid, From}}, AcceptorsQueue} ->
+ setup_new_connection(UserPid, From, Client, Msg,
+ State#state{accepters = AcceptorsQueue});
+ {empty, _} ->
+ %% Drop packet client will resend
+ State
+ end;
+ true ->
+ dispatch(Client, Msg, State)
+ end.
+
+dispatch(Client, Msg, #state{dtls_msq_queues = MsgQueues} = State) ->
+ case kv_lookup(Client, MsgQueues) of
+ {value, Queue0} ->
+ case queue:out(Queue0) of
+ {{value, Pid}, Queue} when is_pid(Pid) ->
+ Pid ! Msg,
+ State#state{dtls_msq_queues =
+ kv_update(Client, Queue, MsgQueues)};
+ {{value, _}, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue), MsgQueues)};
+ {empty, Queue} ->
+ State#state{dtls_msq_queues =
+ kv_update(Client, queue:in(Msg, Queue), MsgQueues)}
+ end
+ end.
+next_datagram(Socket) ->
+ inet:setopts(Socket, [{active, once}]).
+
+handle_active_once(Client, Pid, #state{dtls_msq_queues = MsgQueues} = State0) ->
+ Queue0 = kv_get(Client, MsgQueues),
+ case queue:out(Queue0) of
+ {{value, Pid}, _} when is_pid(Pid) ->
+ State0;
+ {{value, Msg}, Queue} ->
+ Pid ! Msg,
+ State0#state{dtls_msq_queues = kv_update(Client, Queue, MsgQueues)};
+ {empty, Queue0} ->
+ State0#state{dtls_msq_queues = kv_update(Client, queue:in(Pid, Queue0), MsgQueues)}
+ end.
+
+setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
+ clients = Clients,
+ dtls_msq_queues = MsgQueues,
+ dtls_options = DTLSOpts,
+ port = Port,
+ listner = Socket,
+ emulated_options = EmOpts} = State) ->
+ ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
+ {DTLSOpts, EmOpts, udp_listner}, User, dtls_socket:default_cb_info()],
+ case dtls_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ gen_server:reply(From, {ok, Pid, {Client, Socket}}),
+ Pid ! Msg,
+ State#state{clients = set_insert(Client, Clients),
+ dtls_msq_queues = kv_insert(Client, queue:new(), MsgQueues),
+ dtls_processes = kv_insert(Pid, Client, Processes)};
+ {error, Reason} ->
+ gen_server:reply(From, {error, Reason}),
+ State
+ end.
+kv_update(Key, Value, Store) ->
+ gb_trees:update(Key, Value, Store).
+kv_lookup(Key, Store) ->
+ gb_trees:lookup(Key, Store).
+kv_insert(Key, Value, Store) ->
+ gb_trees:insert(Key, Value, Store).
+kv_get(Key, Store) ->
+ gb_trees:get(Key, Store).
+kv_delete(Key, Store) ->
+ gb_trees:delete(Key, Store).
+kv_new() ->
+ gb_trees:empty().
+
+set_new() ->
+ gb_sets:empty().
+set_insert(Item, Set) ->
+ gb_sets:insert(Item, Set).
+set_delete(Item, Set) ->
+ gb_sets:delete(Item, Set).
+set_is_member(Item, Set) ->
+ gb_sets:is_member(Item, Set).
diff --git a/lib/ssl/src/dtls_udp_sup.erl b/lib/ssl/src/dtls_udp_sup.erl
new file mode 100644
index 0000000000..197882e92f
--- /dev/null
+++ b/lib/ssl/src/dtls_udp_sup.erl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Supervisor for a procsses dispatching upd datagrams to
+%% correct DTLS handler
+%%----------------------------------------------------------------------
+-module(dtls_udp_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+-export([start_child/1]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+start_child(Args) ->
+ supervisor:start_child(?MODULE, Args).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+init(_O) ->
+ RestartStrategy = simple_one_for_one,
+ MaxR = 0,
+ MaxT = 3600,
+
+ Name = undefined, % As simple_one_for_one is used.
+ StartFunc = {dtls_udp_listener, start_link, []},
+ Restart = temporary, % E.g. should not be restarted
+ Shutdown = 4000,
+ Modules = [dtls_udp_listener],
+ Type = worker,
+
+ ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
+ {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 8c03bda513..ffd3e4b833 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -21,7 +21,7 @@
-include("ssl_cipher.hrl").
--export([suites/1, mac_hash/7, ecc_curves/1, corresponding_tls_version/1]).
+-export([suites/1, mac_hash/7, ecc_curves/1, corresponding_tls_version/1, corresponding_dtls_version/1]).
-spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
@@ -29,7 +29,7 @@ suites(Minor) ->
tls_v1:suites(corresponding_minor_tls_version(Minor)).
mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, corresponding_tls_version(Version),
+ tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
Length, Fragment).
ecc_curves({_Major, Minor}) ->
@@ -42,3 +42,11 @@ corresponding_minor_tls_version(255) ->
2;
corresponding_minor_tls_version(253) ->
3.
+
+corresponding_dtls_version({3, Minor}) ->
+ {254, corresponding_minor_dtls_version(Minor)}.
+
+corresponding_minor_dtls_version(2) ->
+ 255;
+corresponding_minor_dtls_version(3) ->
+ 253.
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 00b0513891..9c5d795848 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -6,6 +6,7 @@
tls_connection,
tls_handshake,
tls_record,
+ tls_socket,
tls_v1,
ssl_v3,
ssl_v2,
@@ -13,7 +14,10 @@
dtls_connection,
dtls_handshake,
dtls_record,
+ dtls_socket,
dtls_v1,
+ dtls_udp_listener,
+ dtls_udp_sup,
%% API
ssl, %% Main API
tls, %% TLS specific
@@ -27,7 +31,6 @@
ssl_cipher,
ssl_srp_primes,
ssl_alert,
- ssl_socket,
ssl_listen_tracker_sup,
%% Erlang Distribution over SSL/TLS
inet_tls_dist,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index aa62ab8865..0b7229b67e 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -101,33 +101,27 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
{Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
{gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = ssl_socket:emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ EmulatedOptions = tls_socket:emulated_options(),
+ {ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
try handle_options(SslOptions0 ++ SocketValues, client) of
- {ok, #config{transport_info = CbInfo, ssl = SslOptions, emulated = EmOpts,
- connection_cb = ConnectionCb}} ->
-
- ok = ssl_socket:setopts(Transport, Socket, ssl_socket:internal_inet_values()),
- case ssl_socket:peername(Transport, Socket) of
- {ok, {Address, Port}} ->
- ssl_connection:connect(ConnectionCb, Address, Port, Socket,
- {SslOptions, emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout);
- {error, Error} ->
- {error, Error}
- end
+ {ok, Config} ->
+ tls_socket:upgrade(Socket, Config, Timeout)
catch
_:{error, Reason} ->
{error, Reason}
end;
-
connect(Host, Port, Options) ->
connect(Host, Port, Options, infinity).
connect(Host, Port, Options, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- try handle_options(Options, client) of
- {ok, Config} ->
- do_connect(Host,Port,Config,Timeout)
+ try
+ {ok, Config} = handle_options(Options, client),
+ case Config#config.connection_cb of
+ tls_connection ->
+ tls_socket:connect(Host,Port,Config,Timeout);
+ dtls_connection ->
+ dtls_socket:connect(Host,Port,Config,Timeout)
+ end
catch
throw:Error ->
Error
@@ -144,17 +138,7 @@ listen(_Port, []) ->
listen(Port, Options0) ->
try
{ok, Config} = handle_options(Options0, server),
- ConnectionCb = connection_cb(Options0),
- #config{transport_info = {Transport, _, _, _}, inet_user = Options, connection_cb = ConnectionCb,
- ssl = SslOpts, emulated = EmOpts} = Config,
- case Transport:listen(Port, Options) of
- {ok, ListenSocket} ->
- ok = ssl_socket:setopts(Transport, ListenSocket, ssl_socket:internal_inet_values()),
- {ok, Tracker} = ssl_socket:inherit_tracker(ListenSocket, EmOpts, SslOpts),
- {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
- Err = {error, _} ->
- Err
- end
+ do_listen(Port, Config, connection_cb(Options0))
catch
Error = {error, _} ->
Error
@@ -171,27 +155,15 @@ transport_accept(ListenSocket) ->
transport_accept(ListenSocket, infinity).
transport_accept(#sslsocket{pid = {ListenSocket,
- #config{transport_info = {Transport,_,_, _} =CbInfo,
- connection_cb = ConnectionCb,
- ssl = SslOpts,
- emulated = Tracker}}}, Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
- case Transport:accept(ListenSocket, Timeout) of
- {ok, Socket} ->
- {ok, EmOpts} = ssl_socket:get_emulated_opts(Tracker),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
- ConnectionSup = connection_sup(ConnectionCb),
- case ConnectionSup:start_child(ConnArgs) of
- {ok, Pid} ->
- ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
+ #config{connection_cb = ConnectionCb} = Config}}, Timeout)
+ when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
+ case ConnectionCb of
+ tls_connection ->
+ tls_socket:accept(ListenSocket, Config, Timeout);
+ dtls_connection ->
+ dtls_socket:accept(ListenSocket, Config, Timeout)
end.
-
+
%%--------------------------------------------------------------------
-spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
@@ -214,13 +186,14 @@ ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
ssl_accept(ListenSocket, SslOptions, infinity).
ssl_accept(#sslsocket{} = Socket, [], Timeout) when (is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
- ssl_accept(#sslsocket{} = Socket, Timeout);
+ ssl_accept(Socket, Timeout);
ssl_accept(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts0, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, InheritedSslOpts} = ssl_socket:get_all_opts(Tracker),
+ {ok, EmOpts, InheritedSslOpts} = tls_socket:get_all_opts(Tracker),
SslOpts = handle_options(SslOpts0, InheritedSslOpts),
- ssl_connection:handshake(Socket, {SslOpts, emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
+ ssl_connection:handshake(Socket, {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
Error = {error, _Reason} -> Error
end;
@@ -228,15 +201,16 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
{Transport,_,_,_} =
proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = ssl_socket:emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ EmulatedOptions = tls_socket:emulated_options(),
+ {ok, SocketValues} = tls_socket:getopts(Transport, Socket, EmulatedOptions),
ConnetionCb = connection_cb(SslOptions),
try handle_options(SslOptions ++ SocketValues, server) of
{ok, #config{transport_info = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
- ok = ssl_socket:setopts(Transport, Socket, ssl_socket:internal_inet_values()),
- {ok, Port} = ssl_socket:port(Transport, Socket),
+ ok = tls_socket:setopts(Transport, Socket, tls_socket:internal_inet_values()),
+ {ok, Port} = tls_socket:port(Transport, Socket),
ssl_connection:ssl_accept(ConnetionCb, Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ {SslOpts,
+ tls_socket:emulated_socket_options(EmOpts, #socket_options{}), undefined},
self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
@@ -275,6 +249,8 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%--------------------------------------------------------------------
send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
+send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
Transport:send(ListenSocket, Data). %% {error,enotconn}
@@ -358,9 +334,9 @@ connection_info(#sslsocket{} = SSLSocket) ->
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
- ssl_socket:peername(Transport, Socket);
+ tls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
- ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+ tls_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
%%--------------------------------------------------------------------
-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
@@ -456,7 +432,7 @@ getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags)
ssl_connection:get_opts(Pid, OptionTags);
getopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket,
OptionTags) when is_list(OptionTags) ->
- try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
+ try tls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
{error, InetError} ->
@@ -484,7 +460,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
end;
setopts(#sslsocket{pid = {_, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
- try ssl_socket:setopts(Transport, ListenSocket, Options) of
+ try tls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
{error, InetError} ->
@@ -517,10 +493,10 @@ getstat(Socket) ->
%% Description: Get one or more statistic options for a socket.
%%--------------------------------------------------------------------
getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
- ssl_socket:getstat(Transport, Listen, Options);
+ tls_socket:getstat(Transport, Listen, Options);
getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
- ssl_socket:getstat(Transport, Socket, Options).
+ tls_socket:getstat(Transport, Socket, Options).
%%---------------------------------------------------------------
-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
@@ -539,10 +515,13 @@ shutdown(#sslsocket{pid = Pid}, How) ->
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
- ssl_socket:sockname(Transport, Listen);
-
+ tls_socket:sockname(Transport, Listen);
+sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
+ dtls_udp_listener:sockname(Pid);
+sockname(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
+ dtls_socket:sockname(Transport, Socket);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
- ssl_socket:sockname(Transport, Socket).
+ tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
@@ -652,27 +631,12 @@ available_suites(all) ->
Version = tls_record:highest_protocol_version([]),
ssl_cipher:filter_suites(ssl_cipher:all_suites(Version)).
-do_connect(Address, Port,
- #config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
- emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
- Timeout) ->
- {Transport, _, _, _} = CbInfo,
- try Transport:connect(Address, Port, SocketOpts, Timeout) of
- {ok, Socket} ->
- ssl_connection:connect(ConnetionCb, Address, Port, Socket,
- {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), undefined},
- self(), CbInfo, Timeout);
- {error, Reason} ->
- {error, Reason}
- catch
- exit:{function_clause, _} ->
- {error, {options, {cb_info, CbInfo}}};
- exit:badarg ->
- {error, {options, {socket_options, UserOpts}}};
- exit:{badarg, _} ->
- {error, {options, {socket_options, UserOpts}}}
- end.
+do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
+ tls_socket:listen(Transport, Port, Config);
+do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
+ dtls_socket:listen(Transport, Port, Config).
+
%% Handle extra ssl options given to ssl_accept
-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
; ([any()], client | server) -> {ok, #config{}}.
@@ -732,6 +696,8 @@ handle_options(Opts0, Role) ->
[RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
end,
+ Protocol = proplists:get_value(protocol, Opts, tls),
+
SSLOptions = #ssl_options{
versions = Versions,
verify = validate_option(verify, Verify),
@@ -759,7 +725,7 @@ handle_options(Opts0, Role) ->
signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts,
default_option_role(server,
tls_v1:default_signature_algs(Versions), Role)),
- RecordCb:highest_protocol_version(Versions)),
+ tls_version(RecordCb:highest_protocol_version(Versions))),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
reuse_sessions = handle_option(reuse_sessions, Opts, true),
@@ -789,7 +755,7 @@ handle_options(Opts0, Role) ->
honor_ecc_order = handle_option(honor_ecc_order, Opts,
default_option_role(server, false, Role),
server, Role),
- protocol = proplists:get_value(protocol, Opts, tls),
+ protocol = Protocol,
padding_check = proplists:get_value(padding_check, Opts, true),
beast_mitigation = handle_option(beast_mitigation, Opts, one_n_minus_one),
fallback = handle_option(fallback, Opts,
@@ -799,10 +765,11 @@ handle_options(Opts0, Role) ->
client, Role),
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
- v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false)
+ v2_hello_compatible = handle_option(v2_hello_compatible, Opts, false),
+ max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE)
},
- CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
@@ -814,13 +781,14 @@ handle_options(Opts0, Role) ->
alpn_preferred_protocols, next_protocols_advertised,
client_preferred_next_protocols, log_alert,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, v2_hello_compatible],
+ fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation, v2_hello_compatible,
+ max_handshake_size],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
- {Sock, Emulated} = emulated_options(SockOpts),
+ {Sock, Emulated} = emulated_options(Protocol, SockOpts),
ConnetionCb = connection_cb(Opts),
{ok, #config{ssl = SSLOptions, emulated = Emulated, inet_ssl = Sock,
@@ -1062,6 +1030,8 @@ validate_option(beast_mitigation, Value) when Value == one_n_minus_one orelse
Value;
validate_option(v2_hello_compatible, Value) when is_boolean(Value) ->
Value;
+validate_option(max_handshake_size, Value) when is_integer(Value) andalso Value =< ?MAX_UNIT24 ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
@@ -1139,8 +1109,13 @@ ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
%% some trusted certs.
ca_cert_default(verify_peer, undefined, _) ->
"".
-emulated_options(Opts) ->
- emulated_options(Opts, ssl_socket:internal_inet_values(), ssl_socket:default_inet_values()).
+emulated_options(Protocol, Opts) ->
+ case Protocol of
+ tls ->
+ emulated_options(Opts, tls_socket:internal_inet_values(), tls_socket:default_inet_values());
+ dtls ->
+ emulated_options(Opts, dtls_socket:internal_inet_values(), dtls_socket:default_inet_values())
+ end.
emulated_options([{mode, Value} = Opt |Opts], Inet, Emulated) ->
validate_inet_option(mode, Value),
@@ -1281,11 +1256,6 @@ record_cb(dtls) ->
record_cb(Opts) ->
record_cb(proplists:get_value(protocol, Opts, tls)).
-connection_sup(tls_connection) ->
- tls_connection_sup;
-connection_sup(dtls_connection) ->
- dtls_connection_sup.
-
binary_filename(FileName) ->
Enc = file:native_name_encoding(),
unicode:characters_to_binary(FileName, unicode, Enc).
@@ -1304,20 +1274,6 @@ assert_proplist([inet6 | Rest]) ->
assert_proplist([Value | _]) ->
throw({option_not_a_key_value_tuple, Value}).
-emulated_socket_options(InetValues, #socket_options{
- mode = Mode,
- header = Header,
- active = Active,
- packet = Packet,
- packet_size = Size}) ->
- #socket_options{
- mode = proplists:get_value(mode, InetValues, Mode),
- header = proplists:get_value(header, InetValues, Header),
- active = proplists:get_value(active, InetValues, Active),
- packet = proplists:get_value(packet, InetValues, Packet),
- packet_size = proplists:get_value(packet_size, InetValues, Size)
- }.
-
new_ssl_options([], #ssl_options{} = Opts, _) ->
Opts;
new_ssl_options([{verify_client_once, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
@@ -1390,7 +1346,7 @@ new_ssl_options([{signature_algs, Value} | Rest], #ssl_options{} = Opts, RecordC
new_ssl_options(Rest,
Opts#ssl_options{signature_algs =
handle_hashsigns_option(Value,
- RecordCB:highest_protocol_version())},
+ tls_version(RecordCB:highest_protocol_version()))},
RecordCB);
new_ssl_options([{Key, Value} | _Rest], #ssl_options{}, _) ->
@@ -1454,3 +1410,8 @@ default_option_role(Role, Value, Role) ->
Value;
default_option_role(_,_,_) ->
undefined.
+
+default_cb_info(tls) ->
+ {gen_tcp, tcp, tcp_closed, tcp_error};
+default_cb_info(dtls) ->
+ {gen_udp, udp, udp_closed, udp_error}.
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 05dfb4c1b3..696a55e4b9 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,22 +32,13 @@
-include("ssl_record.hrl").
-include("ssl_internal.hrl").
--export([encode/3, decode/1, alert_txt/1, reason_code/2]).
+-export([decode/1, alert_txt/1, reason_code/2]).
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec encode(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
- {iolist(), ssl_record:connection_states()}.
-%%
-%% Description: Encodes an alert
-%%--------------------------------------------------------------------
-encode(#alert{} = Alert, Version, ConnectionStates) ->
- ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
-
-%%--------------------------------------------------------------------
-spec decode(binary()) -> [#alert{}] | #alert{}.
%%
%% Description: Decode alert(s), will return a singel own alert if peer
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 38facb964f..f3743ba0f0 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 605bbd859a..32fec03b8e 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -40,7 +40,7 @@
ec_keyed_suites/0, anonymous_suites/1, psk_suites/1, srp_suites/0,
rc4_suites/1, des_suites/1, openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
- random_bytes/1]).
+ random_bytes/1, calc_aad/3, calc_mac_hash/4]).
-export_type([cipher_suite/0,
erl_cipher_suite/0, openssl_cipher_suite/0,
@@ -311,7 +311,9 @@ aead_decipher(Type, #cipher_state{key = Key, iv = IV} = CipherState,
suites({3, 0}) ->
ssl_v3:suites();
suites({3, N}) ->
- tls_v1:suites(N).
+ tls_v1:suites(N);
+suites(Version) ->
+ suites(dtls_v1:corresponding_tls_version(Version)).
all_suites(Version) ->
suites(Version)
@@ -1525,9 +1527,32 @@ is_fallback(CipherSuites)->
random_bytes(N) ->
crypto:strong_rand_bytes(N).
+calc_aad(Type, {MajVer, MinVer},
+ #{sequence_number := SeqNo}) ->
+ <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
+
+calc_mac_hash(Type, Version,
+ PlainFragment, #{sequence_number := SeqNo,
+ mac_secret := MacSecret,
+ security_parameters:=
+ SecPars}) ->
+ Length = erlang:iolist_size(PlainFragment),
+ mac_hash(Version, SecPars#security_parameters.mac_algorithm,
+ MacSecret, SeqNo, Type,
+ Length, PlainFragment).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
+ _Length, _Fragment) ->
+ <<>>;
+mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
+ ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
+mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
+ when N =:= 1; N =:= 2; N =:= 3 ->
+ tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
+ Length, Fragment).
bulk_cipher_algorithm(null) ->
?NULL;
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index b6e4d5b433..6ed2fc83da 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -44,7 +44,7 @@
-export([send/2, recv/3, close/2, shutdown/2,
new_user/2, get_opts/2, set_opts/2, session_info/1,
peer_certificate/1, renegotiation/1, negotiated_protocol/1, prf/5,
- connection_information/1
+ connection_information/1, handle_common_event/5
]).
%% General gen_statem state functions with extra callback argument
@@ -71,7 +71,8 @@
%%====================================================================
%%--------------------------------------------------------------------
-spec connect(tls_connection | dtls_connection,
- host(), inet:port_number(), port(),
+ host(), inet:port_number(),
+ port() | {tuple(), port()}, %% TLS | DTLS
{#ssl_options{}, #socket_options{},
%% Tracker only needed on server side
undefined},
@@ -145,14 +146,24 @@ socket_control(Connection, Socket, Pid, Transport) ->
-spec socket_control(tls_connection | dtls_connection, port(), pid(), atom(), pid()| undefined) ->
{ok, #sslsocket{}} | {error, reason()}.
%%--------------------------------------------------------------------
-socket_control(Connection, Socket, Pid, Transport, ListenTracker) ->
+socket_control(Connection, Socket, Pid, Transport, udp_listner) ->
+ %% dtls listner process must have the socket control
+ {ok, dtls_socket:socket(Pid, Transport, Socket, Connection)};
+
+socket_control(tls_connection = Connection, Socket, Pid, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, ssl_socket:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, tls_socket:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {error, Reason} ->
+ {error, Reason}
+ end;
+socket_control(dtls_connection = Connection, {_, Socket}, Pid, Transport, ListenTracker) ->
+ case Transport:controlling_process(Socket, Pid) of
+ ok ->
+ {ok, tls_socket:socket(Pid, Transport, Socket, Connection, ListenTracker)};
{error, Reason} ->
{error, Reason}
end.
-
%%--------------------------------------------------------------------
-spec send(pid(), iodata()) -> ok | {error, reason()}.
%%
@@ -461,7 +472,7 @@ certify(internal, #certificate{asn1_certificates = []},
#state{role = server, negotiated_version = Version,
ssl_options = #ssl_options{verify = verify_peer,
fail_if_no_peer_cert = true}} =
- State, _Connection) ->
+ State, _) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
handle_own_alert(Alert, Version, certify, State);
@@ -478,7 +489,7 @@ certify(internal, #certificate{},
#state{role = server,
negotiated_version = Version,
ssl_options = #ssl_options{verify = verify_none}} =
- State, _Connection) ->
+ State, _) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE, unrequested_certificate),
handle_own_alert(Alert, Version, certify, State);
@@ -788,7 +799,7 @@ connection(Type, Msg, State, Connection) ->
downgrade(internal, #alert{description = ?CLOSE_NOTIFY},
#state{transport_cb = Transport, socket = Socket,
downgrade = {Pid, From}} = State, _) ->
- ssl_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
+ tls_socket:setopts(Transport, Socket, [{active, false}, {packet, 0}, {mode, binary}]),
Transport:controlling_process(Socket, Pid),
gen_statem:reply(From, {ok, Socket}),
{stop, normal, State};
@@ -819,7 +830,7 @@ handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName,
%% a client_hello, which needs to be determined by the connection callback.
%% In other cases this is a noop
State = handle_sni_extension(PossibleSNI, State0),
- HsHist = ssl_handshake:update_handshake_history(Hs0, Raw, V2HComp),
+ HsHist = ssl_handshake:update_handshake_history(Hs0, iolist_to_binary(Raw), V2HComp),
{next_state, StateName, State#state{tls_handshake_history = HsHist},
[{next_event, internal, Handshake}]};
handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, State, Connection) ->
@@ -853,24 +864,24 @@ handle_call({close, {Pid, Timeout}}, From, StateName, State0, Connection) when i
%% When downgrading an TLS connection to a transport connection
%% we must recive the close alert from the peer before releasing the
%% transport socket.
- {next_state, downgrade, State, [{timeout, Timeout, downgrade}]};
+ {next_state, downgrade, State#state{terminated = true}, [{timeout, Timeout, downgrade}]};
handle_call({close, _} = Close, From, StateName, State, Connection) ->
%% Run terminate before returning so that the reuseaddr
- %% inet-option
- Result = Connection:terminate(Close, StateName, State),
+ %% inet-option works properly
+ Result = Connection:terminate(Close, StateName, State#state{terminated = true}),
{stop_and_reply, {shutdown, normal},
{reply, From, Result}, State};
handle_call({shutdown, How0}, From, _,
#state{transport_cb = Transport,
negotiated_version = Version,
connection_states = ConnectionStates,
- socket = Socket}, _) ->
+ socket = Socket}, Connection) ->
case How0 of
How when How == write; How == both ->
Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
{BinMsg, _} =
- ssl_alert:encode(Alert, Version, ConnectionStates),
- Transport:send(Socket, BinMsg);
+ Connection:encode_alert(Alert, Version, ConnectionStates),
+ Connection:send(Transport, Socket, BinMsg);
_ ->
ok
end,
@@ -999,7 +1010,10 @@ handle_info(Msg, StateName, #state{socket = Socket, error_tag = Tag} = State) ->
terminate(_, _, #state{terminated = true}) ->
%% Happens when user closes the connection using ssl:close/1
%% we want to guarantee that Transport:close has been called
- %% when ssl:close/1 returns.
+ %% when ssl:close/1 returns unless it is a downgrade where
+ %% we want to guarantee that close alert is recived before
+ %% returning. In both cases terminate has been run manually
+ %% before run by gen_statem which will end up here
ok;
terminate({shutdown, transport_closed} = Reason,
@@ -1025,8 +1039,8 @@ terminate(Reason, connection, #state{negotiated_version = Version,
transport_cb = Transport, socket = Socket
} = State) ->
handle_trusted_certs_db(State),
- {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0),
- Transport:send(Socket, BinAlert),
+ {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0, Connection),
+ Connection:send(Transport, Socket, BinAlert),
Connection:close(Reason, Socket, Transport, ConnectionStates, Check);
terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection,
@@ -1079,8 +1093,8 @@ write_application_data(Data0, From,
Connection:renegotiate(State#state{renegotiation = {true, internal}},
[{next_event, {call, From}, {application_data, Data0}}]);
false ->
- {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
- Result = Transport:send(Socket, Msgs),
+ {Msgs, ConnectionStates} = Connection:encode_data(Data, Version, ConnectionStates0),
+ Result = Connection:send(Transport, Socket, Msgs),
ssl_connection:hibernate_after(connection, State#state{connection_states = ConnectionStates},
[{reply, From, Result}])
end.
@@ -1913,7 +1927,7 @@ get_socket_opts(Transport, Socket, [active | Tags], SockOpts, Acc) ->
get_socket_opts(Transport, Socket, Tags, SockOpts,
[{active, SockOpts#socket_options.active} | Acc]);
get_socket_opts(Transport, Socket, [Tag | Tags], SockOpts, Acc) ->
- try ssl_socket:getopts(Transport, Socket, [Tag]) of
+ try tls_socket:getopts(Transport, Socket, [Tag]) of
{ok, [Opt]} ->
get_socket_opts(Transport, Socket, Tags, SockOpts, [Opt | Acc]);
{error, Error} ->
@@ -1929,7 +1943,7 @@ set_socket_opts(_,_, [], SockOpts, []) ->
{ok, SockOpts};
set_socket_opts(Transport, Socket, [], SockOpts, Other) ->
%% Set non emulated options
- try ssl_socket:setopts(Transport, Socket, Other) of
+ try tls_socket:setopts(Transport, Socket, Other) of
ok ->
{ok, SockOpts};
{error, InetError} ->
@@ -1995,17 +2009,17 @@ hibernate_after(connection = StateName,
hibernate_after(StateName, State, Actions) ->
{next_state, StateName, State, Actions}.
-terminate_alert(normal, Version, ConnectionStates) ->
- ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+terminate_alert(normal, Version, ConnectionStates, Connection) ->
+ Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates);
-terminate_alert({Reason, _}, Version, ConnectionStates) when Reason == close;
- Reason == shutdown ->
- ssl_alert:encode(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+terminate_alert({Reason, _}, Version, ConnectionStates, Connection) when Reason == close;
+ Reason == shutdown ->
+ Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates);
-terminate_alert(_, Version, ConnectionStates) ->
- {BinAlert, _} = ssl_alert:encode(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
- Version, ConnectionStates),
+terminate_alert(_, Version, ConnectionStates, Connection) ->
+ {BinAlert, _} = Connection:encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
+ Version, ConnectionStates),
BinAlert.
handle_trusted_certs_db(#state{ssl_options =
@@ -2285,7 +2299,7 @@ format_reply(_, _,#socket_options{active = false, mode = Mode, packet = Packet,
{ok, do_format_reply(Mode, Packet, Header, Data)};
format_reply(Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
header = Header}, Data, Tracker, Connection) ->
- {ssl, ssl_socket:socket(self(), Transport, Socket, Connection, Tracker),
+ {ssl, tls_socket:socket(self(), Transport, Socket, Connection, Tracker),
do_format_reply(Mode, Packet, Header, Data)}.
deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
@@ -2294,7 +2308,7 @@ deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Da
format_packet_error(_, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
{error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
format_packet_error(Transport, Socket, #socket_options{active = _, mode = Mode}, Data, Tracker, Connection) ->
- {ssl_error, ssl_socket:socket(self(), Transport, Socket, Connection, Tracker),
+ {ssl_error, tls_socket:socket(self(), Transport, Socket, Connection, Tracker),
{invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
@@ -2349,11 +2363,11 @@ alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connectio
case ssl_alert:reason_code(Alert, Role) of
closed ->
send_or_reply(Active, Pid, From,
- {ssl_closed, ssl_socket:socket(self(),
+ {ssl_closed, tls_socket:socket(self(),
Transport, Socket, Connection, Tracker)});
ReasonCode ->
send_or_reply(Active, Pid, From,
- {ssl_error, ssl_socket:socket(self(),
+ {ssl_error, tls_socket:socket(self(),
Transport, Socket, Connection, Tracker), ReasonCode})
end.
@@ -2366,12 +2380,13 @@ log_alert(false, _, _) ->
handle_own_alert(Alert, Version, StateName,
#state{transport_cb = Transport,
socket = Socket,
+ protocol_cb = Connection,
connection_states = ConnectionStates,
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
{BinMsg, _} =
- ssl_alert:encode(Alert, Version, ConnectionStates),
- Transport:send(Socket, BinMsg)
+ Connection:encode_alert(Alert, Version, ConnectionStates),
+ Connection:send(Transport, Socket, BinMsg)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index fca3e11894..b597c059af 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
error_tag :: atom(), % ex tcp_error
host :: string() | inet:ip_address(),
port :: integer(),
- socket :: port(),
+ socket :: port() | tuple(), %% TODO: dtls socket
ssl_options :: #ssl_options{},
socket_options :: #socket_options{},
connection_states :: ssl_record:connection_states() | secret_printout(),
@@ -81,17 +81,18 @@
allow_renegotiate = true ::boolean(),
expecting_next_protocol_negotiation = false ::boolean(),
expecting_finished = false ::boolean(),
- negotiated_protocol = undefined :: undefined | binary(),
+ next_protocol = undefined :: undefined | binary(),
+ negotiated_protocol,
tracker :: pid() | 'undefined', %% Tracker process for listen socket
sni_hostname = undefined,
downgrade,
- flight_buffer = [] :: list() %% Buffer of TLS/DTLS records, used during the TLS handshake
- %% to when possible pack more than on TLS record into the
- %% underlaying packet format. Introduced by DTLS - RFC 4347.
- %% The mecahnism is also usefull in TLS although we do not
- %% need to worry about packet loss in TLS.
+ flight_buffer = [] :: list() | map(), %% Buffer of TLS/DTLS records, used during the TLS handshake
+ %% to when possible pack more than on TLS record into the
+ %% underlaying packet format. Introduced by DTLS - RFC 4347.
+ %% The mecahnism is also usefull in TLS although we do not
+ %% need to worry about packet loss in TLS. In DTLS we need to track DTLS handshake seqnr
+ flight_state = reliable %% reliable | {retransmit, integer()}| {waiting, ref(), integer()} - last two is used in DTLS over udp.
}).
-
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
diff --git a/lib/ssl/src/ssl_crl.erl b/lib/ssl/src/ssl_crl.erl
index 01be1fb9ab..fc60bdba67 100644
--- a/lib/ssl/src/ssl_crl.erl
+++ b/lib/ssl/src/ssl_crl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl
index 647e0465fe..86c0207515 100644
--- a/lib/ssl/src/ssl_crl_cache.erl
+++ b/lib/ssl/src/ssl_crl_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_crl_cache_api.erl b/lib/ssl/src/ssl_crl_cache_api.erl
index c3a57e2f49..d5380583e7 100644
--- a/lib/ssl/src/ssl_crl_cache_api.erl
+++ b/lib/ssl/src/ssl_crl_cache_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl
index a6eb1be1f6..d47cd76bf5 100644
--- a/lib/ssl/src/ssl_dist_sup.erl
+++ b/lib/ssl/src/ssl_dist_sup.erl
@@ -85,10 +85,10 @@ proxy_server_child_spec() ->
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
listen_options_tracker_child_spec() ->
- Name = ssl_socket_dist,
+ Name = tls_socket_dist,
StartFunc = {ssl_listen_tracker_sup, start_link_dist, []},
Restart = permanent,
Shutdown = 4000,
- Modules = [ssl_socket],
+ Modules = [tls_socket],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index fde92035a2..324b7dbde3 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -80,6 +80,9 @@
-define(CLIENT_KEY_EXCHANGE, 16).
-define(FINISHED, 20).
+-define(MAX_UNIT24, 8388607).
+-define(DEFAULT_MAX_HANDSHAKE_SIZE, (256*1024)).
+
-record(random, {
gmt_unix_time, % uint32
random_bytes % opaque random_bytes[28]
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 487d1fa096..c34af9f82c 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -142,7 +142,8 @@
signature_algs,
eccs,
honor_ecc_order :: boolean(),
- v2_hello_compatible :: boolean()
+ v2_hello_compatible :: boolean(),
+ max_handshake_size :: integer()
}).
-record(socket_options,
@@ -156,7 +157,8 @@
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
- emulated, %% Emulated option list or "inherit_tracker" pid
+ emulated, %% Emulated option list or "inherit_tracker" pid
+ udp_handler,
inet_ssl, %% inet options for internal ssl socket
transport_info, %% Callback info
connection_cb
diff --git a/lib/ssl/src/ssl_listen_tracker_sup.erl b/lib/ssl/src/ssl_listen_tracker_sup.erl
index 7f685a2ead..f7e97bcb76 100644
--- a/lib/ssl/src/ssl_listen_tracker_sup.erl
+++ b/lib/ssl/src/ssl_listen_tracker_sup.erl
@@ -57,10 +57,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssl_socket, start_link, []},
+ StartFunc = {tls_socket, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [ssl_socket],
+ Modules = [tls_socket],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index 0006ce14d9..b4299969e4 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 71cd0279f3..b10069c3cb 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -41,10 +41,6 @@
set_server_verify_data/3,
empty_connection_state/2, initial_connection_state/2, record_protocol_role/1]).
-%% Encoding records
--export([encode_handshake/3, encode_alert_record/3,
- encode_change_cipher_spec/2, encode_data/3]).
-
%% Compression
-export([compress/3, uncompress/3, compressions/0]).
@@ -52,6 +48,9 @@
-export([cipher/4, decipher/4, is_correct_mac/2,
cipher_aead/4, decipher_aead/4]).
+%% Encoding
+-export([encode_plain_text/4]).
+
-export_type([ssl_version/0, ssl_atom_version/0, connection_states/0, connection_state/0]).
-type ssl_version() :: {integer(), integer()}.
@@ -272,70 +271,26 @@ set_pending_cipher_state(#{pending_read := Read,
pending_read => Read#{cipher_state => ServerState},
pending_write => Write#{cipher_state => ClientState}}.
-
-%%--------------------------------------------------------------------
--spec encode_handshake(iolist(), ssl_version(), connection_states()) ->
- {iolist(), connection_states()}.
-%%
-%% Description: Encodes a handshake message to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_handshake(Frag, Version,
- #{current_write :=
- #{beast_mitigation := BeastMitigation,
- security_parameters :=
- #security_parameters{bulk_cipher_algorithm = BCA}}} =
- ConnectionStates)
- when is_list(Frag) ->
- case iolist_size(Frag) of
- N when N > ?MAX_PLAIN_TEXT_LENGTH ->
- Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates);
- _ ->
- encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
- end;
-%% TODO: this is a workarround for DTLS
-%%
-%% DTLS need to select the connection write state based on Epoch it wants to
-%% send this fragment in. That Epoch does not nessarily has to be the same
-%% as the current_write epoch.
-%% The right solution might be to pass the WriteState instead of the ConnectionStates,
-%% however, this will require substantion API changes.
-encode_handshake(Frag, Version, ConnectionStates) ->
- encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
-
-%%--------------------------------------------------------------------
--spec encode_alert_record(#alert{}, ssl_version(), connection_states()) ->
- {iolist(), connection_states()}.
-%%
-%% Description: Encodes an alert message to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_alert_record(#alert{level = Level, description = Description},
- Version, ConnectionStates) ->
- encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
- ConnectionStates).
-
-%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(ssl_version(), connection_states()) ->
- {iolist(), connection_states()}.
-%%
-%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
-%%--------------------------------------------------------------------
-encode_change_cipher_spec(Version, ConnectionStates) ->
- encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
-
-%%--------------------------------------------------------------------
--spec encode_data(binary(), ssl_version(), connection_states()) ->
- {iolist(), connection_states()}.
-%%
-%% Description: Encodes data to send on the ssl-socket.
-%%--------------------------------------------------------------------
-encode_data(Frag, Version,
- #{current_write := #{beast_mitigation := BeastMitigation,
- security_parameters :=
- #security_parameters{bulk_cipher_algorithm = BCA}}} =
- ConnectionStates) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
- encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ AAD = ssl_cipher:calc_aad(Type, Version, WriteState1),
+ ssl_record:cipher_aead(Version, Comp, WriteState1, AAD);
+encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ }= WriteState0) ->
+ {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
+ WriteState1 = WriteState0#{compression_state => CompS1},
+ MacHash = ssl_cipher:calc_mac_hash(Type, Version, Comp, WriteState1),
+ ssl_record:cipher(Version, Comp, WriteState1, MacHash);
+encode_plain_text(_,_,_,CS) ->
+ exit({cs, CS}).
uncompress(?NULL, Data, CS) ->
{Data, CS}.
@@ -451,11 +406,6 @@ random() ->
Random_28_bytes = ssl_cipher:random_bytes(28),
<<?UINT32(Secs_since_1970), Random_28_bytes/binary>>.
-%% dtls_next_epoch(#connection_state{epoch = undefined}) -> %% SSL/TLS
-%% undefined;
-%% dtls_next_epoch(#connection_state{epoch = Epoch}) -> %% DTLS
-%% Epoch + 1.
-
is_correct_mac(Mac, Mac) ->
true;
is_correct_mac(_M,_H) ->
@@ -484,47 +434,3 @@ initial_security_params(ConnectionEnd) ->
compression_algorithm = ?NULL},
ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, SecParams).
-
-encode_plain_text(Type, Version, Data, ConnectionStates) ->
- RecordCB = protocol_module(Version),
- RecordCB:encode_plain_text(Type, Version, Data, ConnectionStates).
-
-encode_iolist(Type, Data, Version, ConnectionStates0) ->
- RecordCB = protocol_module(Version),
- {ConnectionStates, EncodedMsg} =
- lists:foldl(fun(Text, {CS0, Encoded}) ->
- {Enc, CS1} =
- RecordCB:encode_plain_text(Type, Version, Text, CS0),
- {CS1, [Enc | Encoded]}
- end, {ConnectionStates0, []}, Data),
- {lists:reverse(EncodedMsg), ConnectionStates}.
-
-%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
-%% not vulnerable to this attack.
-split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA, one_n_minus_one) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Rest, ChunkSize, [[FirstByte]]);
-%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
-%% splitting.
-split_bin(Bin, ChunkSize, Version, BCA, zero_n) when
- BCA =/= ?RC4 andalso ({3, 1} == Version orelse
- {3, 0} == Version) ->
- do_split_bin(Bin, ChunkSize, [[<<>>]]);
-split_bin(Bin, ChunkSize, _, _, _) ->
- do_split_bin(Bin, ChunkSize, []).
-
-do_split_bin(<<>>, _, Acc) ->
- lists:reverse(Acc);
-do_split_bin(Bin, ChunkSize, Acc) ->
- case Bin of
- <<Chunk:ChunkSize/binary, Rest/binary>> ->
- do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
- _ ->
- lists:reverse(Acc, [Bin])
- end.
-
-protocol_module({3, _}) ->
- tls_record;
-protocol_module({254, _}) ->
- dtls_record.
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index ba20f65f44..8245801139 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -46,14 +46,17 @@ start_link() ->
init([]) ->
SessionCertManager = session_and_cert_manager_child_spec(),
TLSConnetionManager = tls_connection_manager_child_spec(),
- %% Not supported yet
- %%DTLSConnetionManager = dtls_connection_manager_child_spec(),
- %% Handles emulated options so that they inherited by the accept socket, even when setopts is performed on
- %% the listen socket
+ %% Handles emulated options so that they inherited by the accept
+ %% socket, even when setopts is performed on the listen socket
ListenOptionsTracker = listen_options_tracker_child_spec(),
+
+ DTLSConnetionManager = dtls_connection_manager_child_spec(),
+ DTLSUdpListeners = dtls_udp_listeners_spec(),
+
{ok, {{one_for_all, 10, 3600}, [SessionCertManager, TLSConnetionManager,
- %%DTLSConnetionManager,
- ListenOptionsTracker]}}.
+ ListenOptionsTracker,
+ DTLSConnetionManager, DTLSUdpListeners
+ ]}}.
manager_opts() ->
@@ -94,24 +97,32 @@ tls_connection_manager_child_spec() ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-%% dtls_connection_manager_child_spec() ->
-%% Name = dtls_connection,
-%% StartFunc = {dtls_connection_sup, start_link, []},
-%% Restart = permanent,
-%% Shutdown = 4000,
-%% Modules = [dtls_connection, ssl_connection],
-%% Type = supervisor,
-%% {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+dtls_connection_manager_child_spec() ->
+ Name = dtls_connection,
+ StartFunc = {dtls_connection_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [dtls_connection_sup],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
listen_options_tracker_child_spec() ->
- Name = ssl_socket,
+ Name = tls_socket,
StartFunc = {ssl_listen_tracker_sup, start_link, []},
Restart = permanent,
Shutdown = 4000,
- Modules = [ssl_socket],
+ Modules = [tls_socket],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
+dtls_udp_listeners_spec() ->
+ Name = dtls_udp_listener,
+ StartFunc = {dtls_udp_sup, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
session_cb_init_args() ->
case application:get_env(ssl, session_cb_init_args) of
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 932bb139c1..77606911be 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -45,6 +45,8 @@
%% Setup
-export([start_fsm/8, start_link/7, init/1]).
+-export([encode_data/3, encode_alert/3]).
+
%% State transition handling
-export([next_record/1, next_event/3]).
@@ -57,7 +59,7 @@
-export([send_alert/2, close/5]).
%% Data handling
--export([passive_receive/2, next_record_if_active/1, handle_common_event/4]).
+-export([passive_receive/2, next_record_if_active/1, handle_common_event/4, send/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
@@ -114,7 +116,7 @@ queue_handshake(Handshake, #state{negotiated_version = Version,
send_handshake_flight(#state{socket = Socket,
transport_cb = Transport,
flight_buffer = Flight} = State0) ->
- Transport:send(Socket, Flight),
+ send(Transport, Socket, Flight),
State0#state{flight_buffer = []}.
queue_change_cipher(Msg, #state{negotiated_version = Version,
@@ -130,8 +132,8 @@ send_alert(Alert, #state{negotiated_version = Version,
transport_cb = Transport,
connection_states = ConnectionStates0} = State0) ->
{BinMsg, ConnectionStates} =
- ssl_alert:encode(Alert, Version, ConnectionStates0),
- Transport:send(Socket, BinMsg),
+ encode_alert(Alert, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State0#state{connection_states = ConnectionStates}.
reinit_handshake_data(State) ->
@@ -149,6 +151,18 @@ select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
select_sni_extension(_) ->
undefined.
+encode_data(Data, Version, ConnectionStates0)->
+ tls_record:encode_data(Data, Version, ConnectionStates0).
+
+%%--------------------------------------------------------------------
+-spec encode_alert(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert
+%%--------------------------------------------------------------------
+encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
+ tls_record:encode_alert_record(Alert, Version, ConnectionStates).
+
%%====================================================================
%% tls_connection_sup API
%%====================================================================
@@ -205,7 +219,7 @@ init({call, From}, {start, Timeout},
Handshake0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0, V2HComp),
- Transport:send(Socket, BinMsg),
+ send(Transport, Socket, BinMsg),
State1 = State0#state{connection_states = ConnectionStates,
negotiated_version = Version, %% Requested version
session =
@@ -410,18 +424,26 @@ handle_common_event(internal, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
ssl_options = Options} = State0) ->
try
{Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0, Options),
- State =
+ State1 =
State0#state{protocol_buffers =
Buffers#protocol_buffers{tls_handshake_buffer = Buf}},
- Events = tls_handshake_events(Packets),
- case StateName of
- connection ->
- ssl_connection:hibernate_after(StateName, State, Events);
- _ ->
- {next_state, StateName, State#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
- end
+ case Packets of
+ [] ->
+ assert_buffer_sanity(Buf, Options),
+ {Record, State} = next_record(State1),
+ next_event(StateName, Record, State);
+ _ ->
+ Events = tls_handshake_events(Packets),
+ case StateName of
+ connection ->
+ ssl_connection:hibernate_after(StateName, State1, Events);
+ _ ->
+ {next_state, StateName,
+ State1#state{unprocessed_handshake_events = unprocessed_events(Events)}, Events}
+ end
+ end
catch throw:#alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
+ ssl_connection:handle_own_alert(Alert, Version, StateName, State0)
end;
%%% TLS record protocol level application data messages
handle_common_event(internal, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State) ->
@@ -450,6 +472,9 @@ handle_common_event(internal, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, Sta
handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
{next_state, StateName, State}.
+send(Transport, Socket, Data) ->
+ tls_socket:send(Transport, Socket, Data).
+
%%--------------------------------------------------------------------
%% gen_statem callbacks
%%--------------------------------------------------------------------
@@ -476,11 +501,11 @@ encode_handshake(Handshake, Version, ConnectionStates0, Hist0, V2HComp) ->
Frag = tls_handshake:encode_handshake(Handshake, Version),
Hist = ssl_handshake:update_handshake_history(Hist0, Frag, V2HComp),
{Encoded, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
{Encoded, ConnectionStates, Hist}.
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
+ tls_record:encode_change_cipher_spec(Version, ConnectionStates).
decode_alerts(Bin) ->
ssl_alert:decode(Bin).
@@ -553,7 +578,7 @@ next_record(#state{protocol_buffers =
next_record(#state{protocol_buffers = #protocol_buffers{tls_packets = [], tls_cipher_texts = []},
socket = Socket,
transport_cb = Transport} = State) ->
- ssl_socket:setopts(Transport, Socket, [{active,once}]),
+ tls_socket:setopts(Transport, Socket, [{active,once}]),
{no_record, State};
next_record(State) ->
{no_record, State}.
@@ -598,8 +623,6 @@ next_event(StateName, Record, State, Actions) ->
{next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
end.
-tls_handshake_events([]) ->
- throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake));
tls_handshake_events(Packets) ->
lists:map(fun(Packet) ->
{next_event, internal, {handshake, Packet}}
@@ -622,8 +645,8 @@ renegotiate(#state{role = server,
Frag = tls_handshake:encode_handshake(HelloRequest, Version),
Hs0 = ssl_handshake:init_handshake_history(),
{BinMsg, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
- Transport:send(Socket, BinMsg),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
State1 = State0#state{connection_states =
ConnectionStates,
tls_handshake_history = Hs0},
@@ -642,7 +665,7 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
%% User closes or recursive call!
close({close, Timeout}, Socket, Transport = gen_tcp, _,_) ->
- ssl_socket:setopts(Transport, Socket, [{active, false}]),
+ tls_socket:setopts(Transport, Socket, [{active, false}]),
Transport:shutdown(Socket, write),
_ = Transport:recv(Socket, 0, Timeout),
ok;
@@ -684,7 +707,7 @@ gen_handshake(GenConnection, StateName, Type, Event,
Result
catch
_:_ ->
- ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ ssl_connection:handle_own_alert(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
malformed_handshake_data),
Version, StateName, State)
end.
@@ -718,3 +741,25 @@ unprocessed_events(Events) ->
%% handshake events left to process before we should
%% process more TLS-records received on the socket.
erlang:length(Events)-1.
+
+
+assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>, #ssl_options{max_handshake_size = Max}) when
+ Length =< Max ->
+ case size(Rest) of
+ N when N < Length ->
+ true;
+ N when N > Length ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ too_big_handshake_data));
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data))
+ end;
+assert_buffer_sanity(Bin, _) ->
+ case size(Bin) of
+ N when N < 3 ->
+ true;
+ _ ->
+ throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ malformed_handshake_data))
+ end.
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 2bd103c18a..2800ee6537 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 5331dd1303..993a1622fe 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,10 +34,9 @@
%% Handling of incoming data
-export([get_tls_records/2, init_connection_states/2]).
-%% Decoding
--export([decode_cipher_text/3]).
-
-%% Encoding
+%% Encoding TLS records
+-export([encode_handshake/3, encode_alert_record/3,
+ encode_change_cipher_spec/2, encode_data/3]).
-export([encode_plain_text/4]).
%% Protocol version handling
@@ -46,6 +45,9 @@
is_higher/2, supported_protocol_versions/0,
is_acceptable_version/1, is_acceptable_version/2]).
+%% Decoding
+-export([decode_cipher_text/3]).
+
-export_type([tls_version/0, tls_atom_version/0]).
-type tls_version() :: ssl_record:ssl_version().
@@ -85,152 +87,61 @@ get_tls_records(Data, <<>>) ->
get_tls_records(Data, Buffer) ->
get_tls_records_aux(list_to_binary([Buffer, Data]), []).
-get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary,
- Rest/binary>>, Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
- get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
-%% Matches an ssl v2 client hello message.
-%% The server must be able to receive such messages, from clients that
-%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
-get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
- Acc) ->
- case Data0 of
- <<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
- Length = Length0-1,
- <<?BYTE(_), Data1:Length/binary>> = Data0,
- Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
- get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- fragment = Data} | Acc]);
- _ ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
-
- end;
-
-get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
- ?UINT16(Length), _/binary>>,
- _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-
-get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
- when Length0 > ?MAX_CIPHER_TEXT_LENGTH ->
- ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version,
+ #{current_write :=
+ #{beast_mitigation := BeastMitigation,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm = BCA}}} =
+ ConnectionStates) ->
+ case iolist_size(Frag) of
+ N when N > ?MAX_PLAIN_TEXT_LENGTH ->
+ Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
+ encode_iolist(?HANDSHAKE, Data, Version, ConnectionStates);
+ _ ->
+ encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates)
+ end.
-get_tls_records_aux(Data, Acc) ->
- case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
- true ->
- {lists:reverse(Acc), Data};
- false ->
- ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
- end.
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ Version, ConnectionStates) ->
+ encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
-encode_plain_text(Type, Version, Data,
- #{current_write :=
- #{sequence_number := Seq,
- compression_state := CompS0,
- security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm = CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- AAD = calc_aad(Type, Version, WriteState1),
- {CipherFragment, WriteState} = ssl_record:cipher_aead(Version, Comp, WriteState1, AAD),
- CipherText = encode_tls_cipher_text(Type, Version, CipherFragment),
- {CipherText, ConnectionStates#{current_write => WriteState#{sequence_number => Seq +1}}};
-
-encode_plain_text(Type, Version, Data,
- #{current_write :=
- #{sequence_number := Seq,
- compression_state := CompS0,
- security_parameters :=
- #security_parameters{compression_algorithm = CompAlg}
- }= WriteState0} = ConnectionStates) ->
- {Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- MacHash = calc_mac_hash(Type, Version, Comp, WriteState1),
- {CipherFragment, WriteState} = ssl_record:cipher(Version, Comp, WriteState1, MacHash),
- CipherText = encode_tls_cipher_text(Type, Version, CipherFragment),
- {CipherText, ConnectionStates#{current_write => WriteState#{sequence_number => Seq +1}}};
-encode_plain_text(_,_,_, CS) ->
- exit({cs, CS}).
+%%--------------------------------------------------------------------
+-spec encode_change_cipher_spec(tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
+%%--------------------------------------------------------------------
+encode_change_cipher_spec(Version, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, ?byte(?CHANGE_CIPHER_SPEC_PROTO), ConnectionStates).
%%--------------------------------------------------------------------
--spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
- {#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
+-spec encode_data(binary(), tls_version(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
%%
-%% Description: Decode cipher text
+%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
- #{current_read :=
- #{compression_state := CompressionS0,
- sequence_number := Seq,
- security_parameters :=
- #security_parameters{
- cipher_type = ?AEAD,
- compression_algorithm = CompAlg}
- } = ReadState0} = ConnnectionStates0, _) ->
- AAD = calc_aad(Type, Version, ReadState0),
- case ssl_record:decipher_aead(Version, CipherFragment, ReadState0, AAD) of
- {PlainFragment, ReadState1} ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
- current_read => ReadState1#{sequence_number => Seq + 1,
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- #alert{} = Alert ->
- Alert
- end;
+encode_data(Frag, Version,
+ #{current_write := #{beast_mitigation := BeastMitigation,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm = BCA}}} =
+ ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version, BCA, BeastMitigation),
+ encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
+
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
- fragment = CipherFragment} = CipherText,
- #{current_read :=
- #{compression_state := CompressionS0,
- sequence_number := Seq,
- security_parameters :=
- #security_parameters{compression_algorithm = CompAlg}
- } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
- case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
- {PlainFragment, Mac, ReadState1} ->
- MacHash = calc_mac_hash(Type, Version, PlainFragment, ReadState1),
- case ssl_record:is_correct_mac(Mac, MacHash) of
- true ->
- {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
- PlainFragment, CompressionS0),
- ConnnectionStates = ConnnectionStates0#{
- current_read => ReadState1#{
- sequence_number => Seq + 1,
- compression_state => CompressionS1}},
- {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end;
- #alert{} = Alert ->
- Alert
- end.
%%--------------------------------------------------------------------
-spec protocol_version(tls_atom_version() | tls_version()) ->
tls_version() | tls_atom_version().
@@ -401,6 +312,70 @@ initial_connection_state(ConnectionEnd, BeastMitigation) ->
server_verify_data => undefined
}.
+get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>>,
+ Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length),
+ Data:Length/binary, Rest/binary>>, Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary,
+ Rest/binary>>, Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>>,
+ Acc) ->
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+%% Matches an ssl v2 client hello message.
+%% The server must be able to receive such messages, from clients that
+%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
+get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
+ Acc) ->
+ case Data0 of
+ <<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
+ Length = Length0-1,
+ <<?BYTE(_), Data1:Length/binary>> = Data0,
+ Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
+ get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
+ version = {MajVer, MinVer},
+ fragment = Data} | Acc]);
+ _ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
+
+ end;
+
+get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
+ ?UINT16(Length), _/binary>>,
+ _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
+ ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+
+get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
+ when Length0 > ?MAX_CIPHER_TEXT_LENGTH ->
+ ?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
+
+get_tls_records_aux(Data, Acc) ->
+ case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
+ true ->
+ {lists:reverse(Acc), Data};
+ false ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE)
+ end.
+
+encode_plain_text(Type, Version, Data, #{current_write := Write0} = ConnectionStates) ->
+ {CipherFragment, Write1} = ssl_record:encode_plain_text(Type, Version, Data, Write0),
+ {CipherText, Write} = encode_tls_cipher_text(Type, Version, CipherFragment, Write1),
+ {CipherText, ConnectionStates#{current_write => Write}}.
+
lowest_list_protocol_version(Ver, []) ->
Ver;
lowest_list_protocol_version(Ver1, [Ver2 | Rest]) ->
@@ -411,20 +386,10 @@ highest_list_protocol_version(Ver, []) ->
highest_list_protocol_version(Ver1, [Ver2 | Rest]) ->
highest_list_protocol_version(highest_protocol_version(Ver1, Ver2), Rest).
-encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) ->
+encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment, #{sequence_number := Seq} = Write) ->
Length = erlang:iolist_size(Fragment),
- [<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment].
-
-
-mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
- _Length, _Fragment) ->
- <<>>;
-mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
-mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
- when N =:= 1; N =:= 2; N =:= 3 ->
- tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
- Length, Fragment).
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment],
+ Write#{sequence_number => Seq +1}}.
highest_protocol_version() ->
highest_protocol_version(supported_protocol_versions()).
@@ -432,21 +397,96 @@ highest_protocol_version() ->
lowest_protocol_version() ->
lowest_protocol_version(supported_protocol_versions()).
-
sufficient_tlsv1_2_crypto_support() ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
-calc_mac_hash(Type, Version,
- PlainFragment, #{sequence_number := SeqNo,
- mac_secret := MacSecret,
- security_parameters:=
- SecPars}) ->
- Length = erlang:iolist_size(PlainFragment),
- mac_hash(Version, SecPars#security_parameters.mac_algorithm,
- MacSecret, SeqNo, Type,
- Length, PlainFragment).
-
-calc_aad(Type, {MajVer, MinVer},
- #{sequence_number := SeqNo}) ->
- <<SeqNo:64/integer, ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
+encode_iolist(Type, Data, Version, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} =
+ encode_plain_text(Type, Version, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
+%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast, RC4 chiphers are
+%% not vulnerable to this attack.
+split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version, BCA, one_n_minus_one) when
+ BCA =/= ?RC4 andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ do_split_bin(Rest, ChunkSize, [[FirstByte]]);
+%% 0/n splitting countermeasure for clients that are incompatible with 1/n-1
+%% splitting.
+split_bin(Bin, ChunkSize, Version, BCA, zero_n) when
+ BCA =/= ?RC4 andalso ({3, 1} == Version orelse
+ {3, 0} == Version) ->
+ do_split_bin(Bin, ChunkSize, [[<<>>]]);
+split_bin(Bin, ChunkSize, _, _, _) ->
+ do_split_bin(Bin, ChunkSize, []).
+
+do_split_bin(<<>>, _, Acc) ->
+ lists:reverse(Acc);
+do_split_bin(Bin, ChunkSize, Acc) ->
+ case Bin of
+ <<Chunk:ChunkSize/binary, Rest/binary>> ->
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ _ ->
+ lists:reverse(Acc, [Bin])
+ end.
+
+%%--------------------------------------------------------------------
+-spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
+ {#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
+%%
+%% Description: Decode cipher text
+%%--------------------------------------------------------------------
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ fragment = CipherFragment} = CipherText,
+ #{current_read :=
+ #{compression_state := CompressionS0,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ compression_algorithm = CompAlg}
+ } = ReadState0} = ConnnectionStates0, _) ->
+ AAD = ssl_cipher:calc_aad(Type, Version, ReadState0),
+ case ssl_record:decipher_aead(Version, CipherFragment, ReadState0, AAD) of
+ {PlainFragment, ReadState1} ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ConnnectionStates = ConnnectionStates0#{
+ current_read => ReadState1#{sequence_number => Seq + 1,
+ compression_state => CompressionS1}},
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ #alert{} = Alert ->
+ Alert
+ end;
+
+decode_cipher_text(#ssl_tls{type = Type, version = Version,
+ fragment = CipherFragment} = CipherText,
+ #{current_read :=
+ #{compression_state := CompressionS0,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{compression_algorithm = CompAlg}
+ } = ReadState0} = ConnnectionStates0, PaddingCheck) ->
+ case ssl_record:decipher(Version, CipherFragment, ReadState0, PaddingCheck) of
+ {PlainFragment, Mac, ReadState1} ->
+ MacHash = ssl_cipher:calc_mac_hash(Type, Version, PlainFragment, ReadState1),
+ case ssl_record:is_correct_mac(Mac, MacHash) of
+ true ->
+ {Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
+ PlainFragment, CompressionS0),
+ ConnnectionStates = ConnnectionStates0#{
+ current_read => ReadState1#{
+ sequence_number => Seq + 1,
+ compression_state => CompressionS1}},
+ {CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+ #alert{} = Alert ->
+ Alert
+ end.
diff --git a/lib/ssl/src/ssl_socket.erl b/lib/ssl/src/tls_socket.erl
index b2aea2ba9c..e76d9c100a 100644
--- a/lib/ssl/src/ssl_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -17,16 +17,19 @@
%%
%% %CopyrightEnd%
%%
--module(ssl_socket).
+-module(tls_socket).
-behaviour(gen_server).
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([socket/5, setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]).
+-export([send/3, listen/3, accept/3, socket/5, connect/4, upgrade/3,
+ setopts/3, getopts/3, getstat/3, peername/2, sockname/2, port/2]).
+-export([split_options/1, get_socket_opts/3]).
-export([emulated_options/0, internal_inet_values/0, default_inet_values/0,
- init/1, start_link/3, terminate/2, inherit_tracker/3, get_emulated_opts/1,
+ init/1, start_link/3, terminate/2, inherit_tracker/3,
+ emulated_socket_options/2, get_emulated_opts/1,
set_emulated_opts/2, get_all_opts/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3]).
@@ -39,6 +42,76 @@
%%--------------------------------------------------------------------
%%% Internal API
%%--------------------------------------------------------------------
+send(Transport, Socket, Data) ->
+ Transport:send(Socket, Data).
+
+listen(Transport, Port, #config{transport_info = {Transport, _, _, _},
+ inet_user = Options,
+ ssl = SslOpts, emulated = EmOpts} = Config) ->
+ case Transport:listen(Port, Options ++ internal_inet_values()) of
+ {ok, ListenSocket} ->
+ {ok, Tracker} = inherit_tracker(ListenSocket, EmOpts, SslOpts),
+ {ok, #sslsocket{pid = {ListenSocket, Config#config{emulated = Tracker}}}};
+ Err = {error, _} ->
+ Err
+ end.
+
+accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
+ connection_cb = ConnectionCb,
+ ssl = SslOpts,
+ emulated = Tracker}, Timeout) ->
+ case Transport:accept(ListenSocket, Timeout) of
+ {ok, Socket} ->
+ {ok, EmOpts} = get_emulated_opts(Tracker),
+ {ok, Port} = tls_socket:port(Transport, Socket),
+ ConnArgs = [server, "localhost", Port, Socket,
+ {SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
+ case tls_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+upgrade(Socket, #config{transport_info = {Transport,_,_,_}= CbInfo,
+ ssl = SslOptions,
+ emulated = EmOpts, connection_cb = ConnectionCb}, Timeout) ->
+ ok = setopts(Transport, Socket, tls_socket:internal_inet_values()),
+ case peername(Transport, Socket) of
+ {ok, {Address, Port}} ->
+ ssl_connection:connect(ConnectionCb, Address, Port, Socket,
+ {SslOptions,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, Error} ->
+ {error, Error}
+ end.
+
+connect(Address, Port,
+ #config{transport_info = CbInfo, inet_user = UserOpts, ssl = SslOpts,
+ emulated = EmOpts, inet_ssl = SocketOpts, connection_cb = ConnetionCb},
+ Timeout) ->
+ {Transport, _, _, _} = CbInfo,
+ try Transport:connect(Address, Port, SocketOpts, Timeout) of
+ {ok, Socket} ->
+ ssl_connection:connect(ConnetionCb, Address, Port, Socket,
+ {SslOpts,
+ emulated_socket_options(EmOpts, #socket_options{}), undefined},
+ self(), CbInfo, Timeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ exit:{function_clause, _} ->
+ {error, {options, {cb_info, CbInfo}}};
+ exit:badarg ->
+ {error, {options, {socket_options, UserOpts}}};
+ exit:{badarg, _} ->
+ {error, {options, {socket_options, UserOpts}}}
+ end.
+
socket(Pid, Transport, Socket, ConnectionCb, Tracker) ->
#sslsocket{pid = Pid,
%% "The name "fd" is keept for backwards compatibility
@@ -241,3 +314,17 @@ get_emulated_opts(TrackerPid, EmOptNames) ->
lists:map(fun(Name) -> {value, Value} = lists:keysearch(Name, 1, EmOpts),
Value end,
EmOptNames).
+
+emulated_socket_options(InetValues, #socket_options{
+ mode = Mode,
+ header = Header,
+ active = Active,
+ packet = Packet,
+ packet_size = Size}) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, Mode),
+ header = proplists:get_value(header, InetValues, Header),
+ active = proplists:get_value(active, InetValues, Active),
+ packet = proplists:get_value(packet, InetValues, Packet),
+ packet_size = proplists:get_value(packet_size, InetValues, Size)
+ }.
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 009bcd81ad..d85be6c69e 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index 76999185b6..f779765b18 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -387,6 +387,7 @@ basic_test(ClientCert, ClientKey, ClientCA, ServerCert, ServerKey, ServerCA, Con
check_result(Server, SType, Client, CType),
close(Server, Client).
+
ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
CCA = proplists:get_value(cacertfile, COpts),
CCert = proplists:get_value(certfile, COpts),
@@ -411,8 +412,10 @@ ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
Error = {error, {tls_alert, "insufficient security"}},
ssl_test_lib:check_result(Server, Error, Client, Error).
-start_client(openssl, Port, PeerCA, OwnCa, Cert, Key, _Config) ->
- CA = new_openssl_ca("openssl_client_ca", PeerCA, OwnCa),
+
+start_client(openssl, Port, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_openssl_ca(filename:join(PrivDir, "openssl_client_ca.pem"), PeerCA, OwnCa),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Exe = "openssl",
Args = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
@@ -424,7 +427,8 @@ start_client(openssl, Port, PeerCA, OwnCa, Cert, Key, _Config) ->
true = port_command(OpenSslPort, "Hello world"),
OpenSslPort;
start_client(erlang, Port, PeerCA, OwnCa, Cert, Key, Config) ->
- CA = new_ca("erlang_client_ca", PeerCA, OwnCa),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir,"erlang_client_ca.pem"), PeerCA, OwnCa),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -434,6 +438,7 @@ start_client(erlang, Port, PeerCA, OwnCa, Cert, Key, Config) ->
{cacertfile, CA},
{certfile, Cert}, {keyfile, Key}]}]).
+
start_client_ecc(erlang, Port, PeerCA, OwnCa, Cert, Key, Expect, ECCOpts, Config) ->
CA = new_ca("erlang_client_ca", PeerCA, OwnCa),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -459,8 +464,10 @@ start_client_ecc_error(erlang, Port, PeerCA, OwnCa, Cert, Key, ECCOpts, Config)
{cacertfile, CA},
{certfile, Cert}, {keyfile, Key}]}]).
-start_server(openssl, PeerCA, OwnCa, Cert, Key, _Config) ->
- CA = new_openssl_ca("openssl_server_ca", PeerCA, OwnCa),
+
+start_server(openssl, PeerCA, OwnCa, Cert, Key, Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_openssl_ca(filename:join(PrivDir,"openssl_server_ca.pem"), PeerCA, OwnCa),
Port = ssl_test_lib:inet_port(node()),
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Exe = "openssl",
@@ -471,7 +478,8 @@ start_server(openssl, PeerCA, OwnCa, Cert, Key, _Config) ->
true = port_command(OpenSslPort, "Hello world"),
{OpenSslPort, Port};
start_server(erlang, PeerCA, OwnCa, Cert, Key, Config) ->
- CA = new_ca("erlang_server_ca", PeerCA, OwnCa),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir,"erlang_server_ca.pem"), PeerCA, OwnCa),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -484,16 +492,17 @@ start_server(erlang, PeerCA, OwnCa, Cert, Key, Config) ->
{Server, ssl_test_lib:inet_port(Server)}.
start_server_with_raw_key(erlang, PeerCA, OwnCa, Cert, Key, Config) ->
- CA = new_ca("erlang_server_ca", PeerCA, OwnCa),
+ PrivDir = proplists:get_value(priv_dir, Config),
+ CA = new_ca(filename:join(PrivDir, "erlang_server_ca.pem"), PeerCA, OwnCa),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active,
- []}},
- {options,
- [{verify, verify_peer}, {cacertfile, CA},
- {certfile, Cert}, {key, Key}]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ send_recv_result_active,
+ []}},
+ {options,
+ [{verify, verify_peer}, {cacertfile, CA},
+ {certfile, Cert}, {key, Key}]}]),
{Server, ssl_test_lib:inet_port(Server)}.
start_server_ecc(erlang, PeerCA, OwnCa, Cert, Key, Expect, ECCOpts, Config) ->
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index 9d57e89b9b..158b3524ac 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 392da738ec..de5895d7ba 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -52,7 +52,7 @@ all() ->
{group, options},
{group, options_tls},
{group, session},
- %%{group, 'dtlsv1.2'},
+ {group, 'dtlsv1.2'},
%%{group, 'dtlsv1'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
@@ -66,6 +66,7 @@ groups() ->
{options, [], options_tests()},
{options_tls, [], options_tests_tls()},
%%{'dtlsv1.2', [], all_versions_groups()},
+ {'dtlsv1.2', [], [connection_information]},
%%{'dtlsv1', [], all_versions_groups()},
{'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]},
{'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()},
@@ -135,7 +136,8 @@ options_tests() ->
honor_server_cipher_order,
honor_client_cipher_order,
unordered_protocol_versions_server,
- unordered_protocol_versions_client
+ unordered_protocol_versions_client,
+ max_handshake_size
].
options_tests_tls() ->
@@ -3859,6 +3861,29 @@ unordered_protocol_versions_client(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
+max_handshake_size() ->
+ [{doc,"Test that we can set max_handshake_size to max value."}].
+
+max_handshake_size(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+%%--------------------------------------------------------------------
server_name_indication_option() ->
[{doc,"Test API server_name_indication option to connect."}].
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 51f0651568..74b14145dd 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 02c98fc40f..f10d27fbc6 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 28637fc32d..9862b3ce64 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_upgrade_SUITE.erl b/lib/ssl/test/ssl_upgrade_SUITE.erl
index f6af1e6182..875399db76 100644
--- a/lib/ssl/test/ssl_upgrade_SUITE.erl
+++ b/lib/ssl/test/ssl_upgrade_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 59732c7926..2cdb825d75 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.0.3
+SSL_VSN = 8.1
diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml
index e2dfc2ab9b..cb91b1f126 100644
--- a/lib/stdlib/doc/src/assert_hrl.xml
+++ b/lib/stdlib/doc/src/assert_hrl.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>2012</year><year>2015</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index d677dd6f83..7bfe477a11 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml
index 9a49d66820..790d4b8bf1 100644
--- a/lib/stdlib/doc/src/gb_trees.xml
+++ b/lib/stdlib/doc/src/gb_trees.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/introduction.xml b/lib/stdlib/doc/src/introduction.xml
index 5bf545c65f..642ca02430 100644
--- a/lib/stdlib/doc/src/introduction.xml
+++ b/lib/stdlib/doc/src/introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>1999</year>
- <year>2013</year>
+ <year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 554150380f..0143686bb2 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,48 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When a simple_one_for_one supervisor is shutting down,
+ and a child exits with an exit reason of the form
+ {shutdown, Term}, an error report was earlier printed.
+ This is now corrected.</p>
+ <p>
+ Own Id: OTP-13907 Aux Id: PR-1158, ERL-163 </p>
+ </item>
+ <item>
+ <p> Allow empty list as parameter of the fun used with
+ <c>dbg:fun2ms/1</c>. </p>
+ <p>
+ Own Id: OTP-13974</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The new behaviour gen_statem has been improved with 3 new
+ features: the possibility to use old style non-proxy
+ timeouts for gen_statem:call/2,3, state entry code, and
+ state timeouts. These are backwards compatible. Minor
+ code and documentation improvements has been performed
+ including a borderline semantics correction of timeout
+ zero handling.</p>
+ <p>
+ Own Id: OTP-13929 Aux Id: PR-1170, ERL-284 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml
index 076b06fc38..d048983c61 100644
--- a/lib/stdlib/doc/src/orddict.xml
+++ b/lib/stdlib/doc/src/orddict.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2015</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml
index 1dcc3de000..eb7870e367 100644
--- a/lib/stdlib/doc/src/rand.xml
+++ b/lib/stdlib/doc/src/rand.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year>
+ <year>2015</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index f7668af1ed..44dc104645 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2015</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 1120b926d5..9091a46df9 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2014</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 40a34aa30f..eafee346eb 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1306,6 +1306,7 @@ partial_eval(Expr) ->
ev_expr({op,_,Op,L,R}) -> erlang:Op(ev_expr(L), ev_expr(R));
ev_expr({op,_,Op,A}) -> erlang:Op(ev_expr(A));
ev_expr({integer,_,X}) -> X;
+ev_expr({char,_,X}) -> X;
ev_expr({float,_,X}) -> X;
ev_expr({atom,_,X}) -> X;
ev_expr({tuple,_,Es}) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 85b2816451..d2dd2848b5 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -156,6 +156,7 @@ type -> '#' atom '{' field_types '}' : {type, ?anno('$1'),
record, ['$2'|'$4']}.
type -> binary_type : '$1'.
type -> integer : '$1'.
+type -> char : '$1'.
type -> 'fun' '(' ')' : {type, ?anno('$1'), 'fun', []}.
type -> 'fun' '(' fun_type_100 ')' : '$3'.
@@ -612,11 +613,11 @@ Erlang code.
| af_bin(abstract_expr())
| af_binary_op(abstract_expr())
| af_unary_op(abstract_expr())
- | af_record_access(abstract_expr())
+ | af_record_creation(abstract_expr())
| af_record_update(abstract_expr())
| af_record_index()
| af_record_field_access(abstract_expr())
- | af_map_access(abstract_expr())
+ | af_map_creation(abstract_expr())
| af_map_update(abstract_expr())
| af_catch()
| af_local_call()
@@ -720,26 +721,25 @@ Erlang code.
| af_bin(af_guard_test())
| af_binary_op(af_guard_test())
| af_unary_op(af_guard_test())
- | af_record_access(af_guard_test())
+ | af_record_creation(af_guard_test())
| af_record_index()
| af_record_field_access(af_guard_test())
- | af_map_access(abstract_expr()) % FIXME
- | af_map_update(abstract_expr()) % FIXME
+ | af_map_creation(abstract_expr())
+ | af_map_update(abstract_expr())
| af_guard_call()
| af_remote_guard_call().
-type af_record_field_access(T) ::
{'record_field', anno(), T, record_name(), af_field_name()}.
--type af_map_access(T) :: {'map', anno(), [af_map_field(T)]}.
-
--type af_map_update(T) :: {'map', anno(), T, [af_map_field(T)]}.
+-type af_map_creation(T) :: {'map', anno(), [af_assoc(T)]}.
--type af_map_field(T) :: af_map_field_assoc(T) | af_map_field_exact(T).
+-type af_map_update(T) :: {'map', anno(), T, [af_assoc(T)]}.
--type af_map_field_assoc(T) :: {'map_field_assoc', anno(), T, T}.
+-type af_assoc(T) :: {'map_field_assoc', anno(), T, T}
+ | af_assoc_exact(T).
--type af_map_field_exact(T) :: {'map_field_exact', anno(), T, T}.
+-type af_assoc_exact(T) :: {'map_field_exact', anno(), T, T}.
-type af_guard_call() :: {'call', anno(), function_name(), [af_guard_test()]}.
@@ -757,20 +757,20 @@ Erlang code.
| af_bin(af_pattern())
| af_binary_op(af_pattern())
| af_unary_op(af_pattern())
- | af_record_access(af_pattern())
+ | af_record_creation(af_pattern())
| af_record_index()
| af_map_pattern().
-type af_record_index() ::
{'record_index', anno(), record_name(), af_field_name()}.
--type af_record_access(T) ::
+-type af_record_creation(T) ::
{'record', anno(), record_name(), [af_record_field(T)]}.
-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}.
-type af_map_pattern() ::
- {'map', anno(), [af_map_field_exact(abstract_expr)]}. % FIXME?
+ {'map', anno(), [af_assoc_exact(abstract_expr)]}.
-type abstract_type() :: af_annotated_type()
| af_atom()
@@ -807,9 +807,9 @@ Erlang code.
{'type', anno(), 'range', [af_singleton_integer_type()]}.
-type af_map_type() :: {'type', anno(), 'map', 'any'}
- | {'type', anno(), 'map', [af_map_pair_type()]}.
+ | {'type', anno(), 'map', [af_assoc_type()]}.
--type af_map_pair_type() ::
+-type af_assoc_type() ::
{'type', anno(), 'map_field_assoc', [abstract_type()]}
| {'type', anno(), 'map_field_exact', [abstract_type()]}.
@@ -1558,13 +1558,17 @@ new_anno(Term) ->
Abstr :: erl_parse_tree().
anno_to_term(Abstract) ->
- map_anno(fun erl_anno:to_term/1, Abstract).
+ F = fun(Anno, Acc) -> {erl_anno:to_term(Anno), Acc} end,
+ {NewAbstract, []} = modify_anno1(Abstract, [], F),
+ NewAbstract.
-spec anno_from_term(Term) -> erl_parse_tree() when
Term :: term().
anno_from_term(Term) ->
- map_anno(fun erl_anno:from_term/1, Term).
+ F = fun(T, Acc) -> {erl_anno:from_term(T), Acc} end,
+ {NewTerm, []} = modify_anno1(Term, [], F),
+ NewTerm.
%% Forms.
%% Recognize what sys_pre_expand does:
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index f53b0e2246..c42ae981e7 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -481,46 +481,49 @@ find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, Sections) ->
%% Look for special comment on second line
Line2 = get_line(Fd),
{ok, HeaderSz2} = file:position(Fd, cur),
- case classify_line(Line2) of
- emu_args ->
- %% Skip special comment on second line
- Line3 = get_line(Fd),
- {HeaderSz2, LineNo + 2, Fd,
- Sections#sections{type = guess_type(Line3),
- comment = undefined,
- emu_args = Line2}};
- Line2Type ->
- %% Look for special comment on third line
- Line3 = get_line(Fd),
- {ok, HeaderSz3} = file:position(Fd, cur),
- Line3Type = classify_line(Line3),
- if
- Line3Type =:= emu_args ->
- %% Skip special comment on third line
- Line4 = get_line(Fd),
- {HeaderSz3, LineNo + 3, Fd,
- Sections#sections{type = guess_type(Line4),
- comment = Line2,
- emu_args = Line3}};
- Sections#sections.shebang =:= undefined,
- KeepFirst =:= true ->
- %% No shebang. Use the entire file
- {HeaderSz0, LineNo, Fd,
- Sections#sections{type = guess_type(Line2)}};
- Sections#sections.shebang =:= undefined ->
- %% No shebang. Skip the first line
- {HeaderSz1, LineNo, Fd,
- Sections#sections{type = guess_type(Line2)}};
- Line2Type =:= comment ->
- %% Skip shebang on first line and comment on second
- {HeaderSz2, LineNo + 2, Fd,
- Sections#sections{type = guess_type(Line3),
- comment = Line2}};
- true ->
- %% Just skip shebang on first line
- {HeaderSz1, LineNo + 1, Fd,
- Sections#sections{type = guess_type(Line2)}}
- end
+ if
+ Sections#sections.shebang =:= undefined,
+ KeepFirst =:= true ->
+ %% No shebang. Use the entire file
+ {HeaderSz0, LineNo, Fd,
+ Sections#sections{type = guess_type(Line2)}};
+ Sections#sections.shebang =:= undefined ->
+ %% No shebang. Skip the first line
+ {HeaderSz1, LineNo, Fd,
+ Sections#sections{type = guess_type(Line2)}};
+ true ->
+ case classify_line(Line2) of
+ emu_args ->
+ %% Skip special comment on second line
+ Line3 = get_line(Fd),
+ {HeaderSz2, LineNo + 2, Fd,
+ Sections#sections{type = guess_type(Line3),
+ comment = undefined,
+ emu_args = Line2}};
+ comment ->
+ %% Look for special comment on third line
+ Line3 = get_line(Fd),
+ {ok, HeaderSz3} = file:position(Fd, cur),
+ Line3Type = classify_line(Line3),
+ if
+ Line3Type =:= emu_args ->
+ %% Skip special comment on third line
+ Line4 = get_line(Fd),
+ {HeaderSz3, LineNo + 3, Fd,
+ Sections#sections{type = guess_type(Line4),
+ comment = Line2,
+ emu_args = Line3}};
+ true ->
+ %% Skip shebang on first line and comment on second
+ {HeaderSz2, LineNo + 2, Fd,
+ Sections#sections{type = guess_type(Line3),
+ comment = Line2}}
+ end;
+ _ ->
+ %% Just skip shebang on first line
+ {HeaderSz1, LineNo + 1, Fd,
+ Sections#sections{type = guess_type(Line2)}}
+ end
end.
classify_line(Line) ->
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
index 28d69232a0..0b9106a99c 100644
--- a/lib/stdlib/test/escript_SUITE.erl
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -28,6 +28,7 @@
strange_name/1,
emulator_flags/1,
emulator_flags_no_shebang/1,
+ two_lines/1,
module_script/1,
beam_script/1,
archive_script/1,
@@ -49,7 +50,7 @@ suite() ->
all() ->
[basic, errors, strange_name, emulator_flags,
- emulator_flags_no_shebang,
+ emulator_flags_no_shebang, two_lines,
module_script, beam_script, archive_script, epp,
create_and_extract, foldl, overflow,
archive_script_file_access, unicode].
@@ -153,6 +154,18 @@ emulator_flags(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+two_lines(Config) when is_list(Config) ->
+ Data = proplists:get_value(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ run(Dir, "two_lines -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
emulator_flags_no_shebang(Config) when is_list(Config) ->
Data = proplists:get_value(data_dir, Config),
Dir = filename:absname(Data), %Get rid of trailing slash.
diff --git a/lib/stdlib/test/escript_SUITE_data/two_lines b/lib/stdlib/test/escript_SUITE_data/two_lines
new file mode 100755
index 0000000000..cf4e99639c
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/two_lines
@@ -0,0 +1,2 @@
+#! /usr/bin/env escript
+main(MainArgs) -> io:format("main:~p\n", [MainArgs]), ErlArgs = init:get_arguments(), io:format("ERL_FLAGS=~p\n", [os:getenv("ERL_FLAGS")]), io:format("unknown:~p\n",[[E || E <- ErlArgs, element(1, E) =:= unknown]]).
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index c409a6949b..80585ca359 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2325,7 +2325,7 @@ otp_6554(Config) when is_list(Config) ->
"[unproper | list]).">>),
%% Cheating:
"exception error: no function clause matching "
- "erl_eval:do_apply(4)" ++ _ =
+ "shell:apply_fun(4)" ++ _ =
comm_err(<<"erlang:error(function_clause, [4]).">>),
"exception error: no function clause matching "
"lists:reverse(" ++ _ =
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 64dd41e75a..6f3979bb77 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -720,20 +720,25 @@ memory(Config) when is_list(Config) ->
%% Test filenames with characters outside the US ASCII range.
unicode(Config) when is_list(Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- do_unicode(PrivDir),
+ run_unicode_node(Config, "+fnu"),
case has_transparent_naming() of
true ->
- Pa = filename:dirname(code:which(?MODULE)),
- Node = start_node(unicode, "+fnl -pa "++Pa),
- ok = rpc:call(Node, erlang, apply,
- [fun() -> do_unicode(PrivDir) end,[]]),
- true = test_server:stop_node(Node),
- ok;
+ run_unicode_node(Config, "+fnl");
false ->
ok
end.
+run_unicode_node(Config, Option) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Pa = filename:dirname(code:which(?MODULE)),
+ Args = Option ++ " -pa "++Pa,
+ io:format("~s\n", [Args]),
+ Node = start_node(unicode, Args),
+ ok = rpc:call(Node, erlang, apply,
+ [fun() -> do_unicode(PrivDir) end,[]]),
+ true = test_server:stop_node(Node),
+ ok.
+
has_transparent_naming() ->
case os:type() of
{unix,darwin} -> false;
@@ -745,10 +750,11 @@ do_unicode(PrivDir) ->
ok = file:set_cwd(PrivDir),
ok = file:make_dir("unicöde"),
- Names = unicode_create_files(),
+ Names = lists:sort(unicode_create_files()),
Tar = "unicöde.tar",
ok = erl_tar:create(Tar, ["unicöde"], []),
- {ok,Names} = erl_tar:table(Tar, []),
+ {ok,Names0} = erl_tar:table(Tar, []),
+ Names = lists:sort(Names0),
_ = [ok = file:delete(Name) || Name <- Names],
ok = erl_tar:extract(Tar),
_ = [{ok,_} = file:read_file(Name) || Name <- Names],
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index c74343d9ca..e67cb9b08d 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.1
+STDLIB_VSN = 3.2
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index 82c4484d96..e8de0ffce2 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 2.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The address to the FSF in the license header has been
+ updated.</p>
+ <p>
+ Own Id: OTP-14084</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 39c522fd11..43e42d8195 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2001-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl
index b5ac564146..8d0e2a10a3 100644
--- a/lib/syntax_tools/src/erl_comment_scan.erl
+++ b/lib/syntax_tools/src/erl_comment_scan.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% =====================================================================
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index df0d78031c..6c812aaa6c 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_recomment.erl b/lib/syntax_tools/src/erl_recomment.erl
index 1d23034991..a774b898e8 100644
--- a/lib/syntax_tools/src/erl_recomment.erl
+++ b/lib/syntax_tools/src/erl_recomment.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index ee42e56172..b856a5d1dd 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index 5aecf5d774..aae6755639 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1997-2006 Richard Carlsson
diff --git a/lib/syntax_tools/src/erl_tidy.erl b/lib/syntax_tools/src/erl_tidy.erl
index 9e273dfb84..2e0ee209f8 100644
--- a/lib/syntax_tools/src/erl_tidy.erl
+++ b/lib/syntax_tools/src/erl_tidy.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1999-2014 Richard Carlsson
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 943250e5cd..4d18f7abcf 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 1998-2014 Richard Carlsson
diff --git a/lib/syntax_tools/src/prettypr.erl b/lib/syntax_tools/src/prettypr.erl
index 1b5ba6b05a..5156af667b 100644
--- a/lib/syntax_tools/src/prettypr.erl
+++ b/lib/syntax_tools/src/prettypr.erl
@@ -11,7 +11,7 @@
%%
%% You should have received a copy of the GNU Lesser General Public
%% License along with this library; if not, write to the Free Software
-%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
%% USA
%%
%% @copyright 2000-2006 Richard Carlsson
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index c0ca083c38..c5e363112b 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 2.1
+SYNTAX_TOOLS_VSN = 2.1.1
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 2d9bee0dd1..415f1b8516 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -31,6 +31,42 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix unhandled trace event send_to_non_existing_process in
+ fprof.</p>
+ <p>
+ Own Id: OTP-13998</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved edoc support in emacs erlang-mode.</p>
+ <p>
+ Own Id: OTP-13945 Aux Id: PR-1157 </p>
+ </item>
+ <item>
+ <p>
+ Added erldoc to emacs mode which opens html documentation
+ in browser from emacs. For example <c>M-x erldoc-browse
+ RET lists:foreach/2</c>.</p>
+ <p>
+ Own Id: OTP-14018 Aux Id: PR-1197 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.8.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/emacs/erlang-edoc.el b/lib/tools/emacs/erlang-edoc.el
index 034036ad04..2801aa8ae7 100644
--- a/lib/tools/emacs/erlang-edoc.el
+++ b/lib/tools/emacs/erlang-edoc.el
@@ -78,7 +78,7 @@
'(("^%+\\s-*\\(@\\w+\\)\\_>" 1 'erlang-edoc-tag prepend)
("^%+\\s-*" ("{\\(@\\w+\\)\\_>" nil nil (1 'erlang-edoc-macro prepend)))
("^%+\\s-*" ("\\(?:@@\\)*\\(@[@{}]\\)" nil nil (1 'escape-glyph prepend)))
- ("^%+\\s-*@\\(deprecated\\)\\_>" 1 font-lock-warning-face prepend)
+ ("^%+\\s-*\\(@deprecated\\)\\_>" 1 font-lock-warning-face prepend)
;; http://www.erlang.org/doc/apps/edoc/chapter.html#Wiki_notation
("^%+\\s-*" ("[^`]`\\([^`]?\\|[^`].*?[^']\\)'"
(forward-char -1) nil (1 'erlang-edoc-verbatim prepend)))
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 40f0bb7f80..39c6065ce4 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -479,6 +479,11 @@ To activate the workaround, place the following in your `~/.emacs' file:
"*Indentation of Erlang calls/clauses within blocks.")
(put 'erlang-indent-level 'safe-local-variable 'integerp)
+(defvar erlang-icr-indent nil
+ "*Indentation of Erlang if/case/receive/ patterns. `nil' means
+ keeping default behavior. When non-nil, indent to th column of
+ if/case/receive.")
+
(defvar erlang-indent-guard 2
"*Indentation of Erlang guards.")
(put 'erlang-indent-guard 'safe-local-variable 'integerp)
@@ -2919,14 +2924,16 @@ Return nil if inside string, t if in a comment."
(t
(save-excursion
(goto-char (nth 1 stack-top))
- (if (looking-at "case[^_a-zA-Z0-9]")
- (+ (nth 2 stack-top) erlang-indent-level)
- (skip-chars-forward "a-z")
- (skip-chars-forward " \t")
- (if (memq (following-char) '(?% ?\n))
+ (if (and erlang-icr-indent
+ (looking-at "\\(if\\|case\\|receive\\)[^_a-zA-Z0-9]"))
+ (+ (nth 2 stack-top) erlang-icr-indent)
+ (if (looking-at "\\(case\\|receive\\)[^_a-zA-Z0-9]")
(+ (nth 2 stack-top) erlang-indent-level)
- (current-column))))))
- )
+ (skip-chars-forward "a-z")
+ (skip-chars-forward " \t")
+ (if (memq (following-char) '(?% ?\n))
+ (+ (nth 2 stack-top) erlang-indent-level)
+ (current-column))))))))
((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\)[^_a-zA-Z0-9]"))
(nth 2 (car (cdr stack))))
;; Real indentation, where operators create extra indentation etc.
@@ -2948,7 +2955,9 @@ Return nil if inside string, t if in a comment."
;; If in fun definition use standard indent level not double
;;(if (not (eq (car (car (cdr stack))) 'fun))
;; Removed it made multi clause fun's look to bad
- (setq off (* 2 erlang-indent-level)))) ;; )
+ (setq off (+ erlang-indent-level (if (not erlang-icr-indent)
+ erlang-indent-level
+ erlang-icr-indent)))))
(let ((base (erlang-indent-find-base stack indent-point off skip)))
;; Special cases
(goto-char indent-point)
diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl
index b833d96c19..fff67eb0fd 100644
--- a/lib/tools/src/tags.erl
+++ b/lib/tools/src/tags.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index 18166cceb0..4c7dd24006 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index e066dbf5e9..07bc39f76e 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.8.6
+TOOLS_VSN = 2.9
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index 5c82750a21..cd67af41ed 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -143,8 +143,9 @@ extract(#analysis{macros = Macros,
MergedRecords = dialyzer_utils:merge_records(NewRecords, OldRecords),
CodeServer2 = dialyzer_codeserver:set_temp_records(MergedRecords, CodeServer1),
CodeServer3 = dialyzer_codeserver:finalize_exported_types(NewExpTypes, CodeServer2),
- CodeServer4 = dialyzer_utils:process_record_remote_types(CodeServer3),
- dialyzer_contracts:process_contract_remote_types(CodeServer4)
+ {CodeServer4, RecordDict} =
+ dialyzer_utils:process_record_remote_types(CodeServer3),
+ dialyzer_contracts:process_contract_remote_types(CodeServer4, RecordDict)
catch
throw:{error, ErrorMsg} ->
compile_error(ErrorMsg)
@@ -156,7 +157,7 @@ extract(#analysis{macros = Macros,
fun(Module, TmpPlt) ->
{ok, ModuleContracts} = dict:find(Module, Contracts),
SpecList = [{MFA, Contract}
- || {MFA, {_FileLine, Contract}} <- dict:to_list(ModuleContracts)],
+ || {MFA, {_FileLine, Contract}} <- maps:to_list(ModuleContracts)],
dialyzer_plt:insert_contract_list(TmpPlt, SpecList)
end,
NewTrustPLT = lists:foldl(FoldFun, TrustPLT, Modules),
@@ -172,8 +173,10 @@ get_type_info(#analysis{callgraph = CallGraph,
StrippedCallGraph = remove_external(CallGraph, TrustPLT),
%% io:format("--- Analyzing callgraph... "),
try
- NewPlt = dialyzer_succ_typings:analyze_callgraph(StrippedCallGraph,
- TrustPLT, CodeServer),
+ NewMiniPlt = dialyzer_succ_typings:analyze_callgraph(StrippedCallGraph,
+ TrustPLT,
+ CodeServer),
+ NewPlt = dialyzer_plt:restore_full_plt(NewMiniPlt),
Analysis#analysis{callgraph = StrippedCallGraph, trust_plt = NewPlt}
catch
error:What ->
@@ -224,7 +227,7 @@ get_external(Exts, Plt) ->
-type fa() :: {atom(), arity()}.
-type func_info() :: {line(), atom(), arity()}.
--record(info, {records = map__new() :: map_dict(),
+-record(info, {records = maps:new() :: erl_types:type_table(),
functions = [] :: [func_info()],
types = map__new() :: map_dict(),
edoc = false :: boolean()}).
@@ -267,7 +270,7 @@ write_inc_files(Inc) ->
Functions = [Key || {Key, _} <- Val],
Val1 = [{{F,A},Type} || {{_Line,F,A},Type} <- Val],
Info = #info{types = map__from_list(Val1),
- records = map__new(),
+ records = maps:new(),
%% Note we need to sort functions here!
functions = lists:keysort(1, Functions)},
%% io:format("Types ~p\n", [Info#info.types]),
@@ -849,8 +852,9 @@ collect_info(Analysis) ->
TmpCServer1 = dialyzer_codeserver:set_temp_records(MergedRecords, TmpCServer),
TmpCServer2 =
dialyzer_codeserver:finalize_exported_types(MergedExpTypes, TmpCServer1),
- TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
+ {TmpCServer3, RecordDict} =
+ dialyzer_utils:process_record_remote_types(TmpCServer2),
+ dialyzer_contracts:process_contract_remote_types(TmpCServer3, RecordDict)
catch
throw:{error, ErrorMsg} ->
fatal_error(ErrorMsg)
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 54635bdd2e..7e3766a43b 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -354,6 +354,7 @@ handle_arg_opt({single,Opt},P=#arg{type=T}) -> P#arg{type=T#type{single=Opt}};
handle_arg_opt({base,{Opt, Sz}}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt, size=Sz}};
handle_arg_opt({base,Opt}, P=#arg{type=T}) -> P#arg{type=T#type{base=Opt}};
handle_arg_opt({c_only,Opt},P) -> P#arg{where=c, alt=Opt};
+handle_arg_opt(list_binary, P) -> P#arg{alt=list_binary};
handle_arg_opt(string, P=#arg{type=T}) -> P#arg{type=T#type{base=string}};
handle_arg_opt({string,Max,Sz}, P=#arg{type=T}) ->
P#arg{type=T#type{base=string, size={Max,Sz}}}.
@@ -588,7 +589,7 @@ lookup(Name,[_|R],Def) ->
lookup(Name,R,Def);
lookup(_,[], Def) -> Def.
-setup_idx_binary(Name,Ext,_Opts) ->
+setup_idx_binary(Name,Ext, Opts) ->
FuncName = Name ++ Ext,
Func = #func{params=Args} = get(FuncName),
Id = next_id(function),
@@ -607,8 +608,7 @@ setup_idx_binary(Name,Ext,_Opts) ->
ok;
(_) -> ok
end, Args),
-
- case setup_idx_binary(Args, []) of
+ case setup_idx_binary_1(Args, []) of
ignore ->
put(FuncName, Func#func{id=Id}),
Name++Ext;
@@ -624,30 +624,41 @@ setup_idx_binary(Name,Ext,_Opts) ->
[FuncName,Extra]
end.
-setup_idx_binary([A=#arg{in=true,type=T=#type{base=idx_binary}}|R], Acc) ->
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{base=idx_binary}}|R], Acc) ->
A1 = A#arg{type=T#type{base=guard_int,size=4}},
A2 = A#arg{type=T#type{base=binary}},
Head = reverse(Acc),
- case setup_idx_binary(R, []) of
+ case setup_idx_binary_1(R, []) of
ignore ->
{bin, Head ++ [A1|R], Head ++ [A2|R]};
{bin, R1,R2} ->
{bin, Head ++ [A1|R1], Head ++ [A2|R2]}
end;
-setup_idx_binary([A=#arg{in=true,type=T=#type{single={tuple,matrix}}}|R], Acc) ->
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{base=int,size=4},alt=list_binary}|R], Acc) ->
+ A1 = A#arg{type=T#type{base=guard_int}},
+ A2 = A#arg{type=T#type{base=binary}},
+ Head = reverse(Acc),
+ case setup_idx_binary_1(R, []) of
+ ignore ->
+ {bin, Head ++ [A1|R], Head ++ [A2|R]};
+ {bin, R1,R2} ->
+ {bin, Head ++ [A1|R1], Head ++ [A2|R2]}
+ end;
+
+setup_idx_binary_1([A=#arg{in=true,type=T=#type{single={tuple,matrix}}}|R], Acc) ->
A1 = A#arg{type=T#type{single={tuple, matrix12}}},
A2 = A#arg{type=T#type{single={tuple, 16}}},
Head = reverse(Acc),
- case setup_idx_binary(R, []) of
+ case setup_idx_binary_1(R, []) of
ignore ->
{matrix, Head ++ [A1|R], Head ++ [A2|R]};
{matrix, R1,R2} ->
{matrix, Head ++ [A1|R1], Head ++ [A2|R2]}
end;
-setup_idx_binary([H|R],Acc) ->
- setup_idx_binary(R,[H|Acc]);
-setup_idx_binary([],_) -> ignore.
-
+setup_idx_binary_1([H|R],Acc) ->
+ setup_idx_binary_1(R,[H|Acc]);
+setup_idx_binary_1([],_) -> ignore.
+
is_equal(F1=#func{type=T1,params=A1},F2=#func{type=T2,params=A2}) ->
Equal = is_equal_type(T1,T2) andalso is_equal_args(A1,A2),
case Equal of
diff --git a/lib/wx/api_gen/gl_gen_c.erl b/lib/wx/api_gen/gl_gen_c.erl
index c6d4f3a520..53c194a315 100644
--- a/lib/wx/api_gen/gl_gen_c.erl
+++ b/lib/wx/api_gen/gl_gen_c.erl
@@ -123,20 +123,14 @@ declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=B,single={list,Sz}}})
when is_number(Sz) ->
w(" ~s ~s[~p] = {~s};~n", [T,N,Sz,args(fun zero/1,",",lists:duplicate(Sz,B))]),
A;
-declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=string,size={Max,_}, single=Single}}) ->
+declare_var(A=#arg{name=N,in=false,type=#type{name=T,base=string,size={Max,_}}}) ->
case is_integer(Max) of
- true ->
+ true ->
w(" ~s ~s[~p];~n", [T,N,Max]);
false ->
- %% w(" ~s ~s[*~s];~n", [T,N,Max]),
- w(" ~s *~s;~n", [T,N]),
+ w(" ~s *~s;~n", [T,N]),
w(" ~s = (~s *) driver_alloc(sizeof(~s) * *~s);~n", [N,T,T,Max]),
- store_free(N)
- %% case Single of
- %% {list, _, _} ->
- %% w(" ~s *~s_p = ~s;~n", [T,N,N]);
- %% _ -> ok
- %% end
+ store_free(N)
end,
A;
declare_var(A=#arg{name=N,in=false,type=#type{base=binary,size={MaxSz, _}}}) ->
@@ -163,9 +157,9 @@ declare_var(A=#arg{name=N,in=false,
type=#type{name=T,base=B,by_val=false,single=true}}) ->
w(" ~s ~s[1] = {~s};~n", [T,N,zero(B)]),
A;
-declare_var(A=#arg{where=c, type=#type{name=T}, alt={size,Var}}) ->
+declare_var(A=#arg{where=c, type=#type{name=T}, alt={size,Var}}) ->
w(" ~s ~s_size = bins_sz[~p];~n", [T, Var, get(bin_count)]),
- A;
+ A;
declare_var(A=#arg{where=_}) ->
A.
@@ -194,9 +188,16 @@ decode_arg(P=#arg{where=erl},A) -> {P,A};
decode_arg(P=#arg{where=c},A) -> {P,A};
decode_arg(P=#arg{in=false},A) -> {P,A};
-decode_arg(P=#arg{name=Name,type=#type{name=Type,base=binary}},A0) ->
+decode_arg(P=#arg{name=Name,alt=Alt,type=#type{name=Type,base=binary}},A0) ->
w(" ~s *~s = (~s *) bins[~p];~n", [Type,Name,Type,next_id(bin_count)]),
- {P, A0};
+ case Alt of
+ list_binary ->
+ A = align(4, A0),
+ w(" int * ~sLen = (int *) bp; bp += 4; (void) ~sLen;~n", [Name, Name]),
+ {P, A};
+ _ ->
+ {P, A0}
+ end;
decode_arg(P=#arg{name=Name,type=#type{name=Type,base=memory}},A0) ->
w(" ~s *~s = (~s *) bins[~p];~n", [Type,Name,Type,next_id(bin_count)]),
{P, A0};
@@ -217,7 +218,7 @@ decode_arg(P=#arg{name=Name,type=#type{size=Sz,single=list,name=Type}},A0) ->
A = align(max([Sz,4]),A0),
w(" int * ~sLen = (int *) bp; bp += ~p;~n", [Name, max([4,Sz])]),
w(" ~s * ~s = (~s *) bp; ", [Type,Name,Type]),
- w(" bp += (8-((*~sLen*~p+~p)%8))%8;~n", [Name,Sz,A]),
+ w(" bp += *~sLen*~p + (8-((*~sLen*~p+~p)%8))%8;~n", [Name,Sz,Name,Sz,A]),
{P, 0};
decode_arg(P=#arg{name=Name,type=#type{size=TSz,name=Type,single={tuple,undefined}}},A0) ->
A = align(TSz,A0),
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 1f9407525d..3ad14825dd 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -496,6 +496,8 @@ doc_arg_type2(#type{base=string, single=list}) ->
"iolist()";
doc_arg_type2(T=#type{single={tuple,Sz}}) ->
"{" ++ args(fun doc_arg_type3/1, ",", lists:duplicate(Sz,T)) ++ "}";
+doc_arg_type2(#type{base=guard_int, single=list}) ->
+ "[integer()]|mem()";
doc_arg_type2(T=#type{single=list}) ->
"[" ++ doc_arg_type3(T) ++ "]";
doc_arg_type2(T=#type{single={list, _Max}}) ->
@@ -516,7 +518,9 @@ doc_arg_type3(#type{base=binary}) -> "binary()";
doc_arg_type3(#type{base=memory}) -> "mem()".
guard_test(As) ->
- Str = args(fun(#arg{name=N,type=#type{base=guard_int}}) ->
+ Str = args(fun(#arg{name=N,type=#type{base=guard_int, single=list}}) ->
+ " is_list("++erl_arg_name(N)++")";
+ (#arg{name=N,type=#type{base=guard_int}}) ->
" is_integer("++erl_arg_name(N)++")";
(_) ->
skip
@@ -526,6 +530,13 @@ guard_test(As) ->
Other -> " when " ++ Other
end.
+pre_marshal([#arg{name=N,in=true, type=#type{base=binary, single=list}=T, alt=list_binary}=A|R]) ->
+ w(" send_bin(~s),~n", [erl_arg_name(N)]),
+ w(" ~sLen = byte_size(if is_binary(~s) -> ~s; is_tuple(~s) -> element(2, ~s) end) div 4,~n",
+ [erl_arg_name(N),erl_arg_name(N), erl_arg_name(N), erl_arg_name(N), erl_arg_name(N)]),
+ Type = T#type{base=int, by_val=true, single=true, ref=undefined},
+ Arg=A#arg{name=N++"Len", where=both, type=Type},
+ [Arg|pre_marshal(R)];
pre_marshal([#arg{name=N,in=true,type=#type{base=binary}}|R]) ->
w(" send_bin(~s),~n", [erl_arg_name(N)]),
pre_marshal(R);
@@ -534,8 +545,18 @@ pre_marshal([#arg{name=N,type=#type{base=memory}}|R]) ->
pre_marshal(R);
pre_marshal([A=#arg{name=N,type=#type{base=string,single=list}}|R]) ->
%% With null terminations
- w(" ~sTemp = list_to_binary([[Str|[0]] || Str <- ~s ]),~n",
+ w(" ~sTemp = list_to_binary([[Str|[0]] || Str <- ~s ]),~n",
[erl_arg_name(N), erl_arg_name(N)]),
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{base=string,single=true,ref={pointer,1}}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{single=list}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
+ [A|pre_marshal(R)];
+pre_marshal([A=#arg{name=N,type=#type{single={tuple_list,_}}}|R]) ->
+ w(" ~sLen = length(~s),~n",[erl_arg_name(N), erl_arg_name(N)]),
[A|pre_marshal(R)];
pre_marshal([A|R]) ->
[A|pre_marshal(R)];
@@ -587,9 +608,9 @@ marshal_arg(#type{size=BSz,name=Type,single={tuple,matrix12}},Name,A0) ->
align(BSz,16,A0,All);
marshal_arg(#type{size=Sz,name=Type,base=Base,single=list},Name,A0)
- when Base =:= float; Base =:= int ->
+ when Base =:= float; Base =:= int; Base =:= guard_int ->
KeepA = case Sz of 8 -> "0:32,"; _ -> "" end,
- Str0 = "(length("++Name++")):?GLuint,"++KeepA++"\n"
+ Str0 = Name++"Len:?GLuint,"++KeepA++"\n"
" (<< <<C:?"++Type++">> || C <- "++Name++">>)/binary",
{Str,Align} = align(max([Sz,4]),A0,Str0),
align_after(Sz,Align,0,1,Name,Str);
@@ -610,7 +631,7 @@ marshal_arg(#type{base=string,single=true,ref={pointer,1}},Name,A0) ->
marshal_arg(#type{base=string,single=list,ref={pointer,2}},Name,A0) ->
Str0 =
- "(length("++Name++")):?GLuint,"
+ Name++"Len:?GLuint,"
"(size("++Name ++ "Temp)):?GLuint,"
"(" ++ Name ++ "Temp)/binary",
{Str,A} = align(4,A0,Str0),
@@ -624,7 +645,7 @@ marshal_arg(#type{size=Sz,name=Type,single={tuple_list,TSz}},Name,A0) ->
TBin = args(fun(ElName) -> ElName ++ ":?" ++ Type end, ",", Names),
KeepA = case Sz of 8 -> "0:32,"; 4 -> "" end,
- Str0 = "(length("++Name++")):?GLuint,"++KeepA++"\n"
+ Str0 = Name++"Len:?GLuint,"++KeepA++"\n"
" (<< <<"++TBin++">> || {"++TTup++"} <- "++Name++">>)/binary",
align(Sz,A0,Str0);
@@ -660,19 +681,19 @@ align(8,_,7,Str) -> {"0:8," ++Str, 0}.
align_after(8,0,_Add,_Multiplier,_Name,Str) -> {Str,0};
align_after(4,0,Add,Mult,Name,Str) ->
Extra = extra_align(Add,Mult),
- Align = ",0:(((length("++Name++")"++Extra++") rem 2)*32)",
+ Align = ",0:((("++Name++"Len"++Extra++") rem 2)*32)",
{Str ++ Align,0};
align_after(4,4,Add,Mult,Name,Str) ->
Extra = extra_align(Add,Mult),
- Align = ",0:(((1+length("++Name++")"++Extra++") rem 2)*32)",
+ Align = ",0:(((1+"++Name++"Len"++Extra++") rem 2)*32)",
{Str ++ Align,0};
align_after(2,A,Add,Mult,Name,Str) when (A rem 2) =:= 0 ->
Extra = extra_align(A+Add*2,Mult),
- Align = ",0:((8-((length("++Name++")*2"++Extra++") rem 8)) rem 8)",
+ Align = ",0:((8-(("++Name++"Len*2"++Extra++") rem 8)) rem 8)",
{Str ++ Align,0};
align_after(1,A,Add,Mult,Name,Str) ->
Extra = extra_align(A+Add,Mult),
- Align = ",0:((8-((length("++Name++")"++Extra++") rem 8)) rem 8)",
+ Align = ",0:((8-(("++Name++"Len"++Extra++") rem 8)) rem 8)",
{Str ++ Align,0};
align_after(Sz,A,Add,Mult,Name,Str) ->
io:format("~p ~p with ~p ~p ~s~n, ~p", [Sz,A,Add,Mult,Name,Str]),
diff --git a/lib/wx/api_gen/glapi.conf b/lib/wx/api_gen/glapi.conf
index 59fa8f7727..57f30a3f7e 100644
--- a/lib/wx/api_gen/glapi.conf
+++ b/lib/wx/api_gen/glapi.conf
@@ -181,9 +181,9 @@
{"glLoadTransposeMatrix", {"m", {single,{tuple,matrix}}}}.
{"glMultTransposeMatrix", {"m",{single,{tuple,matrix}}}}.
-{"glMultiDrawArrays", [{"first", [in,{single,list}]},
- {"count", [in,{single,list}]},
- {"primcount", {c_only, {length,"first"}}}]}.
+{"glMultiDrawArrays", [{"first", [in,{single,list}, list_binary]},
+ {"count", [in,{single,list}, list_binary]},
+ {"primcount", {c_only, {length,"count"}}}]}.
{"glGenQueries", {"ids", {single,{list, "n", "n"}}}}.
{"glGetQueryiv", {"params", {single, true}}}.
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 0a0b1f9209..d4b6db8153 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1316,7 +1316,8 @@ encode_events(Evs) ->
w(" } else {~n"),
w(" send_res = rt.send();~n"),
w(" if(cb->skip) event->Skip();~n"),
- w(" if(app->recurse_level < 1) {~n"),
+ #class{id=MouseId} = lists:keyfind("wxMouseEvent", #class.name, Evs),
+ w(" if(app->recurse_level < 1 && Etype->cID != ~p) {~n", [MouseId]),
w(" app->recurse_level++;~n"),
w(" app->dispatch_cmds();~n"),
w(" app->recurse_level--;~n"),
diff --git a/lib/wx/c_src/gen/gl_funcs.cpp b/lib/wx/c_src/gen/gl_funcs.cpp
index 4dd3ad44ef..bc8d5bbdca 100644
--- a/lib/wx/c_src/gen/gl_funcs.cpp
+++ b/lib/wx/c_src/gen/gl_funcs.cpp
@@ -815,7 +815,7 @@ case 5107: { // glCallList
}; break;
case 5108: { // glCallLists
int * listsLen = (int *) bp; bp += 4;
- GLuint * lists = (GLuint *) bp; bp += (8-((*listsLen*4+4)%8))%8;
+ GLuint * lists = (GLuint *) bp; bp += *listsLen*4 + (8-((*listsLen*4+4)%8))%8;
weglCallLists(*listsLen,GL_UNSIGNED_INT,lists);
}; break;
case 5109: { // glListBase
@@ -1866,7 +1866,7 @@ case 5271: { // glGenTextures
}; break;
case 5272: { // glDeleteTextures
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
weglDeleteTextures(*texturesLen,textures);
}; break;
case 5273: { // glBindTexture
@@ -1876,14 +1876,14 @@ case 5273: { // glBindTexture
}; break;
case 5274: { // glPrioritizeTextures
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
int * prioritiesLen = (int *) bp; bp += 4;
- GLclampf * priorities = (GLclampf *) bp; bp += (8-((*prioritiesLen*4+4)%8))%8;
+ GLclampf * priorities = (GLclampf *) bp; bp += *prioritiesLen*4 + (8-((*prioritiesLen*4+4)%8))%8;
weglPrioritizeTextures(*texturesLen,textures,priorities);
}; break;
case 5275: { // glAreTexturesResident
int * texturesLen = (int *) bp; bp += 4;
- GLuint * textures = (GLuint *) bp; bp += (8-((*texturesLen*4+4)%8))%8;
+ GLuint * textures = (GLuint *) bp; bp += *texturesLen*4 + (8-((*texturesLen*4+4)%8))%8;
GLboolean *residences;
residences = (GLboolean *) driver_alloc(sizeof(GLboolean) * *texturesLen);
GLboolean result = weglAreTexturesResident(*texturesLen,textures,residences);
@@ -2921,132 +2921,140 @@ case 5394: { // glBlendFuncSeparate
case 5395: { // glMultiDrawArrays
GLenum *mode = (GLenum *) bp; bp += 4;
int * firstLen = (int *) bp; bp += 4;
- GLint * first = (GLint *) bp; bp += (8-((*firstLen*4+0)%8))%8;
+ GLint * first = (GLint *) bp; bp += *firstLen*4 + (8-((*firstLen*4+0)%8))%8;
int * countLen = (int *) bp; bp += 4;
- GLsizei * count = (GLsizei *) bp; bp += (8-((*countLen*4+4)%8))%8;
- weglMultiDrawArrays(*mode,first,count,*firstLen);
+ GLsizei * count = (GLsizei *) bp; bp += *countLen*4 + (8-((*countLen*4+4)%8))%8;
+ weglMultiDrawArrays(*mode,first,count,*countLen);
}; break;
-case 5396: { // glPointParameterf
+case 5396: { // glMultiDrawArrays
+ GLenum *mode = (GLenum *) bp; bp += 4;
+ GLint *first = (GLint *) bins[0];
+ int * firstLen = (int *) bp; bp += 4; (void) firstLen;
+ GLsizei *count = (GLsizei *) bins[1];
+ int * countLen = (int *) bp; bp += 4; (void) countLen;
+ weglMultiDrawArrays(*mode,first,count,*countLen);
+}; break;
+case 5397: { // glPointParameterf
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat *param = (GLfloat *) bp; bp += 4;
weglPointParameterf(*pname,*param);
}; break;
-case 5397: { // glPointParameterfv
+case 5398: { // glPointParameterfv
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLfloat *params = (GLfloat *) bp; bp += *paramsLen*4+((*paramsLen)+0)%2*4;
weglPointParameterfv(*pname,params);
}; break;
-case 5398: { // glPointParameteri
+case 5399: { // glPointParameteri
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *param = (GLint *) bp; bp += 4;
weglPointParameteri(*pname,*param);
}; break;
-case 5399: { // glPointParameteriv
+case 5400: { // glPointParameteriv
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLint *params = (GLint *) bp; bp += *paramsLen*4+((*paramsLen)+0)%2*4;
weglPointParameteriv(*pname,params);
}; break;
-case 5400: { // glFogCoordfv
+case 5401: { // glFogCoordfv
GLfloat *coord = (GLfloat *) bp; bp += 4;
weglFogCoordfv(coord);
}; break;
-case 5401: { // glFogCoorddv
+case 5402: { // glFogCoorddv
GLdouble *coord = (GLdouble *) bp; bp += 8;
weglFogCoorddv(coord);
}; break;
-case 5402: { // glFogCoordPointer
+case 5403: { // glFogCoordPointer
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglFogCoordPointer(*type,*stride,pointer);
}; break;
-case 5403: { // glFogCoordPointer
+case 5404: { // glFogCoordPointer
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) bins[0];
weglFogCoordPointer(*type,*stride,pointer);
}; break;
-case 5404: { // glSecondaryColor3bv
+case 5405: { // glSecondaryColor3bv
GLbyte *v = (GLbyte *) bp; bp += 1;
weglSecondaryColor3bv(v);
}; break;
-case 5405: { // glSecondaryColor3dv
+case 5406: { // glSecondaryColor3dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglSecondaryColor3dv(v);
}; break;
-case 5406: { // glSecondaryColor3fv
+case 5407: { // glSecondaryColor3fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglSecondaryColor3fv(v);
}; break;
-case 5407: { // glSecondaryColor3iv
+case 5408: { // glSecondaryColor3iv
GLint *v = (GLint *) bp; bp += 4;
weglSecondaryColor3iv(v);
}; break;
-case 5408: { // glSecondaryColor3sv
+case 5409: { // glSecondaryColor3sv
GLshort *v = (GLshort *) bp; bp += 2;
weglSecondaryColor3sv(v);
}; break;
-case 5409: { // glSecondaryColor3ubv
+case 5410: { // glSecondaryColor3ubv
GLubyte *v = (GLubyte *) bp; bp += 1;
weglSecondaryColor3ubv(v);
}; break;
-case 5410: { // glSecondaryColor3uiv
+case 5411: { // glSecondaryColor3uiv
GLuint *v = (GLuint *) bp; bp += 4;
weglSecondaryColor3uiv(v);
}; break;
-case 5411: { // glSecondaryColor3usv
+case 5412: { // glSecondaryColor3usv
GLushort *v = (GLushort *) bp; bp += 2;
weglSecondaryColor3usv(v);
}; break;
-case 5412: { // glSecondaryColorPointer
+case 5413: { // glSecondaryColorPointer
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglSecondaryColorPointer(*size,*type,*stride,pointer);
}; break;
-case 5413: { // glSecondaryColorPointer
+case 5414: { // glSecondaryColorPointer
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLsizei *stride = (GLsizei *) bp; bp += 4;
GLvoid *pointer = (GLvoid *) bins[0];
weglSecondaryColorPointer(*size,*type,*stride,pointer);
}; break;
-case 5414: { // glWindowPos2dv
+case 5415: { // glWindowPos2dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglWindowPos2dv(v);
}; break;
-case 5415: { // glWindowPos2fv
+case 5416: { // glWindowPos2fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglWindowPos2fv(v);
}; break;
-case 5416: { // glWindowPos2iv
+case 5417: { // glWindowPos2iv
GLint *v = (GLint *) bp; bp += 4;
weglWindowPos2iv(v);
}; break;
-case 5417: { // glWindowPos2sv
+case 5418: { // glWindowPos2sv
GLshort *v = (GLshort *) bp; bp += 2;
weglWindowPos2sv(v);
}; break;
-case 5418: { // glWindowPos3dv
+case 5419: { // glWindowPos3dv
GLdouble *v = (GLdouble *) bp; bp += 8;
weglWindowPos3dv(v);
}; break;
-case 5419: { // glWindowPos3fv
+case 5420: { // glWindowPos3fv
GLfloat *v = (GLfloat *) bp; bp += 4;
weglWindowPos3fv(v);
}; break;
-case 5420: { // glWindowPos3iv
+case 5421: { // glWindowPos3iv
GLint *v = (GLint *) bp; bp += 4;
weglWindowPos3iv(v);
}; break;
-case 5421: { // glWindowPos3sv
+case 5422: { // glWindowPos3sv
GLshort *v = (GLshort *) bp; bp += 2;
weglWindowPos3sv(v);
}; break;
-case 5422: { // glGenQueries
+case 5423: { // glGenQueries
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *ids;
ids = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -3062,12 +3070,12 @@ case 5422: { // glGenQueries
driver_free(rt);
driver_free(ids);
}; break;
-case 5423: { // glDeleteQueries
+case 5424: { // glDeleteQueries
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+4)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+4)%8))%8;
weglDeleteQueries(*idsLen,ids);
}; break;
-case 5424: { // glIsQuery
+case 5425: { // glIsQuery
GLuint *id = (GLuint *) bp; bp += 4;
GLboolean result = weglIsQuery(*id);
int AP = 0; ErlDrvTermData rt[6];
@@ -3076,16 +3084,16 @@ case 5424: { // glIsQuery
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5425: { // glBeginQuery
+case 5426: { // glBeginQuery
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBeginQuery(*target,*id);
}; break;
-case 5426: { // glEndQuery
+case 5427: { // glEndQuery
GLenum *target = (GLenum *) bp; bp += 4;
weglEndQuery(*target);
}; break;
-case 5427: { // glGetQueryiv
+case 5428: { // glGetQueryiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3096,7 +3104,7 @@ case 5427: { // glGetQueryiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5428: { // glGetQueryObjectiv
+case 5429: { // glGetQueryObjectiv
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3107,7 +3115,7 @@ case 5428: { // glGetQueryObjectiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5429: { // glGetQueryObjectuiv
+case 5430: { // glGetQueryObjectuiv
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[1] = {0};
@@ -3118,17 +3126,17 @@ case 5429: { // glGetQueryObjectuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5430: { // glBindBuffer
+case 5431: { // glBindBuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglBindBuffer(*target,*buffer);
}; break;
-case 5431: { // glDeleteBuffers
+case 5432: { // glDeleteBuffers
int * buffersLen = (int *) bp; bp += 4;
- GLuint * buffers = (GLuint *) bp; bp += (8-((*buffersLen*4+4)%8))%8;
+ GLuint * buffers = (GLuint *) bp; bp += *buffersLen*4 + (8-((*buffersLen*4+4)%8))%8;
weglDeleteBuffers(*buffersLen,buffers);
}; break;
-case 5432: { // glGenBuffers
+case 5433: { // glGenBuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *buffers;
buffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -3144,7 +3152,7 @@ case 5432: { // glGenBuffers
driver_free(rt);
driver_free(buffers);
}; break;
-case 5433: { // glIsBuffer
+case 5434: { // glIsBuffer
GLuint *buffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsBuffer(*buffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -3153,7 +3161,7 @@ case 5433: { // glIsBuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5434: { // glBufferData
+case 5435: { // glBufferData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3161,7 +3169,7 @@ case 5434: { // glBufferData
GLenum *usage = (GLenum *) bp; bp += 4;
weglBufferData(*target,size,data,*usage);
}; break;
-case 5435: { // glBufferData
+case 5436: { // glBufferData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3169,7 +3177,7 @@ case 5435: { // glBufferData
GLenum *usage = (GLenum *) bp; bp += 4;
weglBufferData(*target,size,data,*usage);
}; break;
-case 5436: { // glBufferSubData
+case 5437: { // glBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3177,7 +3185,7 @@ case 5436: { // glBufferSubData
GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglBufferSubData(*target,offset,size,data);
}; break;
-case 5437: { // glBufferSubData
+case 5438: { // glBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3185,7 +3193,7 @@ case 5437: { // glBufferSubData
GLvoid *data = (GLvoid *) bins[0];
weglBufferSubData(*target,offset,size,data);
}; break;
-case 5438: { // glGetBufferSubData
+case 5439: { // glGetBufferSubData
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -3198,7 +3206,7 @@ case 5438: { // glGetBufferSubData
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5439: { // glGetBufferParameteriv
+case 5440: { // glGetBufferParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3209,52 +3217,52 @@ case 5439: { // glGetBufferParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5440: { // glBlendEquationSeparate
+case 5441: { // glBlendEquationSeparate
GLenum *modeRGB = (GLenum *) bp; bp += 4;
GLenum *modeAlpha = (GLenum *) bp; bp += 4;
weglBlendEquationSeparate(*modeRGB,*modeAlpha);
}; break;
-case 5441: { // glDrawBuffers
+case 5442: { // glDrawBuffers
int * bufsLen = (int *) bp; bp += 4;
- GLenum * bufs = (GLenum *) bp; bp += (8-((*bufsLen*4+4)%8))%8;
+ GLenum * bufs = (GLenum *) bp; bp += *bufsLen*4 + (8-((*bufsLen*4+4)%8))%8;
weglDrawBuffers(*bufsLen,bufs);
}; break;
-case 5442: { // glStencilOpSeparate
+case 5443: { // glStencilOpSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLenum *sfail = (GLenum *) bp; bp += 4;
GLenum *dpfail = (GLenum *) bp; bp += 4;
GLenum *dppass = (GLenum *) bp; bp += 4;
weglStencilOpSeparate(*face,*sfail,*dpfail,*dppass);
}; break;
-case 5443: { // glStencilFuncSeparate
+case 5444: { // glStencilFuncSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLenum *func = (GLenum *) bp; bp += 4;
GLint *ref = (GLint *) bp; bp += 4;
GLuint *mask = (GLuint *) bp; bp += 4;
weglStencilFuncSeparate(*face,*func,*ref,*mask);
}; break;
-case 5444: { // glStencilMaskSeparate
+case 5445: { // glStencilMaskSeparate
GLenum *face = (GLenum *) bp; bp += 4;
GLuint *mask = (GLuint *) bp; bp += 4;
weglStencilMaskSeparate(*face,*mask);
}; break;
-case 5445: { // glAttachShader
+case 5446: { // glAttachShader
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *shader = (GLuint *) bp; bp += 4;
weglAttachShader(*program,*shader);
}; break;
-case 5446: { // glBindAttribLocation
+case 5447: { // glBindAttribLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglBindAttribLocation(*program,*index,name);
}; break;
-case 5447: { // glCompileShader
+case 5448: { // glCompileShader
GLuint *shader = (GLuint *) bp; bp += 4;
weglCompileShader(*shader);
}; break;
-case 5448: { // glCreateProgram
+case 5449: { // glCreateProgram
GLuint result = weglCreateProgram();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -3262,7 +3270,7 @@ case 5448: { // glCreateProgram
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5449: { // glCreateShader
+case 5450: { // glCreateShader
GLenum *type = (GLenum *) bp; bp += 4;
GLuint result = weglCreateShader(*type);
int AP = 0; ErlDrvTermData rt[6];
@@ -3271,28 +3279,28 @@ case 5449: { // glCreateShader
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5450: { // glDeleteProgram
+case 5451: { // glDeleteProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglDeleteProgram(*program);
}; break;
-case 5451: { // glDeleteShader
+case 5452: { // glDeleteShader
GLuint *shader = (GLuint *) bp; bp += 4;
weglDeleteShader(*shader);
}; break;
-case 5452: { // glDetachShader
+case 5453: { // glDetachShader
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *shader = (GLuint *) bp; bp += 4;
weglDetachShader(*program,*shader);
}; break;
-case 5453: { // glDisableVertexAttribArray
+case 5454: { // glDisableVertexAttribArray
GLuint *index = (GLuint *) bp; bp += 4;
weglDisableVertexAttribArray(*index);
}; break;
-case 5454: { // glEnableVertexAttribArray
+case 5455: { // glEnableVertexAttribArray
GLuint *index = (GLuint *) bp; bp += 4;
weglEnableVertexAttribArray(*index);
}; break;
-case 5455: { // glGetActiveAttrib
+case 5456: { // glGetActiveAttrib
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -3312,7 +3320,7 @@ case 5455: { // glGetActiveAttrib
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5456: { // glGetActiveUniform
+case 5457: { // glGetActiveUniform
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -3332,7 +3340,7 @@ case 5456: { // glGetActiveUniform
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5457: { // glGetAttachedShaders
+case 5458: { // glGetAttachedShaders
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *maxCount = (GLsizei *) bp; bp += 4;
GLsizei count[1] = {0};
@@ -3350,7 +3358,7 @@ case 5457: { // glGetAttachedShaders
driver_free(rt);
driver_free(obj);
}; break;
-case 5458: { // glGetAttribLocation
+case 5459: { // glGetAttribLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -3361,7 +3369,7 @@ case 5458: { // glGetAttribLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5459: { // glGetProgramiv
+case 5460: { // glGetProgramiv
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3372,7 +3380,7 @@ case 5459: { // glGetProgramiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5460: { // glGetProgramInfoLog
+case 5461: { // glGetProgramInfoLog
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3386,7 +3394,7 @@ case 5460: { // glGetProgramInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5461: { // glGetShaderiv
+case 5462: { // glGetShaderiv
GLuint *shader = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -3397,7 +3405,7 @@ case 5461: { // glGetShaderiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5462: { // glGetShaderInfoLog
+case 5463: { // glGetShaderInfoLog
GLuint *shader = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3411,7 +3419,7 @@ case 5462: { // glGetShaderInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5463: { // glGetShaderSource
+case 5464: { // glGetShaderSource
GLuint *shader = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -3425,7 +3433,7 @@ case 5463: { // glGetShaderSource
driver_send_term(port,caller,rt,AP);
driver_free(source);
}; break;
-case 5464: { // glGetUniformLocation
+case 5465: { // glGetUniformLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -3436,7 +3444,7 @@ case 5464: { // glGetUniformLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5465: { // glGetUniformfv
+case 5466: { // glGetUniformfv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -3465,7 +3473,7 @@ case 5465: { // glGetUniformfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5466: { // glGetUniformiv
+case 5467: { // glGetUniformiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3493,7 +3501,7 @@ case 5466: { // glGetUniformiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5467: { // glGetVertexAttribdv
+case 5468: { // glGetVertexAttribdv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -3509,7 +3517,7 @@ case 5467: { // glGetVertexAttribdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5468: { // glGetVertexAttribfv
+case 5469: { // glGetVertexAttribfv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -3526,7 +3534,7 @@ case 5468: { // glGetVertexAttribfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5469: { // glGetVertexAttribiv
+case 5470: { // glGetVertexAttribiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -3542,7 +3550,7 @@ case 5469: { // glGetVertexAttribiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5470: { // glIsProgram
+case 5471: { // glIsProgram
GLuint *program = (GLuint *) bp; bp += 4;
GLboolean result = weglIsProgram(*program);
int AP = 0; ErlDrvTermData rt[6];
@@ -3551,7 +3559,7 @@ case 5470: { // glIsProgram
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5471: { // glIsShader
+case 5472: { // glIsShader
GLuint *shader = (GLuint *) bp; bp += 4;
GLboolean result = weglIsShader(*shader);
int AP = 0; ErlDrvTermData rt[6];
@@ -3560,11 +3568,11 @@ case 5471: { // glIsShader
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5472: { // glLinkProgram
+case 5473: { // glLinkProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglLinkProgram(*program);
}; break;
-case 5473: { // glShaderSource
+case 5474: { // glShaderSource
GLuint *shader = (GLuint *) bp; bp += 4;
int * stringLen = (int *) bp; bp += 4;
int * stringTotSize = (int *) bp; bp += 4;
@@ -3576,29 +3584,29 @@ case 5473: { // glShaderSource
weglShaderSource(*shader,*stringLen,(const GLchar **) string,NULL);
driver_free(string);
}; break;
-case 5474: { // glUseProgram
+case 5475: { // glUseProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglUseProgram(*program);
}; break;
-case 5475: { // glUniform1f
+case 5476: { // glUniform1f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
weglUniform1f(*location,*v0);
}; break;
-case 5476: { // glUniform2f
+case 5477: { // glUniform2f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
weglUniform2f(*location,*v0,*v1);
}; break;
-case 5477: { // glUniform3f
+case 5478: { // glUniform3f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
GLfloat *v2 = (GLfloat *) bp; bp += 4;
weglUniform3f(*location,*v0,*v1,*v2);
}; break;
-case 5478: { // glUniform4f
+case 5479: { // glUniform4f
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
@@ -3606,25 +3614,25 @@ case 5478: { // glUniform4f
GLfloat *v3 = (GLfloat *) bp; bp += 4;
weglUniform4f(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5479: { // glUniform1i
+case 5480: { // glUniform1i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
weglUniform1i(*location,*v0);
}; break;
-case 5480: { // glUniform2i
+case 5481: { // glUniform2i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
weglUniform2i(*location,*v0,*v1);
}; break;
-case 5481: { // glUniform3i
+case 5482: { // glUniform3i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
GLint *v2 = (GLint *) bp; bp += 4;
weglUniform3i(*location,*v0,*v1,*v2);
}; break;
-case 5482: { // glUniform4i
+case 5483: { // glUniform4i
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
@@ -3632,55 +3640,55 @@ case 5482: { // glUniform4i
GLint *v3 = (GLint *) bp; bp += 4;
weglUniform4i(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5483: { // glUniform1fv
+case 5484: { // glUniform1fv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLfloat * value = (GLfloat *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLfloat * value = (GLfloat *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1fv(*location,*valueLen,value);
}; break;
-case 5484: { // glUniform2fv
+case 5485: { // glUniform2fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*8;
weglUniform2fv(*location,*valueLen,value);
}; break;
-case 5485: { // glUniform3fv
+case 5486: { // glUniform3fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*12;
weglUniform3fv(*location,*valueLen,value);
}; break;
-case 5486: { // glUniform4fv
+case 5487: { // glUniform4fv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglUniform4fv(*location,*valueLen,value);
}; break;
-case 5487: { // glUniform1iv
+case 5488: { // glUniform1iv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLint * value = (GLint *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLint * value = (GLint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1iv(*location,*valueLen,value);
}; break;
-case 5488: { // glUniform2iv
+case 5489: { // glUniform2iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*8;
weglUniform2iv(*location,*valueLen,value);
}; break;
-case 5489: { // glUniform3iv
+case 5490: { // glUniform3iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*12;
weglUniform3iv(*location,*valueLen,value);
}; break;
-case 5490: { // glUniform4iv
+case 5491: { // glUniform4iv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*16;
weglUniform4iv(*location,*valueLen,value);
}; break;
-case 5491: { // glUniformMatrix2fv
+case 5492: { // glUniformMatrix2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3688,7 +3696,7 @@ case 5491: { // glUniformMatrix2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglUniformMatrix2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5492: { // glUniformMatrix3fv
+case 5493: { // glUniformMatrix3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3696,7 +3704,7 @@ case 5492: { // glUniformMatrix3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*36;
weglUniformMatrix3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5493: { // glUniformMatrix4fv
+case 5494: { // glUniformMatrix4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3704,130 +3712,130 @@ case 5493: { // glUniformMatrix4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*64;
weglUniformMatrix4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5494: { // glValidateProgram
+case 5495: { // glValidateProgram
GLuint *program = (GLuint *) bp; bp += 4;
weglValidateProgram(*program);
}; break;
-case 5495: { // glVertexAttrib1dv
+case 5496: { // glVertexAttrib1dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib1dv(*index,v);
}; break;
-case 5496: { // glVertexAttrib1fv
+case 5497: { // glVertexAttrib1fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib1fv(*index,v);
}; break;
-case 5497: { // glVertexAttrib1sv
+case 5498: { // glVertexAttrib1sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib1sv(*index,v);
}; break;
-case 5498: { // glVertexAttrib2dv
+case 5499: { // glVertexAttrib2dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib2dv(*index,v);
}; break;
-case 5499: { // glVertexAttrib2fv
+case 5500: { // glVertexAttrib2fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib2fv(*index,v);
}; break;
-case 5500: { // glVertexAttrib2sv
+case 5501: { // glVertexAttrib2sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib2sv(*index,v);
}; break;
-case 5501: { // glVertexAttrib3dv
+case 5502: { // glVertexAttrib3dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttrib3dv(*index,v);
}; break;
-case 5502: { // glVertexAttrib3fv
+case 5503: { // glVertexAttrib3fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *v = (GLfloat *) bp; bp += 4;
weglVertexAttrib3fv(*index,v);
}; break;
-case 5503: { // glVertexAttrib3sv
+case 5504: { // glVertexAttrib3sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort *v = (GLshort *) bp; bp += 2;
weglVertexAttrib3sv(*index,v);
}; break;
-case 5504: { // glVertexAttrib4Nbv
+case 5505: { // glVertexAttrib4Nbv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttrib4Nbv(*index,v);
}; break;
-case 5505: { // glVertexAttrib4Niv
+case 5506: { // glVertexAttrib4Niv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttrib4Niv(*index,v);
}; break;
-case 5506: { // glVertexAttrib4Nsv
+case 5507: { // glVertexAttrib4Nsv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttrib4Nsv(*index,v);
}; break;
-case 5507: { // glVertexAttrib4Nubv
+case 5508: { // glVertexAttrib4Nubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttrib4Nubv(*index,v);
}; break;
-case 5508: { // glVertexAttrib4Nuiv
+case 5509: { // glVertexAttrib4Nuiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttrib4Nuiv(*index,v);
}; break;
-case 5509: { // glVertexAttrib4Nusv
+case 5510: { // glVertexAttrib4Nusv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttrib4Nusv(*index,v);
}; break;
-case 5510: { // glVertexAttrib4bv
+case 5511: { // glVertexAttrib4bv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttrib4bv(*index,v);
}; break;
-case 5511: { // glVertexAttrib4dv
+case 5512: { // glVertexAttrib4dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble * v = (GLdouble *) bp; bp += 32;
weglVertexAttrib4dv(*index,v);
}; break;
-case 5512: { // glVertexAttrib4fv
+case 5513: { // glVertexAttrib4fv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += 16;
weglVertexAttrib4fv(*index,v);
}; break;
-case 5513: { // glVertexAttrib4iv
+case 5514: { // glVertexAttrib4iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttrib4iv(*index,v);
}; break;
-case 5514: { // glVertexAttrib4sv
+case 5515: { // glVertexAttrib4sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttrib4sv(*index,v);
}; break;
-case 5515: { // glVertexAttrib4ubv
+case 5516: { // glVertexAttrib4ubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttrib4ubv(*index,v);
}; break;
-case 5516: { // glVertexAttrib4uiv
+case 5517: { // glVertexAttrib4uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttrib4uiv(*index,v);
}; break;
-case 5517: { // glVertexAttrib4usv
+case 5518: { // glVertexAttrib4usv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttrib4usv(*index,v);
}; break;
-case 5518: { // glVertexAttribPointer
+case 5519: { // glVertexAttribPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -3837,7 +3845,7 @@ case 5518: { // glVertexAttribPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribPointer(*index,*size,*type,*normalized,*stride,pointer);
}; break;
-case 5519: { // glVertexAttribPointer
+case 5520: { // glVertexAttribPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -3847,7 +3855,7 @@ case 5519: { // glVertexAttribPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribPointer(*index,*size,*type,*normalized,*stride,pointer);
}; break;
-case 5520: { // glUniformMatrix2x3fv
+case 5521: { // glUniformMatrix2x3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3855,7 +3863,7 @@ case 5520: { // glUniformMatrix2x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglUniformMatrix2x3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5521: { // glUniformMatrix3x2fv
+case 5522: { // glUniformMatrix3x2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3863,7 +3871,7 @@ case 5521: { // glUniformMatrix3x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglUniformMatrix3x2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5522: { // glUniformMatrix2x4fv
+case 5523: { // glUniformMatrix2x4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3871,7 +3879,7 @@ case 5522: { // glUniformMatrix2x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglUniformMatrix2x4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5523: { // glUniformMatrix4x2fv
+case 5524: { // glUniformMatrix4x2fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3879,7 +3887,7 @@ case 5523: { // glUniformMatrix4x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglUniformMatrix4x2fv(*location,*valueLen,*transpose,value);
}; break;
-case 5524: { // glUniformMatrix3x4fv
+case 5525: { // glUniformMatrix3x4fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3887,7 +3895,7 @@ case 5524: { // glUniformMatrix3x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglUniformMatrix3x4fv(*location,*valueLen,*transpose,value);
}; break;
-case 5525: { // glUniformMatrix4x3fv
+case 5526: { // glUniformMatrix4x3fv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -3895,7 +3903,7 @@ case 5525: { // glUniformMatrix4x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglUniformMatrix4x3fv(*location,*valueLen,*transpose,value);
}; break;
-case 5526: { // glColorMaski
+case 5527: { // glColorMaski
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean *r = (GLboolean *) bp; bp += 1;
GLboolean *g = (GLboolean *) bp; bp += 1;
@@ -3903,7 +3911,7 @@ case 5526: { // glColorMaski
GLboolean *a = (GLboolean *) bp; bp += 1;
weglColorMaski(*index,*r,*g,*b,*a);
}; break;
-case 5527: { // glGetBooleani_v
+case 5528: { // glGetBooleani_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3931,7 +3939,7 @@ case 5527: { // glGetBooleani_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5528: { // glGetIntegeri_v
+case 5529: { // glGetIntegeri_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLint data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -3959,17 +3967,17 @@ case 5528: { // glGetIntegeri_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5529: { // glEnablei
+case 5530: { // glEnablei
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglEnablei(*target,*index);
}; break;
-case 5530: { // glDisablei
+case 5531: { // glDisablei
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglDisablei(*target,*index);
}; break;
-case 5531: { // glIsEnabledi
+case 5532: { // glIsEnabledi
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLboolean result = weglIsEnabledi(*target,*index);
@@ -3979,14 +3987,14 @@ case 5531: { // glIsEnabledi
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5532: { // glBeginTransformFeedback
+case 5533: { // glBeginTransformFeedback
GLenum *primitiveMode = (GLenum *) bp; bp += 4;
weglBeginTransformFeedback(*primitiveMode);
}; break;
-case 5533: { // glEndTransformFeedback
+case 5534: { // glEndTransformFeedback
weglEndTransformFeedback();
}; break;
-case 5534: { // glBindBufferRange
+case 5535: { // glBindBufferRange
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
@@ -3995,13 +4003,13 @@ case 5534: { // glBindBufferRange
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglBindBufferRange(*target,*index,*buffer,offset,size);
}; break;
-case 5535: { // glBindBufferBase
+case 5536: { // glBindBufferBase
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglBindBufferBase(*target,*index,*buffer);
}; break;
-case 5536: { // glTransformFeedbackVaryings
+case 5537: { // glTransformFeedbackVaryings
GLuint *program = (GLuint *) bp; bp += 4;
int * varyingsLen = (int *) bp; bp += 4;
int * varyingsTotSize = (int *) bp; bp += 4;
@@ -4014,7 +4022,7 @@ case 5536: { // glTransformFeedbackVaryings
weglTransformFeedbackVaryings(*program,*varyingsLen,(const GLchar **) varyings,*bufferMode);
driver_free(varyings);
}; break;
-case 5537: { // glGetTransformFeedbackVarying
+case 5538: { // glGetTransformFeedbackVarying
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -4034,20 +4042,20 @@ case 5537: { // glGetTransformFeedbackVarying
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5538: { // glClampColor
+case 5539: { // glClampColor
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *clamp = (GLenum *) bp; bp += 4;
weglClampColor(*target,*clamp);
}; break;
-case 5539: { // glBeginConditionalRender
+case 5540: { // glBeginConditionalRender
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *mode = (GLenum *) bp; bp += 4;
weglBeginConditionalRender(*id,*mode);
}; break;
-case 5540: { // glEndConditionalRender
+case 5541: { // glEndConditionalRender
weglEndConditionalRender();
}; break;
-case 5541: { // glVertexAttribIPointer
+case 5542: { // glVertexAttribIPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4055,7 +4063,7 @@ case 5541: { // glVertexAttribIPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribIPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5542: { // glVertexAttribIPointer
+case 5543: { // glVertexAttribIPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4063,7 +4071,7 @@ case 5542: { // glVertexAttribIPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribIPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5543: { // glGetVertexAttribIiv
+case 5544: { // glGetVertexAttribIiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -4079,7 +4087,7 @@ case 5543: { // glGetVertexAttribIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5544: { // glGetVertexAttribIuiv
+case 5545: { // glGetVertexAttribIuiv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -4095,67 +4103,67 @@ case 5544: { // glGetVertexAttribIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5545: { // glVertexAttribI1iv
+case 5546: { // glVertexAttribI1iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI1iv(*index,v);
}; break;
-case 5546: { // glVertexAttribI2iv
+case 5547: { // glVertexAttribI2iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI2iv(*index,v);
}; break;
-case 5547: { // glVertexAttribI3iv
+case 5548: { // glVertexAttribI3iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint *v = (GLint *) bp; bp += 4;
weglVertexAttribI3iv(*index,v);
}; break;
-case 5548: { // glVertexAttribI4iv
+case 5549: { // glVertexAttribI4iv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglVertexAttribI4iv(*index,v);
}; break;
-case 5549: { // glVertexAttribI1uiv
+case 5550: { // glVertexAttribI1uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI1uiv(*index,v);
}; break;
-case 5550: { // glVertexAttribI2uiv
+case 5551: { // glVertexAttribI2uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI2uiv(*index,v);
}; break;
-case 5551: { // glVertexAttribI3uiv
+case 5552: { // glVertexAttribI3uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *v = (GLuint *) bp; bp += 4;
weglVertexAttribI3uiv(*index,v);
}; break;
-case 5552: { // glVertexAttribI4uiv
+case 5553: { // glVertexAttribI4uiv
GLuint *index = (GLuint *) bp; bp += 4;
GLuint * v = (GLuint *) bp; bp += 16;
weglVertexAttribI4uiv(*index,v);
}; break;
-case 5553: { // glVertexAttribI4bv
+case 5554: { // glVertexAttribI4bv
GLuint *index = (GLuint *) bp; bp += 4;
GLbyte * v = (GLbyte *) bp; bp += 4;
weglVertexAttribI4bv(*index,v);
}; break;
-case 5554: { // glVertexAttribI4sv
+case 5555: { // glVertexAttribI4sv
GLuint *index = (GLuint *) bp; bp += 4;
GLshort * v = (GLshort *) bp; bp += 8;
weglVertexAttribI4sv(*index,v);
}; break;
-case 5555: { // glVertexAttribI4ubv
+case 5556: { // glVertexAttribI4ubv
GLuint *index = (GLuint *) bp; bp += 4;
GLubyte * v = (GLubyte *) bp; bp += 4;
weglVertexAttribI4ubv(*index,v);
}; break;
-case 5556: { // glVertexAttribI4usv
+case 5557: { // glVertexAttribI4usv
GLuint *index = (GLuint *) bp; bp += 4;
GLushort * v = (GLushort *) bp; bp += 8;
weglVertexAttribI4usv(*index,v);
}; break;
-case 5557: { // glGetUniformuiv
+case 5558: { // glGetUniformuiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4183,14 +4191,14 @@ case 5557: { // glGetUniformuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5558: { // glBindFragDataLocation
+case 5559: { // glBindFragDataLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *color = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglBindFragDataLocation(*program,*color,name);
}; break;
-case 5559: { // glGetFragDataLocation
+case 5560: { // glGetFragDataLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -4201,25 +4209,25 @@ case 5559: { // glGetFragDataLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5560: { // glUniform1ui
+case 5561: { // glUniform1ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
weglUniform1ui(*location,*v0);
}; break;
-case 5561: { // glUniform2ui
+case 5562: { // glUniform2ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
weglUniform2ui(*location,*v0,*v1);
}; break;
-case 5562: { // glUniform3ui
+case 5563: { // glUniform3ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
GLuint *v2 = (GLuint *) bp; bp += 4;
weglUniform3ui(*location,*v0,*v1,*v2);
}; break;
-case 5563: { // glUniform4ui
+case 5564: { // glUniform4ui
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
@@ -4227,45 +4235,45 @@ case 5563: { // glUniform4ui
GLuint *v3 = (GLuint *) bp; bp += 4;
weglUniform4ui(*location,*v0,*v1,*v2,*v3);
}; break;
-case 5564: { // glUniform1uiv
+case 5565: { // glUniform1uiv
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLuint * value = (GLuint *) bp; bp += (8-((*valueLen*4+0)%8))%8;
+ GLuint * value = (GLuint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+0)%8))%8;
weglUniform1uiv(*location,*valueLen,value);
}; break;
-case 5565: { // glUniform2uiv
+case 5566: { // glUniform2uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*8;
weglUniform2uiv(*location,*valueLen,value);
}; break;
-case 5566: { // glUniform3uiv
+case 5567: { // glUniform3uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*12;
weglUniform3uiv(*location,*valueLen,value);
}; break;
-case 5567: { // glUniform4uiv
+case 5568: { // glUniform4uiv
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*16;
weglUniform4uiv(*location,*valueLen,value);
}; break;
-case 5568: { // glTexParameterIiv
+case 5569: { // glTexParameterIiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLint *params = (GLint *) bp; bp += *paramsLen*4+((*paramsLen)+1)%2*4;
weglTexParameterIiv(*target,*pname,params);
}; break;
-case 5569: { // glTexParameterIuiv
+case 5570: { // glTexParameterIuiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int *paramsLen = (int *) bp; bp += 4;
GLuint *params = (GLuint *) bp; bp += *paramsLen*4+((*paramsLen)+1)%2*4;
weglTexParameterIuiv(*target,*pname,params);
}; break;
-case 5570: { // glGetTexParameterIiv
+case 5571: { // glGetTexParameterIiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -4281,7 +4289,7 @@ case 5570: { // glGetTexParameterIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5571: { // glGetTexParameterIuiv
+case 5572: { // glGetTexParameterIuiv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -4297,35 +4305,35 @@ case 5571: { // glGetTexParameterIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5572: { // glClearBufferiv
+case 5573: { // glClearBufferiv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferiv(*buffer,*drawbuffer,value);
}; break;
-case 5573: { // glClearBufferuiv
+case 5574: { // glClearBufferuiv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint *value = (GLuint *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferuiv(*buffer,*drawbuffer,value);
}; break;
-case 5574: { // glClearBufferfv
+case 5575: { // glClearBufferfv
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat *value = (GLfloat *) bp; bp += *valueLen*4+((*valueLen)+1)%2*4;
weglClearBufferfv(*buffer,*drawbuffer,value);
}; break;
-case 5575: { // glClearBufferfi
+case 5576: { // glClearBufferfi
GLenum *buffer = (GLenum *) bp; bp += 4;
GLint *drawbuffer = (GLint *) bp; bp += 4;
GLfloat *depth = (GLfloat *) bp; bp += 4;
GLint *stencil = (GLint *) bp; bp += 4;
weglClearBufferfi(*buffer,*drawbuffer,*depth,*stencil);
}; break;
-case 5576: { // glGetStringi
+case 5577: { // glGetStringi
GLenum *name = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
const GLubyte * result = weglGetStringi(*name,*index);
@@ -4335,14 +4343,14 @@ case 5576: { // glGetStringi
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5577: { // glDrawArraysInstanced
+case 5578: { // glDrawArraysInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLint *first = (GLint *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawArraysInstanced(*mode,*first,*count,*primcount);
}; break;
-case 5578: { // glDrawElementsInstanced
+case 5579: { // glDrawElementsInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4350,7 +4358,7 @@ case 5578: { // glDrawElementsInstanced
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawElementsInstanced(*mode,*count,*type,indices,*primcount);
}; break;
-case 5579: { // glDrawElementsInstanced
+case 5580: { // glDrawElementsInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -4358,17 +4366,17 @@ case 5579: { // glDrawElementsInstanced
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawElementsInstanced(*mode,*count,*type,indices,*primcount);
}; break;
-case 5580: { // glTexBuffer
+case 5581: { // glTexBuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLuint *buffer = (GLuint *) bp; bp += 4;
weglTexBuffer(*target,*internalformat,*buffer);
}; break;
-case 5581: { // glPrimitiveRestartIndex
+case 5582: { // glPrimitiveRestartIndex
GLuint *index = (GLuint *) bp; bp += 4;
weglPrimitiveRestartIndex(*index);
}; break;
-case 5582: { // glGetInteger64i_v
+case 5583: { // glGetInteger64i_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLint64 data[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4396,7 +4404,7 @@ case 5582: { // glGetInteger64i_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5583: { // glGetBufferParameteri64v
+case 5584: { // glGetBufferParameteri64v
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4424,40 +4432,40 @@ case 5583: { // glGetBufferParameteri64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5584: { // glFramebufferTexture
+case 5585: { // glFramebufferTexture
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture(*target,*attachment,*texture,*level);
}; break;
-case 5585: { // glVertexAttribDivisor
+case 5586: { // glVertexAttribDivisor
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *divisor = (GLuint *) bp; bp += 4;
weglVertexAttribDivisor(*index,*divisor);
}; break;
-case 5586: { // glMinSampleShading
+case 5587: { // glMinSampleShading
GLclampf *value = (GLclampf *) bp; bp += 4;
weglMinSampleShading(*value);
}; break;
-case 5587: { // glBlendEquationi
+case 5588: { // glBlendEquationi
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *mode = (GLenum *) bp; bp += 4;
weglBlendEquationi(*buf,*mode);
}; break;
-case 5588: { // glBlendEquationSeparatei
+case 5589: { // glBlendEquationSeparatei
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *modeRGB = (GLenum *) bp; bp += 4;
GLenum *modeAlpha = (GLenum *) bp; bp += 4;
weglBlendEquationSeparatei(*buf,*modeRGB,*modeAlpha);
}; break;
-case 5589: { // glBlendFunci
+case 5590: { // glBlendFunci
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *src = (GLenum *) bp; bp += 4;
GLenum *dst = (GLenum *) bp; bp += 4;
weglBlendFunci(*buf,*src,*dst);
}; break;
-case 5590: { // glBlendFuncSeparatei
+case 5591: { // glBlendFuncSeparatei
GLuint *buf = (GLuint *) bp; bp += 4;
GLenum *srcRGB = (GLenum *) bp; bp += 4;
GLenum *dstRGB = (GLenum *) bp; bp += 4;
@@ -4465,103 +4473,103 @@ case 5590: { // glBlendFuncSeparatei
GLenum *dstAlpha = (GLenum *) bp; bp += 4;
weglBlendFuncSeparatei(*buf,*srcRGB,*dstRGB,*srcAlpha,*dstAlpha);
}; break;
-case 5591: { // glLoadTransposeMatrixfARB
+case 5592: { // glLoadTransposeMatrixfARB
GLfloat * m = (GLfloat *) bp; bp += 64;
weglLoadTransposeMatrixfARB(m);
}; break;
-case 5592: { // glLoadTransposeMatrixdARB
+case 5593: { // glLoadTransposeMatrixdARB
GLdouble * m = (GLdouble *) bp; bp += 128;
weglLoadTransposeMatrixdARB(m);
}; break;
-case 5593: { // glMultTransposeMatrixfARB
+case 5594: { // glMultTransposeMatrixfARB
GLfloat * m = (GLfloat *) bp; bp += 64;
weglMultTransposeMatrixfARB(m);
}; break;
-case 5594: { // glMultTransposeMatrixdARB
+case 5595: { // glMultTransposeMatrixdARB
GLdouble * m = (GLdouble *) bp; bp += 128;
weglMultTransposeMatrixdARB(m);
}; break;
-case 5595: { // glWeightbvARB
+case 5596: { // glWeightbvARB
int * weightsLen = (int *) bp; bp += 4;
- GLbyte * weights = (GLbyte *) bp; bp += (8-((*weightsLen*1+4)%8))%8;
+ GLbyte * weights = (GLbyte *) bp; bp += *weightsLen*1 + (8-((*weightsLen*1+4)%8))%8;
weglWeightbvARB(*weightsLen,weights);
}; break;
-case 5596: { // glWeightsvARB
+case 5597: { // glWeightsvARB
int * weightsLen = (int *) bp; bp += 4;
- GLshort * weights = (GLshort *) bp; bp += (8-((*weightsLen*2+4)%8))%8;
+ GLshort * weights = (GLshort *) bp; bp += *weightsLen*2 + (8-((*weightsLen*2+4)%8))%8;
weglWeightsvARB(*weightsLen,weights);
}; break;
-case 5597: { // glWeightivARB
+case 5598: { // glWeightivARB
int * weightsLen = (int *) bp; bp += 4;
- GLint * weights = (GLint *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLint * weights = (GLint *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightivARB(*weightsLen,weights);
}; break;
-case 5598: { // glWeightfvARB
+case 5599: { // glWeightfvARB
int * weightsLen = (int *) bp; bp += 4;
- GLfloat * weights = (GLfloat *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLfloat * weights = (GLfloat *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightfvARB(*weightsLen,weights);
}; break;
-case 5599: { // glWeightdvARB
+case 5600: { // glWeightdvARB
int * weightsLen = (int *) bp; bp += 8;
- GLdouble * weights = (GLdouble *) bp; bp += (8-((*weightsLen*8+0)%8))%8;
+ GLdouble * weights = (GLdouble *) bp; bp += *weightsLen*8 + (8-((*weightsLen*8+0)%8))%8;
weglWeightdvARB(*weightsLen,weights);
}; break;
-case 5600: { // glWeightubvARB
+case 5601: { // glWeightubvARB
int * weightsLen = (int *) bp; bp += 4;
- GLubyte * weights = (GLubyte *) bp; bp += (8-((*weightsLen*1+4)%8))%8;
+ GLubyte * weights = (GLubyte *) bp; bp += *weightsLen*1 + (8-((*weightsLen*1+4)%8))%8;
weglWeightubvARB(*weightsLen,weights);
}; break;
-case 5601: { // glWeightusvARB
+case 5602: { // glWeightusvARB
int * weightsLen = (int *) bp; bp += 4;
- GLushort * weights = (GLushort *) bp; bp += (8-((*weightsLen*2+4)%8))%8;
+ GLushort * weights = (GLushort *) bp; bp += *weightsLen*2 + (8-((*weightsLen*2+4)%8))%8;
weglWeightusvARB(*weightsLen,weights);
}; break;
-case 5602: { // glWeightuivARB
+case 5603: { // glWeightuivARB
int * weightsLen = (int *) bp; bp += 4;
- GLuint * weights = (GLuint *) bp; bp += (8-((*weightsLen*4+4)%8))%8;
+ GLuint * weights = (GLuint *) bp; bp += *weightsLen*4 + (8-((*weightsLen*4+4)%8))%8;
weglWeightuivARB(*weightsLen,weights);
}; break;
-case 5603: { // glVertexBlendARB
+case 5604: { // glVertexBlendARB
GLint *count = (GLint *) bp; bp += 4;
weglVertexBlendARB(*count);
}; break;
-case 5604: { // glCurrentPaletteMatrixARB
+case 5605: { // glCurrentPaletteMatrixARB
GLint *index = (GLint *) bp; bp += 4;
weglCurrentPaletteMatrixARB(*index);
}; break;
-case 5605: { // glMatrixIndexubvARB
+case 5606: { // glMatrixIndexubvARB
int * indicesLen = (int *) bp; bp += 4;
- GLubyte * indices = (GLubyte *) bp; bp += (8-((*indicesLen*1+4)%8))%8;
+ GLubyte * indices = (GLubyte *) bp; bp += *indicesLen*1 + (8-((*indicesLen*1+4)%8))%8;
weglMatrixIndexubvARB(*indicesLen,indices);
}; break;
-case 5606: { // glMatrixIndexusvARB
+case 5607: { // glMatrixIndexusvARB
int * indicesLen = (int *) bp; bp += 4;
- GLushort * indices = (GLushort *) bp; bp += (8-((*indicesLen*2+4)%8))%8;
+ GLushort * indices = (GLushort *) bp; bp += *indicesLen*2 + (8-((*indicesLen*2+4)%8))%8;
weglMatrixIndexusvARB(*indicesLen,indices);
}; break;
-case 5607: { // glMatrixIndexuivARB
+case 5608: { // glMatrixIndexuivARB
int * indicesLen = (int *) bp; bp += 4;
- GLuint * indices = (GLuint *) bp; bp += (8-((*indicesLen*4+4)%8))%8;
+ GLuint * indices = (GLuint *) bp; bp += *indicesLen*4 + (8-((*indicesLen*4+4)%8))%8;
weglMatrixIndexuivARB(*indicesLen,indices);
}; break;
-case 5608: { // glProgramStringARB
+case 5609: { // glProgramStringARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *format = (GLenum *) bp; bp += 4;
GLvoid *string = (GLvoid *) bp;
int stringLen[1] = {(int)strlen((char *)string)}; bp += stringLen[0]+1+((8-((1+stringLen[0]+0)%8))%8);
weglProgramStringARB(*target,*format,*stringLen,string);
}; break;
-case 5609: { // glBindProgramARB
+case 5610: { // glBindProgramARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglBindProgramARB(*target,*program);
}; break;
-case 5610: { // glDeleteProgramsARB
+case 5611: { // glDeleteProgramsARB
int * programsLen = (int *) bp; bp += 4;
- GLuint * programs = (GLuint *) bp; bp += (8-((*programsLen*4+4)%8))%8;
+ GLuint * programs = (GLuint *) bp; bp += *programsLen*4 + (8-((*programsLen*4+4)%8))%8;
weglDeleteProgramsARB(*programsLen,programs);
}; break;
-case 5611: { // glGenProgramsARB
+case 5612: { // glGenProgramsARB
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *programs;
programs = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -4577,7 +4585,7 @@ case 5611: { // glGenProgramsARB
driver_free(rt);
driver_free(programs);
}; break;
-case 5612: { // glProgramEnvParameter4dARB
+case 5613: { // glProgramEnvParameter4dARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -4586,13 +4594,13 @@ case 5612: { // glProgramEnvParameter4dARB
GLdouble *w = (GLdouble *) bp; bp += 8;
weglProgramEnvParameter4dARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5613: { // glProgramEnvParameter4dvARB
+case 5614: { // glProgramEnvParameter4dvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble * params = (GLdouble *) bp; bp += 32;
weglProgramEnvParameter4dvARB(*target,*index,params);
}; break;
-case 5614: { // glProgramEnvParameter4fARB
+case 5615: { // glProgramEnvParameter4fARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
@@ -4601,13 +4609,13 @@ case 5614: { // glProgramEnvParameter4fARB
GLfloat *w = (GLfloat *) bp; bp += 4;
weglProgramEnvParameter4fARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5615: { // glProgramEnvParameter4fvARB
+case 5616: { // glProgramEnvParameter4fvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * params = (GLfloat *) bp; bp += 16;
weglProgramEnvParameter4fvARB(*target,*index,params);
}; break;
-case 5616: { // glProgramLocalParameter4dARB
+case 5617: { // glProgramLocalParameter4dARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -4616,13 +4624,13 @@ case 5616: { // glProgramLocalParameter4dARB
GLdouble *w = (GLdouble *) bp; bp += 8;
weglProgramLocalParameter4dARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5617: { // glProgramLocalParameter4dvARB
+case 5618: { // glProgramLocalParameter4dvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble * params = (GLdouble *) bp; bp += 32;
weglProgramLocalParameter4dvARB(*target,*index,params);
}; break;
-case 5618: { // glProgramLocalParameter4fARB
+case 5619: { // glProgramLocalParameter4fARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
@@ -4631,13 +4639,13 @@ case 5618: { // glProgramLocalParameter4fARB
GLfloat *w = (GLfloat *) bp; bp += 4;
weglProgramLocalParameter4fARB(*target,*index,*x,*y,*z,*w);
}; break;
-case 5619: { // glProgramLocalParameter4fvARB
+case 5620: { // glProgramLocalParameter4fvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * params = (GLfloat *) bp; bp += 16;
weglProgramLocalParameter4fvARB(*target,*index,params);
}; break;
-case 5620: { // glGetProgramEnvParameterdvARB
+case 5621: { // glGetProgramEnvParameterdvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -4653,7 +4661,7 @@ case 5620: { // glGetProgramEnvParameterdvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5621: { // glGetProgramEnvParameterfvARB
+case 5622: { // glGetProgramEnvParameterfvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -4670,7 +4678,7 @@ case 5621: { // glGetProgramEnvParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5622: { // glGetProgramLocalParameterdvARB
+case 5623: { // glGetProgramLocalParameterdvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -4686,7 +4694,7 @@ case 5622: { // glGetProgramLocalParameterdvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5623: { // glGetProgramLocalParameterfvARB
+case 5624: { // glGetProgramLocalParameterfvARB
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -4703,7 +4711,7 @@ case 5623: { // glGetProgramLocalParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5624: { // glGetProgramStringARB
+case 5625: { // glGetProgramStringARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLvoid *string = (GLvoid *) bins[0];
@@ -4714,7 +4722,7 @@ case 5624: { // glGetProgramStringARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5625: { // glGetBufferParameterivARB
+case 5626: { // glGetBufferParameterivARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4742,11 +4750,11 @@ case 5625: { // glGetBufferParameterivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5626: { // glDeleteObjectARB
+case 5627: { // glDeleteObjectARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglDeleteObjectARB(obj);
}; break;
-case 5627: { // glGetHandleARB
+case 5628: { // glGetHandleARB
GLenum *pname = (GLenum *) bp; bp += 4;
GLhandleARB result = weglGetHandleARB(*pname);
int AP = 0; ErlDrvTermData rt[6];
@@ -4755,12 +4763,12 @@ case 5627: { // glGetHandleARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5628: { // glDetachObjectARB
+case 5629: { // glDetachObjectARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLhandleARB attachedObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglDetachObjectARB(containerObj,attachedObj);
}; break;
-case 5629: { // glCreateShaderObjectARB
+case 5630: { // glCreateShaderObjectARB
GLenum *shaderType = (GLenum *) bp; bp += 4;
GLhandleARB result = weglCreateShaderObjectARB(*shaderType);
int AP = 0; ErlDrvTermData rt[6];
@@ -4769,7 +4777,7 @@ case 5629: { // glCreateShaderObjectARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5630: { // glShaderSourceARB
+case 5631: { // glShaderSourceARB
GLhandleARB shaderObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
int * stringLen = (int *) bp; bp += 4;
int * stringTotSize = (int *) bp; bp += 4;
@@ -4781,11 +4789,11 @@ case 5630: { // glShaderSourceARB
weglShaderSourceARB(shaderObj,*stringLen,(const GLchar **) string,NULL);
driver_free(string);
}; break;
-case 5631: { // glCompileShaderARB
+case 5632: { // glCompileShaderARB
GLhandleARB shaderObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglCompileShaderARB(shaderObj);
}; break;
-case 5632: { // glCreateProgramObjectARB
+case 5633: { // glCreateProgramObjectARB
GLhandleARB result = weglCreateProgramObjectARB();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -4793,24 +4801,24 @@ case 5632: { // glCreateProgramObjectARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5633: { // glAttachObjectARB
+case 5634: { // glAttachObjectARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglAttachObjectARB(containerObj,obj);
}; break;
-case 5634: { // glLinkProgramARB
+case 5635: { // glLinkProgramARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglLinkProgramARB(programObj);
}; break;
-case 5635: { // glUseProgramObjectARB
+case 5636: { // glUseProgramObjectARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglUseProgramObjectARB(programObj);
}; break;
-case 5636: { // glValidateProgramARB
+case 5637: { // glValidateProgramARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
weglValidateProgramARB(programObj);
}; break;
-case 5637: { // glGetObjectParameterfvARB
+case 5638: { // glGetObjectParameterfvARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[1] = {0.0};
@@ -4822,7 +4830,7 @@ case 5637: { // glGetObjectParameterfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5638: { // glGetObjectParameterivARB
+case 5639: { // glGetObjectParameterivARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -4833,7 +4841,7 @@ case 5638: { // glGetObjectParameterivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5639: { // glGetInfoLogARB
+case 5640: { // glGetInfoLogARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -4847,7 +4855,7 @@ case 5639: { // glGetInfoLogARB
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5640: { // glGetAttachedObjectsARB
+case 5641: { // glGetAttachedObjectsARB
GLhandleARB containerObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxCount = (GLsizei *) bp; bp += 4;
GLsizei count[1] = {0};
@@ -4865,7 +4873,7 @@ case 5640: { // glGetAttachedObjectsARB
driver_free(rt);
driver_free(obj);
}; break;
-case 5641: { // glGetUniformLocationARB
+case 5642: { // glGetUniformLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
@@ -4876,7 +4884,7 @@ case 5641: { // glGetUniformLocationARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5642: { // glGetActiveUniformARB
+case 5643: { // glGetActiveUniformARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
@@ -4896,7 +4904,7 @@ case 5642: { // glGetActiveUniformARB
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5643: { // glGetUniformfvARB
+case 5644: { // glGetUniformfvARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLint *location = (GLint *) bp; bp += 4;
GLfloat params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -4925,7 +4933,7 @@ case 5643: { // glGetUniformfvARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5644: { // glGetUniformivARB
+case 5645: { // glGetUniformivARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLint *location = (GLint *) bp; bp += 4;
GLint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -4953,7 +4961,7 @@ case 5644: { // glGetUniformivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5645: { // glGetShaderSourceARB
+case 5646: { // glGetShaderSourceARB
GLhandleARB obj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -4967,14 +4975,14 @@ case 5645: { // glGetShaderSourceARB
driver_send_term(port,caller,rt,AP);
driver_free(source);
}; break;
-case 5646: { // glBindAttribLocationARB
+case 5647: { // glBindAttribLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
weglBindAttribLocationARB(programObj,*index,name);
}; break;
-case 5647: { // glGetActiveAttribARB
+case 5648: { // glGetActiveAttribARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLuint *index = (GLuint *) bp; bp += 4;
GLsizei *maxLength = (GLsizei *) bp; bp += 4;
@@ -4994,7 +5002,7 @@ case 5647: { // glGetActiveAttribARB
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5648: { // glGetAttribLocationARB
+case 5649: { // glGetAttribLocationARB
GLhandleARB programObj = (GLhandleARB) * (GLuint64EXT *) bp; bp += 8;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
@@ -5005,7 +5013,7 @@ case 5648: { // glGetAttribLocationARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5649: { // glIsRenderbuffer
+case 5650: { // glIsRenderbuffer
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsRenderbuffer(*renderbuffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -5014,17 +5022,17 @@ case 5649: { // glIsRenderbuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5650: { // glBindRenderbuffer
+case 5651: { // glBindRenderbuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
weglBindRenderbuffer(*target,*renderbuffer);
}; break;
-case 5651: { // glDeleteRenderbuffers
+case 5652: { // glDeleteRenderbuffers
int * renderbuffersLen = (int *) bp; bp += 4;
- GLuint * renderbuffers = (GLuint *) bp; bp += (8-((*renderbuffersLen*4+4)%8))%8;
+ GLuint * renderbuffers = (GLuint *) bp; bp += *renderbuffersLen*4 + (8-((*renderbuffersLen*4+4)%8))%8;
weglDeleteRenderbuffers(*renderbuffersLen,renderbuffers);
}; break;
-case 5652: { // glGenRenderbuffers
+case 5653: { // glGenRenderbuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *renderbuffers;
renderbuffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5040,14 +5048,14 @@ case 5652: { // glGenRenderbuffers
driver_free(rt);
driver_free(renderbuffers);
}; break;
-case 5653: { // glRenderbufferStorage
+case 5654: { // glRenderbufferStorage
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLsizei *width = (GLsizei *) bp; bp += 4;
GLsizei *height = (GLsizei *) bp; bp += 4;
weglRenderbufferStorage(*target,*internalformat,*width,*height);
}; break;
-case 5654: { // glGetRenderbufferParameteriv
+case 5655: { // glGetRenderbufferParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -5058,7 +5066,7 @@ case 5654: { // glGetRenderbufferParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5655: { // glIsFramebuffer
+case 5656: { // glIsFramebuffer
GLuint *framebuffer = (GLuint *) bp; bp += 4;
GLboolean result = weglIsFramebuffer(*framebuffer);
int AP = 0; ErlDrvTermData rt[6];
@@ -5067,17 +5075,17 @@ case 5655: { // glIsFramebuffer
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5656: { // glBindFramebuffer
+case 5657: { // glBindFramebuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *framebuffer = (GLuint *) bp; bp += 4;
weglBindFramebuffer(*target,*framebuffer);
}; break;
-case 5657: { // glDeleteFramebuffers
+case 5658: { // glDeleteFramebuffers
int * framebuffersLen = (int *) bp; bp += 4;
- GLuint * framebuffers = (GLuint *) bp; bp += (8-((*framebuffersLen*4+4)%8))%8;
+ GLuint * framebuffers = (GLuint *) bp; bp += *framebuffersLen*4 + (8-((*framebuffersLen*4+4)%8))%8;
weglDeleteFramebuffers(*framebuffersLen,framebuffers);
}; break;
-case 5658: { // glGenFramebuffers
+case 5659: { // glGenFramebuffers
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *framebuffers;
framebuffers = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5093,7 +5101,7 @@ case 5658: { // glGenFramebuffers
driver_free(rt);
driver_free(framebuffers);
}; break;
-case 5659: { // glCheckFramebufferStatus
+case 5660: { // glCheckFramebufferStatus
GLenum *target = (GLenum *) bp; bp += 4;
GLenum result = weglCheckFramebufferStatus(*target);
int AP = 0; ErlDrvTermData rt[6];
@@ -5102,7 +5110,7 @@ case 5659: { // glCheckFramebufferStatus
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5660: { // glFramebufferTexture1D
+case 5661: { // glFramebufferTexture1D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5110,7 +5118,7 @@ case 5660: { // glFramebufferTexture1D
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture1D(*target,*attachment,*textarget,*texture,*level);
}; break;
-case 5661: { // glFramebufferTexture2D
+case 5662: { // glFramebufferTexture2D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5118,7 +5126,7 @@ case 5661: { // glFramebufferTexture2D
GLint *level = (GLint *) bp; bp += 4;
weglFramebufferTexture2D(*target,*attachment,*textarget,*texture,*level);
}; break;
-case 5662: { // glFramebufferTexture3D
+case 5663: { // glFramebufferTexture3D
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *textarget = (GLenum *) bp; bp += 4;
@@ -5127,14 +5135,14 @@ case 5662: { // glFramebufferTexture3D
GLint *zoffset = (GLint *) bp; bp += 4;
weglFramebufferTexture3D(*target,*attachment,*textarget,*texture,*level,*zoffset);
}; break;
-case 5663: { // glFramebufferRenderbuffer
+case 5664: { // glFramebufferRenderbuffer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *renderbuffertarget = (GLenum *) bp; bp += 4;
GLuint *renderbuffer = (GLuint *) bp; bp += 4;
weglFramebufferRenderbuffer(*target,*attachment,*renderbuffertarget,*renderbuffer);
}; break;
-case 5664: { // glGetFramebufferAttachmentParameteriv
+case 5665: { // glGetFramebufferAttachmentParameteriv
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5146,11 +5154,11 @@ case 5664: { // glGetFramebufferAttachmentParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5665: { // glGenerateMipmap
+case 5666: { // glGenerateMipmap
GLenum *target = (GLenum *) bp; bp += 4;
weglGenerateMipmap(*target);
}; break;
-case 5666: { // glBlitFramebuffer
+case 5667: { // glBlitFramebuffer
GLint *srcX0 = (GLint *) bp; bp += 4;
GLint *srcY0 = (GLint *) bp; bp += 4;
GLint *srcX1 = (GLint *) bp; bp += 4;
@@ -5163,7 +5171,7 @@ case 5666: { // glBlitFramebuffer
GLenum *filter = (GLenum *) bp; bp += 4;
weglBlitFramebuffer(*srcX0,*srcY0,*srcX1,*srcY1,*dstX0,*dstY0,*dstX1,*dstY1,*mask,*filter);
}; break;
-case 5667: { // glRenderbufferStorageMultisample
+case 5668: { // glRenderbufferStorageMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -5171,7 +5179,7 @@ case 5667: { // glRenderbufferStorageMultisample
GLsizei *height = (GLsizei *) bp; bp += 4;
weglRenderbufferStorageMultisample(*target,*samples,*internalformat,*width,*height);
}; break;
-case 5668: { // glFramebufferTextureLayer
+case 5669: { // glFramebufferTextureLayer
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
@@ -5179,7 +5187,7 @@ case 5668: { // glFramebufferTextureLayer
GLint *layer = (GLint *) bp; bp += 4;
weglFramebufferTextureLayer(*target,*attachment,*texture,*level,*layer);
}; break;
-case 5669: { // glFramebufferTextureFaceARB
+case 5670: { // glFramebufferTextureFaceARB
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *attachment = (GLenum *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
@@ -5187,23 +5195,23 @@ case 5669: { // glFramebufferTextureFaceARB
GLenum *face = (GLenum *) bp; bp += 4;
weglFramebufferTextureFaceARB(*target,*attachment,*texture,*level,*face);
}; break;
-case 5670: { // glFlushMappedBufferRange
+case 5671: { // glFlushMappedBufferRange
GLenum *target = (GLenum *) bp; bp += 4;
bp += 4;
GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
GLsizeiptr length = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglFlushMappedBufferRange(*target,offset,length);
}; break;
-case 5671: { // glBindVertexArray
+case 5672: { // glBindVertexArray
GLuint *array = (GLuint *) bp; bp += 4;
weglBindVertexArray(*array);
}; break;
-case 5672: { // glDeleteVertexArrays
+case 5673: { // glDeleteVertexArrays
int * arraysLen = (int *) bp; bp += 4;
- GLuint * arrays = (GLuint *) bp; bp += (8-((*arraysLen*4+4)%8))%8;
+ GLuint * arrays = (GLuint *) bp; bp += *arraysLen*4 + (8-((*arraysLen*4+4)%8))%8;
weglDeleteVertexArrays(*arraysLen,arrays);
}; break;
-case 5673: { // glGenVertexArrays
+case 5674: { // glGenVertexArrays
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *arrays;
arrays = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -5219,7 +5227,7 @@ case 5673: { // glGenVertexArrays
driver_free(rt);
driver_free(arrays);
}; break;
-case 5674: { // glIsVertexArray
+case 5675: { // glIsVertexArray
GLuint *array = (GLuint *) bp; bp += 4;
GLboolean result = weglIsVertexArray(*array);
int AP = 0; ErlDrvTermData rt[6];
@@ -5228,7 +5236,7 @@ case 5674: { // glIsVertexArray
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5675: { // glGetUniformIndices
+case 5676: { // glGetUniformIndices
GLuint *program = (GLuint *) bp; bp += 4;
int * uniformNamesLen = (int *) bp; bp += 4;
int * uniformNamesTotSize = (int *) bp; bp += 4;
@@ -5252,10 +5260,10 @@ case 5675: { // glGetUniformIndices
driver_free(uniformIndices);
driver_free(uniformNames);
}; break;
-case 5676: { // glGetActiveUniformsiv
+case 5677: { // glGetActiveUniformsiv
GLuint *program = (GLuint *) bp; bp += 4;
int * uniformIndicesLen = (int *) bp; bp += 4;
- GLuint * uniformIndices = (GLuint *) bp; bp += (8-((*uniformIndicesLen*4+0)%8))%8;
+ GLuint * uniformIndices = (GLuint *) bp; bp += *uniformIndicesLen*4 + (8-((*uniformIndicesLen*4+0)%8))%8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *params;
params = (GLint *) driver_alloc(sizeof(GLint) * *uniformIndicesLen);
@@ -5271,7 +5279,7 @@ case 5676: { // glGetActiveUniformsiv
driver_free(rt);
driver_free(params);
}; break;
-case 5677: { // glGetActiveUniformName
+case 5678: { // glGetActiveUniformName
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformIndex = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5286,7 +5294,7 @@ case 5677: { // glGetActiveUniformName
driver_send_term(port,caller,rt,AP);
driver_free(uniformName);
}; break;
-case 5678: { // glGetUniformBlockIndex
+case 5679: { // glGetUniformBlockIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *uniformBlockName = (GLchar *) bp;
int uniformBlockNameLen[1] = {(int)strlen((char *)uniformBlockName)}; bp += uniformBlockNameLen[0]+1+((8-((1+uniformBlockNameLen[0]+4)%8))%8);
@@ -5297,7 +5305,7 @@ case 5678: { // glGetUniformBlockIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5679: { // glGetActiveUniformBlockiv
+case 5680: { // glGetActiveUniformBlockiv
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5309,7 +5317,7 @@ case 5679: { // glGetActiveUniformBlockiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5680: { // glGetActiveUniformBlockName
+case 5681: { // glGetActiveUniformBlockName
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5324,13 +5332,13 @@ case 5680: { // glGetActiveUniformBlockName
driver_send_term(port,caller,rt,AP);
driver_free(uniformBlockName);
}; break;
-case 5681: { // glUniformBlockBinding
+case 5682: { // glUniformBlockBinding
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *uniformBlockIndex = (GLuint *) bp; bp += 4;
GLuint *uniformBlockBinding = (GLuint *) bp; bp += 4;
weglUniformBlockBinding(*program,*uniformBlockIndex,*uniformBlockBinding);
}; break;
-case 5682: { // glCopyBufferSubData
+case 5683: { // glCopyBufferSubData
GLenum *readTarget = (GLenum *) bp; bp += 4;
GLenum *writeTarget = (GLenum *) bp; bp += 4;
GLintptr readOffset = (GLintptr) * (GLuint64EXT *) bp; bp += 8;
@@ -5338,7 +5346,7 @@ case 5682: { // glCopyBufferSubData
GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8;
weglCopyBufferSubData(*readTarget,*writeTarget,readOffset,writeOffset,size);
}; break;
-case 5683: { // glDrawElementsBaseVertex
+case 5684: { // glDrawElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5346,7 +5354,7 @@ case 5683: { // glDrawElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsBaseVertex(*mode,*count,*type,indices,*basevertex);
}; break;
-case 5684: { // glDrawElementsBaseVertex
+case 5685: { // glDrawElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5354,7 +5362,7 @@ case 5684: { // glDrawElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsBaseVertex(*mode,*count,*type,indices,*basevertex);
}; break;
-case 5685: { // glDrawRangeElementsBaseVertex
+case 5686: { // glDrawRangeElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *start = (GLuint *) bp; bp += 4;
GLuint *end = (GLuint *) bp; bp += 4;
@@ -5364,7 +5372,7 @@ case 5685: { // glDrawRangeElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawRangeElementsBaseVertex(*mode,*start,*end,*count,*type,indices,*basevertex);
}; break;
-case 5686: { // glDrawRangeElementsBaseVertex
+case 5687: { // glDrawRangeElementsBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *start = (GLuint *) bp; bp += 4;
GLuint *end = (GLuint *) bp; bp += 4;
@@ -5374,7 +5382,7 @@ case 5686: { // glDrawRangeElementsBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawRangeElementsBaseVertex(*mode,*start,*end,*count,*type,indices,*basevertex);
}; break;
-case 5687: { // glDrawElementsInstancedBaseVertex
+case 5688: { // glDrawElementsInstancedBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5383,7 +5391,7 @@ case 5687: { // glDrawElementsInstancedBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertex(*mode,*count,*type,indices,*primcount,*basevertex);
}; break;
-case 5688: { // glDrawElementsInstancedBaseVertex
+case 5689: { // glDrawElementsInstancedBaseVertex
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -5392,11 +5400,11 @@ case 5688: { // glDrawElementsInstancedBaseVertex
GLint *basevertex = (GLint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertex(*mode,*count,*type,indices,*primcount,*basevertex);
}; break;
-case 5689: { // glProvokingVertex
+case 5690: { // glProvokingVertex
GLenum *mode = (GLenum *) bp; bp += 4;
weglProvokingVertex(*mode);
}; break;
-case 5690: { // glFenceSync
+case 5691: { // glFenceSync
GLenum *condition = (GLenum *) bp; bp += 4;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
GLsync result = weglFenceSync(*condition,*flags);
@@ -5406,7 +5414,7 @@ case 5690: { // glFenceSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5691: { // glIsSync
+case 5692: { // glIsSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLboolean result = weglIsSync(sync);
int AP = 0; ErlDrvTermData rt[6];
@@ -5415,11 +5423,11 @@ case 5691: { // glIsSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5692: { // glDeleteSync
+case 5693: { // glDeleteSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
weglDeleteSync(sync);
}; break;
-case 5693: { // glClientWaitSync
+case 5694: { // glClientWaitSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
bp += 4;
@@ -5431,14 +5439,14 @@ case 5693: { // glClientWaitSync
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5694: { // glWaitSync
+case 5695: { // glWaitSync
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLbitfield *flags = (GLbitfield *) bp; bp += 4;
bp += 4;
GLuint64 timeout = (GLuint64) * (GLuint64EXT *) bp; bp += 8;
weglWaitSync(sync,*flags,timeout);
}; break;
-case 5695: { // glGetInteger64v
+case 5696: { // glGetInteger64v
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
weglGetInteger64v(*pname,params);
@@ -5465,7 +5473,7 @@ case 5695: { // glGetInteger64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5696: { // glGetSynciv
+case 5697: { // glGetSynciv
GLsync sync = (GLsync) * (GLuint64EXT *) bp; bp += 8;
GLenum *pname = (GLenum *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5484,7 +5492,7 @@ case 5696: { // glGetSynciv
driver_free(rt);
driver_free(values);
}; break;
-case 5697: { // glTexImage2DMultisample
+case 5698: { // glTexImage2DMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLint *internalformat = (GLint *) bp; bp += 4;
@@ -5493,7 +5501,7 @@ case 5697: { // glTexImage2DMultisample
GLboolean *fixedsamplelocations = (GLboolean *) bp; bp += 1;
weglTexImage2DMultisample(*target,*samples,*internalformat,*width,*height,*fixedsamplelocations);
}; break;
-case 5698: { // glTexImage3DMultisample
+case 5699: { // glTexImage3DMultisample
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *samples = (GLsizei *) bp; bp += 4;
GLint *internalformat = (GLint *) bp; bp += 4;
@@ -5503,7 +5511,7 @@ case 5698: { // glTexImage3DMultisample
GLboolean *fixedsamplelocations = (GLboolean *) bp; bp += 1;
weglTexImage3DMultisample(*target,*samples,*internalformat,*width,*height,*depth,*fixedsamplelocations);
}; break;
-case 5699: { // glGetMultisamplefv
+case 5700: { // glGetMultisamplefv
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat val[2] = {0.0,0.0};
@@ -5518,12 +5526,12 @@ case 5699: { // glGetMultisamplefv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5700: { // glSampleMaski
+case 5701: { // glSampleMaski
GLuint *index = (GLuint *) bp; bp += 4;
GLbitfield *mask = (GLbitfield *) bp; bp += 4;
weglSampleMaski(*index,*mask);
}; break;
-case 5701: { // glNamedStringARB
+case 5702: { // glNamedStringARB
GLenum *type = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -5531,12 +5539,12 @@ case 5701: { // glNamedStringARB
int stringLen[1] = {(int)strlen((char *)string)}; bp += stringLen[0]+1+((8-((1+stringLen[0]+0)%8))%8);
weglNamedStringARB(*type,*nameLen,name,*stringLen,string);
}; break;
-case 5702: { // glDeleteNamedStringARB
+case 5703: { // glDeleteNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
weglDeleteNamedStringARB(*nameLen,name);
}; break;
-case 5703: { // glCompileShaderIncludeARB
+case 5704: { // glCompileShaderIncludeARB
GLuint *shader = (GLuint *) bp; bp += 4;
int * pathLen = (int *) bp; bp += 4;
int * pathTotSize = (int *) bp; bp += 4;
@@ -5548,7 +5556,7 @@ case 5703: { // glCompileShaderIncludeARB
weglCompileShaderIncludeARB(*shader,*pathLen,(const GLchar **) path,NULL);
driver_free(path);
}; break;
-case 5704: { // glIsNamedStringARB
+case 5705: { // glIsNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLboolean result = weglIsNamedStringARB(*nameLen,name);
@@ -5558,7 +5566,7 @@ case 5704: { // glIsNamedStringARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5705: { // glGetNamedStringARB
+case 5706: { // glGetNamedStringARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
@@ -5573,7 +5581,7 @@ case 5705: { // glGetNamedStringARB
driver_send_term(port,caller,rt,AP);
driver_free(string);
}; break;
-case 5706: { // glGetNamedStringivARB
+case 5707: { // glGetNamedStringivARB
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+0)%8))%8);
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -5585,7 +5593,7 @@ case 5706: { // glGetNamedStringivARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5707: { // glBindFragDataLocationIndexed
+case 5708: { // glBindFragDataLocationIndexed
GLuint *program = (GLuint *) bp; bp += 4;
GLuint *colorNumber = (GLuint *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -5593,7 +5601,7 @@ case 5707: { // glBindFragDataLocationIndexed
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
weglBindFragDataLocationIndexed(*program,*colorNumber,*index,name);
}; break;
-case 5708: { // glGetFragDataIndex
+case 5709: { // glGetFragDataIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
int nameLen[1] = {(int)strlen((char *)name)}; bp += nameLen[0]+1+((8-((1+nameLen[0]+4)%8))%8);
@@ -5604,7 +5612,7 @@ case 5708: { // glGetFragDataIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5709: { // glGenSamplers
+case 5710: { // glGenSamplers
GLsizei *count = (GLsizei *) bp; bp += 4;
GLuint *samplers;
samplers = (GLuint *) driver_alloc(sizeof(GLuint) * *count);
@@ -5620,12 +5628,12 @@ case 5709: { // glGenSamplers
driver_free(rt);
driver_free(samplers);
}; break;
-case 5710: { // glDeleteSamplers
+case 5711: { // glDeleteSamplers
int * samplersLen = (int *) bp; bp += 4;
- GLuint * samplers = (GLuint *) bp; bp += (8-((*samplersLen*4+4)%8))%8;
+ GLuint * samplers = (GLuint *) bp; bp += *samplersLen*4 + (8-((*samplersLen*4+4)%8))%8;
weglDeleteSamplers(*samplersLen,samplers);
}; break;
-case 5711: { // glIsSampler
+case 5712: { // glIsSampler
GLuint *sampler = (GLuint *) bp; bp += 4;
GLboolean result = weglIsSampler(*sampler);
int AP = 0; ErlDrvTermData rt[6];
@@ -5634,52 +5642,52 @@ case 5711: { // glIsSampler
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5712: { // glBindSampler
+case 5713: { // glBindSampler
GLuint *unit = (GLuint *) bp; bp += 4;
GLuint *sampler = (GLuint *) bp; bp += 4;
weglBindSampler(*unit,*sampler);
}; break;
-case 5713: { // glSamplerParameteri
+case 5714: { // glSamplerParameteri
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *param = (GLint *) bp; bp += 4;
weglSamplerParameteri(*sampler,*pname,*param);
}; break;
-case 5714: { // glSamplerParameteriv
+case 5715: { // glSamplerParameteriv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLint * param = (GLint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLint * param = (GLint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameteriv(*sampler,*pname,param);
}; break;
-case 5715: { // glSamplerParameterf
+case 5716: { // glSamplerParameterf
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat *param = (GLfloat *) bp; bp += 4;
weglSamplerParameterf(*sampler,*pname,*param);
}; break;
-case 5716: { // glSamplerParameterfv
+case 5717: { // glSamplerParameterfv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLfloat * param = (GLfloat *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLfloat * param = (GLfloat *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterfv(*sampler,*pname,param);
}; break;
-case 5717: { // glSamplerParameterIiv
+case 5718: { // glSamplerParameterIiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLint * param = (GLint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLint * param = (GLint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterIiv(*sampler,*pname,param);
}; break;
-case 5718: { // glSamplerParameterIuiv
+case 5719: { // glSamplerParameterIuiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
int * paramLen = (int *) bp; bp += 4;
- GLuint * param = (GLuint *) bp; bp += (8-((*paramLen*4+4)%8))%8;
+ GLuint * param = (GLuint *) bp; bp += *paramLen*4 + (8-((*paramLen*4+4)%8))%8;
weglSamplerParameterIuiv(*sampler,*pname,param);
}; break;
-case 5719: { // glGetSamplerParameteriv
+case 5720: { // glGetSamplerParameteriv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -5695,7 +5703,7 @@ case 5719: { // glGetSamplerParameteriv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5720: { // glGetSamplerParameterIiv
+case 5721: { // glGetSamplerParameterIiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[4] = {0,0,0,0};
@@ -5711,7 +5719,7 @@ case 5720: { // glGetSamplerParameterIiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5721: { // glGetSamplerParameterfv
+case 5722: { // glGetSamplerParameterfv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLfloat params[4] = {0.0,0.0,0.0,0.0};
@@ -5728,7 +5736,7 @@ case 5721: { // glGetSamplerParameterfv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5722: { // glGetSamplerParameterIuiv
+case 5723: { // glGetSamplerParameterIuiv
GLuint *sampler = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint params[4] = {0,0,0,0};
@@ -5744,12 +5752,12 @@ case 5722: { // glGetSamplerParameterIuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5723: { // glQueryCounter
+case 5724: { // glQueryCounter
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *target = (GLenum *) bp; bp += 4;
weglQueryCounter(*id,*target);
}; break;
-case 5724: { // glGetQueryObjecti64v
+case 5725: { // glGetQueryObjecti64v
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint64 params[1] = {0};
@@ -5760,7 +5768,7 @@ case 5724: { // glGetQueryObjecti64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5725: { // glGetQueryObjectui64v
+case 5726: { // glGetQueryObjectui64v
GLuint *id = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLuint64 params[1] = {0};
@@ -5771,42 +5779,42 @@ case 5725: { // glGetQueryObjectui64v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5726: { // glDrawArraysIndirect
+case 5727: { // glDrawArraysIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglDrawArraysIndirect(*mode,indirect);
}; break;
-case 5727: { // glDrawArraysIndirect
+case 5728: { // glDrawArraysIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) bins[0];
weglDrawArraysIndirect(*mode,indirect);
}; break;
-case 5728: { // glDrawElementsIndirect
+case 5729: { // glDrawElementsIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglDrawElementsIndirect(*mode,*type,indirect);
}; break;
-case 5729: { // glDrawElementsIndirect
+case 5730: { // glDrawElementsIndirect
GLenum *mode = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLvoid *indirect = (GLvoid *) bins[0];
weglDrawElementsIndirect(*mode,*type,indirect);
}; break;
-case 5730: { // glUniform1d
+case 5731: { // glUniform1d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
weglUniform1d(*location,*x);
}; break;
-case 5731: { // glUniform2d
+case 5732: { // glUniform2d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
GLdouble *y = (GLdouble *) bp; bp += 8;
weglUniform2d(*location,*x,*y);
}; break;
-case 5732: { // glUniform3d
+case 5733: { // glUniform3d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -5814,7 +5822,7 @@ case 5732: { // glUniform3d
GLdouble *z = (GLdouble *) bp; bp += 8;
weglUniform3d(*location,*x,*y,*z);
}; break;
-case 5733: { // glUniform4d
+case 5734: { // glUniform4d
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
GLdouble *x = (GLdouble *) bp; bp += 8;
@@ -5823,35 +5831,35 @@ case 5733: { // glUniform4d
GLdouble *w = (GLdouble *) bp; bp += 8;
weglUniform4d(*location,*x,*y,*z,*w);
}; break;
-case 5734: { // glUniform1dv
+case 5735: { // glUniform1dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int * valueLen = (int *) bp; bp += 8;
- GLdouble * value = (GLdouble *) bp; bp += (8-((*valueLen*8+0)%8))%8;
+ GLdouble * value = (GLdouble *) bp; bp += *valueLen*8 + (8-((*valueLen*8+0)%8))%8;
weglUniform1dv(*location,*valueLen,value);
}; break;
-case 5735: { // glUniform2dv
+case 5736: { // glUniform2dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*16;
weglUniform2dv(*location,*valueLen,value);
}; break;
-case 5736: { // glUniform3dv
+case 5737: { // glUniform3dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*24;
weglUniform3dv(*location,*valueLen,value);
}; break;
-case 5737: { // glUniform4dv
+case 5738: { // glUniform4dv
GLint *location = (GLint *) bp; bp += 4;
bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglUniform4dv(*location,*valueLen,value);
}; break;
-case 5738: { // glUniformMatrix2dv
+case 5739: { // glUniformMatrix2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5859,7 +5867,7 @@ case 5738: { // glUniformMatrix2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglUniformMatrix2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5739: { // glUniformMatrix3dv
+case 5740: { // glUniformMatrix3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5867,7 +5875,7 @@ case 5739: { // glUniformMatrix3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*72;
weglUniformMatrix3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5740: { // glUniformMatrix4dv
+case 5741: { // glUniformMatrix4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5875,7 +5883,7 @@ case 5740: { // glUniformMatrix4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*128;
weglUniformMatrix4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5741: { // glUniformMatrix2x3dv
+case 5742: { // glUniformMatrix2x3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5883,7 +5891,7 @@ case 5741: { // glUniformMatrix2x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglUniformMatrix2x3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5742: { // glUniformMatrix2x4dv
+case 5743: { // glUniformMatrix2x4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5891,7 +5899,7 @@ case 5742: { // glUniformMatrix2x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglUniformMatrix2x4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5743: { // glUniformMatrix3x2dv
+case 5744: { // glUniformMatrix3x2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5899,7 +5907,7 @@ case 5743: { // glUniformMatrix3x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglUniformMatrix3x2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5744: { // glUniformMatrix3x4dv
+case 5745: { // glUniformMatrix3x4dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5907,7 +5915,7 @@ case 5744: { // glUniformMatrix3x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglUniformMatrix3x4dv(*location,*valueLen,*transpose,value);
}; break;
-case 5745: { // glUniformMatrix4x2dv
+case 5746: { // glUniformMatrix4x2dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5915,7 +5923,7 @@ case 5745: { // glUniformMatrix4x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglUniformMatrix4x2dv(*location,*valueLen,*transpose,value);
}; break;
-case 5746: { // glUniformMatrix4x3dv
+case 5747: { // glUniformMatrix4x3dv
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
bp += 3;
@@ -5923,7 +5931,7 @@ case 5746: { // glUniformMatrix4x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglUniformMatrix4x3dv(*location,*valueLen,*transpose,value);
}; break;
-case 5747: { // glGetUniformdv
+case 5748: { // glGetUniformdv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble params[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -5951,7 +5959,7 @@ case 5747: { // glGetUniformdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5748: { // glGetSubroutineUniformLocation
+case 5749: { // glGetSubroutineUniformLocation
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
@@ -5963,7 +5971,7 @@ case 5748: { // glGetSubroutineUniformLocation
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5749: { // glGetSubroutineIndex
+case 5750: { // glGetSubroutineIndex
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLchar *name = (GLchar *) bp;
@@ -5975,7 +5983,7 @@ case 5749: { // glGetSubroutineIndex
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5750: { // glGetActiveSubroutineUniformName
+case 5751: { // glGetActiveSubroutineUniformName
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -5991,7 +5999,7 @@ case 5750: { // glGetActiveSubroutineUniformName
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5751: { // glGetActiveSubroutineName
+case 5752: { // glGetActiveSubroutineName
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
@@ -6007,13 +6015,13 @@ case 5751: { // glGetActiveSubroutineName
driver_send_term(port,caller,rt,AP);
driver_free(name);
}; break;
-case 5752: { // glUniformSubroutinesuiv
+case 5753: { // glUniformSubroutinesuiv
GLenum *shadertype = (GLenum *) bp; bp += 4;
int * indicesLen = (int *) bp; bp += 4;
- GLuint * indices = (GLuint *) bp; bp += (8-((*indicesLen*4+0)%8))%8;
+ GLuint * indices = (GLuint *) bp; bp += *indicesLen*4 + (8-((*indicesLen*4+0)%8))%8;
weglUniformSubroutinesuiv(*shadertype,*indicesLen,indices);
}; break;
-case 5753: { // glGetUniformSubroutineuiv
+case 5754: { // glGetUniformSubroutineuiv
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
@@ -6041,7 +6049,7 @@ case 5753: { // glGetUniformSubroutineuiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5754: { // glGetProgramStageiv
+case 5755: { // glGetProgramStageiv
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -6053,28 +6061,28 @@ case 5754: { // glGetProgramStageiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5755: { // glPatchParameteri
+case 5756: { // glPatchParameteri
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += 4;
weglPatchParameteri(*pname,*value);
}; break;
-case 5756: { // glPatchParameterfv
+case 5757: { // glPatchParameterfv
GLenum *pname = (GLenum *) bp; bp += 4;
int * valuesLen = (int *) bp; bp += 4;
- GLfloat * values = (GLfloat *) bp; bp += (8-((*valuesLen*4+0)%8))%8;
+ GLfloat * values = (GLfloat *) bp; bp += *valuesLen*4 + (8-((*valuesLen*4+0)%8))%8;
weglPatchParameterfv(*pname,values);
}; break;
-case 5757: { // glBindTransformFeedback
+case 5758: { // glBindTransformFeedback
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBindTransformFeedback(*target,*id);
}; break;
-case 5758: { // glDeleteTransformFeedbacks
+case 5759: { // glDeleteTransformFeedbacks
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+4)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+4)%8))%8;
weglDeleteTransformFeedbacks(*idsLen,ids);
}; break;
-case 5759: { // glGenTransformFeedbacks
+case 5760: { // glGenTransformFeedbacks
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *ids;
ids = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -6090,7 +6098,7 @@ case 5759: { // glGenTransformFeedbacks
driver_free(rt);
driver_free(ids);
}; break;
-case 5760: { // glIsTransformFeedback
+case 5761: { // glIsTransformFeedback
GLuint *id = (GLuint *) bp; bp += 4;
GLboolean result = weglIsTransformFeedback(*id);
int AP = 0; ErlDrvTermData rt[6];
@@ -6099,35 +6107,35 @@ case 5760: { // glIsTransformFeedback
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5761: { // glPauseTransformFeedback
+case 5762: { // glPauseTransformFeedback
weglPauseTransformFeedback();
}; break;
-case 5762: { // glResumeTransformFeedback
+case 5763: { // glResumeTransformFeedback
weglResumeTransformFeedback();
}; break;
-case 5763: { // glDrawTransformFeedback
+case 5764: { // glDrawTransformFeedback
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglDrawTransformFeedback(*mode,*id);
}; break;
-case 5764: { // glDrawTransformFeedbackStream
+case 5765: { // glDrawTransformFeedbackStream
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLuint *stream = (GLuint *) bp; bp += 4;
weglDrawTransformFeedbackStream(*mode,*id,*stream);
}; break;
-case 5765: { // glBeginQueryIndexed
+case 5766: { // glBeginQueryIndexed
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
weglBeginQueryIndexed(*target,*index,*id);
}; break;
-case 5766: { // glEndQueryIndexed
+case 5767: { // glEndQueryIndexed
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
weglEndQueryIndexed(*target,*index);
}; break;
-case 5767: { // glGetQueryIndexediv
+case 5768: { // glGetQueryIndexediv
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -6139,18 +6147,18 @@ case 5767: { // glGetQueryIndexediv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5768: { // glReleaseShaderCompiler
+case 5769: { // glReleaseShaderCompiler
weglReleaseShaderCompiler();
}; break;
-case 5769: { // glShaderBinary
+case 5770: { // glShaderBinary
int * shadersLen = (int *) bp; bp += 4;
- GLuint * shaders = (GLuint *) bp; bp += (8-((*shadersLen*4+4)%8))%8;
+ GLuint * shaders = (GLuint *) bp; bp += *shadersLen*4 + (8-((*shadersLen*4+4)%8))%8;
GLenum *binaryformat = (GLenum *) bp; bp += 4;
GLvoid *binary = (GLvoid *) bins[0];
GLsizei binary_size = bins_sz[0];
weglShaderBinary(*shadersLen,shaders,*binaryformat,binary,binary_size);
}; break;
-case 5770: { // glGetShaderPrecisionFormat
+case 5771: { // glGetShaderPrecisionFormat
GLenum *shadertype = (GLenum *) bp; bp += 4;
GLenum *precisiontype = (GLenum *) bp; bp += 4;
GLint range[2] = {0,0};
@@ -6167,16 +6175,16 @@ case 5770: { // glGetShaderPrecisionFormat
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5771: { // glDepthRangef
+case 5772: { // glDepthRangef
GLclampf *n = (GLclampf *) bp; bp += 4;
GLclampf *f = (GLclampf *) bp; bp += 4;
weglDepthRangef(*n,*f);
}; break;
-case 5772: { // glClearDepthf
+case 5773: { // glClearDepthf
GLclampf *d = (GLclampf *) bp; bp += 4;
weglClearDepthf(*d);
}; break;
-case 5773: { // glGetProgramBinary
+case 5774: { // glGetProgramBinary
GLuint *program = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -6192,31 +6200,31 @@ case 5773: { // glGetProgramBinary
driver_send_term(port,caller,rt,AP);
driver_free_binary(binary);
}; break;
-case 5774: { // glProgramBinary
+case 5775: { // glProgramBinary
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *binaryFormat = (GLenum *) bp; bp += 4;
GLvoid *binary = (GLvoid *) bins[0];
GLsizei binary_size = bins_sz[0];
weglProgramBinary(*program,*binaryFormat,binary,binary_size);
}; break;
-case 5775: { // glProgramParameteri
+case 5776: { // glProgramParameteri
GLuint *program = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint *value = (GLint *) bp; bp += 4;
weglProgramParameteri(*program,*pname,*value);
}; break;
-case 5776: { // glUseProgramStages
+case 5777: { // glUseProgramStages
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLbitfield *stages = (GLbitfield *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglUseProgramStages(*pipeline,*stages,*program);
}; break;
-case 5777: { // glActiveShaderProgram
+case 5778: { // glActiveShaderProgram
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLuint *program = (GLuint *) bp; bp += 4;
weglActiveShaderProgram(*pipeline,*program);
}; break;
-case 5778: { // glCreateShaderProgramv
+case 5779: { // glCreateShaderProgramv
GLenum *type = (GLenum *) bp; bp += 4;
int * stringsLen = (int *) bp; bp += 4;
int * stringsTotSize = (int *) bp; bp += 4;
@@ -6233,16 +6241,16 @@ case 5778: { // glCreateShaderProgramv
driver_send_term(port,caller,rt,AP);
driver_free(strings);
}; break;
-case 5779: { // glBindProgramPipeline
+case 5780: { // glBindProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
weglBindProgramPipeline(*pipeline);
}; break;
-case 5780: { // glDeleteProgramPipelines
+case 5781: { // glDeleteProgramPipelines
int * pipelinesLen = (int *) bp; bp += 4;
- GLuint * pipelines = (GLuint *) bp; bp += (8-((*pipelinesLen*4+4)%8))%8;
+ GLuint * pipelines = (GLuint *) bp; bp += *pipelinesLen*4 + (8-((*pipelinesLen*4+4)%8))%8;
weglDeleteProgramPipelines(*pipelinesLen,pipelines);
}; break;
-case 5781: { // glGenProgramPipelines
+case 5782: { // glGenProgramPipelines
GLsizei *n = (GLsizei *) bp; bp += 4;
GLuint *pipelines;
pipelines = (GLuint *) driver_alloc(sizeof(GLuint) * *n);
@@ -6258,7 +6266,7 @@ case 5781: { // glGenProgramPipelines
driver_free(rt);
driver_free(pipelines);
}; break;
-case 5782: { // glIsProgramPipeline
+case 5783: { // glIsProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLboolean result = weglIsProgramPipeline(*pipeline);
int AP = 0; ErlDrvTermData rt[6];
@@ -6267,7 +6275,7 @@ case 5782: { // glIsProgramPipeline
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5783: { // glGetProgramPipelineiv
+case 5784: { // glGetProgramPipelineiv
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLint params[1] = {0};
@@ -6278,115 +6286,115 @@ case 5783: { // glGetProgramPipelineiv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5784: { // glProgramUniform1i
+case 5785: { // glProgramUniform1i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
weglProgramUniform1i(*program,*location,*v0);
}; break;
-case 5785: { // glProgramUniform1iv
+case 5786: { // glProgramUniform1iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLint * value = (GLint *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLint * value = (GLint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1iv(*program,*location,*valueLen,value);
}; break;
-case 5786: { // glProgramUniform1f
+case 5787: { // glProgramUniform1f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
weglProgramUniform1f(*program,*location,*v0);
}; break;
-case 5787: { // glProgramUniform1fv
+case 5788: { // glProgramUniform1fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLfloat * value = (GLfloat *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLfloat * value = (GLfloat *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1fv(*program,*location,*valueLen,value);
}; break;
-case 5788: { // glProgramUniform1d
+case 5789: { // glProgramUniform1d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
weglProgramUniform1d(*program,*location,*v0);
}; break;
-case 5789: { // glProgramUniform1dv
+case 5790: { // glProgramUniform1dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 8;
- GLdouble * value = (GLdouble *) bp; bp += (8-((*valueLen*8+0)%8))%8;
+ GLdouble * value = (GLdouble *) bp; bp += *valueLen*8 + (8-((*valueLen*8+0)%8))%8;
weglProgramUniform1dv(*program,*location,*valueLen,value);
}; break;
-case 5790: { // glProgramUniform1ui
+case 5791: { // glProgramUniform1ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
weglProgramUniform1ui(*program,*location,*v0);
}; break;
-case 5791: { // glProgramUniform1uiv
+case 5792: { // glProgramUniform1uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int * valueLen = (int *) bp; bp += 4;
- GLuint * value = (GLuint *) bp; bp += (8-((*valueLen*4+4)%8))%8;
+ GLuint * value = (GLuint *) bp; bp += *valueLen*4 + (8-((*valueLen*4+4)%8))%8;
weglProgramUniform1uiv(*program,*location,*valueLen,value);
}; break;
-case 5792: { // glProgramUniform2i
+case 5793: { // glProgramUniform2i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
GLint *v1 = (GLint *) bp; bp += 4;
weglProgramUniform2i(*program,*location,*v0,*v1);
}; break;
-case 5793: { // glProgramUniform2iv
+case 5794: { // glProgramUniform2iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*8;
weglProgramUniform2iv(*program,*location,*valueLen,value);
}; break;
-case 5794: { // glProgramUniform2f
+case 5795: { // glProgramUniform2f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
GLfloat *v1 = (GLfloat *) bp; bp += 4;
weglProgramUniform2f(*program,*location,*v0,*v1);
}; break;
-case 5795: { // glProgramUniform2fv
+case 5796: { // glProgramUniform2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*8;
weglProgramUniform2fv(*program,*location,*valueLen,value);
}; break;
-case 5796: { // glProgramUniform2d
+case 5797: { // glProgramUniform2d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
GLdouble *v1 = (GLdouble *) bp; bp += 8;
weglProgramUniform2d(*program,*location,*v0,*v1);
}; break;
-case 5797: { // glProgramUniform2dv
+case 5798: { // glProgramUniform2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*16;
weglProgramUniform2dv(*program,*location,*valueLen,value);
}; break;
-case 5798: { // glProgramUniform2ui
+case 5799: { // glProgramUniform2ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
GLuint *v1 = (GLuint *) bp; bp += 4;
weglProgramUniform2ui(*program,*location,*v0,*v1);
}; break;
-case 5799: { // glProgramUniform2uiv
+case 5800: { // glProgramUniform2uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*8;
weglProgramUniform2uiv(*program,*location,*valueLen,value);
}; break;
-case 5800: { // glProgramUniform3i
+case 5801: { // glProgramUniform3i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
@@ -6394,14 +6402,14 @@ case 5800: { // glProgramUniform3i
GLint *v2 = (GLint *) bp; bp += 4;
weglProgramUniform3i(*program,*location,*v0,*v1,*v2);
}; break;
-case 5801: { // glProgramUniform3iv
+case 5802: { // glProgramUniform3iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*12;
weglProgramUniform3iv(*program,*location,*valueLen,value);
}; break;
-case 5802: { // glProgramUniform3f
+case 5803: { // glProgramUniform3f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
@@ -6409,14 +6417,14 @@ case 5802: { // glProgramUniform3f
GLfloat *v2 = (GLfloat *) bp; bp += 4;
weglProgramUniform3f(*program,*location,*v0,*v1,*v2);
}; break;
-case 5803: { // glProgramUniform3fv
+case 5804: { // glProgramUniform3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*12;
weglProgramUniform3fv(*program,*location,*valueLen,value);
}; break;
-case 5804: { // glProgramUniform3d
+case 5805: { // glProgramUniform3d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
@@ -6424,14 +6432,14 @@ case 5804: { // glProgramUniform3d
GLdouble *v2 = (GLdouble *) bp; bp += 8;
weglProgramUniform3d(*program,*location,*v0,*v1,*v2);
}; break;
-case 5805: { // glProgramUniform3dv
+case 5806: { // glProgramUniform3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*24;
weglProgramUniform3dv(*program,*location,*valueLen,value);
}; break;
-case 5806: { // glProgramUniform3ui
+case 5807: { // glProgramUniform3ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
@@ -6439,14 +6447,14 @@ case 5806: { // glProgramUniform3ui
GLuint *v2 = (GLuint *) bp; bp += 4;
weglProgramUniform3ui(*program,*location,*v0,*v1,*v2);
}; break;
-case 5807: { // glProgramUniform3uiv
+case 5808: { // glProgramUniform3uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*12;
weglProgramUniform3uiv(*program,*location,*valueLen,value);
}; break;
-case 5808: { // glProgramUniform4i
+case 5809: { // glProgramUniform4i
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLint *v0 = (GLint *) bp; bp += 4;
@@ -6455,14 +6463,14 @@ case 5808: { // glProgramUniform4i
GLint *v3 = (GLint *) bp; bp += 4;
weglProgramUniform4i(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5809: { // glProgramUniform4iv
+case 5810: { // glProgramUniform4iv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLint * value = (GLint *) bp; bp += *valueLen*16;
weglProgramUniform4iv(*program,*location,*valueLen,value);
}; break;
-case 5810: { // glProgramUniform4f
+case 5811: { // glProgramUniform4f
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLfloat *v0 = (GLfloat *) bp; bp += 4;
@@ -6471,14 +6479,14 @@ case 5810: { // glProgramUniform4f
GLfloat *v3 = (GLfloat *) bp; bp += 4;
weglProgramUniform4f(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5811: { // glProgramUniform4fv
+case 5812: { // glProgramUniform4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglProgramUniform4fv(*program,*location,*valueLen,value);
}; break;
-case 5812: { // glProgramUniform4d
+case 5813: { // glProgramUniform4d
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLdouble *v0 = (GLdouble *) bp; bp += 8;
@@ -6487,14 +6495,14 @@ case 5812: { // glProgramUniform4d
GLdouble *v3 = (GLdouble *) bp; bp += 8;
weglProgramUniform4d(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5813: { // glProgramUniform4dv
+case 5814: { // glProgramUniform4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 8;
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglProgramUniform4dv(*program,*location,*valueLen,value);
}; break;
-case 5814: { // glProgramUniform4ui
+case 5815: { // glProgramUniform4ui
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLuint *v0 = (GLuint *) bp; bp += 4;
@@ -6503,14 +6511,14 @@ case 5814: { // glProgramUniform4ui
GLuint *v3 = (GLuint *) bp; bp += 4;
weglProgramUniform4ui(*program,*location,*v0,*v1,*v2,*v3);
}; break;
-case 5815: { // glProgramUniform4uiv
+case 5816: { // glProgramUniform4uiv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
int *valueLen = (int *) bp; bp += 4;
GLuint * value = (GLuint *) bp; bp += *valueLen*16;
weglProgramUniform4uiv(*program,*location,*valueLen,value);
}; break;
-case 5816: { // glProgramUniformMatrix2fv
+case 5817: { // glProgramUniformMatrix2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6519,7 +6527,7 @@ case 5816: { // glProgramUniformMatrix2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*16;
weglProgramUniformMatrix2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5817: { // glProgramUniformMatrix3fv
+case 5818: { // glProgramUniformMatrix3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6528,7 +6536,7 @@ case 5817: { // glProgramUniformMatrix3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*36;
weglProgramUniformMatrix3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5818: { // glProgramUniformMatrix4fv
+case 5819: { // glProgramUniformMatrix4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6537,7 +6545,7 @@ case 5818: { // glProgramUniformMatrix4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*64;
weglProgramUniformMatrix4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5819: { // glProgramUniformMatrix2dv
+case 5820: { // glProgramUniformMatrix2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6546,7 +6554,7 @@ case 5819: { // glProgramUniformMatrix2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*32;
weglProgramUniformMatrix2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5820: { // glProgramUniformMatrix3dv
+case 5821: { // glProgramUniformMatrix3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6555,7 +6563,7 @@ case 5820: { // glProgramUniformMatrix3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*72;
weglProgramUniformMatrix3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5821: { // glProgramUniformMatrix4dv
+case 5822: { // glProgramUniformMatrix4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6564,7 +6572,7 @@ case 5821: { // glProgramUniformMatrix4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*128;
weglProgramUniformMatrix4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5822: { // glProgramUniformMatrix2x3fv
+case 5823: { // glProgramUniformMatrix2x3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6573,7 +6581,7 @@ case 5822: { // glProgramUniformMatrix2x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglProgramUniformMatrix2x3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5823: { // glProgramUniformMatrix3x2fv
+case 5824: { // glProgramUniformMatrix3x2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6582,7 +6590,7 @@ case 5823: { // glProgramUniformMatrix3x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*24;
weglProgramUniformMatrix3x2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5824: { // glProgramUniformMatrix2x4fv
+case 5825: { // glProgramUniformMatrix2x4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6591,7 +6599,7 @@ case 5824: { // glProgramUniformMatrix2x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglProgramUniformMatrix2x4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5825: { // glProgramUniformMatrix4x2fv
+case 5826: { // glProgramUniformMatrix4x2fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6600,7 +6608,7 @@ case 5825: { // glProgramUniformMatrix4x2fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*32;
weglProgramUniformMatrix4x2fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5826: { // glProgramUniformMatrix3x4fv
+case 5827: { // glProgramUniformMatrix3x4fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6609,7 +6617,7 @@ case 5826: { // glProgramUniformMatrix3x4fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglProgramUniformMatrix3x4fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5827: { // glProgramUniformMatrix4x3fv
+case 5828: { // glProgramUniformMatrix4x3fv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6618,7 +6626,7 @@ case 5827: { // glProgramUniformMatrix4x3fv
GLfloat * value = (GLfloat *) bp; bp += *valueLen*48;
weglProgramUniformMatrix4x3fv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5828: { // glProgramUniformMatrix2x3dv
+case 5829: { // glProgramUniformMatrix2x3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6627,7 +6635,7 @@ case 5828: { // glProgramUniformMatrix2x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglProgramUniformMatrix2x3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5829: { // glProgramUniformMatrix3x2dv
+case 5830: { // glProgramUniformMatrix3x2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6636,7 +6644,7 @@ case 5829: { // glProgramUniformMatrix3x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*48;
weglProgramUniformMatrix3x2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5830: { // glProgramUniformMatrix2x4dv
+case 5831: { // glProgramUniformMatrix2x4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6645,7 +6653,7 @@ case 5830: { // glProgramUniformMatrix2x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglProgramUniformMatrix2x4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5831: { // glProgramUniformMatrix4x2dv
+case 5832: { // glProgramUniformMatrix4x2dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6654,7 +6662,7 @@ case 5831: { // glProgramUniformMatrix4x2dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*64;
weglProgramUniformMatrix4x2dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5832: { // glProgramUniformMatrix3x4dv
+case 5833: { // glProgramUniformMatrix3x4dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6663,7 +6671,7 @@ case 5832: { // glProgramUniformMatrix3x4dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglProgramUniformMatrix3x4dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5833: { // glProgramUniformMatrix4x3dv
+case 5834: { // glProgramUniformMatrix4x3dv
GLuint *program = (GLuint *) bp; bp += 4;
GLint *location = (GLint *) bp; bp += 4;
GLboolean *transpose = (GLboolean *) bp; bp += 1;
@@ -6672,11 +6680,11 @@ case 5833: { // glProgramUniformMatrix4x3dv
GLdouble * value = (GLdouble *) bp; bp += *valueLen*96;
weglProgramUniformMatrix4x3dv(*program,*location,*valueLen,*transpose,value);
}; break;
-case 5834: { // glValidateProgramPipeline
+case 5835: { // glValidateProgramPipeline
GLuint *pipeline = (GLuint *) bp; bp += 4;
weglValidateProgramPipeline(*pipeline);
}; break;
-case 5835: { // glGetProgramPipelineInfoLog
+case 5836: { // glGetProgramPipelineInfoLog
GLuint *pipeline = (GLuint *) bp; bp += 4;
GLsizei *bufSize = (GLsizei *) bp; bp += 4;
GLsizei length[1] = {0};
@@ -6690,31 +6698,31 @@ case 5835: { // glGetProgramPipelineInfoLog
driver_send_term(port,caller,rt,AP);
driver_free(infoLog);
}; break;
-case 5836: { // glVertexAttribL1dv
+case 5837: { // glVertexAttribL1dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL1dv(*index,v);
}; break;
-case 5837: { // glVertexAttribL2dv
+case 5838: { // glVertexAttribL2dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL2dv(*index,v);
}; break;
-case 5838: { // glVertexAttribL3dv
+case 5839: { // glVertexAttribL3dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL3dv(*index,v);
}; break;
-case 5839: { // glVertexAttribL4dv
+case 5840: { // glVertexAttribL4dv
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLdouble *v = (GLdouble *) bp; bp += 8;
weglVertexAttribL4dv(*index,v);
}; break;
-case 5840: { // glVertexAttribLPointer
+case 5841: { // glVertexAttribLPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6722,7 +6730,7 @@ case 5840: { // glVertexAttribLPointer
GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4;
weglVertexAttribLPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5841: { // glVertexAttribLPointer
+case 5842: { // glVertexAttribLPointer
GLuint *index = (GLuint *) bp; bp += 4;
GLint *size = (GLint *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6730,7 +6738,7 @@ case 5841: { // glVertexAttribLPointer
GLvoid *pointer = (GLvoid *) bins[0];
weglVertexAttribLPointer(*index,*size,*type,*stride,pointer);
}; break;
-case 5842: { // glGetVertexAttribLdv
+case 5843: { // glGetVertexAttribLdv
GLuint *index = (GLuint *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
GLdouble params[4] = {0.0,0.0,0.0,0.0};
@@ -6746,13 +6754,13 @@ case 5842: { // glGetVertexAttribLdv
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5843: { // glViewportArrayv
+case 5844: { // glViewportArrayv
GLuint *first = (GLuint *) bp; bp += 4;
int *vLen = (int *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += *vLen*16;
weglViewportArrayv(*first,*vLen,v);
}; break;
-case 5844: { // glViewportIndexedf
+case 5845: { // glViewportIndexedf
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat *x = (GLfloat *) bp; bp += 4;
GLfloat *y = (GLfloat *) bp; bp += 4;
@@ -6760,18 +6768,18 @@ case 5844: { // glViewportIndexedf
GLfloat *h = (GLfloat *) bp; bp += 4;
weglViewportIndexedf(*index,*x,*y,*w,*h);
}; break;
-case 5845: { // glViewportIndexedfv
+case 5846: { // glViewportIndexedfv
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat * v = (GLfloat *) bp; bp += 16;
weglViewportIndexedfv(*index,v);
}; break;
-case 5846: { // glScissorArrayv
+case 5847: { // glScissorArrayv
GLuint *first = (GLuint *) bp; bp += 4;
int *vLen = (int *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += *vLen*16;
weglScissorArrayv(*first,*vLen,v);
}; break;
-case 5847: { // glScissorIndexed
+case 5848: { // glScissorIndexed
GLuint *index = (GLuint *) bp; bp += 4;
GLint *left = (GLint *) bp; bp += 4;
GLint *bottom = (GLint *) bp; bp += 4;
@@ -6779,26 +6787,26 @@ case 5847: { // glScissorIndexed
GLsizei *height = (GLsizei *) bp; bp += 4;
weglScissorIndexed(*index,*left,*bottom,*width,*height);
}; break;
-case 5848: { // glScissorIndexedv
+case 5849: { // glScissorIndexedv
GLuint *index = (GLuint *) bp; bp += 4;
GLint * v = (GLint *) bp; bp += 16;
weglScissorIndexedv(*index,v);
}; break;
-case 5849: { // glDepthRangeArrayv
+case 5850: { // glDepthRangeArrayv
GLuint *first = (GLuint *) bp; bp += 4;
bp += 4;
int *vLen = (int *) bp; bp += 8;
GLclampd * v = (GLclampd *) bp; bp += *vLen*16;
weglDepthRangeArrayv(*first,*vLen,v);
}; break;
-case 5850: { // glDepthRangeIndexed
+case 5851: { // glDepthRangeIndexed
GLuint *index = (GLuint *) bp; bp += 4;
bp += 4;
GLclampd *n = (GLclampd *) bp; bp += 8;
GLclampd *f = (GLclampd *) bp; bp += 8;
weglDepthRangeIndexed(*index,*n,*f);
}; break;
-case 5851: { // glGetFloati_v
+case 5852: { // glGetFloati_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLfloat data[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -6827,7 +6835,7 @@ case 5851: { // glGetFloati_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5852: { // glGetDoublei_v
+case 5853: { // glGetDoublei_v
GLenum *target = (GLenum *) bp; bp += 4;
GLuint *index = (GLuint *) bp; bp += 4;
GLdouble data[16] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
@@ -6855,16 +6863,16 @@ case 5852: { // glGetDoublei_v
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5853: { // glDebugMessageControlARB
+case 5854: { // glDebugMessageControlARB
GLenum *source = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLenum *severity = (GLenum *) bp; bp += 4;
int * idsLen = (int *) bp; bp += 4;
- GLuint * ids = (GLuint *) bp; bp += (8-((*idsLen*4+0)%8))%8;
+ GLuint * ids = (GLuint *) bp; bp += *idsLen*4 + (8-((*idsLen*4+0)%8))%8;
GLboolean *enabled = (GLboolean *) bp; bp += 1;
weglDebugMessageControlARB(*source,*type,*severity,*idsLen,ids,*enabled);
}; break;
-case 5854: { // glDebugMessageInsertARB
+case 5855: { // glDebugMessageInsertARB
GLenum *source = (GLenum *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
@@ -6873,7 +6881,7 @@ case 5854: { // glDebugMessageInsertARB
int bufLen[1] = {(int)strlen((char *)buf)}; bp += bufLen[0]+1+((8-((1+bufLen[0]+0)%8))%8);
weglDebugMessageInsertARB(*source,*type,*id,*severity,*bufLen,buf);
}; break;
-case 5855: { // glGetDebugMessageLogARB
+case 5856: { // glGetDebugMessageLogARB
GLuint *count = (GLuint *) bp; bp += 4;
GLsizei *bufsize = (GLsizei *) bp; bp += 4;
GLenum *sources;
@@ -6920,7 +6928,7 @@ case 5855: { // glGetDebugMessageLogARB
driver_free(types);
driver_free(sources);
}; break;
-case 5856: { // glGetGraphicsResetStatusARB
+case 5857: { // glGetGraphicsResetStatusARB
GLenum result = weglGetGraphicsResetStatusARB();
int AP = 0; ErlDrvTermData rt[6];
rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_");
@@ -6928,7 +6936,7 @@ case 5856: { // glGetGraphicsResetStatusARB
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2;
driver_send_term(port,caller,rt,AP);
}; break;
-case 5857: { // glDrawArraysInstancedBaseInstance
+case 5858: { // glDrawArraysInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLint *first = (GLint *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
@@ -6936,7 +6944,7 @@ case 5857: { // glDrawArraysInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawArraysInstancedBaseInstance(*mode,*first,*count,*primcount,*baseinstance);
}; break;
-case 5858: { // glDrawElementsInstancedBaseInstance
+case 5859: { // glDrawElementsInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6945,7 +6953,7 @@ case 5858: { // glDrawElementsInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseInstance(*mode,*count,*type,indices,*primcount,*baseinstance);
}; break;
-case 5859: { // glDrawElementsInstancedBaseInstance
+case 5860: { // glDrawElementsInstancedBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6954,7 +6962,7 @@ case 5859: { // glDrawElementsInstancedBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseInstance(*mode,*count,*type,indices,*primcount,*baseinstance);
}; break;
-case 5860: { // glDrawElementsInstancedBaseVertexBaseInstance
+case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6964,7 +6972,7 @@ case 5860: { // glDrawElementsInstancedBaseVertexBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertexBaseInstance(*mode,*count,*type,indices,*primcount,*basevertex,*baseinstance);
}; break;
-case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
+case 5862: { // glDrawElementsInstancedBaseVertexBaseInstance
GLenum *mode = (GLenum *) bp; bp += 4;
GLsizei *count = (GLsizei *) bp; bp += 4;
GLenum *type = (GLenum *) bp; bp += 4;
@@ -6974,20 +6982,20 @@ case 5861: { // glDrawElementsInstancedBaseVertexBaseInstance
GLuint *baseinstance = (GLuint *) bp; bp += 4;
weglDrawElementsInstancedBaseVertexBaseInstance(*mode,*count,*type,indices,*primcount,*basevertex,*baseinstance);
}; break;
-case 5862: { // glDrawTransformFeedbackInstanced
+case 5863: { // glDrawTransformFeedbackInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawTransformFeedbackInstanced(*mode,*id,*primcount);
}; break;
-case 5863: { // glDrawTransformFeedbackStreamInstanced
+case 5864: { // glDrawTransformFeedbackStreamInstanced
GLenum *mode = (GLenum *) bp; bp += 4;
GLuint *id = (GLuint *) bp; bp += 4;
GLuint *stream = (GLuint *) bp; bp += 4;
GLsizei *primcount = (GLsizei *) bp; bp += 4;
weglDrawTransformFeedbackStreamInstanced(*mode,*id,*stream,*primcount);
}; break;
-case 5864: { // glGetInternalformativ
+case 5865: { // glGetInternalformativ
GLenum *target = (GLenum *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLenum *pname = (GLenum *) bp; bp += 4;
@@ -7006,7 +7014,7 @@ case 5864: { // glGetInternalformativ
driver_free(rt);
driver_free(params);
}; break;
-case 5865: { // glBindImageTexture
+case 5866: { // glBindImageTexture
GLuint *unit = (GLuint *) bp; bp += 4;
GLuint *texture = (GLuint *) bp; bp += 4;
GLint *level = (GLint *) bp; bp += 4;
@@ -7017,18 +7025,18 @@ case 5865: { // glBindImageTexture
GLenum *format = (GLenum *) bp; bp += 4;
weglBindImageTexture(*unit,*texture,*level,*layered,*layer,*access,*format);
}; break;
-case 5866: { // glMemoryBarrier
+case 5867: { // glMemoryBarrier
GLbitfield *barriers = (GLbitfield *) bp; bp += 4;
weglMemoryBarrier(*barriers);
}; break;
-case 5867: { // glTexStorage1D
+case 5868: { // glTexStorage1D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
GLsizei *width = (GLsizei *) bp; bp += 4;
weglTexStorage1D(*target,*levels,*internalformat,*width);
}; break;
-case 5868: { // glTexStorage2D
+case 5869: { // glTexStorage2D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -7036,7 +7044,7 @@ case 5868: { // glTexStorage2D
GLsizei *height = (GLsizei *) bp; bp += 4;
weglTexStorage2D(*target,*levels,*internalformat,*width,*height);
}; break;
-case 5869: { // glTexStorage3D
+case 5870: { // glTexStorage3D
GLenum *target = (GLenum *) bp; bp += 4;
GLsizei *levels = (GLsizei *) bp; bp += 4;
GLenum *internalformat = (GLenum *) bp; bp += 4;
@@ -7045,12 +7053,12 @@ case 5869: { // glTexStorage3D
GLsizei *depth = (GLsizei *) bp; bp += 4;
weglTexStorage3D(*target,*levels,*internalformat,*width,*height,*depth);
}; break;
-case 5870: { // glDepthBoundsEXT
+case 5871: { // glDepthBoundsEXT
GLclampd *zmin = (GLclampd *) bp; bp += 8;
GLclampd *zmax = (GLclampd *) bp; bp += 8;
weglDepthBoundsEXT(*zmin,*zmax);
}; break;
-case 5871: { // glStencilClearTagEXT
+case 5872: { // glStencilClearTagEXT
GLsizei *stencilTagBits = (GLsizei *) bp; bp += 4;
GLuint *stencilClearTag = (GLuint *) bp; bp += 4;
weglStencilClearTagEXT(*stencilTagBits,*stencilClearTag);
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index b6d3c2db18..01787c8a64 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -910,7 +910,7 @@ case 238: {// wxDropFilesEvent
} else {
send_res = rt.send();
if(cb->skip) event->Skip();
- if(app->recurse_level < 1) {
+ if(app->recurse_level < 1 && Etype->cID != 168) {
app->recurse_level++;
app->dispatch_cmds();
app->recurse_level--;
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 70ff0a92b7..9086117c81 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -32,6 +32,35 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Allow string arguments to be binaries as specified, i.e.
+ unicode:chardata().</p>
+ <p>
+ Own Id: OTP-13934 Aux Id: ERL-270 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add wxWindow:dragAcceptFiles/2 and wxDropFilesEvent to
+ support simple drag and drop from file browser.</p>
+ <p>
+ Own Id: OTP-13933</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.7.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/src/gen/gl.erl b/lib/wx/src/gen/gl.erl
index 3780cca651..4a178ea1e4 100644
--- a/lib/wx/src/gen/gl.erl
+++ b/lib/wx/src/gen/gl.erl
@@ -2953,8 +2953,9 @@ callList(List) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCallLists.xml">external</a> documentation.
-spec callLists(Lists) -> 'ok' when Lists :: [integer()].
callLists(Lists) ->
- cast(5108, <<(length(Lists)):?GLuint,
- (<< <<C:?GLuint>> || C <- Lists>>)/binary,0:(((1+length(Lists)) rem 2)*32)>>).
+ ListsLen = length(Lists),
+ cast(5108, <<ListsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Lists>>)/binary,0:(((1+ListsLen) rem 2)*32)>>).
%% @doc set the display-list base for
%%
@@ -6949,8 +6950,9 @@ genTextures(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteTextures.xml">external</a> documentation.
-spec deleteTextures(Textures) -> 'ok' when Textures :: [integer()].
deleteTextures(Textures) ->
- cast(5272, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ cast(5272, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32)>>).
%% @doc Bind a named texture to a texturing target
%%
@@ -7030,9 +7032,11 @@ bindTexture(Target,Texture) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPrioritizeTextures.xml">external</a> documentation.
-spec prioritizeTextures(Textures, Priorities) -> 'ok' when Textures :: [integer()],Priorities :: [clamp()].
prioritizeTextures(Textures,Priorities) ->
- cast(5274, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32),(length(Priorities)):?GLuint,
- (<< <<C:?GLclampf>> || C <- Priorities>>)/binary,0:(((1+length(Priorities)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ PrioritiesLen = length(Priorities),
+ cast(5274, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32),PrioritiesLen:?GLuint,
+ (<< <<C:?GLclampf>> || C <- Priorities>>)/binary,0:(((1+PrioritiesLen) rem 2)*32)>>).
%% @doc Determine if textures are loaded in texture memory
%%
@@ -7056,8 +7060,9 @@ prioritizeTextures(Textures,Priorities) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAreTexturesResident.xml">external</a> documentation.
-spec areTexturesResident(Textures) -> {0|1,Residences :: [0|1]} when Textures :: [integer()].
areTexturesResident(Textures) ->
- call(5275, <<(length(Textures)):?GLuint,
- (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+length(Textures)) rem 2)*32)>>).
+ TexturesLen = length(Textures),
+ call(5275, <<TexturesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Textures>>)/binary,0:(((1+TexturesLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a texture
%%
@@ -9654,11 +9659,19 @@ blendFuncSeparate(SfactorRGB,DfactorRGB,SfactorAlpha,DfactorAlpha) ->
%%
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultiDrawArrays.xml">external</a> documentation.
--spec multiDrawArrays(Mode, First, Count) -> 'ok' when Mode :: enum(),First :: [integer()],Count :: [integer()].
+-spec multiDrawArrays(Mode, First, Count) -> 'ok' when Mode :: enum(),First :: [integer()]|mem(),Count :: [integer()]|mem().
+multiDrawArrays(Mode,First,Count) when is_list(First), is_list(Count) ->
+ FirstLen = length(First),
+ CountLen = length(Count),
+ cast(5395, <<Mode:?GLenum,FirstLen:?GLuint,
+ (<< <<C:?GLint>> || C <- First>>)/binary,0:(((FirstLen) rem 2)*32),CountLen:?GLuint,
+ (<< <<C:?GLsizei>> || C <- Count>>)/binary,0:(((1+CountLen) rem 2)*32)>>);
multiDrawArrays(Mode,First,Count) ->
- cast(5395, <<Mode:?GLenum,(length(First)):?GLuint,
- (<< <<C:?GLint>> || C <- First>>)/binary,0:(((length(First)) rem 2)*32),(length(Count)):?GLuint,
- (<< <<C:?GLsizei>> || C <- Count>>)/binary,0:(((1+length(Count)) rem 2)*32)>>).
+ send_bin(First),
+ FirstLen = byte_size(if is_binary(First) -> First; is_tuple(First) -> element(2, First) end) div 4,
+ send_bin(Count),
+ CountLen = byte_size(if is_binary(Count) -> Count; is_tuple(Count) -> element(2, Count) end) div 4,
+ cast(5396, <<Mode:?GLenum,FirstLen:?GLint,CountLen:?GLsizei>>).
%% @doc Specify point parameters
%%
@@ -9675,26 +9688,26 @@ multiDrawArrays(Mode,First,Count) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPointParameter.xml">external</a> documentation.
-spec pointParameterf(Pname, Param) -> 'ok' when Pname :: enum(),Param :: float().
pointParameterf(Pname,Param) ->
- cast(5396, <<Pname:?GLenum,Param:?GLfloat>>).
+ cast(5397, <<Pname:?GLenum,Param:?GLfloat>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameterfv(Pname, Params) -> 'ok' when Pname :: enum(),Params :: tuple().
pointParameterfv(Pname,Params) ->
- cast(5397, <<Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5398, <<Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLfloat>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameteri(Pname, Param) -> 'ok' when Pname :: enum(),Param :: integer().
pointParameteri(Pname,Param) ->
- cast(5398, <<Pname:?GLenum,Param:?GLint>>).
+ cast(5399, <<Pname:?GLenum,Param:?GLint>>).
%% @doc
%% See {@link pointParameterf/2}
-spec pointParameteriv(Pname, Params) -> 'ok' when Pname :: enum(),Params :: tuple().
pointParameteriv(Pname,Params) ->
- cast(5399, <<Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5400, <<Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((0+size(Params)) rem 2)*32)>>).
%% @doc Set the current fog coordinates
@@ -9706,7 +9719,7 @@ pointParameteriv(Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFogCoord.xml">external</a> documentation.
-spec fogCoordf(Coord) -> 'ok' when Coord :: float().
fogCoordf(Coord) ->
- cast(5400, <<Coord:?GLfloat>>).
+ cast(5401, <<Coord:?GLfloat>>).
%% @equiv fogCoordf(Coord)
-spec fogCoordfv(Coord) -> 'ok' when Coord :: {Coord :: float()}.
@@ -9716,7 +9729,7 @@ fogCoordfv({Coord}) -> fogCoordf(Coord).
%% See {@link fogCoordf/1}
-spec fogCoordd(Coord) -> 'ok' when Coord :: float().
fogCoordd(Coord) ->
- cast(5401, <<Coord:?GLdouble>>).
+ cast(5402, <<Coord:?GLdouble>>).
%% @equiv fogCoordd(Coord)
-spec fogCoorddv(Coord) -> 'ok' when Coord :: {Coord :: float()}.
@@ -9747,10 +9760,10 @@ fogCoorddv({Coord}) -> fogCoordd(Coord).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFogCoordPointer.xml">external</a> documentation.
-spec fogCoordPointer(Type, Stride, Pointer) -> 'ok' when Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
fogCoordPointer(Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5402, <<Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5403, <<Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
fogCoordPointer(Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5403, <<Type:?GLenum,Stride:?GLsizei>>).
+ cast(5404, <<Type:?GLenum,Stride:?GLsizei>>).
%% @doc Set the current secondary color
%%
@@ -9784,7 +9797,7 @@ fogCoordPointer(Type,Stride,Pointer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSecondaryColor.xml">external</a> documentation.
-spec secondaryColor3b(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3b(Red,Green,Blue) ->
- cast(5404, <<Red:?GLbyte,Green:?GLbyte,Blue:?GLbyte>>).
+ cast(5405, <<Red:?GLbyte,Green:?GLbyte,Blue:?GLbyte>>).
%% @equiv secondaryColor3b(Red,Green,Blue)
-spec secondaryColor3bv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9794,7 +9807,7 @@ secondaryColor3bv({Red,Green,Blue}) -> secondaryColor3b(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3d(Red, Green, Blue) -> 'ok' when Red :: float(),Green :: float(),Blue :: float().
secondaryColor3d(Red,Green,Blue) ->
- cast(5405, <<Red:?GLdouble,Green:?GLdouble,Blue:?GLdouble>>).
+ cast(5406, <<Red:?GLdouble,Green:?GLdouble,Blue:?GLdouble>>).
%% @equiv secondaryColor3d(Red,Green,Blue)
-spec secondaryColor3dv(V) -> 'ok' when V :: {Red :: float(),Green :: float(),Blue :: float()}.
@@ -9804,7 +9817,7 @@ secondaryColor3dv({Red,Green,Blue}) -> secondaryColor3d(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3f(Red, Green, Blue) -> 'ok' when Red :: float(),Green :: float(),Blue :: float().
secondaryColor3f(Red,Green,Blue) ->
- cast(5406, <<Red:?GLfloat,Green:?GLfloat,Blue:?GLfloat>>).
+ cast(5407, <<Red:?GLfloat,Green:?GLfloat,Blue:?GLfloat>>).
%% @equiv secondaryColor3f(Red,Green,Blue)
-spec secondaryColor3fv(V) -> 'ok' when V :: {Red :: float(),Green :: float(),Blue :: float()}.
@@ -9814,7 +9827,7 @@ secondaryColor3fv({Red,Green,Blue}) -> secondaryColor3f(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3i(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3i(Red,Green,Blue) ->
- cast(5407, <<Red:?GLint,Green:?GLint,Blue:?GLint>>).
+ cast(5408, <<Red:?GLint,Green:?GLint,Blue:?GLint>>).
%% @equiv secondaryColor3i(Red,Green,Blue)
-spec secondaryColor3iv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9824,7 +9837,7 @@ secondaryColor3iv({Red,Green,Blue}) -> secondaryColor3i(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3s(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3s(Red,Green,Blue) ->
- cast(5408, <<Red:?GLshort,Green:?GLshort,Blue:?GLshort>>).
+ cast(5409, <<Red:?GLshort,Green:?GLshort,Blue:?GLshort>>).
%% @equiv secondaryColor3s(Red,Green,Blue)
-spec secondaryColor3sv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9834,7 +9847,7 @@ secondaryColor3sv({Red,Green,Blue}) -> secondaryColor3s(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3ub(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3ub(Red,Green,Blue) ->
- cast(5409, <<Red:?GLubyte,Green:?GLubyte,Blue:?GLubyte>>).
+ cast(5410, <<Red:?GLubyte,Green:?GLubyte,Blue:?GLubyte>>).
%% @equiv secondaryColor3ub(Red,Green,Blue)
-spec secondaryColor3ubv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9844,7 +9857,7 @@ secondaryColor3ubv({Red,Green,Blue}) -> secondaryColor3ub(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3ui(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3ui(Red,Green,Blue) ->
- cast(5410, <<Red:?GLuint,Green:?GLuint,Blue:?GLuint>>).
+ cast(5411, <<Red:?GLuint,Green:?GLuint,Blue:?GLuint>>).
%% @equiv secondaryColor3ui(Red,Green,Blue)
-spec secondaryColor3uiv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9854,7 +9867,7 @@ secondaryColor3uiv({Red,Green,Blue}) -> secondaryColor3ui(Red,Green,Blue).
%% See {@link secondaryColor3b/3}
-spec secondaryColor3us(Red, Green, Blue) -> 'ok' when Red :: integer(),Green :: integer(),Blue :: integer().
secondaryColor3us(Red,Green,Blue) ->
- cast(5411, <<Red:?GLushort,Green:?GLushort,Blue:?GLushort>>).
+ cast(5412, <<Red:?GLushort,Green:?GLushort,Blue:?GLushort>>).
%% @equiv secondaryColor3us(Red,Green,Blue)
-spec secondaryColor3usv(V) -> 'ok' when V :: {Red :: integer(),Green :: integer(),Blue :: integer()}.
@@ -9887,10 +9900,10 @@ secondaryColor3usv({Red,Green,Blue}) -> secondaryColor3us(Red,Green,Blue).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSecondaryColorPointer.xml">external</a> documentation.
-spec secondaryColorPointer(Size, Type, Stride, Pointer) -> 'ok' when Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
secondaryColorPointer(Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5412, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5413, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
secondaryColorPointer(Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5413, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5414, <<Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc Specify the raster position in window coordinates for pixel operations
%%
@@ -9933,7 +9946,7 @@ secondaryColorPointer(Size,Type,Stride,Pointer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWindowPos.xml">external</a> documentation.
-spec windowPos2d(X, Y) -> 'ok' when X :: float(),Y :: float().
windowPos2d(X,Y) ->
- cast(5414, <<X:?GLdouble,Y:?GLdouble>>).
+ cast(5415, <<X:?GLdouble,Y:?GLdouble>>).
%% @equiv windowPos2d(X,Y)
-spec windowPos2dv(V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -9943,7 +9956,7 @@ windowPos2dv({X,Y}) -> windowPos2d(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2f(X, Y) -> 'ok' when X :: float(),Y :: float().
windowPos2f(X,Y) ->
- cast(5415, <<X:?GLfloat,Y:?GLfloat>>).
+ cast(5416, <<X:?GLfloat,Y:?GLfloat>>).
%% @equiv windowPos2f(X,Y)
-spec windowPos2fv(V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -9953,7 +9966,7 @@ windowPos2fv({X,Y}) -> windowPos2f(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2i(X, Y) -> 'ok' when X :: integer(),Y :: integer().
windowPos2i(X,Y) ->
- cast(5416, <<X:?GLint,Y:?GLint>>).
+ cast(5417, <<X:?GLint,Y:?GLint>>).
%% @equiv windowPos2i(X,Y)
-spec windowPos2iv(V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -9963,7 +9976,7 @@ windowPos2iv({X,Y}) -> windowPos2i(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos2s(X, Y) -> 'ok' when X :: integer(),Y :: integer().
windowPos2s(X,Y) ->
- cast(5417, <<X:?GLshort,Y:?GLshort>>).
+ cast(5418, <<X:?GLshort,Y:?GLshort>>).
%% @equiv windowPos2s(X,Y)
-spec windowPos2sv(V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -9973,7 +9986,7 @@ windowPos2sv({X,Y}) -> windowPos2s(X,Y).
%% See {@link windowPos2d/2}
-spec windowPos3d(X, Y, Z) -> 'ok' when X :: float(),Y :: float(),Z :: float().
windowPos3d(X,Y,Z) ->
- cast(5418, <<X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5419, <<X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @equiv windowPos3d(X,Y,Z)
-spec windowPos3dv(V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -9983,7 +9996,7 @@ windowPos3dv({X,Y,Z}) -> windowPos3d(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3f(X, Y, Z) -> 'ok' when X :: float(),Y :: float(),Z :: float().
windowPos3f(X,Y,Z) ->
- cast(5419, <<X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
+ cast(5420, <<X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
%% @equiv windowPos3f(X,Y,Z)
-spec windowPos3fv(V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -9993,7 +10006,7 @@ windowPos3fv({X,Y,Z}) -> windowPos3f(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3i(X, Y, Z) -> 'ok' when X :: integer(),Y :: integer(),Z :: integer().
windowPos3i(X,Y,Z) ->
- cast(5420, <<X:?GLint,Y:?GLint,Z:?GLint>>).
+ cast(5421, <<X:?GLint,Y:?GLint,Z:?GLint>>).
%% @equiv windowPos3i(X,Y,Z)
-spec windowPos3iv(V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -10003,7 +10016,7 @@ windowPos3iv({X,Y,Z}) -> windowPos3i(X,Y,Z).
%% See {@link windowPos2d/2}
-spec windowPos3s(X, Y, Z) -> 'ok' when X :: integer(),Y :: integer(),Z :: integer().
windowPos3s(X,Y,Z) ->
- cast(5421, <<X:?GLshort,Y:?GLshort,Z:?GLshort>>).
+ cast(5422, <<X:?GLshort,Y:?GLshort,Z:?GLshort>>).
%% @equiv windowPos3s(X,Y,Z)
-spec windowPos3sv(V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -10024,7 +10037,7 @@ windowPos3sv({X,Y,Z}) -> windowPos3s(X,Y,Z).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenQueries.xml">external</a> documentation.
-spec genQueries(N) -> [integer()] when N :: integer().
genQueries(N) ->
- call(5422, <<N:?GLsizei>>).
+ call(5423, <<N:?GLsizei>>).
%% @doc Delete named query objects
%%
@@ -10038,8 +10051,9 @@ genQueries(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteQueries.xml">external</a> documentation.
-spec deleteQueries(Ids) -> 'ok' when Ids :: [integer()].
deleteQueries(Ids) ->
- cast(5423, <<(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+length(Ids)) rem 2)*32)>>).
+ IdsLen = length(Ids),
+ cast(5424, <<IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+IdsLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a query object
%%
@@ -10053,7 +10067,7 @@ deleteQueries(Ids) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsQuery.xml">external</a> documentation.
-spec isQuery(Id) -> 0|1 when Id :: integer().
isQuery(Id) ->
- call(5424, <<Id:?GLuint>>).
+ call(5425, <<Id:?GLuint>>).
%% @doc Delimit the boundaries of a query object
%%
@@ -10120,20 +10134,20 @@ isQuery(Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQuery.xml">external</a> documentation.
-spec beginQuery(Target, Id) -> 'ok' when Target :: enum(),Id :: integer().
beginQuery(Target,Id) ->
- cast(5425, <<Target:?GLenum,Id:?GLuint>>).
+ cast(5426, <<Target:?GLenum,Id:?GLuint>>).
%% @doc
%% See {@link beginQuery/2}
-spec endQuery(Target) -> 'ok' when Target :: enum().
endQuery(Target) ->
- cast(5426, <<Target:?GLenum>>).
+ cast(5427, <<Target:?GLenum>>).
%% @doc glGetQuery
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQuery.xml">external</a> documentation.
-spec getQueryiv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getQueryiv(Target,Pname) ->
- call(5427, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5428, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Return parameters of a query object
%%
@@ -10153,13 +10167,13 @@ getQueryiv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObject.xml">external</a> documentation.
-spec getQueryObjectiv(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectiv(Id,Pname) ->
- call(5428, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5429, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getQueryObjectiv/2}
-spec getQueryObjectuiv(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectuiv(Id,Pname) ->
- call(5429, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5430, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc Bind a named buffer object
%%
@@ -10242,7 +10256,7 @@ getQueryObjectuiv(Id,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBuffer.xml">external</a> documentation.
-spec bindBuffer(Target, Buffer) -> 'ok' when Target :: enum(),Buffer :: integer().
bindBuffer(Target,Buffer) ->
- cast(5430, <<Target:?GLenum,Buffer:?GLuint>>).
+ cast(5431, <<Target:?GLenum,Buffer:?GLuint>>).
%% @doc Delete named buffer objects
%%
@@ -10257,8 +10271,9 @@ bindBuffer(Target,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteBuffers.xml">external</a> documentation.
-spec deleteBuffers(Buffers) -> 'ok' when Buffers :: [integer()].
deleteBuffers(Buffers) ->
- cast(5431, <<(length(Buffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Buffers>>)/binary,0:(((1+length(Buffers)) rem 2)*32)>>).
+ BuffersLen = length(Buffers),
+ cast(5432, <<BuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Buffers>>)/binary,0:(((1+BuffersLen) rem 2)*32)>>).
%% @doc Generate buffer object names
%%
@@ -10276,7 +10291,7 @@ deleteBuffers(Buffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenBuffers.xml">external</a> documentation.
-spec genBuffers(N) -> [integer()] when N :: integer().
genBuffers(N) ->
- call(5432, <<N:?GLsizei>>).
+ call(5433, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a buffer object
%%
@@ -10291,7 +10306,7 @@ genBuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsBuffer.xml">external</a> documentation.
-spec isBuffer(Buffer) -> 0|1 when Buffer :: integer().
isBuffer(Buffer) ->
- call(5433, <<Buffer:?GLuint>>).
+ call(5434, <<Buffer:?GLuint>>).
%% @doc Creates and initializes a buffer object's data store
%%
@@ -10329,10 +10344,10 @@ isBuffer(Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBufferData.xml">external</a> documentation.
-spec bufferData(Target, Size, Data, Usage) -> 'ok' when Target :: enum(),Size :: integer(),Data :: offset()|mem(),Usage :: enum().
bufferData(Target,Size,Data,Usage) when is_integer(Data) ->
- cast(5434, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Data:?GLuint,Usage:?GLenum>>);
+ cast(5435, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Data:?GLuint,Usage:?GLenum>>);
bufferData(Target,Size,Data,Usage) ->
send_bin(Data),
- cast(5435, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Usage:?GLenum>>).
+ cast(5436, <<Target:?GLenum,0:32,Size:?GLsizeiptr,Usage:?GLenum>>).
%% @doc Updates a subset of a buffer object's data store
%%
@@ -10345,10 +10360,10 @@ bufferData(Target,Size,Data,Usage) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBufferSubData.xml">external</a> documentation.
-spec bufferSubData(Target, Offset, Size, Data) -> 'ok' when Target :: enum(),Offset :: integer(),Size :: integer(),Data :: offset()|mem().
bufferSubData(Target,Offset,Size,Data) when is_integer(Data) ->
- cast(5436, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr,Data:?GLuint>>);
+ cast(5437, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr,Data:?GLuint>>);
bufferSubData(Target,Offset,Size,Data) ->
send_bin(Data),
- cast(5437, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5438, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Returns a subset of a buffer object's data store
%%
@@ -10362,7 +10377,7 @@ bufferSubData(Target,Offset,Size,Data) ->
-spec getBufferSubData(Target, Offset, Size, Data) -> 'ok' when Target :: enum(),Offset :: integer(),Size :: integer(),Data :: mem().
getBufferSubData(Target,Offset,Size,Data) ->
send_bin(Data),
- call(5438, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ call(5439, <<Target:?GLenum,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Return parameters of a buffer object
%%
@@ -10386,7 +10401,7 @@ getBufferSubData(Target,Offset,Size,Data) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameteriv.xml">external</a> documentation.
-spec getBufferParameteriv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getBufferParameteriv(Target,Pname) ->
- call(5439, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5440, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Set the RGB blend equation and the alpha blend equation separately
%%
@@ -10428,7 +10443,7 @@ getBufferParameteriv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlendEquationSeparate.xml">external</a> documentation.
-spec blendEquationSeparate(ModeRGB, ModeAlpha) -> 'ok' when ModeRGB :: enum(),ModeAlpha :: enum().
blendEquationSeparate(ModeRGB,ModeAlpha) ->
- cast(5440, <<ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
+ cast(5441, <<ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
%% @doc Specifies a list of color buffers to be drawn into
%%
@@ -10468,8 +10483,9 @@ blendEquationSeparate(ModeRGB,ModeAlpha) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawBuffers.xml">external</a> documentation.
-spec drawBuffers(Bufs) -> 'ok' when Bufs :: [enum()].
drawBuffers(Bufs) ->
- cast(5441, <<(length(Bufs)):?GLuint,
- (<< <<C:?GLenum>> || C <- Bufs>>)/binary,0:(((1+length(Bufs)) rem 2)*32)>>).
+ BufsLen = length(Bufs),
+ cast(5442, <<BufsLen:?GLuint,
+ (<< <<C:?GLenum>> || C <- Bufs>>)/binary,0:(((1+BufsLen) rem 2)*32)>>).
%% @doc Set front and/or back stencil test actions
%%
@@ -10530,7 +10546,7 @@ drawBuffers(Bufs) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilOpSeparate.xml">external</a> documentation.
-spec stencilOpSeparate(Face, Sfail, Dpfail, Dppass) -> 'ok' when Face :: enum(),Sfail :: enum(),Dpfail :: enum(),Dppass :: enum().
stencilOpSeparate(Face,Sfail,Dpfail,Dppass) ->
- cast(5442, <<Face:?GLenum,Sfail:?GLenum,Dpfail:?GLenum,Dppass:?GLenum>>).
+ cast(5443, <<Face:?GLenum,Sfail:?GLenum,Dpfail:?GLenum,Dppass:?GLenum>>).
%% @doc Set front and/or back function and reference value for stencil testing
%%
@@ -10593,7 +10609,7 @@ stencilOpSeparate(Face,Sfail,Dpfail,Dppass) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilFuncSeparate.xml">external</a> documentation.
-spec stencilFuncSeparate(Face, Func, Ref, Mask) -> 'ok' when Face :: enum(),Func :: enum(),Ref :: integer(),Mask :: integer().
stencilFuncSeparate(Face,Func,Ref,Mask) ->
- cast(5443, <<Face:?GLenum,Func:?GLenum,Ref:?GLint,Mask:?GLuint>>).
+ cast(5444, <<Face:?GLenum,Func:?GLenum,Ref:?GLint,Mask:?GLuint>>).
%% @doc Control the front and/or back writing of individual bits in the stencil planes
%%
@@ -10611,7 +10627,7 @@ stencilFuncSeparate(Face,Func,Ref,Mask) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilMaskSeparate.xml">external</a> documentation.
-spec stencilMaskSeparate(Face, Mask) -> 'ok' when Face :: enum(),Mask :: integer().
stencilMaskSeparate(Face,Mask) ->
- cast(5444, <<Face:?GLenum,Mask:?GLuint>>).
+ cast(5445, <<Face:?GLenum,Mask:?GLuint>>).
%% @doc Attaches a shader object to a program object
%%
@@ -10635,7 +10651,7 @@ stencilMaskSeparate(Face,Mask) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAttachShader.xml">external</a> documentation.
-spec attachShader(Program, Shader) -> 'ok' when Program :: integer(),Shader :: integer().
attachShader(Program,Shader) ->
- cast(5445, <<Program:?GLuint,Shader:?GLuint>>).
+ cast(5446, <<Program:?GLuint,Shader:?GLuint>>).
%% @doc Associates a generic vertex attribute index with a named attribute variable
%%
@@ -10672,7 +10688,8 @@ attachShader(Program,Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindAttribLocation.xml">external</a> documentation.
-spec bindAttribLocation(Program, Index, Name) -> 'ok' when Program :: integer(),Index :: integer(),Name :: string().
bindAttribLocation(Program,Index,Name) ->
- cast(5446, <<Program:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5447, <<Program:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Compiles a shader object
%%
@@ -10692,7 +10709,7 @@ bindAttribLocation(Program,Index,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShader.xml">external</a> documentation.
-spec compileShader(Shader) -> 'ok' when Shader :: integer().
compileShader(Shader) ->
- cast(5447, <<Shader:?GLuint>>).
+ cast(5448, <<Shader:?GLuint>>).
%% @doc Creates a program object
%%
@@ -10715,7 +10732,7 @@ compileShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateProgram.xml">external</a> documentation.
-spec createProgram() -> integer().
createProgram() ->
- call(5448, <<>>).
+ call(5449, <<>>).
%% @doc Creates a shader object
%%
@@ -10738,7 +10755,7 @@ createProgram() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShader.xml">external</a> documentation.
-spec createShader(Type) -> integer() when Type :: enum().
createShader(Type) ->
- call(5449, <<Type:?GLenum>>).
+ call(5450, <<Type:?GLenum>>).
%% @doc Deletes a program object
%%
@@ -10759,7 +10776,7 @@ createShader(Type) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgram.xml">external</a> documentation.
-spec deleteProgram(Program) -> 'ok' when Program :: integer().
deleteProgram(Program) ->
- cast(5450, <<Program:?GLuint>>).
+ cast(5451, <<Program:?GLuint>>).
%% @doc Deletes a shader object
%%
@@ -10778,7 +10795,7 @@ deleteProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteShader.xml">external</a> documentation.
-spec deleteShader(Shader) -> 'ok' when Shader :: integer().
deleteShader(Shader) ->
- cast(5451, <<Shader:?GLuint>>).
+ cast(5452, <<Shader:?GLuint>>).
%% @doc Detaches a shader object from a program object to which it is attached
%%
@@ -10793,7 +10810,7 @@ deleteShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDetachShader.xml">external</a> documentation.
-spec detachShader(Program, Shader) -> 'ok' when Program :: integer(),Shader :: integer().
detachShader(Program,Shader) ->
- cast(5452, <<Program:?GLuint,Shader:?GLuint>>).
+ cast(5453, <<Program:?GLuint,Shader:?GLuint>>).
%% @doc Enable or disable a generic vertex attribute array
%%
@@ -10808,13 +10825,13 @@ detachShader(Program,Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml">external</a> documentation.
-spec disableVertexAttribArray(Index) -> 'ok' when Index :: integer().
disableVertexAttribArray(Index) ->
- cast(5453, <<Index:?GLuint>>).
+ cast(5454, <<Index:?GLuint>>).
%% @doc
%% See {@link disableVertexAttribArray/1}
-spec enableVertexAttribArray(Index) -> 'ok' when Index :: integer().
enableVertexAttribArray(Index) ->
- cast(5454, <<Index:?GLuint>>).
+ cast(5455, <<Index:?GLuint>>).
%% @doc Returns information about an active attribute variable for the specified program object
%%
@@ -10872,7 +10889,7 @@ enableVertexAttribArray(Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttrib.xml">external</a> documentation.
-spec getActiveAttrib(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getActiveAttrib(Program,Index,BufSize) ->
- call(5455, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5456, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns information about an active uniform variable for the specified program object
%%
@@ -11019,7 +11036,7 @@ getActiveAttrib(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniform.xml">external</a> documentation.
-spec getActiveUniform(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getActiveUniform(Program,Index,BufSize) ->
- call(5456, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5457, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the handles of the shader objects attached to a program object
%%
@@ -11039,7 +11056,7 @@ getActiveUniform(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttachedShaders.xml">external</a> documentation.
-spec getAttachedShaders(Program, MaxCount) -> [integer()] when Program :: integer(),MaxCount :: integer().
getAttachedShaders(Program,MaxCount) ->
- call(5457, <<Program:?GLuint,MaxCount:?GLsizei>>).
+ call(5458, <<Program:?GLuint,MaxCount:?GLsizei>>).
%% @doc Returns the location of an attribute variable
%%
@@ -11063,7 +11080,8 @@ getAttachedShaders(Program,MaxCount) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttribLocation.xml">external</a> documentation.
-spec getAttribLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getAttribLocation(Program,Name) ->
- call(5458, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5459, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Returns a parameter from a program object
%%
@@ -11134,7 +11152,7 @@ getAttribLocation(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgram.xml">external</a> documentation.
-spec getProgramiv(Program, Pname) -> integer() when Program :: integer(),Pname :: enum().
getProgramiv(Program,Pname) ->
- call(5459, <<Program:?GLuint,Pname:?GLenum>>).
+ call(5460, <<Program:?GLuint,Pname:?GLenum>>).
%% @doc Returns the information log for a program object
%%
@@ -11159,7 +11177,7 @@ getProgramiv(Program,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramInfoLog.xml">external</a> documentation.
-spec getProgramInfoLog(Program, BufSize) -> string() when Program :: integer(),BufSize :: integer().
getProgramInfoLog(Program,BufSize) ->
- call(5460, <<Program:?GLuint,BufSize:?GLsizei>>).
+ call(5461, <<Program:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns a parameter from a shader object
%%
@@ -11190,7 +11208,7 @@ getProgramInfoLog(Program,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShader.xml">external</a> documentation.
-spec getShaderiv(Shader, Pname) -> integer() when Shader :: integer(),Pname :: enum().
getShaderiv(Shader,Pname) ->
- call(5461, <<Shader:?GLuint,Pname:?GLenum>>).
+ call(5462, <<Shader:?GLuint,Pname:?GLenum>>).
%% @doc Returns the information log for a shader object
%%
@@ -11213,7 +11231,7 @@ getShaderiv(Shader,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderInfoLog.xml">external</a> documentation.
-spec getShaderInfoLog(Shader, BufSize) -> string() when Shader :: integer(),BufSize :: integer().
getShaderInfoLog(Shader,BufSize) ->
- call(5462, <<Shader:?GLuint,BufSize:?GLsizei>>).
+ call(5463, <<Shader:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the source code string from a shader object
%%
@@ -11233,7 +11251,7 @@ getShaderInfoLog(Shader,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderSource.xml">external</a> documentation.
-spec getShaderSource(Shader, BufSize) -> string() when Shader :: integer(),BufSize :: integer().
getShaderSource(Shader,BufSize) ->
- call(5463, <<Shader:?GLuint,BufSize:?GLsizei>>).
+ call(5464, <<Shader:?GLuint,BufSize:?GLsizei>>).
%% @doc Returns the location of a uniform variable
%%
@@ -11266,7 +11284,8 @@ getShaderSource(Shader,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml">external</a> documentation.
-spec getUniformLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getUniformLocation(Program,Name) ->
- call(5464, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5465, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Returns the value of a uniform variable
%%
@@ -11292,13 +11311,13 @@ getUniformLocation(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniform.xml">external</a> documentation.
-spec getUniformfv(Program, Location) -> matrix() when Program :: integer(),Location :: integer().
getUniformfv(Program,Location) ->
- call(5465, <<Program:?GLuint,Location:?GLint>>).
+ call(5466, <<Program:?GLuint,Location:?GLint>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformiv(Program, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Program :: integer(),Location :: integer().
getUniformiv(Program,Location) ->
- call(5466, <<Program:?GLuint,Location:?GLint>>).
+ call(5467, <<Program:?GLuint,Location:?GLint>>).
%% @doc Return a generic vertex attribute parameter
%%
@@ -11365,19 +11384,19 @@ getUniformiv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttrib.xml">external</a> documentation.
-spec getVertexAttribdv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribdv(Index,Pname) ->
- call(5467, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5468, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribfv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribfv(Index,Pname) ->
- call(5468, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5469, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribiv(Index,Pname) ->
- call(5469, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5470, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc Determines if a name corresponds to a program object
%%
@@ -11389,7 +11408,7 @@ getVertexAttribiv(Index,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsProgram.xml">external</a> documentation.
-spec isProgram(Program) -> 0|1 when Program :: integer().
isProgram(Program) ->
- call(5470, <<Program:?GLuint>>).
+ call(5471, <<Program:?GLuint>>).
%% @doc Determines if a name corresponds to a shader object
%%
@@ -11401,7 +11420,7 @@ isProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsShader.xml">external</a> documentation.
-spec isShader(Shader) -> 0|1 when Shader :: integer().
isShader(Shader) ->
- call(5471, <<Shader:?GLuint>>).
+ call(5472, <<Shader:?GLuint>>).
%% @doc Links a program object
%%
@@ -11521,7 +11540,7 @@ isShader(Shader) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLinkProgram.xml">external</a> documentation.
-spec linkProgram(Program) -> 'ok' when Program :: integer().
linkProgram(Program) ->
- cast(5472, <<Program:?GLuint>>).
+ cast(5473, <<Program:?GLuint>>).
%% @doc Replaces the source code in a shader object
%%
@@ -11539,8 +11558,9 @@ linkProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSource.xml">external</a> documentation.
-spec shaderSource(Shader, String) -> 'ok' when Shader :: integer(),String :: iolist().
shaderSource(Shader,String) ->
- StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
- cast(5473, <<Shader:?GLuint,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+0) rem 8)) rem 8)>>).
+ StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
+ StringLen = length(String),
+ cast(5474, <<Shader:?GLuint,StringLen:?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+0) rem 8)) rem 8)>>).
%% @doc Installs a program object as part of current rendering state
%%
@@ -11581,7 +11601,7 @@ shaderSource(Shader,String) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgram.xml">external</a> documentation.
-spec useProgram(Program) -> 'ok' when Program :: integer().
useProgram(Program) ->
- cast(5474, <<Program:?GLuint>>).
+ cast(5475, <<Program:?GLuint>>).
%% @doc Specify the value of a uniform variable for the current program object
%%
@@ -11649,125 +11669,136 @@ useProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniform.xml">external</a> documentation.
-spec uniform1f(Location, V0) -> 'ok' when Location :: integer(),V0 :: float().
uniform1f(Location,V0) ->
- cast(5475, <<Location:?GLint,V0:?GLfloat>>).
+ cast(5476, <<Location:?GLint,V0:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2f(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float().
uniform2f(Location,V0,V1) ->
- cast(5476, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
+ cast(5477, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3f(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
uniform3f(Location,V0,V1,V2) ->
- cast(5477, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
+ cast(5478, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4f(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
uniform4f(Location,V0,V1,V2,V3) ->
- cast(5478, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
+ cast(5479, <<Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1i(Location, V0) -> 'ok' when Location :: integer(),V0 :: integer().
uniform1i(Location,V0) ->
- cast(5479, <<Location:?GLint,V0:?GLint>>).
+ cast(5480, <<Location:?GLint,V0:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2i(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer().
uniform2i(Location,V0,V1) ->
- cast(5480, <<Location:?GLint,V0:?GLint,V1:?GLint>>).
+ cast(5481, <<Location:?GLint,V0:?GLint,V1:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3i(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
uniform3i(Location,V0,V1,V2) ->
- cast(5481, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
+ cast(5482, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4i(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
uniform4i(Location,V0,V1,V2,V3) ->
- cast(5482, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
+ cast(5483, <<Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [float()].
uniform1fv(Location,Value) ->
- cast(5483, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5484, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float()}].
uniform2fv(Location,Value) ->
- cast(5484, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5485, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float()}].
uniform3fv(Location,Value) ->
- cast(5485, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5486, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4fv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float(),float()}].
uniform4fv(Location,Value) ->
- cast(5486, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5487, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [integer()].
uniform1iv(Location,Value) ->
- cast(5487, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5488, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer()}].
uniform2iv(Location,Value) ->
- cast(5488, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5489, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer()}].
uniform3iv(Location,Value) ->
- cast(5489, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5490, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4iv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
uniform4iv(Location,Value) ->
- cast(5490, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5491, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
uniformMatrix2fv(Location,Transpose,Value) ->
- cast(5491, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5492, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3fv(Location,Transpose,Value) ->
- cast(5492, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5493, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4fv(Location,Transpose,Value) ->
- cast(5493, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5494, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat,V13:?GLfloat,V14:?GLfloat,V15:?GLfloat,V16:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc Validates a program object
@@ -11795,7 +11826,7 @@ uniformMatrix4fv(Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgram.xml">external</a> documentation.
-spec validateProgram(Program) -> 'ok' when Program :: integer().
validateProgram(Program) ->
- cast(5494, <<Program:?GLuint>>).
+ cast(5495, <<Program:?GLuint>>).
%% @doc Specifies the value of a generic vertex attribute
%%
@@ -11870,7 +11901,7 @@ validateProgram(Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttrib.xml">external</a> documentation.
-spec vertexAttrib1d(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttrib1d(Index,X) ->
- cast(5495, <<Index:?GLuint,0:32,X:?GLdouble>>).
+ cast(5496, <<Index:?GLuint,0:32,X:?GLdouble>>).
%% @equiv vertexAttrib1d(Index,X)
-spec vertexAttrib1dv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -11880,7 +11911,7 @@ vertexAttrib1dv(Index,{X}) -> vertexAttrib1d(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib1f(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttrib1f(Index,X) ->
- cast(5496, <<Index:?GLuint,X:?GLfloat>>).
+ cast(5497, <<Index:?GLuint,X:?GLfloat>>).
%% @equiv vertexAttrib1f(Index,X)
-spec vertexAttrib1fv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -11890,7 +11921,7 @@ vertexAttrib1fv(Index,{X}) -> vertexAttrib1f(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib1s(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttrib1s(Index,X) ->
- cast(5497, <<Index:?GLuint,X:?GLshort>>).
+ cast(5498, <<Index:?GLuint,X:?GLshort>>).
%% @equiv vertexAttrib1s(Index,X)
-spec vertexAttrib1sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer()}.
@@ -11900,7 +11931,7 @@ vertexAttrib1sv(Index,{X}) -> vertexAttrib1s(Index,X).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2d(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttrib2d(Index,X,Y) ->
- cast(5498, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5499, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @equiv vertexAttrib2d(Index,X,Y)
-spec vertexAttrib2dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -11910,7 +11941,7 @@ vertexAttrib2dv(Index,{X,Y}) -> vertexAttrib2d(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2f(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttrib2f(Index,X,Y) ->
- cast(5499, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat>>).
+ cast(5500, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat>>).
%% @equiv vertexAttrib2f(Index,X,Y)
-spec vertexAttrib2fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float()}.
@@ -11920,7 +11951,7 @@ vertexAttrib2fv(Index,{X,Y}) -> vertexAttrib2f(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib2s(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttrib2s(Index,X,Y) ->
- cast(5500, <<Index:?GLuint,X:?GLshort,Y:?GLshort>>).
+ cast(5501, <<Index:?GLuint,X:?GLshort,Y:?GLshort>>).
%% @equiv vertexAttrib2s(Index,X,Y)
-spec vertexAttrib2sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer()}.
@@ -11930,7 +11961,7 @@ vertexAttrib2sv(Index,{X,Y}) -> vertexAttrib2s(Index,X,Y).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3d(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttrib3d(Index,X,Y,Z) ->
- cast(5501, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5502, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @equiv vertexAttrib3d(Index,X,Y,Z)
-spec vertexAttrib3dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -11940,7 +11971,7 @@ vertexAttrib3dv(Index,{X,Y,Z}) -> vertexAttrib3d(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3f(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttrib3f(Index,X,Y,Z) ->
- cast(5502, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
+ cast(5503, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat>>).
%% @equiv vertexAttrib3f(Index,X,Y,Z)
-spec vertexAttrib3fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float()}.
@@ -11950,7 +11981,7 @@ vertexAttrib3fv(Index,{X,Y,Z}) -> vertexAttrib3f(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib3s(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttrib3s(Index,X,Y,Z) ->
- cast(5503, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort>>).
+ cast(5504, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort>>).
%% @equiv vertexAttrib3s(Index,X,Y,Z)
-spec vertexAttrib3sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer()}.
@@ -11960,25 +11991,25 @@ vertexAttrib3sv(Index,{X,Y,Z}) -> vertexAttrib3s(Index,X,Y,Z).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nbv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nbv(Index,{V1,V2,V3,V4}) ->
- cast(5504, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5505, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Niv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Niv(Index,{V1,V2,V3,V4}) ->
- cast(5505, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5506, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nsv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nsv(Index,{V1,V2,V3,V4}) ->
- cast(5506, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
+ cast(5507, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nub(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttrib4Nub(Index,X,Y,Z,W) ->
- cast(5507, <<Index:?GLuint,X:?GLubyte,Y:?GLubyte,Z:?GLubyte,W:?GLubyte>>).
+ cast(5508, <<Index:?GLuint,X:?GLubyte,Y:?GLubyte,Z:?GLubyte,W:?GLubyte>>).
%% @equiv vertexAttrib4Nub(Index,X,Y,Z,W)
-spec vertexAttrib4Nubv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer(),W :: integer()}.
@@ -11988,25 +12019,25 @@ vertexAttrib4Nubv(Index,{X,Y,Z,W}) -> vertexAttrib4Nub(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nuiv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nuiv(Index,{V1,V2,V3,V4}) ->
- cast(5508, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
+ cast(5509, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4Nusv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4Nusv(Index,{V1,V2,V3,V4}) ->
- cast(5509, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5510, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4bv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4bv(Index,{V1,V2,V3,V4}) ->
- cast(5510, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5511, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4d(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttrib4d(Index,X,Y,Z,W) ->
- cast(5511, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5512, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @equiv vertexAttrib4d(Index,X,Y,Z,W)
-spec vertexAttrib4dv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float(),W :: float()}.
@@ -12016,7 +12047,7 @@ vertexAttrib4dv(Index,{X,Y,Z,W}) -> vertexAttrib4d(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4f(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttrib4f(Index,X,Y,Z,W) ->
- cast(5512, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5513, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @equiv vertexAttrib4f(Index,X,Y,Z,W)
-spec vertexAttrib4fv(Index :: integer(),V) -> 'ok' when V :: {X :: float(),Y :: float(),Z :: float(),W :: float()}.
@@ -12026,13 +12057,13 @@ vertexAttrib4fv(Index,{X,Y,Z,W}) -> vertexAttrib4f(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4iv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4iv(Index,{V1,V2,V3,V4}) ->
- cast(5513, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5514, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4s(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttrib4s(Index,X,Y,Z,W) ->
- cast(5514, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort,W:?GLshort>>).
+ cast(5515, <<Index:?GLuint,X:?GLshort,Y:?GLshort,Z:?GLshort,W:?GLshort>>).
%% @equiv vertexAttrib4s(Index,X,Y,Z,W)
-spec vertexAttrib4sv(Index :: integer(),V) -> 'ok' when V :: {X :: integer(),Y :: integer(),Z :: integer(),W :: integer()}.
@@ -12042,19 +12073,19 @@ vertexAttrib4sv(Index,{X,Y,Z,W}) -> vertexAttrib4s(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4ubv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4ubv(Index,{V1,V2,V3,V4}) ->
- cast(5515, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
+ cast(5516, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4uiv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4uiv(Index,{V1,V2,V3,V4}) ->
- cast(5516, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
+ cast(5517, <<Index:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttrib4usv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttrib4usv(Index,{V1,V2,V3,V4}) ->
- cast(5517, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5518, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc Define an array of generic vertex attribute data
%%
@@ -12098,51 +12129,57 @@ vertexAttrib4usv(Index,{V1,V2,V3,V4}) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribPointer.xml">external</a> documentation.
-spec vertexAttribPointer(Index, Size, Type, Normalized, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Normalized :: 0|1,Stride :: integer(),Pointer :: offset()|mem().
vertexAttribPointer(Index,Size,Type,Normalized,Stride,Pointer) when is_integer(Pointer) ->
- cast(5518, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5519, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribPointer(Index,Size,Type,Normalized,Stride,Pointer) ->
send_bin(Pointer),
- cast(5519, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei>>).
+ cast(5520, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Normalized:?GLboolean,0:24,Stride:?GLsizei>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix2x3fv(Location,Transpose,Value) ->
- cast(5520, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5521, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix3x2fv(Location,Transpose,Value) ->
- cast(5521, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5522, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix2x4fv(Location,Transpose,Value) ->
- cast(5522, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5523, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x2fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x2fv(Location,Transpose,Value) ->
- cast(5523, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5524, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x4fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3x4fv(Location,Transpose,Value) ->
- cast(5524, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5525, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x3fv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x3fv(Location,Transpose,Value) ->
- cast(5525, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5526, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc glColorMaski
@@ -12150,39 +12187,39 @@ uniformMatrix4x3fv(Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glColorMaski.xml">external</a> documentation.
-spec colorMaski(Index, R, G, B, A) -> 'ok' when Index :: integer(),R :: 0|1,G :: 0|1,B :: 0|1,A :: 0|1.
colorMaski(Index,R,G,B,A) ->
- cast(5526, <<Index:?GLuint,R:?GLboolean,G:?GLboolean,B:?GLboolean,A:?GLboolean>>).
+ cast(5527, <<Index:?GLuint,R:?GLboolean,G:?GLboolean,B:?GLboolean,A:?GLboolean>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getBooleani_v(Target, Index) -> [0|1] when Target :: enum(),Index :: integer().
getBooleani_v(Target,Index) ->
- call(5527, <<Target:?GLenum,Index:?GLuint>>).
+ call(5528, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getIntegeri_v(Target, Index) -> [integer()] when Target :: enum(),Index :: integer().
getIntegeri_v(Target,Index) ->
- call(5528, <<Target:?GLenum,Index:?GLuint>>).
+ call(5529, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link enable/1}
-spec enablei(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
enablei(Target,Index) ->
- cast(5529, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5530, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glEnablei
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnablei.xml">external</a> documentation.
-spec disablei(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
disablei(Target,Index) ->
- cast(5530, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5531, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glIsEnabledi
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsEnabledi.xml">external</a> documentation.
-spec isEnabledi(Target, Index) -> 0|1 when Target :: enum(),Index :: integer().
isEnabledi(Target,Index) ->
- call(5531, <<Target:?GLenum,Index:?GLuint>>).
+ call(5532, <<Target:?GLenum,Index:?GLuint>>).
%% @doc Start transform feedback operation
%%
@@ -12210,13 +12247,13 @@ isEnabledi(Target,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginTransformFeedback.xml">external</a> documentation.
-spec beginTransformFeedback(PrimitiveMode) -> 'ok' when PrimitiveMode :: enum().
beginTransformFeedback(PrimitiveMode) ->
- cast(5532, <<PrimitiveMode:?GLenum>>).
+ cast(5533, <<PrimitiveMode:?GLenum>>).
%% @doc
%% See {@link beginTransformFeedback/1}
-spec endTransformFeedback() -> 'ok'.
endTransformFeedback() ->
- cast(5533, <<>>).
+ cast(5534, <<>>).
%% @doc Bind a range within a buffer object to an indexed buffer target
%%
@@ -12235,7 +12272,7 @@ endTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBufferRange.xml">external</a> documentation.
-spec bindBufferRange(Target, Index, Buffer, Offset, Size) -> 'ok' when Target :: enum(),Index :: integer(),Buffer :: integer(),Offset :: integer(),Size :: integer().
bindBufferRange(Target,Index,Buffer,Offset,Size) ->
- cast(5534, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5535, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint,0:32,Offset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Bind a buffer object to an indexed buffer target
%%
@@ -12250,7 +12287,7 @@ bindBufferRange(Target,Index,Buffer,Offset,Size) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindBufferBase.xml">external</a> documentation.
-spec bindBufferBase(Target, Index, Buffer) -> 'ok' when Target :: enum(),Index :: integer(),Buffer :: integer().
bindBufferBase(Target,Index,Buffer) ->
- cast(5535, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint>>).
+ cast(5536, <<Target:?GLenum,Index:?GLuint,Buffer:?GLuint>>).
%% @doc Specify values to record in transform feedback buffers
%%
@@ -12288,8 +12325,9 @@ bindBufferBase(Target,Index,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTransformFeedbackVaryings.xml">external</a> documentation.
-spec transformFeedbackVaryings(Program, Varyings, BufferMode) -> 'ok' when Program :: integer(),Varyings :: iolist(),BufferMode :: enum().
transformFeedbackVaryings(Program,Varyings,BufferMode) ->
- VaryingsTemp = list_to_binary([[Str|[0]] || Str <- Varyings ]),
- cast(5536, <<Program:?GLuint,(length(Varyings)):?GLuint,(size(VaryingsTemp)):?GLuint,(VaryingsTemp)/binary,0:((8-((size(VaryingsTemp)+0) rem 8)) rem 8),BufferMode:?GLenum>>).
+ VaryingsTemp = list_to_binary([[Str|[0]] || Str <- Varyings ]),
+ VaryingsLen = length(Varyings),
+ cast(5537, <<Program:?GLuint,VaryingsLen:?GLuint,(size(VaryingsTemp)):?GLuint,(VaryingsTemp)/binary,0:((8-((size(VaryingsTemp)+0) rem 8)) rem 8),BufferMode:?GLenum>>).
%% @doc Retrieve information about varying variables selected for transform feedback
%%
@@ -12322,7 +12360,7 @@ transformFeedbackVaryings(Program,Varyings,BufferMode) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetTransformFeedbackVarying.xml">external</a> documentation.
-spec getTransformFeedbackVarying(Program, Index, BufSize) -> {Size :: integer(),Type :: enum(),Name :: string()} when Program :: integer(),Index :: integer(),BufSize :: integer().
getTransformFeedbackVarying(Program,Index,BufSize) ->
- call(5537, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
+ call(5538, <<Program:?GLuint,Index:?GLuint,BufSize:?GLsizei>>).
%% @doc specify whether data read via
%%
@@ -12337,7 +12375,7 @@ getTransformFeedbackVarying(Program,Index,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClampColor.xml">external</a> documentation.
-spec clampColor(Target, Clamp) -> 'ok' when Target :: enum(),Clamp :: enum().
clampColor(Target,Clamp) ->
- cast(5538, <<Target:?GLenum,Clamp:?GLenum>>).
+ cast(5539, <<Target:?GLenum,Clamp:?GLenum>>).
%% @doc Start conditional rendering
%%
@@ -12369,84 +12407,84 @@ clampColor(Target,Clamp) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginConditionalRender.xml">external</a> documentation.
-spec beginConditionalRender(Id, Mode) -> 'ok' when Id :: integer(),Mode :: enum().
beginConditionalRender(Id,Mode) ->
- cast(5539, <<Id:?GLuint,Mode:?GLenum>>).
+ cast(5540, <<Id:?GLuint,Mode:?GLenum>>).
%% @doc
%% See {@link beginConditionalRender/2}
-spec endConditionalRender() -> 'ok'.
endConditionalRender() ->
- cast(5540, <<>>).
+ cast(5541, <<>>).
%% @doc glVertexAttribIPointer
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribIPointer.xml">external</a> documentation.
-spec vertexAttribIPointer(Index, Size, Type, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
vertexAttribIPointer(Index,Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5541, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5542, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribIPointer(Index,Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5542, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5543, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc
%% See {@link getVertexAttribdv/2}
-spec getVertexAttribIiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribIiv(Index,Pname) ->
- call(5543, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5544, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc glGetVertexAttribI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttribI.xml">external</a> documentation.
-spec getVertexAttribIuiv(Index, Pname) -> {integer(),integer(),integer(),integer()} when Index :: integer(),Pname :: enum().
getVertexAttribIuiv(Index,Pname) ->
- call(5544, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5545, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI1i(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttribI1i(Index,X) ->
- cast(5545, <<Index:?GLuint,X:?GLint>>).
+ cast(5546, <<Index:?GLuint,X:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI2i(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttribI2i(Index,X,Y) ->
- cast(5546, <<Index:?GLuint,X:?GLint,Y:?GLint>>).
+ cast(5547, <<Index:?GLuint,X:?GLint,Y:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI3i(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttribI3i(Index,X,Y,Z) ->
- cast(5547, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint>>).
+ cast(5548, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4i(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttribI4i(Index,X,Y,Z,W) ->
- cast(5548, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint,W:?GLint>>).
+ cast(5549, <<Index:?GLuint,X:?GLint,Y:?GLint,Z:?GLint,W:?GLint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI1ui(Index, X) -> 'ok' when Index :: integer(),X :: integer().
vertexAttribI1ui(Index,X) ->
- cast(5549, <<Index:?GLuint,X:?GLuint>>).
+ cast(5550, <<Index:?GLuint,X:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI2ui(Index, X, Y) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer().
vertexAttribI2ui(Index,X,Y) ->
- cast(5550, <<Index:?GLuint,X:?GLuint,Y:?GLuint>>).
+ cast(5551, <<Index:?GLuint,X:?GLuint,Y:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI3ui(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer().
vertexAttribI3ui(Index,X,Y,Z) ->
- cast(5551, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint>>).
+ cast(5552, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4ui(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: integer(),Y :: integer(),Z :: integer(),W :: integer().
vertexAttribI4ui(Index,X,Y,Z,W) ->
- cast(5552, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint,W:?GLuint>>).
+ cast(5553, <<Index:?GLuint,X:?GLuint,Y:?GLuint,Z:?GLuint,W:?GLuint>>).
%% @equiv vertexAttribI1i(Index,X)
-spec vertexAttribI1iv(Index :: integer(),V) -> 'ok' when V :: {X :: integer()}.
@@ -12484,31 +12522,31 @@ vertexAttribI4uiv(Index,{X,Y,Z,W}) -> vertexAttribI4ui(Index,X,Y,Z,W).
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4bv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4bv(Index,{V1,V2,V3,V4}) ->
- cast(5553, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
+ cast(5554, <<Index:?GLuint,V1:?GLbyte,V2:?GLbyte,V3:?GLbyte,V4:?GLbyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4sv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4sv(Index,{V1,V2,V3,V4}) ->
- cast(5554, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
+ cast(5555, <<Index:?GLuint,V1:?GLshort,V2:?GLshort,V3:?GLshort,V4:?GLshort>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4ubv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4ubv(Index,{V1,V2,V3,V4}) ->
- cast(5555, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
+ cast(5556, <<Index:?GLuint,V1:?GLubyte,V2:?GLubyte,V3:?GLubyte,V4:?GLubyte>>).
%% @doc
%% See {@link vertexAttrib1d/2}
-spec vertexAttribI4usv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
vertexAttribI4usv(Index,{V1,V2,V3,V4}) ->
- cast(5556, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
+ cast(5557, <<Index:?GLuint,V1:?GLushort,V2:?GLushort,V3:?GLushort,V4:?GLushort>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformuiv(Program, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Program :: integer(),Location :: integer().
getUniformuiv(Program,Location) ->
- call(5557, <<Program:?GLuint,Location:?GLint>>).
+ call(5558, <<Program:?GLuint,Location:?GLint>>).
%% @doc Bind a user-defined varying out variable to a fragment shader color number
%%
@@ -12535,7 +12573,8 @@ getUniformuiv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFragDataLocation.xml">external</a> documentation.
-spec bindFragDataLocation(Program, Color, Name) -> 'ok' when Program :: integer(),Color :: integer(),Name :: string().
bindFragDataLocation(Program,Color,Name) ->
- cast(5558, <<Program:?GLuint,Color:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5559, <<Program:?GLuint,Color:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Query the bindings of color numbers to user-defined varying out variables
%%
@@ -12548,65 +12587,70 @@ bindFragDataLocation(Program,Color,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFragDataLocation.xml">external</a> documentation.
-spec getFragDataLocation(Program, Name) -> integer() when Program :: integer(),Name :: string().
getFragDataLocation(Program,Name) ->
- call(5559, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5560, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1ui(Location, V0) -> 'ok' when Location :: integer(),V0 :: integer().
uniform1ui(Location,V0) ->
- cast(5560, <<Location:?GLint,V0:?GLuint>>).
+ cast(5561, <<Location:?GLint,V0:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2ui(Location, V0, V1) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer().
uniform2ui(Location,V0,V1) ->
- cast(5561, <<Location:?GLint,V0:?GLuint,V1:?GLuint>>).
+ cast(5562, <<Location:?GLint,V0:?GLuint,V1:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3ui(Location, V0, V1, V2) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
uniform3ui(Location,V0,V1,V2) ->
- cast(5562, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
+ cast(5563, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4ui(Location, V0, V1, V2, V3) -> 'ok' when Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
uniform4ui(Location,V0,V1,V2,V3) ->
- cast(5563, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
+ cast(5564, <<Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [integer()].
uniform1uiv(Location,Value) ->
- cast(5564, <<Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5565, <<Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer()}].
uniform2uiv(Location,Value) ->
- cast(5565, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5566, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer()}].
uniform3uiv(Location,Value) ->
- cast(5566, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5567, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4uiv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
uniform4uiv(Location,Value) ->
- cast(5567, <<Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5568, <<Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link texParameterf/3}
-spec texParameterIiv(Target, Pname, Params) -> 'ok' when Target :: enum(),Pname :: enum(),Params :: tuple().
texParameterIiv(Target,Pname,Params) ->
- cast(5568, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5569, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>).
%% @doc glTexParameterI
@@ -12614,21 +12658,21 @@ texParameterIiv(Target,Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexParameterI.xml">external</a> documentation.
-spec texParameterIuiv(Target, Pname, Params) -> 'ok' when Target :: enum(),Pname :: enum(),Params :: tuple().
texParameterIuiv(Target,Pname,Params) ->
- cast(5569, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
+ cast(5570, <<Target:?GLenum,Pname:?GLenum,(size(Params)):?GLuint,
(<< <<C:?GLuint>> ||C <- tuple_to_list(Params)>>)/binary,0:(((1+size(Params)) rem 2)*32)>>).
%% @doc
%% See {@link getTexParameterfv/2}
-spec getTexParameterIiv(Target, Pname) -> {integer(),integer(),integer(),integer()} when Target :: enum(),Pname :: enum().
getTexParameterIiv(Target,Pname) ->
- call(5570, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5571, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glGetTexParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetTexParameterI.xml">external</a> documentation.
-spec getTexParameterIuiv(Target, Pname) -> {integer(),integer(),integer(),integer()} when Target :: enum(),Pname :: enum().
getTexParameterIuiv(Target,Pname) ->
- call(5571, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5572, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Clear individual buffers of the currently bound draw framebuffer
%%
@@ -12661,21 +12705,21 @@ getTexParameterIuiv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearBuffer.xml">external</a> documentation.
-spec clearBufferiv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferiv(Buffer,Drawbuffer,Value) ->
- cast(5572, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5573, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc
%% See {@link clearBufferiv/3}
-spec clearBufferuiv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferuiv(Buffer,Drawbuffer,Value) ->
- cast(5573, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5574, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLuint>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc
%% See {@link clearBufferiv/3}
-spec clearBufferfv(Buffer, Drawbuffer, Value) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Value :: tuple().
clearBufferfv(Buffer,Drawbuffer,Value) ->
- cast(5574, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
+ cast(5575, <<Buffer:?GLenum,Drawbuffer:?GLint,(size(Value)):?GLuint,
(<< <<C:?GLfloat>> ||C <- tuple_to_list(Value)>>)/binary,0:(((1+size(Value)) rem 2)*32)>>).
%% @doc glClearBufferfi
@@ -12683,30 +12727,30 @@ clearBufferfv(Buffer,Drawbuffer,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearBufferfi.xml">external</a> documentation.
-spec clearBufferfi(Buffer, Drawbuffer, Depth, Stencil) -> 'ok' when Buffer :: enum(),Drawbuffer :: integer(),Depth :: float(),Stencil :: integer().
clearBufferfi(Buffer,Drawbuffer,Depth,Stencil) ->
- cast(5575, <<Buffer:?GLenum,Drawbuffer:?GLint,Depth:?GLfloat,Stencil:?GLint>>).
+ cast(5576, <<Buffer:?GLenum,Drawbuffer:?GLint,Depth:?GLfloat,Stencil:?GLint>>).
%% @doc
%% See {@link getString/1}
-spec getStringi(Name, Index) -> string() when Name :: enum(),Index :: integer().
getStringi(Name,Index) ->
- call(5576, <<Name:?GLenum,Index:?GLuint>>).
+ call(5577, <<Name:?GLenum,Index:?GLuint>>).
%% @doc glDrawArraysInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysInstance.xml">external</a> documentation.
-spec drawArraysInstanced(Mode, First, Count, Primcount) -> 'ok' when Mode :: enum(),First :: integer(),Count :: integer(),Primcount :: integer().
drawArraysInstanced(Mode,First,Count,Primcount) ->
- cast(5577, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei>>).
+ cast(5578, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei>>).
%% @doc glDrawElementsInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstance.xml">external</a> documentation.
-spec drawElementsInstanced(Mode, Count, Type, Indices, Primcount) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer().
drawElementsInstanced(Mode,Count,Type,Indices,Primcount) when is_integer(Indices) ->
- cast(5578, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei>>);
+ cast(5579, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei>>);
drawElementsInstanced(Mode,Count,Type,Indices,Primcount) ->
send_bin(Indices),
- cast(5579, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei>>).
+ cast(5580, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei>>).
%% @doc Attach the storage for a buffer object to the active buffer texture
%%
@@ -12774,7 +12818,7 @@ drawElementsInstanced(Mode,Count,Type,Indices,Primcount) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexBuffer.xml">external</a> documentation.
-spec texBuffer(Target, Internalformat, Buffer) -> 'ok' when Target :: enum(),Internalformat :: enum(),Buffer :: integer().
texBuffer(Target,Internalformat,Buffer) ->
- cast(5580, <<Target:?GLenum,Internalformat:?GLenum,Buffer:?GLuint>>).
+ cast(5581, <<Target:?GLenum,Internalformat:?GLenum,Buffer:?GLuint>>).
%% @doc Specify the primitive restart index
%%
@@ -12796,20 +12840,20 @@ texBuffer(Target,Internalformat,Buffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPrimitiveRestartIndex.xml">external</a> documentation.
-spec primitiveRestartIndex(Index) -> 'ok' when Index :: integer().
primitiveRestartIndex(Index) ->
- cast(5581, <<Index:?GLuint>>).
+ cast(5582, <<Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getInteger64i_v(Target, Index) -> [integer()] when Target :: enum(),Index :: integer().
getInteger64i_v(Target,Index) ->
- call(5582, <<Target:?GLenum,Index:?GLuint>>).
+ call(5583, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetBufferParameteri64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameteri64v.xml">external</a> documentation.
-spec getBufferParameteri64v(Target, Pname) -> [integer()] when Target :: enum(),Pname :: enum().
getBufferParameteri64v(Target,Pname) ->
- call(5583, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5584, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Attach a level of a texture object as a logical buffer to the currently bound framebuffer object
%%
@@ -12866,7 +12910,7 @@ getBufferParameteri64v(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFramebufferTexture.xml">external</a> documentation.
-spec framebufferTexture(Target, Attachment, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture(Target,Attachment,Texture,Level) ->
- cast(5584, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5585, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc Modify the rate at which generic vertex attributes advance during instanced rendering
%%
@@ -12882,7 +12926,7 @@ framebufferTexture(Target,Attachment,Texture,Level) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribDivisor.xml">external</a> documentation.
-spec vertexAttribDivisor(Index, Divisor) -> 'ok' when Index :: integer(),Divisor :: integer().
vertexAttribDivisor(Index,Divisor) ->
- cast(5585, <<Index:?GLuint,Divisor:?GLuint>>).
+ cast(5586, <<Index:?GLuint,Divisor:?GLuint>>).
%% @doc Specifies minimum rate at which sample shaing takes place
%%
@@ -12903,107 +12947,112 @@ vertexAttribDivisor(Index,Divisor) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMinSampleShading.xml">external</a> documentation.
-spec minSampleShading(Value) -> 'ok' when Value :: clamp().
minSampleShading(Value) ->
- cast(5586, <<Value:?GLclampf>>).
+ cast(5587, <<Value:?GLclampf>>).
%% @doc
%% See {@link blendEquation/1}
-spec blendEquationi(Buf, Mode) -> 'ok' when Buf :: integer(),Mode :: enum().
blendEquationi(Buf,Mode) ->
- cast(5587, <<Buf:?GLuint,Mode:?GLenum>>).
+ cast(5588, <<Buf:?GLuint,Mode:?GLenum>>).
%% @doc
%% See {@link blendEquationSeparate/2}
-spec blendEquationSeparatei(Buf, ModeRGB, ModeAlpha) -> 'ok' when Buf :: integer(),ModeRGB :: enum(),ModeAlpha :: enum().
blendEquationSeparatei(Buf,ModeRGB,ModeAlpha) ->
- cast(5588, <<Buf:?GLuint,ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
+ cast(5589, <<Buf:?GLuint,ModeRGB:?GLenum,ModeAlpha:?GLenum>>).
%% @doc glBlendFunci
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlendFunci.xml">external</a> documentation.
-spec blendFunci(Buf, Src, Dst) -> 'ok' when Buf :: integer(),Src :: enum(),Dst :: enum().
blendFunci(Buf,Src,Dst) ->
- cast(5589, <<Buf:?GLuint,Src:?GLenum,Dst:?GLenum>>).
+ cast(5590, <<Buf:?GLuint,Src:?GLenum,Dst:?GLenum>>).
%% @doc
%% See {@link blendFuncSeparate/4}
-spec blendFuncSeparatei(Buf, SrcRGB, DstRGB, SrcAlpha, DstAlpha) -> 'ok' when Buf :: integer(),SrcRGB :: enum(),DstRGB :: enum(),SrcAlpha :: enum(),DstAlpha :: enum().
blendFuncSeparatei(Buf,SrcRGB,DstRGB,SrcAlpha,DstAlpha) ->
- cast(5590, <<Buf:?GLuint,SrcRGB:?GLenum,DstRGB:?GLenum,SrcAlpha:?GLenum,DstAlpha:?GLenum>>).
+ cast(5591, <<Buf:?GLuint,SrcRGB:?GLenum,DstRGB:?GLenum,SrcAlpha:?GLenum,DstAlpha:?GLenum>>).
%% @doc glLoadTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLoadTransposeMatrixARB.xml">external</a> documentation.
-spec loadTransposeMatrixfARB(M) -> 'ok' when M :: matrix().
loadTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5591, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
+ cast(5592, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
loadTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5591, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
+ cast(5592, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
%% @doc glLoadTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLoadTransposeMatrixARB.xml">external</a> documentation.
-spec loadTransposeMatrixdARB(M) -> 'ok' when M :: matrix().
loadTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5592, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
+ cast(5593, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
loadTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5592, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
+ cast(5593, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
%% @doc glMultTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultTransposeMatrixARB.xml">external</a> documentation.
-spec multTransposeMatrixfARB(M) -> 'ok' when M :: matrix().
multTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5593, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
+ cast(5594, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,M13:?GLfloat,M14:?GLfloat,M15:?GLfloat,M16:?GLfloat>>);
multTransposeMatrixfARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5593, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
+ cast(5594, <<M1:?GLfloat,M2:?GLfloat,M3:?GLfloat,0:?GLfloat,M4:?GLfloat,M5:?GLfloat,M6:?GLfloat,0:?GLfloat,M7:?GLfloat,M8:?GLfloat,M9:?GLfloat,0:?GLfloat,M10:?GLfloat,M11:?GLfloat,M12:?GLfloat,1:?GLfloat>>).
%% @doc glMultTransposeMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMultTransposeMatrixARB.xml">external</a> documentation.
-spec multTransposeMatrixdARB(M) -> 'ok' when M :: matrix().
multTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12,M13,M14,M15,M16}) ->
- cast(5594, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
+ cast(5595, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,M13:?GLdouble,M14:?GLdouble,M15:?GLdouble,M16:?GLdouble>>);
multTransposeMatrixdARB({M1,M2,M3,M4,M5,M6,M7,M8,M9,M10,M11,M12}) ->
- cast(5594, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
+ cast(5595, <<M1:?GLdouble,M2:?GLdouble,M3:?GLdouble,0:?GLdouble,M4:?GLdouble,M5:?GLdouble,M6:?GLdouble,0:?GLdouble,M7:?GLdouble,M8:?GLdouble,M9:?GLdouble,0:?GLdouble,M10:?GLdouble,M11:?GLdouble,M12:?GLdouble,1:?GLdouble>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightbvARB(Weights) -> 'ok' when Weights :: [integer()].
weightbvARB(Weights) ->
- cast(5595, <<(length(Weights)):?GLuint,
- (<< <<C:?GLbyte>> || C <- Weights>>)/binary,0:((8-((length(Weights)+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5596, <<WeightsLen:?GLuint,
+ (<< <<C:?GLbyte>> || C <- Weights>>)/binary,0:((8-((WeightsLen+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightsvARB(Weights) -> 'ok' when Weights :: [integer()].
weightsvARB(Weights) ->
- cast(5596, <<(length(Weights)):?GLuint,
- (<< <<C:?GLshort>> || C <- Weights>>)/binary,0:((8-((length(Weights)*2+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5597, <<WeightsLen:?GLuint,
+ (<< <<C:?GLshort>> || C <- Weights>>)/binary,0:((8-((WeightsLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightivARB(Weights) -> 'ok' when Weights :: [integer()].
weightivARB(Weights) ->
- cast(5597, <<(length(Weights)):?GLuint,
- (<< <<C:?GLint>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5598, <<WeightsLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightfvARB(Weights) -> 'ok' when Weights :: [float()].
weightfvARB(Weights) ->
- cast(5598, <<(length(Weights)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5599, <<WeightsLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightdvARB(Weights) -> 'ok' when Weights :: [float()].
weightdvARB(Weights) ->
- cast(5599, <<(length(Weights)):?GLuint,0:32,
+ WeightsLen = length(Weights),
+ cast(5600, <<WeightsLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Weights>>)/binary>>).
%% @doc glWeightARB
@@ -13011,175 +13060,183 @@ weightdvARB(Weights) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightubvARB(Weights) -> 'ok' when Weights :: [integer()].
weightubvARB(Weights) ->
- cast(5600, <<(length(Weights)):?GLuint,
- (<< <<C:?GLubyte>> || C <- Weights>>)/binary,0:((8-((length(Weights)+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5601, <<WeightsLen:?GLuint,
+ (<< <<C:?GLubyte>> || C <- Weights>>)/binary,0:((8-((WeightsLen+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightusvARB(Weights) -> 'ok' when Weights :: [integer()].
weightusvARB(Weights) ->
- cast(5601, <<(length(Weights)):?GLuint,
- (<< <<C:?GLushort>> || C <- Weights>>)/binary,0:((8-((length(Weights)*2+ 4) rem 8)) rem 8)>>).
+ WeightsLen = length(Weights),
+ cast(5602, <<WeightsLen:?GLuint,
+ (<< <<C:?GLushort>> || C <- Weights>>)/binary,0:((8-((WeightsLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glWeightARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWeightARB.xml">external</a> documentation.
-spec weightuivARB(Weights) -> 'ok' when Weights :: [integer()].
weightuivARB(Weights) ->
- cast(5602, <<(length(Weights)):?GLuint,
- (<< <<C:?GLuint>> || C <- Weights>>)/binary,0:(((1+length(Weights)) rem 2)*32)>>).
+ WeightsLen = length(Weights),
+ cast(5603, <<WeightsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Weights>>)/binary,0:(((1+WeightsLen) rem 2)*32)>>).
%% @doc glVertexBlenARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexBlenARB.xml">external</a> documentation.
-spec vertexBlendARB(Count) -> 'ok' when Count :: integer().
vertexBlendARB(Count) ->
- cast(5603, <<Count:?GLint>>).
+ cast(5604, <<Count:?GLint>>).
%% @doc glCurrentPaletteMatrixARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCurrentPaletteMatrixARB.xml">external</a> documentation.
-spec currentPaletteMatrixARB(Index) -> 'ok' when Index :: integer().
currentPaletteMatrixARB(Index) ->
- cast(5604, <<Index:?GLint>>).
+ cast(5605, <<Index:?GLint>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexubvARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexubvARB(Indices) ->
- cast(5605, <<(length(Indices)):?GLuint,
- (<< <<C:?GLubyte>> || C <- Indices>>)/binary,0:((8-((length(Indices)+ 4) rem 8)) rem 8)>>).
+ IndicesLen = length(Indices),
+ cast(5606, <<IndicesLen:?GLuint,
+ (<< <<C:?GLubyte>> || C <- Indices>>)/binary,0:((8-((IndicesLen+ 4) rem 8)) rem 8)>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexusvARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexusvARB(Indices) ->
- cast(5606, <<(length(Indices)):?GLuint,
- (<< <<C:?GLushort>> || C <- Indices>>)/binary,0:((8-((length(Indices)*2+ 4) rem 8)) rem 8)>>).
+ IndicesLen = length(Indices),
+ cast(5607, <<IndicesLen:?GLuint,
+ (<< <<C:?GLushort>> || C <- Indices>>)/binary,0:((8-((IndicesLen*2+ 4) rem 8)) rem 8)>>).
%% @doc glMatrixIndexARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMatrixIndexARB.xml">external</a> documentation.
-spec matrixIndexuivARB(Indices) -> 'ok' when Indices :: [integer()].
matrixIndexuivARB(Indices) ->
- cast(5607, <<(length(Indices)):?GLuint,
- (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((1+length(Indices)) rem 2)*32)>>).
+ IndicesLen = length(Indices),
+ cast(5608, <<IndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((1+IndicesLen) rem 2)*32)>>).
%% @doc glProgramStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramStringARB.xml">external</a> documentation.
-spec programStringARB(Target, Format, String) -> 'ok' when Target :: enum(),Format :: enum(),String :: string().
programStringARB(Target,Format,String) ->
- cast(5608, <<Target:?GLenum,Format:?GLenum,(list_to_binary([String|[0]]))/binary,0:((8-((length(String)+ 1) rem 8)) rem 8)>>).
+ StringLen = length(String),
+ cast(5609, <<Target:?GLenum,Format:?GLenum,(list_to_binary([String|[0]]))/binary,0:((8-((StringLen+ 1) rem 8)) rem 8)>>).
%% @doc glBindProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindProgramARB.xml">external</a> documentation.
-spec bindProgramARB(Target, Program) -> 'ok' when Target :: enum(),Program :: integer().
bindProgramARB(Target,Program) ->
- cast(5609, <<Target:?GLenum,Program:?GLuint>>).
+ cast(5610, <<Target:?GLenum,Program:?GLuint>>).
%% @doc glDeleteProgramsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgramsARB.xml">external</a> documentation.
-spec deleteProgramsARB(Programs) -> 'ok' when Programs :: [integer()].
deleteProgramsARB(Programs) ->
- cast(5610, <<(length(Programs)):?GLuint,
- (<< <<C:?GLuint>> || C <- Programs>>)/binary,0:(((1+length(Programs)) rem 2)*32)>>).
+ ProgramsLen = length(Programs),
+ cast(5611, <<ProgramsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Programs>>)/binary,0:(((1+ProgramsLen) rem 2)*32)>>).
%% @doc glGenProgramsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenProgramsARB.xml">external</a> documentation.
-spec genProgramsARB(N) -> [integer()] when N :: integer().
genProgramsARB(N) ->
- call(5611, <<N:?GLsizei>>).
+ call(5612, <<N:?GLsizei>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4dARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programEnvParameter4dARB(Target,Index,X,Y,Z,W) ->
- cast(5612, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5613, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4dvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programEnvParameter4dvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5613, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
+ cast(5614, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4fARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programEnvParameter4fARB(Target,Index,X,Y,Z,W) ->
- cast(5614, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5615, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @doc glProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramEnvParameterARB.xml">external</a> documentation.
-spec programEnvParameter4fvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programEnvParameter4fvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5615, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
+ cast(5616, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4dARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programLocalParameter4dARB(Target,Index,X,Y,Z,W) ->
- cast(5616, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5617, <<Target:?GLenum,Index:?GLuint,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4dvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programLocalParameter4dvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5617, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
+ cast(5618, <<Target:?GLenum,Index:?GLuint,P1:?GLdouble,P2:?GLdouble,P3:?GLdouble,P4:?GLdouble>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4fARB(Target, Index, X, Y, Z, W) -> 'ok' when Target :: enum(),Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
programLocalParameter4fARB(Target,Index,X,Y,Z,W) ->
- cast(5618, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
+ cast(5619, <<Target:?GLenum,Index:?GLuint,X:?GLfloat,Y:?GLfloat,Z:?GLfloat,W:?GLfloat>>).
%% @doc glProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramLocalParameterARB.xml">external</a> documentation.
-spec programLocalParameter4fvARB(Target, Index, Params) -> 'ok' when Target :: enum(),Index :: integer(),Params :: {float(),float(),float(),float()}.
programLocalParameter4fvARB(Target,Index,{P1,P2,P3,P4}) ->
- cast(5619, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
+ cast(5620, <<Target:?GLenum,Index:?GLuint,P1:?GLfloat,P2:?GLfloat,P3:?GLfloat,P4:?GLfloat>>).
%% @doc glGetProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramEnvParameterARB.xml">external</a> documentation.
-spec getProgramEnvParameterdvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramEnvParameterdvARB(Target,Index) ->
- call(5620, <<Target:?GLenum,Index:?GLuint>>).
+ call(5621, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramEnvParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramEnvParameterARB.xml">external</a> documentation.
-spec getProgramEnvParameterfvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramEnvParameterfvARB(Target,Index) ->
- call(5621, <<Target:?GLenum,Index:?GLuint>>).
+ call(5622, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramLocalParameterARB.xml">external</a> documentation.
-spec getProgramLocalParameterdvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramLocalParameterdvARB(Target,Index) ->
- call(5622, <<Target:?GLenum,Index:?GLuint>>).
+ call(5623, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramLocalParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramLocalParameterARB.xml">external</a> documentation.
-spec getProgramLocalParameterfvARB(Target, Index) -> {float(),float(),float(),float()} when Target :: enum(),Index :: integer().
getProgramLocalParameterfvARB(Target,Index) ->
- call(5623, <<Target:?GLenum,Index:?GLuint>>).
+ call(5624, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glGetProgramStringARB
%%
@@ -13187,176 +13244,180 @@ getProgramLocalParameterfvARB(Target,Index) ->
-spec getProgramStringARB(Target, Pname, String) -> 'ok' when Target :: enum(),Pname :: enum(),String :: mem().
getProgramStringARB(Target,Pname,String) ->
send_bin(String),
- call(5624, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5625, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glGetBufferParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetBufferParameterARB.xml">external</a> documentation.
-spec getBufferParameterivARB(Target, Pname) -> [integer()] when Target :: enum(),Pname :: enum().
getBufferParameterivARB(Target,Pname) ->
- call(5625, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5626, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc glDeleteObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteObjectARB.xml">external</a> documentation.
-spec deleteObjectARB(Obj) -> 'ok' when Obj :: integer().
deleteObjectARB(Obj) ->
- cast(5626, <<Obj:?GLhandleARB>>).
+ cast(5627, <<Obj:?GLhandleARB>>).
%% @doc glGetHandleARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetHandleARB.xml">external</a> documentation.
-spec getHandleARB(Pname) -> integer() when Pname :: enum().
getHandleARB(Pname) ->
- call(5627, <<Pname:?GLenum>>).
+ call(5628, <<Pname:?GLenum>>).
%% @doc glDetachObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDetachObjectARB.xml">external</a> documentation.
-spec detachObjectARB(ContainerObj, AttachedObj) -> 'ok' when ContainerObj :: integer(),AttachedObj :: integer().
detachObjectARB(ContainerObj,AttachedObj) ->
- cast(5628, <<ContainerObj:?GLhandleARB,AttachedObj:?GLhandleARB>>).
+ cast(5629, <<ContainerObj:?GLhandleARB,AttachedObj:?GLhandleARB>>).
%% @doc glCreateShaderObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShaderObjectARB.xml">external</a> documentation.
-spec createShaderObjectARB(ShaderType) -> integer() when ShaderType :: enum().
createShaderObjectARB(ShaderType) ->
- call(5629, <<ShaderType:?GLenum>>).
+ call(5630, <<ShaderType:?GLenum>>).
%% @doc glShaderSourceARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderSourceARB.xml">external</a> documentation.
-spec shaderSourceARB(ShaderObj, String) -> 'ok' when ShaderObj :: integer(),String :: iolist().
shaderSourceARB(ShaderObj,String) ->
- StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
- cast(5630, <<ShaderObj:?GLhandleARB,(length(String)):?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+4) rem 8)) rem 8)>>).
+ StringTemp = list_to_binary([[Str|[0]] || Str <- String ]),
+ StringLen = length(String),
+ cast(5631, <<ShaderObj:?GLhandleARB,StringLen:?GLuint,(size(StringTemp)):?GLuint,(StringTemp)/binary,0:((8-((size(StringTemp)+4) rem 8)) rem 8)>>).
%% @doc glCompileShaderARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShaderARB.xml">external</a> documentation.
-spec compileShaderARB(ShaderObj) -> 'ok' when ShaderObj :: integer().
compileShaderARB(ShaderObj) ->
- cast(5631, <<ShaderObj:?GLhandleARB>>).
+ cast(5632, <<ShaderObj:?GLhandleARB>>).
%% @doc glCreateProgramObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateProgramObjectARB.xml">external</a> documentation.
-spec createProgramObjectARB() -> integer().
createProgramObjectARB() ->
- call(5632, <<>>).
+ call(5633, <<>>).
%% @doc glAttachObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glAttachObjectARB.xml">external</a> documentation.
-spec attachObjectARB(ContainerObj, Obj) -> 'ok' when ContainerObj :: integer(),Obj :: integer().
attachObjectARB(ContainerObj,Obj) ->
- cast(5633, <<ContainerObj:?GLhandleARB,Obj:?GLhandleARB>>).
+ cast(5634, <<ContainerObj:?GLhandleARB,Obj:?GLhandleARB>>).
%% @doc glLinkProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glLinkProgramARB.xml">external</a> documentation.
-spec linkProgramARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
linkProgramARB(ProgramObj) ->
- cast(5634, <<ProgramObj:?GLhandleARB>>).
+ cast(5635, <<ProgramObj:?GLhandleARB>>).
%% @doc glUseProgramObjectARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgramObjectARB.xml">external</a> documentation.
-spec useProgramObjectARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
useProgramObjectARB(ProgramObj) ->
- cast(5635, <<ProgramObj:?GLhandleARB>>).
+ cast(5636, <<ProgramObj:?GLhandleARB>>).
%% @doc glValidateProgramARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgramARB.xml">external</a> documentation.
-spec validateProgramARB(ProgramObj) -> 'ok' when ProgramObj :: integer().
validateProgramARB(ProgramObj) ->
- cast(5636, <<ProgramObj:?GLhandleARB>>).
+ cast(5637, <<ProgramObj:?GLhandleARB>>).
%% @doc glGetObjectParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetObjectParameterARB.xml">external</a> documentation.
-spec getObjectParameterfvARB(Obj, Pname) -> float() when Obj :: integer(),Pname :: enum().
getObjectParameterfvARB(Obj,Pname) ->
- call(5637, <<Obj:?GLhandleARB,Pname:?GLenum>>).
+ call(5638, <<Obj:?GLhandleARB,Pname:?GLenum>>).
%% @doc glGetObjectParameterARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetObjectParameterARB.xml">external</a> documentation.
-spec getObjectParameterivARB(Obj, Pname) -> integer() when Obj :: integer(),Pname :: enum().
getObjectParameterivARB(Obj,Pname) ->
- call(5638, <<Obj:?GLhandleARB,Pname:?GLenum>>).
+ call(5639, <<Obj:?GLhandleARB,Pname:?GLenum>>).
%% @doc glGetInfoLogARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetInfoLogARB.xml">external</a> documentation.
-spec getInfoLogARB(Obj, MaxLength) -> string() when Obj :: integer(),MaxLength :: integer().
getInfoLogARB(Obj,MaxLength) ->
- call(5639, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
+ call(5640, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
%% @doc glGetAttachedObjectsARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttachedObjectsARB.xml">external</a> documentation.
-spec getAttachedObjectsARB(ContainerObj, MaxCount) -> [integer()] when ContainerObj :: integer(),MaxCount :: integer().
getAttachedObjectsARB(ContainerObj,MaxCount) ->
- call(5640, <<ContainerObj:?GLhandleARB,MaxCount:?GLsizei>>).
+ call(5641, <<ContainerObj:?GLhandleARB,MaxCount:?GLsizei>>).
%% @doc glGetUniformLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocationARB.xml">external</a> documentation.
-spec getUniformLocationARB(ProgramObj, Name) -> integer() when ProgramObj :: integer(),Name :: string().
getUniformLocationARB(ProgramObj,Name) ->
- call(5641, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5642, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetActiveUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformARB.xml">external</a> documentation.
-spec getActiveUniformARB(ProgramObj, Index, MaxLength) -> {Size :: integer(),Type :: enum(),Name :: string()} when ProgramObj :: integer(),Index :: integer(),MaxLength :: integer().
getActiveUniformARB(ProgramObj,Index,MaxLength) ->
- call(5642, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
+ call(5643, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
%% @doc glGetUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformARB.xml">external</a> documentation.
-spec getUniformfvARB(ProgramObj, Location) -> matrix() when ProgramObj :: integer(),Location :: integer().
getUniformfvARB(ProgramObj,Location) ->
- call(5643, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
+ call(5644, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
%% @doc glGetUniformARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformARB.xml">external</a> documentation.
-spec getUniformivARB(ProgramObj, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when ProgramObj :: integer(),Location :: integer().
getUniformivARB(ProgramObj,Location) ->
- call(5644, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
+ call(5645, <<ProgramObj:?GLhandleARB,Location:?GLint>>).
%% @doc glGetShaderSourceARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderSourceARB.xml">external</a> documentation.
-spec getShaderSourceARB(Obj, MaxLength) -> string() when Obj :: integer(),MaxLength :: integer().
getShaderSourceARB(Obj,MaxLength) ->
- call(5645, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
+ call(5646, <<Obj:?GLhandleARB,MaxLength:?GLsizei>>).
%% @doc glBindAttribLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindAttribLocationARB.xml">external</a> documentation.
-spec bindAttribLocationARB(ProgramObj, Index, Name) -> 'ok' when ProgramObj :: integer(),Index :: integer(),Name :: string().
bindAttribLocationARB(ProgramObj,Index,Name) ->
- cast(5646, <<ProgramObj:?GLhandleARB,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5647, <<ProgramObj:?GLhandleARB,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc glGetActiveAttribARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveAttribARB.xml">external</a> documentation.
-spec getActiveAttribARB(ProgramObj, Index, MaxLength) -> {Size :: integer(),Type :: enum(),Name :: string()} when ProgramObj :: integer(),Index :: integer(),MaxLength :: integer().
getActiveAttribARB(ProgramObj,Index,MaxLength) ->
- call(5647, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
+ call(5648, <<ProgramObj:?GLhandleARB,Index:?GLuint,MaxLength:?GLsizei>>).
%% @doc glGetAttribLocationARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetAttribLocationARB.xml">external</a> documentation.
-spec getAttribLocationARB(ProgramObj, Name) -> integer() when ProgramObj :: integer(),Name :: string().
getAttribLocationARB(ProgramObj,Name) ->
- call(5648, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5649, <<ProgramObj:?GLhandleARB,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Determine if a name corresponds to a renderbuffer object
%%
@@ -13371,7 +13432,7 @@ getAttribLocationARB(ProgramObj,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsRenderbuffer.xml">external</a> documentation.
-spec isRenderbuffer(Renderbuffer) -> 0|1 when Renderbuffer :: integer().
isRenderbuffer(Renderbuffer) ->
- call(5649, <<Renderbuffer:?GLuint>>).
+ call(5650, <<Renderbuffer:?GLuint>>).
%% @doc Bind a renderbuffer to a renderbuffer target
%%
@@ -13384,7 +13445,7 @@ isRenderbuffer(Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindRenderbuffer.xml">external</a> documentation.
-spec bindRenderbuffer(Target, Renderbuffer) -> 'ok' when Target :: enum(),Renderbuffer :: integer().
bindRenderbuffer(Target,Renderbuffer) ->
- cast(5650, <<Target:?GLenum,Renderbuffer:?GLuint>>).
+ cast(5651, <<Target:?GLenum,Renderbuffer:?GLuint>>).
%% @doc Delete renderbuffer objects
%%
@@ -13406,8 +13467,9 @@ bindRenderbuffer(Target,Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteRenderbuffers.xml">external</a> documentation.
-spec deleteRenderbuffers(Renderbuffers) -> 'ok' when Renderbuffers :: [integer()].
deleteRenderbuffers(Renderbuffers) ->
- cast(5651, <<(length(Renderbuffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Renderbuffers>>)/binary,0:(((1+length(Renderbuffers)) rem 2)*32)>>).
+ RenderbuffersLen = length(Renderbuffers),
+ cast(5652, <<RenderbuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Renderbuffers>>)/binary,0:(((1+RenderbuffersLen) rem 2)*32)>>).
%% @doc Generate renderbuffer object names
%%
@@ -13425,7 +13487,7 @@ deleteRenderbuffers(Renderbuffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenRenderbuffers.xml">external</a> documentation.
-spec genRenderbuffers(N) -> [integer()] when N :: integer().
genRenderbuffers(N) ->
- call(5652, <<N:?GLsizei>>).
+ call(5653, <<N:?GLsizei>>).
%% @doc Establish data storage, format and dimensions of a renderbuffer object's image
%%
@@ -13446,7 +13508,7 @@ genRenderbuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glRenderbufferStorage.xml">external</a> documentation.
-spec renderbufferStorage(Target, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Internalformat :: enum(),Width :: integer(),Height :: integer().
renderbufferStorage(Target,Internalformat,Width,Height) ->
- cast(5653, <<Target:?GLenum,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5654, <<Target:?GLenum,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc Retrieve information about a bound renderbuffer object
%%
@@ -13474,7 +13536,7 @@ renderbufferStorage(Target,Internalformat,Width,Height) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetRenderbufferParameter.xml">external</a> documentation.
-spec getRenderbufferParameteriv(Target, Pname) -> integer() when Target :: enum(),Pname :: enum().
getRenderbufferParameteriv(Target,Pname) ->
- call(5654, <<Target:?GLenum,Pname:?GLenum>>).
+ call(5655, <<Target:?GLenum,Pname:?GLenum>>).
%% @doc Determine if a name corresponds to a framebuffer object
%%
@@ -13488,7 +13550,7 @@ getRenderbufferParameteriv(Target,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsFramebuffer.xml">external</a> documentation.
-spec isFramebuffer(Framebuffer) -> 0|1 when Framebuffer :: integer().
isFramebuffer(Framebuffer) ->
- call(5655, <<Framebuffer:?GLuint>>).
+ call(5656, <<Framebuffer:?GLuint>>).
%% @doc Bind a framebuffer to a framebuffer target
%%
@@ -13506,7 +13568,7 @@ isFramebuffer(Framebuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFramebuffer.xml">external</a> documentation.
-spec bindFramebuffer(Target, Framebuffer) -> 'ok' when Target :: enum(),Framebuffer :: integer().
bindFramebuffer(Target,Framebuffer) ->
- cast(5656, <<Target:?GLenum,Framebuffer:?GLuint>>).
+ cast(5657, <<Target:?GLenum,Framebuffer:?GLuint>>).
%% @doc Delete framebuffer objects
%%
@@ -13521,8 +13583,9 @@ bindFramebuffer(Target,Framebuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteFramebuffers.xml">external</a> documentation.
-spec deleteFramebuffers(Framebuffers) -> 'ok' when Framebuffers :: [integer()].
deleteFramebuffers(Framebuffers) ->
- cast(5657, <<(length(Framebuffers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Framebuffers>>)/binary,0:(((1+length(Framebuffers)) rem 2)*32)>>).
+ FramebuffersLen = length(Framebuffers),
+ cast(5658, <<FramebuffersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Framebuffers>>)/binary,0:(((1+FramebuffersLen) rem 2)*32)>>).
%% @doc Generate framebuffer object names
%%
@@ -13540,7 +13603,7 @@ deleteFramebuffers(Framebuffers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenFramebuffers.xml">external</a> documentation.
-spec genFramebuffers(N) -> [integer()] when N :: integer().
genFramebuffers(N) ->
- call(5658, <<N:?GLsizei>>).
+ call(5659, <<N:?GLsizei>>).
%% @doc Check the completeness status of a framebuffer
%%
@@ -13591,25 +13654,25 @@ genFramebuffers(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCheckFramebufferStatus.xml">external</a> documentation.
-spec checkFramebufferStatus(Target) -> enum() when Target :: enum().
checkFramebufferStatus(Target) ->
- call(5659, <<Target:?GLenum>>).
+ call(5660, <<Target:?GLenum>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture1D(Target, Attachment, Textarget, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture1D(Target,Attachment,Textarget,Texture,Level) ->
- cast(5660, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5661, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture2D(Target, Attachment, Textarget, Texture, Level) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer().
framebufferTexture2D(Target,Attachment,Textarget,Texture,Level) ->
- cast(5661, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
+ cast(5662, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTexture3D(Target, Attachment, Textarget, Texture, Level, Zoffset) -> 'ok' when Target :: enum(),Attachment :: enum(),Textarget :: enum(),Texture :: integer(),Level :: integer(),Zoffset :: integer().
framebufferTexture3D(Target,Attachment,Textarget,Texture,Level,Zoffset) ->
- cast(5662, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint,Zoffset:?GLint>>).
+ cast(5663, <<Target:?GLenum,Attachment:?GLenum,Textarget:?GLenum,Texture:?GLuint,Level:?GLint,Zoffset:?GLint>>).
%% @doc Attach a renderbuffer as a logical buffer to the currently bound framebuffer object
%%
@@ -13641,7 +13704,7 @@ framebufferTexture3D(Target,Attachment,Textarget,Texture,Level,Zoffset) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFramebufferRenderbuffer.xml">external</a> documentation.
-spec framebufferRenderbuffer(Target, Attachment, Renderbuffertarget, Renderbuffer) -> 'ok' when Target :: enum(),Attachment :: enum(),Renderbuffertarget :: enum(),Renderbuffer :: integer().
framebufferRenderbuffer(Target,Attachment,Renderbuffertarget,Renderbuffer) ->
- cast(5663, <<Target:?GLenum,Attachment:?GLenum,Renderbuffertarget:?GLenum,Renderbuffer:?GLuint>>).
+ cast(5664, <<Target:?GLenum,Attachment:?GLenum,Renderbuffertarget:?GLenum,Renderbuffer:?GLuint>>).
%% @doc Retrieve information about attachments of a bound framebuffer object
%%
@@ -13737,7 +13800,7 @@ framebufferRenderbuffer(Target,Attachment,Renderbuffertarget,Renderbuffer) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFramebufferAttachmentParameter.xml">external</a> documentation.
-spec getFramebufferAttachmentParameteriv(Target, Attachment, Pname) -> integer() when Target :: enum(),Attachment :: enum(),Pname :: enum().
getFramebufferAttachmentParameteriv(Target,Attachment,Pname) ->
- call(5664, <<Target:?GLenum,Attachment:?GLenum,Pname:?GLenum>>).
+ call(5665, <<Target:?GLenum,Attachment:?GLenum,Pname:?GLenum>>).
%% @doc Generate mipmaps for a specified texture target
%%
@@ -13757,7 +13820,7 @@ getFramebufferAttachmentParameteriv(Target,Attachment,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenerateMipmap.xml">external</a> documentation.
-spec generateMipmap(Target) -> 'ok' when Target :: enum().
generateMipmap(Target) ->
- cast(5665, <<Target:?GLenum>>).
+ cast(5666, <<Target:?GLenum>>).
%% @doc Copy a block of pixels from the read framebuffer to the draw framebuffer
%%
@@ -13799,7 +13862,7 @@ generateMipmap(Target) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBlitFramebuffer.xml">external</a> documentation.
-spec blitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter) -> 'ok' when SrcX0 :: integer(),SrcY0 :: integer(),SrcX1 :: integer(),SrcY1 :: integer(),DstX0 :: integer(),DstY0 :: integer(),DstX1 :: integer(),DstY1 :: integer(),Mask :: integer(),Filter :: enum().
blitFramebuffer(SrcX0,SrcY0,SrcX1,SrcY1,DstX0,DstY0,DstX1,DstY1,Mask,Filter) ->
- cast(5666, <<SrcX0:?GLint,SrcY0:?GLint,SrcX1:?GLint,SrcY1:?GLint,DstX0:?GLint,DstY0:?GLint,DstX1:?GLint,DstY1:?GLint,Mask:?GLbitfield,Filter:?GLenum>>).
+ cast(5667, <<SrcX0:?GLint,SrcY0:?GLint,SrcX1:?GLint,SrcY1:?GLint,DstX0:?GLint,DstY0:?GLint,DstX1:?GLint,DstY1:?GLint,Mask:?GLbitfield,Filter:?GLenum>>).
%% @doc Establish data storage, format, dimensions and sample count of a renderbuffer object's image
%%
@@ -13823,19 +13886,19 @@ blitFramebuffer(SrcX0,SrcY0,SrcX1,SrcY1,DstX0,DstY0,DstX1,DstY1,Mask,Filter) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glRenderbufferStorageMultisample.xml">external</a> documentation.
-spec renderbufferStorageMultisample(Target, Samples, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer().
renderbufferStorageMultisample(Target,Samples,Internalformat,Width,Height) ->
- cast(5667, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5668, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTextureLayer(Target, Attachment, Texture, Level, Layer) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer(),Layer :: integer().
framebufferTextureLayer(Target,Attachment,Texture,Level,Layer) ->
- cast(5668, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Layer:?GLint>>).
+ cast(5669, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Layer:?GLint>>).
%% @doc
%% See {@link framebufferTexture/4}
-spec framebufferTextureFaceARB(Target, Attachment, Texture, Level, Face) -> 'ok' when Target :: enum(),Attachment :: enum(),Texture :: integer(),Level :: integer(),Face :: enum().
framebufferTextureFaceARB(Target,Attachment,Texture,Level,Face) ->
- cast(5669, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Face:?GLenum>>).
+ cast(5670, <<Target:?GLenum,Attachment:?GLenum,Texture:?GLuint,Level:?GLint,Face:?GLenum>>).
%% @doc Indicate modifications to a range of a mapped buffer
%%
@@ -13849,7 +13912,7 @@ framebufferTextureFaceARB(Target,Attachment,Texture,Level,Face) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFlushMappedBufferRange.xml">external</a> documentation.
-spec flushMappedBufferRange(Target, Offset, Length) -> 'ok' when Target :: enum(),Offset :: integer(),Length :: integer().
flushMappedBufferRange(Target,Offset,Length) ->
- cast(5670, <<Target:?GLenum,0:32,Offset:?GLintptr,Length:?GLsizeiptr>>).
+ cast(5671, <<Target:?GLenum,0:32,Offset:?GLintptr,Length:?GLsizeiptr>>).
%% @doc Bind a vertex array object
%%
@@ -13864,7 +13927,7 @@ flushMappedBufferRange(Target,Offset,Length) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindVertexArray.xml">external</a> documentation.
-spec bindVertexArray(Array) -> 'ok' when Array :: integer().
bindVertexArray(Array) ->
- cast(5671, <<Array:?GLuint>>).
+ cast(5672, <<Array:?GLuint>>).
%% @doc Delete vertex array objects
%%
@@ -13877,8 +13940,9 @@ bindVertexArray(Array) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteVertexArrays.xml">external</a> documentation.
-spec deleteVertexArrays(Arrays) -> 'ok' when Arrays :: [integer()].
deleteVertexArrays(Arrays) ->
- cast(5672, <<(length(Arrays)):?GLuint,
- (<< <<C:?GLuint>> || C <- Arrays>>)/binary,0:(((1+length(Arrays)) rem 2)*32)>>).
+ ArraysLen = length(Arrays),
+ cast(5673, <<ArraysLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Arrays>>)/binary,0:(((1+ArraysLen) rem 2)*32)>>).
%% @doc Generate vertex array object names
%%
@@ -13896,7 +13960,7 @@ deleteVertexArrays(Arrays) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenVertexArrays.xml">external</a> documentation.
-spec genVertexArrays(N) -> [integer()] when N :: integer().
genVertexArrays(N) ->
- call(5673, <<N:?GLsizei>>).
+ call(5674, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a vertex array object
%%
@@ -13910,7 +13974,7 @@ genVertexArrays(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsVertexArray.xml">external</a> documentation.
-spec isVertexArray(Array) -> 0|1 when Array :: integer().
isVertexArray(Array) ->
- call(5674, <<Array:?GLuint>>).
+ call(5675, <<Array:?GLuint>>).
%% @doc Retrieve the index of a named uniform block
%%
@@ -13937,16 +14001,18 @@ isVertexArray(Array) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformIndices.xml">external</a> documentation.
-spec getUniformIndices(Program, UniformNames) -> [integer()] when Program :: integer(),UniformNames :: iolist().
getUniformIndices(Program,UniformNames) ->
- UniformNamesTemp = list_to_binary([[Str|[0]] || Str <- UniformNames ]),
- call(5675, <<Program:?GLuint,(length(UniformNames)):?GLuint,(size(UniformNamesTemp)):?GLuint,(UniformNamesTemp)/binary,0:((8-((size(UniformNamesTemp)+0) rem 8)) rem 8)>>).
+ UniformNamesTemp = list_to_binary([[Str|[0]] || Str <- UniformNames ]),
+ UniformNamesLen = length(UniformNames),
+ call(5676, <<Program:?GLuint,UniformNamesLen:?GLuint,(size(UniformNamesTemp)):?GLuint,(UniformNamesTemp)/binary,0:((8-((size(UniformNamesTemp)+0) rem 8)) rem 8)>>).
%% @doc glGetActiveUniforms
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniforms.xml">external</a> documentation.
-spec getActiveUniformsiv(Program, UniformIndices, Pname) -> [integer()] when Program :: integer(),UniformIndices :: [integer()],Pname :: enum().
getActiveUniformsiv(Program,UniformIndices,Pname) ->
- call(5676, <<Program:?GLuint,(length(UniformIndices)):?GLuint,
- (<< <<C:?GLuint>> || C <- UniformIndices>>)/binary,0:(((length(UniformIndices)) rem 2)*32),Pname:?GLenum>>).
+ UniformIndicesLen = length(UniformIndices),
+ call(5677, <<Program:?GLuint,UniformIndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- UniformIndices>>)/binary,0:(((UniformIndicesLen) rem 2)*32),Pname:?GLenum>>).
%% @doc Query the name of an active uniform
%%
@@ -13975,7 +14041,7 @@ getActiveUniformsiv(Program,UniformIndices,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformName.xml">external</a> documentation.
-spec getActiveUniformName(Program, UniformIndex, BufSize) -> string() when Program :: integer(),UniformIndex :: integer(),BufSize :: integer().
getActiveUniformName(Program,UniformIndex,BufSize) ->
- call(5677, <<Program:?GLuint,UniformIndex:?GLuint,BufSize:?GLsizei>>).
+ call(5678, <<Program:?GLuint,UniformIndex:?GLuint,BufSize:?GLsizei>>).
%% @doc Retrieve the index of a named uniform block
%%
@@ -13999,7 +14065,8 @@ getActiveUniformName(Program,UniformIndex,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformBlockIndex.xml">external</a> documentation.
-spec getUniformBlockIndex(Program, UniformBlockName) -> integer() when Program :: integer(),UniformBlockName :: string().
getUniformBlockIndex(Program,UniformBlockName) ->
- call(5678, <<Program:?GLuint,(list_to_binary([UniformBlockName|[0]]))/binary,0:((8-((length(UniformBlockName)+ 5) rem 8)) rem 8)>>).
+ UniformBlockNameLen = length(UniformBlockName),
+ call(5679, <<Program:?GLuint,(list_to_binary([UniformBlockName|[0]]))/binary,0:((8-((UniformBlockNameLen+ 5) rem 8)) rem 8)>>).
%% @doc Query information about an active uniform block
%%
@@ -14052,7 +14119,7 @@ getUniformBlockIndex(Program,UniformBlockName) ->
-spec getActiveUniformBlockiv(Program, UniformBlockIndex, Pname, Params) -> 'ok' when Program :: integer(),UniformBlockIndex :: integer(),Pname :: enum(),Params :: mem().
getActiveUniformBlockiv(Program,UniformBlockIndex,Pname,Params) ->
send_bin(Params),
- call(5679, <<Program:?GLuint,UniformBlockIndex:?GLuint,Pname:?GLenum>>).
+ call(5680, <<Program:?GLuint,UniformBlockIndex:?GLuint,Pname:?GLenum>>).
%% @doc Retrieve the name of an active uniform block
%%
@@ -14081,7 +14148,7 @@ getActiveUniformBlockiv(Program,UniformBlockIndex,Pname,Params) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveUniformBlockName.xml">external</a> documentation.
-spec getActiveUniformBlockName(Program, UniformBlockIndex, BufSize) -> string() when Program :: integer(),UniformBlockIndex :: integer(),BufSize :: integer().
getActiveUniformBlockName(Program,UniformBlockIndex,BufSize) ->
- call(5680, <<Program:?GLuint,UniformBlockIndex:?GLuint,BufSize:?GLsizei>>).
+ call(5681, <<Program:?GLuint,UniformBlockIndex:?GLuint,BufSize:?GLsizei>>).
%% @doc Assign a binding point to an active uniform block
%%
@@ -14101,7 +14168,7 @@ getActiveUniformBlockName(Program,UniformBlockIndex,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniformBlockBinding.xml">external</a> documentation.
-spec uniformBlockBinding(Program, UniformBlockIndex, UniformBlockBinding) -> 'ok' when Program :: integer(),UniformBlockIndex :: integer(),UniformBlockBinding :: integer().
uniformBlockBinding(Program,UniformBlockIndex,UniformBlockBinding) ->
- cast(5681, <<Program:?GLuint,UniformBlockIndex:?GLuint,UniformBlockBinding:?GLuint>>).
+ cast(5682, <<Program:?GLuint,UniformBlockIndex:?GLuint,UniformBlockBinding:?GLuint>>).
%% @doc Copy part of the data store of a buffer object to the data store of another buffer object
%%
@@ -14127,7 +14194,7 @@ uniformBlockBinding(Program,UniformBlockIndex,UniformBlockBinding) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCopyBufferSubData.xml">external</a> documentation.
-spec copyBufferSubData(ReadTarget, WriteTarget, ReadOffset, WriteOffset, Size) -> 'ok' when ReadTarget :: enum(),WriteTarget :: enum(),ReadOffset :: integer(),WriteOffset :: integer(),Size :: integer().
copyBufferSubData(ReadTarget,WriteTarget,ReadOffset,WriteOffset,Size) ->
- cast(5682, <<ReadTarget:?GLenum,WriteTarget:?GLenum,ReadOffset:?GLintptr,WriteOffset:?GLintptr,Size:?GLsizeiptr>>).
+ cast(5683, <<ReadTarget:?GLenum,WriteTarget:?GLenum,ReadOffset:?GLintptr,WriteOffset:?GLintptr,Size:?GLsizeiptr>>).
%% @doc Render primitives from array data with a per-element offset
%%
@@ -14141,10 +14208,10 @@ copyBufferSubData(ReadTarget,WriteTarget,ReadOffset,WriteOffset,Size) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsBaseVertex.xml">external</a> documentation.
-spec drawElementsBaseVertex(Mode, Count, Type, Indices, Basevertex) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Basevertex :: integer().
drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) when is_integer(Indices) ->
- cast(5683, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
+ cast(5684, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) ->
send_bin(Indices),
- cast(5684, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
+ cast(5685, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
%% @doc Render primitives from array data with a per-element offset
%%
@@ -14163,10 +14230,10 @@ drawElementsBaseVertex(Mode,Count,Type,Indices,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawRangeElementsBaseVertex.xml">external</a> documentation.
-spec drawRangeElementsBaseVertex(Mode, Start, End, Count, Type, Indices, Basevertex) -> 'ok' when Mode :: enum(),Start :: integer(),End :: integer(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Basevertex :: integer().
drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) when is_integer(Indices) ->
- cast(5685, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
+ cast(5686, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Basevertex:?GLint>>);
drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) ->
send_bin(Indices),
- cast(5686, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
+ cast(5687, <<Mode:?GLenum,Start:?GLuint,End:?GLuint,Count:?GLsizei,Type:?GLenum,Basevertex:?GLint>>).
%% @doc Render multiple instances of a set of primitives from array data with a per-element offset
%%
@@ -14180,10 +14247,10 @@ drawRangeElementsBaseVertex(Mode,Start,End,Count,Type,Indices,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseVertex.xml">external</a> documentation.
-spec drawElementsInstancedBaseVertex(Mode, Count, Type, Indices, Primcount, Basevertex) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Basevertex :: integer().
drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) when is_integer(Indices) ->
- cast(5687, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint>>);
+ cast(5688, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint>>);
drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) ->
send_bin(Indices),
- cast(5688, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint>>).
+ cast(5689, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint>>).
%% @doc Specifiy the vertex to be used as the source of data for flat shaded varyings
%%
@@ -14217,7 +14284,7 @@ drawElementsInstancedBaseVertex(Mode,Count,Type,Indices,Primcount,Basevertex) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProvokingVertex.xml">external</a> documentation.
-spec provokingVertex(Mode) -> 'ok' when Mode :: enum().
provokingVertex(Mode) ->
- cast(5689, <<Mode:?GLenum>>).
+ cast(5690, <<Mode:?GLenum>>).
%% @doc Create a new sync object and insert it into the GL command stream
%%
@@ -14241,7 +14308,7 @@ provokingVertex(Mode) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glFenceSync.xml">external</a> documentation.
-spec fenceSync(Condition, Flags) -> integer() when Condition :: enum(),Flags :: integer().
fenceSync(Condition,Flags) ->
- call(5690, <<Condition:?GLenum,Flags:?GLbitfield>>).
+ call(5691, <<Condition:?GLenum,Flags:?GLbitfield>>).
%% @doc Determine if a name corresponds to a sync object
%%
@@ -14252,7 +14319,7 @@ fenceSync(Condition,Flags) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsSync.xml">external</a> documentation.
-spec isSync(Sync) -> 0|1 when Sync :: integer().
isSync(Sync) ->
- call(5691, <<Sync:?GLsync>>).
+ call(5692, <<Sync:?GLsync>>).
%% @doc Delete a sync object
%%
@@ -14269,7 +14336,7 @@ isSync(Sync) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteSync.xml">external</a> documentation.
-spec deleteSync(Sync) -> 'ok' when Sync :: integer().
deleteSync(Sync) ->
- cast(5692, <<Sync:?GLsync>>).
+ cast(5693, <<Sync:?GLsync>>).
%% @doc Block and wait for a sync object to become signaled
%%
@@ -14295,7 +14362,7 @@ deleteSync(Sync) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClientWaitSync.xml">external</a> documentation.
-spec clientWaitSync(Sync, Flags, Timeout) -> enum() when Sync :: integer(),Flags :: integer(),Timeout :: integer().
clientWaitSync(Sync,Flags,Timeout) ->
- call(5693, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
+ call(5694, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
%% @doc Instruct the GL server to block until the specified sync object becomes signaled
%%
@@ -14317,13 +14384,13 @@ clientWaitSync(Sync,Flags,Timeout) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glWaitSync.xml">external</a> documentation.
-spec waitSync(Sync, Flags, Timeout) -> 'ok' when Sync :: integer(),Flags :: integer(),Timeout :: integer().
waitSync(Sync,Flags,Timeout) ->
- cast(5694, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
+ cast(5695, <<Sync:?GLsync,Flags:?GLbitfield,0:32,Timeout:?GLuint64>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getInteger64v(Pname) -> [integer()] when Pname :: enum().
getInteger64v(Pname) ->
- call(5695, <<Pname:?GLenum>>).
+ call(5696, <<Pname:?GLenum>>).
%% @doc Query the properties of a sync object
%%
@@ -14358,7 +14425,7 @@ getInteger64v(Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSync.xml">external</a> documentation.
-spec getSynciv(Sync, Pname, BufSize) -> [integer()] when Sync :: integer(),Pname :: enum(),BufSize :: integer().
getSynciv(Sync,Pname,BufSize) ->
- call(5696, <<Sync:?GLsync,Pname:?GLenum,BufSize:?GLsizei>>).
+ call(5697, <<Sync:?GLsync,Pname:?GLenum,BufSize:?GLsizei>>).
%% @doc Establish the data storage, format, dimensions, and number of samples of a multisample texture's image
%%
@@ -14386,7 +14453,7 @@ getSynciv(Sync,Pname,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2DMultisample.xml">external</a> documentation.
-spec texImage2DMultisample(Target, Samples, Internalformat, Width, Height, Fixedsamplelocations) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: integer(),Width :: integer(),Height :: integer(),Fixedsamplelocations :: 0|1.
texImage2DMultisample(Target,Samples,Internalformat,Width,Height,Fixedsamplelocations) ->
- cast(5697, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Fixedsamplelocations:?GLboolean>>).
+ cast(5698, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Fixedsamplelocations:?GLboolean>>).
%% @doc Establish the data storage, format, dimensions, and number of samples of a multisample texture's image
%%
@@ -14414,7 +14481,7 @@ texImage2DMultisample(Target,Samples,Internalformat,Width,Height,Fixedsampleloca
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexImage3DMultisample.xml">external</a> documentation.
-spec texImage3DMultisample(Target, Samples, Internalformat, Width, Height, Depth, Fixedsamplelocations) -> 'ok' when Target :: enum(),Samples :: integer(),Internalformat :: integer(),Width :: integer(),Height :: integer(),Depth :: integer(),Fixedsamplelocations :: 0|1.
texImage3DMultisample(Target,Samples,Internalformat,Width,Height,Depth,Fixedsamplelocations) ->
- cast(5698, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei,Fixedsamplelocations:?GLboolean>>).
+ cast(5699, <<Target:?GLenum,Samples:?GLsizei,Internalformat:?GLint,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei,Fixedsamplelocations:?GLboolean>>).
%% @doc Retrieve the location of a sample
%%
@@ -14432,7 +14499,7 @@ texImage3DMultisample(Target,Samples,Internalformat,Width,Height,Depth,Fixedsamp
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetMultisample.xml">external</a> documentation.
-spec getMultisamplefv(Pname, Index) -> {float(),float()} when Pname :: enum(),Index :: integer().
getMultisamplefv(Pname,Index) ->
- call(5699, <<Pname:?GLenum,Index:?GLuint>>).
+ call(5700, <<Pname:?GLenum,Index:?GLuint>>).
%% @doc Set the value of a sub-word of the sample mask
%%
@@ -14447,57 +14514,65 @@ getMultisamplefv(Pname,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSampleMaski.xml">external</a> documentation.
-spec sampleMaski(Index, Mask) -> 'ok' when Index :: integer(),Mask :: integer().
sampleMaski(Index,Mask) ->
- cast(5700, <<Index:?GLuint,Mask:?GLbitfield>>).
+ cast(5701, <<Index:?GLuint,Mask:?GLbitfield>>).
%% @doc glNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glNamedStringARB.xml">external</a> documentation.
-spec namedStringARB(Type, Name, String) -> 'ok' when Type :: enum(),Name :: string(),String :: string().
namedStringARB(Type,Name,String) ->
- cast(5701, <<Type:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8),(list_to_binary([String|[0]]))/binary,0:((8-((length(String)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ StringLen = length(String),
+ cast(5702, <<Type:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8),(list_to_binary([String|[0]]))/binary,0:((8-((StringLen+ 1) rem 8)) rem 8)>>).
%% @doc glDeleteNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteNamedStringARB.xml">external</a> documentation.
-spec deleteNamedStringARB(Name) -> 'ok' when Name :: string().
deleteNamedStringARB(Name) ->
- cast(5702, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5703, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glCompileShaderIncludeARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCompileShaderIncludeARB.xml">external</a> documentation.
-spec compileShaderIncludeARB(Shader, Path) -> 'ok' when Shader :: integer(),Path :: iolist().
compileShaderIncludeARB(Shader,Path) ->
- PathTemp = list_to_binary([[Str|[0]] || Str <- Path ]),
- cast(5703, <<Shader:?GLuint,(length(Path)):?GLuint,(size(PathTemp)):?GLuint,(PathTemp)/binary,0:((8-((size(PathTemp)+0) rem 8)) rem 8)>>).
+ PathTemp = list_to_binary([[Str|[0]] || Str <- Path ]),
+ PathLen = length(Path),
+ cast(5704, <<Shader:?GLuint,PathLen:?GLuint,(size(PathTemp)):?GLuint,(PathTemp)/binary,0:((8-((size(PathTemp)+0) rem 8)) rem 8)>>).
%% @doc glIsNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsNamedStringARB.xml">external</a> documentation.
-spec isNamedStringARB(Name) -> 0|1 when Name :: string().
isNamedStringARB(Name) ->
- call(5704, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5705, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetNamedStringARB.xml">external</a> documentation.
-spec getNamedStringARB(Name, BufSize) -> string() when Name :: string(),BufSize :: integer().
getNamedStringARB(Name,BufSize) ->
- call(5705, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8),BufSize:?GLsizei>>).
+ NameLen = length(Name),
+ call(5706, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8),BufSize:?GLsizei>>).
%% @doc glGetNamedStringARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetNamedStringARB.xml">external</a> documentation.
-spec getNamedStringivARB(Name, Pname) -> integer() when Name :: string(),Pname :: enum().
getNamedStringivARB(Name,Pname) ->
- call(5706, <<(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8),Pname:?GLenum>>).
+ NameLen = length(Name),
+ call(5707, <<(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8),Pname:?GLenum>>).
%% @doc glBindFragDataLocationIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindFragDataLocationIndexe.xml">external</a> documentation.
-spec bindFragDataLocationIndexed(Program, ColorNumber, Index, Name) -> 'ok' when Program :: integer(),ColorNumber :: integer(),Index :: integer(),Name :: string().
bindFragDataLocationIndexed(Program,ColorNumber,Index,Name) ->
- cast(5707, <<Program:?GLuint,ColorNumber:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ cast(5708, <<Program:?GLuint,ColorNumber:?GLuint,Index:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Query the bindings of color indices to user-defined varying out variables
%%
@@ -14508,7 +14583,8 @@ bindFragDataLocationIndexed(Program,ColorNumber,Index,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetFragDataIndex.xml">external</a> documentation.
-spec getFragDataIndex(Program, Name) -> integer() when Program :: integer(),Name :: string().
getFragDataIndex(Program,Name) ->
- call(5708, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 5) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5709, <<Program:?GLuint,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 5) rem 8)) rem 8)>>).
%% @doc Generate sampler object names
%%
@@ -14526,7 +14602,7 @@ getFragDataIndex(Program,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenSamplers.xml">external</a> documentation.
-spec genSamplers(Count) -> [integer()] when Count :: integer().
genSamplers(Count) ->
- call(5709, <<Count:?GLsizei>>).
+ call(5710, <<Count:?GLsizei>>).
%% @doc Delete named sampler objects
%%
@@ -14539,8 +14615,9 @@ genSamplers(Count) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteSamplers.xml">external</a> documentation.
-spec deleteSamplers(Samplers) -> 'ok' when Samplers :: [integer()].
deleteSamplers(Samplers) ->
- cast(5710, <<(length(Samplers)):?GLuint,
- (<< <<C:?GLuint>> || C <- Samplers>>)/binary,0:(((1+length(Samplers)) rem 2)*32)>>).
+ SamplersLen = length(Samplers),
+ cast(5711, <<SamplersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Samplers>>)/binary,0:(((1+SamplersLen) rem 2)*32)>>).
%% @doc Determine if a name corresponds to a sampler object
%%
@@ -14553,7 +14630,7 @@ deleteSamplers(Samplers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsSampler.xml">external</a> documentation.
-spec isSampler(Sampler) -> 0|1 when Sampler :: integer().
isSampler(Sampler) ->
- call(5711, <<Sampler:?GLuint>>).
+ call(5712, <<Sampler:?GLuint>>).
%% @doc Bind a named sampler to a texturing target
%%
@@ -14570,7 +14647,7 @@ isSampler(Sampler) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindSampler.xml">external</a> documentation.
-spec bindSampler(Unit, Sampler) -> 'ok' when Unit :: integer(),Sampler :: integer().
bindSampler(Unit,Sampler) ->
- cast(5712, <<Unit:?GLuint,Sampler:?GLuint>>).
+ cast(5713, <<Unit:?GLuint,Sampler:?GLuint>>).
%% @doc Set sampler parameters
%%
@@ -14716,42 +14793,46 @@ bindSampler(Unit,Sampler) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSamplerParameter.xml">external</a> documentation.
-spec samplerParameteri(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: integer().
samplerParameteri(Sampler,Pname,Param) ->
- cast(5713, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLint>>).
+ cast(5714, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLint>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameteriv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameteriv(Sampler,Pname,Param) ->
- cast(5714, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5715, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterf(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: float().
samplerParameterf(Sampler,Pname,Param) ->
- cast(5715, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLfloat>>).
+ cast(5716, <<Sampler:?GLuint,Pname:?GLenum,Param:?GLfloat>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterfv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [float()].
samplerParameterfv(Sampler,Pname,Param) ->
- cast(5716, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5717, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc
%% See {@link samplerParameteri/3}
-spec samplerParameterIiv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameterIiv(Sampler,Pname,Param) ->
- cast(5717, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5718, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc glSamplerParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glSamplerParameterI.xml">external</a> documentation.
-spec samplerParameterIuiv(Sampler, Pname, Param) -> 'ok' when Sampler :: integer(),Pname :: enum(),Param :: [integer()].
samplerParameterIuiv(Sampler,Pname,Param) ->
- cast(5718, <<Sampler:?GLuint,Pname:?GLenum,(length(Param)):?GLuint,
- (<< <<C:?GLuint>> || C <- Param>>)/binary,0:(((1+length(Param)) rem 2)*32)>>).
+ ParamLen = length(Param),
+ cast(5719, <<Sampler:?GLuint,Pname:?GLenum,ParamLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Param>>)/binary,0:(((1+ParamLen) rem 2)*32)>>).
%% @doc Return sampler parameter values
%%
@@ -14798,26 +14879,26 @@ samplerParameterIuiv(Sampler,Pname,Param) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSamplerParameter.xml">external</a> documentation.
-spec getSamplerParameteriv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameteriv(Sampler,Pname) ->
- call(5719, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5720, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getSamplerParameteriv/2}
-spec getSamplerParameterIiv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterIiv(Sampler,Pname) ->
- call(5720, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5721, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc
%% See {@link getSamplerParameteriv/2}
-spec getSamplerParameterfv(Sampler, Pname) -> [float()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterfv(Sampler,Pname) ->
- call(5721, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5722, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc glGetSamplerParameterI
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSamplerParameterI.xml">external</a> documentation.
-spec getSamplerParameterIuiv(Sampler, Pname) -> [integer()] when Sampler :: integer(),Pname :: enum().
getSamplerParameterIuiv(Sampler,Pname) ->
- call(5722, <<Sampler:?GLuint,Pname:?GLenum>>).
+ call(5723, <<Sampler:?GLuint,Pname:?GLenum>>).
%% @doc Record the GL time into a query object after all previous commands have reached the GL server but have not yet necessarily executed.
%%
@@ -14832,21 +14913,21 @@ getSamplerParameterIuiv(Sampler,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glQueryCounter.xml">external</a> documentation.
-spec queryCounter(Id, Target) -> 'ok' when Id :: integer(),Target :: enum().
queryCounter(Id,Target) ->
- cast(5723, <<Id:?GLuint,Target:?GLenum>>).
+ cast(5724, <<Id:?GLuint,Target:?GLenum>>).
%% @doc glGetQueryObjecti64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObjecti64v.xml">external</a> documentation.
-spec getQueryObjecti64v(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjecti64v(Id,Pname) ->
- call(5724, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5725, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc glGetQueryObjectui64v
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryObjectui64v.xml">external</a> documentation.
-spec getQueryObjectui64v(Id, Pname) -> integer() when Id :: integer(),Pname :: enum().
getQueryObjectui64v(Id,Pname) ->
- call(5725, <<Id:?GLuint,Pname:?GLenum>>).
+ call(5726, <<Id:?GLuint,Pname:?GLenum>>).
%% @doc Render primitives from array data, taking parameters from memory
%%
@@ -14876,10 +14957,10 @@ getQueryObjectui64v(Id,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysIndirect.xml">external</a> documentation.
-spec drawArraysIndirect(Mode, Indirect) -> 'ok' when Mode :: enum(),Indirect :: offset()|mem().
drawArraysIndirect(Mode,Indirect) when is_integer(Indirect) ->
- cast(5726, <<Mode:?GLenum,Indirect:?GLuint>>);
+ cast(5727, <<Mode:?GLenum,Indirect:?GLuint>>);
drawArraysIndirect(Mode,Indirect) ->
send_bin(Indirect),
- cast(5727, <<Mode:?GLenum>>).
+ cast(5728, <<Mode:?GLenum>>).
%% @doc Render indexed primitives from array data, taking parameters from memory
%%
@@ -14916,131 +14997,144 @@ drawArraysIndirect(Mode,Indirect) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsIndirect.xml">external</a> documentation.
-spec drawElementsIndirect(Mode, Type, Indirect) -> 'ok' when Mode :: enum(),Type :: enum(),Indirect :: offset()|mem().
drawElementsIndirect(Mode,Type,Indirect) when is_integer(Indirect) ->
- cast(5728, <<Mode:?GLenum,Type:?GLenum,Indirect:?GLuint>>);
+ cast(5729, <<Mode:?GLenum,Type:?GLenum,Indirect:?GLuint>>);
drawElementsIndirect(Mode,Type,Indirect) ->
send_bin(Indirect),
- cast(5729, <<Mode:?GLenum,Type:?GLenum>>).
+ cast(5730, <<Mode:?GLenum,Type:?GLenum>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1d(Location, X) -> 'ok' when Location :: integer(),X :: float().
uniform1d(Location,X) ->
- cast(5730, <<Location:?GLint,0:32,X:?GLdouble>>).
+ cast(5731, <<Location:?GLint,0:32,X:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2d(Location, X, Y) -> 'ok' when Location :: integer(),X :: float(),Y :: float().
uniform2d(Location,X,Y) ->
- cast(5731, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5732, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3d(Location, X, Y, Z) -> 'ok' when Location :: integer(),X :: float(),Y :: float(),Z :: float().
uniform3d(Location,X,Y,Z) ->
- cast(5732, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5733, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4d(Location, X, Y, Z, W) -> 'ok' when Location :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
uniform4d(Location,X,Y,Z,W) ->
- cast(5733, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5734, <<Location:?GLint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform1dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [float()].
uniform1dv(Location,Value) ->
- cast(5734, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5735, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform2dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float()}].
uniform2dv(Location,Value) ->
- cast(5735, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5736, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform3dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float()}].
uniform3dv(Location,Value) ->
- cast(5736, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5737, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniform4dv(Location, Value) -> 'ok' when Location :: integer(),Value :: [{float(),float(),float(),float()}].
uniform4dv(Location,Value) ->
- cast(5737, <<Location:?GLint,0:32,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5738, <<Location:?GLint,0:32,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
uniformMatrix2dv(Location,Transpose,Value) ->
- cast(5738, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5739, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3dv(Location,Transpose,Value) ->
- cast(5739, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5740, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4dv(Location,Transpose,Value) ->
- cast(5740, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5741, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble,V13:?GLdouble,V14:?GLdouble,V15:?GLdouble,V16:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix2x3dv(Location,Transpose,Value) ->
- cast(5741, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5742, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix2x4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix2x4dv(Location,Transpose,Value) ->
- cast(5742, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5743, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
uniformMatrix3x2dv(Location,Transpose,Value) ->
- cast(5743, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5744, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix3x4dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix3x4dv(Location,Transpose,Value) ->
- cast(5744, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5745, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x2dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x2dv(Location,Transpose,Value) ->
- cast(5745, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5746, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link uniform1f/2}
-spec uniformMatrix4x3dv(Location, Transpose, Value) -> 'ok' when Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
uniformMatrix4x3dv(Location,Transpose,Value) ->
- cast(5746, <<Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5747, <<Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link getUniformfv/2}
-spec getUniformdv(Program, Location) -> matrix() when Program :: integer(),Location :: integer().
getUniformdv(Program,Location) ->
- call(5747, <<Program:?GLuint,Location:?GLint>>).
+ call(5748, <<Program:?GLuint,Location:?GLint>>).
%% @doc Retrieve the location of a subroutine uniform of a given shader stage within a program
%%
@@ -15059,7 +15153,8 @@ getUniformdv(Program,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSubroutineUniformLocation.xml">external</a> documentation.
-spec getSubroutineUniformLocation(Program, Shadertype, Name) -> integer() when Program :: integer(),Shadertype :: enum(),Name :: string().
getSubroutineUniformLocation(Program,Shadertype,Name) ->
- call(5748, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5749, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Retrieve the index of a subroutine uniform of a given shader stage within a program
%%
@@ -15079,7 +15174,8 @@ getSubroutineUniformLocation(Program,Shadertype,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetSubroutineIndex.xml">external</a> documentation.
-spec getSubroutineIndex(Program, Shadertype, Name) -> integer() when Program :: integer(),Shadertype :: enum(),Name :: string().
getSubroutineIndex(Program,Shadertype,Name) ->
- call(5749, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((length(Name)+ 1) rem 8)) rem 8)>>).
+ NameLen = length(Name),
+ call(5750, <<Program:?GLuint,Shadertype:?GLenum,(list_to_binary([Name|[0]]))/binary,0:((8-((NameLen+ 1) rem 8)) rem 8)>>).
%% @doc Query the name of an active shader subroutine uniform
%%
@@ -15100,7 +15196,7 @@ getSubroutineIndex(Program,Shadertype,Name) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveSubroutineUniformName.xml">external</a> documentation.
-spec getActiveSubroutineUniformName(Program, Shadertype, Index, Bufsize) -> string() when Program :: integer(),Shadertype :: enum(),Index :: integer(),Bufsize :: integer().
getActiveSubroutineUniformName(Program,Shadertype,Index,Bufsize) ->
- call(5750, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
+ call(5751, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
%% @doc Query the name of an active shader subroutine
%%
@@ -15118,7 +15214,7 @@ getActiveSubroutineUniformName(Program,Shadertype,Index,Bufsize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetActiveSubroutineName.xml">external</a> documentation.
-spec getActiveSubroutineName(Program, Shadertype, Index, Bufsize) -> string() when Program :: integer(),Shadertype :: enum(),Index :: integer(),Bufsize :: integer().
getActiveSubroutineName(Program,Shadertype,Index,Bufsize) ->
- call(5751, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
+ call(5752, <<Program:?GLuint,Shadertype:?GLenum,Index:?GLuint,Bufsize:?GLsizei>>).
%% @doc Load active subroutine uniforms
%%
@@ -15132,8 +15228,9 @@ getActiveSubroutineName(Program,Shadertype,Index,Bufsize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUniformSubroutines.xml">external</a> documentation.
-spec uniformSubroutinesuiv(Shadertype, Indices) -> 'ok' when Shadertype :: enum(),Indices :: [integer()].
uniformSubroutinesuiv(Shadertype,Indices) ->
- cast(5752, <<Shadertype:?GLenum,(length(Indices)):?GLuint,
- (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((length(Indices)) rem 2)*32)>>).
+ IndicesLen = length(Indices),
+ cast(5753, <<Shadertype:?GLenum,IndicesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Indices>>)/binary,0:(((IndicesLen) rem 2)*32)>>).
%% @doc Retrieve the value of a subroutine uniform of a given shader stage of the current program
%%
@@ -15146,7 +15243,7 @@ uniformSubroutinesuiv(Shadertype,Indices) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformSubroutine.xml">external</a> documentation.
-spec getUniformSubroutineuiv(Shadertype, Location) -> {integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer(),integer()} when Shadertype :: enum(),Location :: integer().
getUniformSubroutineuiv(Shadertype,Location) ->
- call(5753, <<Shadertype:?GLenum,Location:?GLint>>).
+ call(5754, <<Shadertype:?GLenum,Location:?GLint>>).
%% @doc Retrieve properties of a program object corresponding to a specified shader stage
%%
@@ -15178,7 +15275,7 @@ getUniformSubroutineuiv(Shadertype,Location) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramStage.xml">external</a> documentation.
-spec getProgramStageiv(Program, Shadertype, Pname) -> integer() when Program :: integer(),Shadertype :: enum(),Pname :: enum().
getProgramStageiv(Program,Shadertype,Pname) ->
- call(5754, <<Program:?GLuint,Shadertype:?GLenum,Pname:?GLenum>>).
+ call(5755, <<Program:?GLuint,Shadertype:?GLenum,Pname:?GLenum>>).
%% @doc Specifies the parameters for patch primitives
%%
@@ -15205,14 +15302,15 @@ getProgramStageiv(Program,Shadertype,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPatchParameter.xml">external</a> documentation.
-spec patchParameteri(Pname, Value) -> 'ok' when Pname :: enum(),Value :: integer().
patchParameteri(Pname,Value) ->
- cast(5755, <<Pname:?GLenum,Value:?GLint>>).
+ cast(5756, <<Pname:?GLenum,Value:?GLint>>).
%% @doc
%% See {@link patchParameteri/2}
-spec patchParameterfv(Pname, Values) -> 'ok' when Pname :: enum(),Values :: [float()].
patchParameterfv(Pname,Values) ->
- cast(5756, <<Pname:?GLenum,(length(Values)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Values>>)/binary,0:(((length(Values)) rem 2)*32)>>).
+ ValuesLen = length(Values),
+ cast(5757, <<Pname:?GLenum,ValuesLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Values>>)/binary,0:(((ValuesLen) rem 2)*32)>>).
%% @doc Bind a transform feedback object
%%
@@ -15235,7 +15333,7 @@ patchParameterfv(Pname,Values) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindTransformFeedback.xml">external</a> documentation.
-spec bindTransformFeedback(Target, Id) -> 'ok' when Target :: enum(),Id :: integer().
bindTransformFeedback(Target,Id) ->
- cast(5757, <<Target:?GLenum,Id:?GLuint>>).
+ cast(5758, <<Target:?GLenum,Id:?GLuint>>).
%% @doc Delete transform feedback objects
%%
@@ -15248,8 +15346,9 @@ bindTransformFeedback(Target,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteTransformFeedbacks.xml">external</a> documentation.
-spec deleteTransformFeedbacks(Ids) -> 'ok' when Ids :: [integer()].
deleteTransformFeedbacks(Ids) ->
- cast(5758, <<(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+length(Ids)) rem 2)*32)>>).
+ IdsLen = length(Ids),
+ cast(5759, <<IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((1+IdsLen) rem 2)*32)>>).
%% @doc Reserve transform feedback object names
%%
@@ -15260,7 +15359,7 @@ deleteTransformFeedbacks(Ids) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenTransformFeedbacks.xml">external</a> documentation.
-spec genTransformFeedbacks(N) -> [integer()] when N :: integer().
genTransformFeedbacks(N) ->
- call(5759, <<N:?GLsizei>>).
+ call(5760, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a transform feedback object
%%
@@ -15275,7 +15374,7 @@ genTransformFeedbacks(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsTransformFeedback.xml">external</a> documentation.
-spec isTransformFeedback(Id) -> 0|1 when Id :: integer().
isTransformFeedback(Id) ->
- call(5760, <<Id:?GLuint>>).
+ call(5761, <<Id:?GLuint>>).
%% @doc Pause transform feedback operations
%%
@@ -15288,7 +15387,7 @@ isTransformFeedback(Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glPauseTransformFeedback.xml">external</a> documentation.
-spec pauseTransformFeedback() -> 'ok'.
pauseTransformFeedback() ->
- cast(5761, <<>>).
+ cast(5762, <<>>).
%% @doc Resume transform feedback operations
%%
@@ -15301,7 +15400,7 @@ pauseTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glResumeTransformFeedback.xml">external</a> documentation.
-spec resumeTransformFeedback() -> 'ok'.
resumeTransformFeedback() ->
- cast(5762, <<>>).
+ cast(5763, <<>>).
%% @doc Render primitives using a count derived from a transform feedback object
%%
@@ -15315,7 +15414,7 @@ resumeTransformFeedback() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedback.xml">external</a> documentation.
-spec drawTransformFeedback(Mode, Id) -> 'ok' when Mode :: enum(),Id :: integer().
drawTransformFeedback(Mode,Id) ->
- cast(5763, <<Mode:?GLenum,Id:?GLuint>>).
+ cast(5764, <<Mode:?GLenum,Id:?GLuint>>).
%% @doc Render primitives using a count derived from a specifed stream of a transform feedback object
%%
@@ -15333,14 +15432,14 @@ drawTransformFeedback(Mode,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackStream.xml">external</a> documentation.
-spec drawTransformFeedbackStream(Mode, Id, Stream) -> 'ok' when Mode :: enum(),Id :: integer(),Stream :: integer().
drawTransformFeedbackStream(Mode,Id,Stream) ->
- cast(5764, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint>>).
+ cast(5765, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint>>).
%% @doc glBeginQueryIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQueryIndexe.xml">external</a> documentation.
-spec beginQueryIndexed(Target, Index, Id) -> 'ok' when Target :: enum(),Index :: integer(),Id :: integer().
beginQueryIndexed(Target,Index,Id) ->
- cast(5765, <<Target:?GLenum,Index:?GLuint,Id:?GLuint>>).
+ cast(5766, <<Target:?GLenum,Index:?GLuint,Id:?GLuint>>).
%% @doc Delimit the boundaries of a query object on an indexed target
%%
@@ -15417,7 +15516,7 @@ beginQueryIndexed(Target,Index,Id) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBeginQueryIndexed.xml">external</a> documentation.
-spec endQueryIndexed(Target, Index) -> 'ok' when Target :: enum(),Index :: integer().
endQueryIndexed(Target,Index) ->
- cast(5766, <<Target:?GLenum,Index:?GLuint>>).
+ cast(5767, <<Target:?GLenum,Index:?GLuint>>).
%% @doc Return parameters of an indexed query object target
%%
@@ -15435,7 +15534,7 @@ endQueryIndexed(Target,Index) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetQueryIndexed.xml">external</a> documentation.
-spec getQueryIndexediv(Target, Index, Pname) -> integer() when Target :: enum(),Index :: integer(),Pname :: enum().
getQueryIndexediv(Target,Index,Pname) ->
- call(5767, <<Target:?GLenum,Index:?GLuint,Pname:?GLenum>>).
+ call(5768, <<Target:?GLenum,Index:?GLuint,Pname:?GLenum>>).
%% @doc Release resources consumed by the implementation's shader compiler
%%
@@ -15447,7 +15546,7 @@ getQueryIndexediv(Target,Index,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glReleaseShaderCompiler.xml">external</a> documentation.
-spec releaseShaderCompiler() -> 'ok'.
releaseShaderCompiler() ->
- cast(5768, <<>>).
+ cast(5769, <<>>).
%% @doc Load pre-compiled shader binaries
%%
@@ -15469,9 +15568,10 @@ releaseShaderCompiler() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glShaderBinary.xml">external</a> documentation.
-spec shaderBinary(Shaders, Binaryformat, Binary) -> 'ok' when Shaders :: [integer()],Binaryformat :: enum(),Binary :: binary().
shaderBinary(Shaders,Binaryformat,Binary) ->
+ ShadersLen = length(Shaders),
send_bin(Binary),
- cast(5769, <<(length(Shaders)):?GLuint,
- (<< <<C:?GLuint>> || C <- Shaders>>)/binary,0:(((1+length(Shaders)) rem 2)*32),Binaryformat:?GLenum>>).
+ cast(5770, <<ShadersLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Shaders>>)/binary,0:(((1+ShadersLen) rem 2)*32),Binaryformat:?GLenum>>).
%% @doc Retrieve the range and precision for numeric formats supported by the shader compiler
%%
@@ -15496,20 +15596,20 @@ shaderBinary(Shaders,Binaryformat,Binary) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetShaderPrecisionFormat.xml">external</a> documentation.
-spec getShaderPrecisionFormat(Shadertype, Precisiontype) -> {Range :: {integer(),integer()},Precision :: integer()} when Shadertype :: enum(),Precisiontype :: enum().
getShaderPrecisionFormat(Shadertype,Precisiontype) ->
- call(5770, <<Shadertype:?GLenum,Precisiontype:?GLenum>>).
+ call(5771, <<Shadertype:?GLenum,Precisiontype:?GLenum>>).
%% @doc
%% See {@link depthRange/2}
-spec depthRangef(N, F) -> 'ok' when N :: clamp(),F :: clamp().
depthRangef(N,F) ->
- cast(5771, <<N:?GLclampf,F:?GLclampf>>).
+ cast(5772, <<N:?GLclampf,F:?GLclampf>>).
%% @doc glClearDepthf
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glClearDepthf.xml">external</a> documentation.
-spec clearDepthf(D) -> 'ok' when D :: clamp().
clearDepthf(D) ->
- cast(5772, <<D:?GLclampf>>).
+ cast(5773, <<D:?GLclampf>>).
%% @doc Return a binary representation of a program object's compiled and linked executable source
%%
@@ -15530,7 +15630,7 @@ clearDepthf(D) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramBinary.xml">external</a> documentation.
-spec getProgramBinary(Program, BufSize) -> {BinaryFormat :: enum(),Binary :: binary()} when Program :: integer(),BufSize :: integer().
getProgramBinary(Program,BufSize) ->
- call(5773, <<Program:?GLuint,BufSize:?GLsizei>>).
+ call(5774, <<Program:?GLuint,BufSize:?GLsizei>>).
%% @doc Load a program object with a program binary
%%
@@ -15558,7 +15658,7 @@ getProgramBinary(Program,BufSize) ->
-spec programBinary(Program, BinaryFormat, Binary) -> 'ok' when Program :: integer(),BinaryFormat :: enum(),Binary :: binary().
programBinary(Program,BinaryFormat,Binary) ->
send_bin(Binary),
- cast(5774, <<Program:?GLuint,BinaryFormat:?GLenum>>).
+ cast(5775, <<Program:?GLuint,BinaryFormat:?GLenum>>).
%% @doc Specify a parameter for a program object
%%
@@ -15583,7 +15683,7 @@ programBinary(Program,BinaryFormat,Binary) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramParameter.xml">external</a> documentation.
-spec programParameteri(Program, Pname, Value) -> 'ok' when Program :: integer(),Pname :: enum(),Value :: integer().
programParameteri(Program,Pname,Value) ->
- cast(5775, <<Program:?GLuint,Pname:?GLenum,Value:?GLint>>).
+ cast(5776, <<Program:?GLuint,Pname:?GLenum,Value:?GLint>>).
%% @doc Bind stages of a program object to a program pipeline
%%
@@ -15608,7 +15708,7 @@ programParameteri(Program,Pname,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glUseProgramStages.xml">external</a> documentation.
-spec useProgramStages(Pipeline, Stages, Program) -> 'ok' when Pipeline :: integer(),Stages :: integer(),Program :: integer().
useProgramStages(Pipeline,Stages,Program) ->
- cast(5776, <<Pipeline:?GLuint,Stages:?GLbitfield,Program:?GLuint>>).
+ cast(5777, <<Pipeline:?GLuint,Stages:?GLbitfield,Program:?GLuint>>).
%% @doc Set the active program object for a program pipeline object
%%
@@ -15620,15 +15720,16 @@ useProgramStages(Pipeline,Stages,Program) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glActiveShaderProgram.xml">external</a> documentation.
-spec activeShaderProgram(Pipeline, Program) -> 'ok' when Pipeline :: integer(),Program :: integer().
activeShaderProgram(Pipeline,Program) ->
- cast(5777, <<Pipeline:?GLuint,Program:?GLuint>>).
+ cast(5778, <<Pipeline:?GLuint,Program:?GLuint>>).
%% @doc glCreateShaderProgramv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glCreateShaderProgramv.xml">external</a> documentation.
-spec createShaderProgramv(Type, Strings) -> integer() when Type :: enum(),Strings :: iolist().
createShaderProgramv(Type,Strings) ->
- StringsTemp = list_to_binary([[Str|[0]] || Str <- Strings ]),
- call(5778, <<Type:?GLenum,(length(Strings)):?GLuint,(size(StringsTemp)):?GLuint,(StringsTemp)/binary,0:((8-((size(StringsTemp)+0) rem 8)) rem 8)>>).
+ StringsTemp = list_to_binary([[Str|[0]] || Str <- Strings ]),
+ StringsLen = length(Strings),
+ call(5779, <<Type:?GLenum,StringsLen:?GLuint,(size(StringsTemp)):?GLuint,(StringsTemp)/binary,0:((8-((size(StringsTemp)+0) rem 8)) rem 8)>>).
%% @doc Bind a program pipeline to the current context
%%
@@ -15650,7 +15751,7 @@ createShaderProgramv(Type,Strings) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindProgramPipeline.xml">external</a> documentation.
-spec bindProgramPipeline(Pipeline) -> 'ok' when Pipeline :: integer().
bindProgramPipeline(Pipeline) ->
- cast(5779, <<Pipeline:?GLuint>>).
+ cast(5780, <<Pipeline:?GLuint>>).
%% @doc Delete program pipeline objects
%%
@@ -15664,8 +15765,9 @@ bindProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDeleteProgramPipelines.xml">external</a> documentation.
-spec deleteProgramPipelines(Pipelines) -> 'ok' when Pipelines :: [integer()].
deleteProgramPipelines(Pipelines) ->
- cast(5780, <<(length(Pipelines)):?GLuint,
- (<< <<C:?GLuint>> || C <- Pipelines>>)/binary,0:(((1+length(Pipelines)) rem 2)*32)>>).
+ PipelinesLen = length(Pipelines),
+ cast(5781, <<PipelinesLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Pipelines>>)/binary,0:(((1+PipelinesLen) rem 2)*32)>>).
%% @doc Reserve program pipeline object names
%%
@@ -15676,7 +15778,7 @@ deleteProgramPipelines(Pipelines) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGenProgramPipelines.xml">external</a> documentation.
-spec genProgramPipelines(N) -> [integer()] when N :: integer().
genProgramPipelines(N) ->
- call(5781, <<N:?GLsizei>>).
+ call(5782, <<N:?GLsizei>>).
%% @doc Determine if a name corresponds to a program pipeline object
%%
@@ -15691,7 +15793,7 @@ genProgramPipelines(N) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsProgramPipeline.xml">external</a> documentation.
-spec isProgramPipeline(Pipeline) -> 0|1 when Pipeline :: integer().
isProgramPipeline(Pipeline) ->
- call(5782, <<Pipeline:?GLuint>>).
+ call(5783, <<Pipeline:?GLuint>>).
%% @doc Retrieve properties of a program pipeline object
%%
@@ -15729,7 +15831,7 @@ isProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramPipeline.xml">external</a> documentation.
-spec getProgramPipelineiv(Pipeline, Pname) -> integer() when Pipeline :: integer(),Pname :: enum().
getProgramPipelineiv(Pipeline,Pname) ->
- call(5783, <<Pipeline:?GLuint,Pname:?GLenum>>).
+ call(5784, <<Pipeline:?GLuint,Pname:?GLenum>>).
%% @doc Specify the value of a uniform variable for a specified program object
%%
@@ -15796,334 +15898,368 @@ getProgramPipelineiv(Pipeline,Pname) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glProgramUniform.xml">external</a> documentation.
-spec programUniform1i(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer().
programUniform1i(Program,Location,V0) ->
- cast(5784, <<Program:?GLuint,Location:?GLint,V0:?GLint>>).
+ cast(5785, <<Program:?GLuint,Location:?GLint,V0:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [integer()].
programUniform1iv(Program,Location,Value) ->
- cast(5785, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5786, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLint>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1f(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float().
programUniform1f(Program,Location,V0) ->
- cast(5786, <<Program:?GLuint,Location:?GLint,V0:?GLfloat>>).
+ cast(5787, <<Program:?GLuint,Location:?GLint,V0:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [float()].
programUniform1fv(Program,Location,Value) ->
- cast(5787, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5788, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLfloat>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1d(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float().
programUniform1d(Program,Location,V0) ->
- cast(5788, <<Program:?GLuint,Location:?GLint,V0:?GLdouble>>).
+ cast(5789, <<Program:?GLuint,Location:?GLint,V0:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [float()].
programUniform1dv(Program,Location,Value) ->
- cast(5789, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5790, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<C:?GLdouble>> || C <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1ui(Program, Location, V0) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer().
programUniform1ui(Program,Location,V0) ->
- cast(5790, <<Program:?GLuint,Location:?GLint,V0:?GLuint>>).
+ cast(5791, <<Program:?GLuint,Location:?GLint,V0:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform1uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [integer()].
programUniform1uiv(Program,Location,Value) ->
- cast(5791, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
- (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((1+length(Value)) rem 2)*32)>>).
+ ValueLen = length(Value),
+ cast(5792, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Value>>)/binary,0:(((1+ValueLen) rem 2)*32)>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2i(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer().
programUniform2i(Program,Location,V0,V1) ->
- cast(5792, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint>>).
+ cast(5793, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer()}].
programUniform2iv(Program,Location,Value) ->
- cast(5793, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5794, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2f(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float().
programUniform2f(Program,Location,V0,V1) ->
- cast(5794, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
+ cast(5795, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float()}].
programUniform2fv(Program,Location,Value) ->
- cast(5795, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5796, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2d(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float().
programUniform2d(Program,Location,V0,V1) ->
- cast(5796, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble>>).
+ cast(5797, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float()}].
programUniform2dv(Program,Location,Value) ->
- cast(5797, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5798, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2ui(Program, Location, V0, V1) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer().
programUniform2ui(Program,Location,V0,V1) ->
- cast(5798, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint>>).
+ cast(5799, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform2uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer()}].
programUniform2uiv(Program,Location,Value) ->
- cast(5799, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5800, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint>> || {V1,V2} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3i(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
programUniform3i(Program,Location,V0,V1,V2) ->
- cast(5800, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
+ cast(5801, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer()}].
programUniform3iv(Program,Location,Value) ->
- cast(5801, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5802, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3f(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
programUniform3f(Program,Location,V0,V1,V2) ->
- cast(5802, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
+ cast(5803, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float()}].
programUniform3fv(Program,Location,Value) ->
- cast(5803, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5804, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3d(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float().
programUniform3d(Program,Location,V0,V1,V2) ->
- cast(5804, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble>>).
+ cast(5805, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float()}].
programUniform3dv(Program,Location,Value) ->
- cast(5805, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5806, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3ui(Program, Location, V0, V1, V2) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer().
programUniform3ui(Program,Location,V0,V1,V2) ->
- cast(5806, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
+ cast(5807, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform3uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer()}].
programUniform3uiv(Program,Location,Value) ->
- cast(5807, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5808, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint>> || {V1,V2,V3} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4i(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
programUniform4i(Program,Location,V0,V1,V2,V3) ->
- cast(5808, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
+ cast(5809, <<Program:?GLuint,Location:?GLint,V0:?GLint,V1:?GLint,V2:?GLint,V3:?GLint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4iv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
programUniform4iv(Program,Location,Value) ->
- cast(5809, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5810, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4f(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
programUniform4f(Program,Location,V0,V1,V2,V3) ->
- cast(5810, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
+ cast(5811, <<Program:?GLuint,Location:?GLint,V0:?GLfloat,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4fv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float(),float()}].
programUniform4fv(Program,Location,Value) ->
- cast(5811, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5812, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4d(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: float(),V1 :: float(),V2 :: float(),V3 :: float().
programUniform4d(Program,Location,V0,V1,V2,V3) ->
- cast(5812, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>>).
+ cast(5813, <<Program:?GLuint,Location:?GLint,V0:?GLdouble,V1:?GLdouble,V2:?GLdouble,V3:?GLdouble>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4dv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{float(),float(),float(),float()}].
programUniform4dv(Program,Location,Value) ->
- cast(5813, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5814, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4ui(Program, Location, V0, V1, V2, V3) -> 'ok' when Program :: integer(),Location :: integer(),V0 :: integer(),V1 :: integer(),V2 :: integer(),V3 :: integer().
programUniform4ui(Program,Location,V0,V1,V2,V3) ->
- cast(5814, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
+ cast(5815, <<Program:?GLuint,Location:?GLint,V0:?GLuint,V1:?GLuint,V2:?GLuint,V3:?GLuint>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniform4uiv(Program, Location, Value) -> 'ok' when Program :: integer(),Location :: integer(),Value :: [{integer(),integer(),integer(),integer()}].
programUniform4uiv(Program,Location,Value) ->
- cast(5815, <<Program:?GLuint,Location:?GLint,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5816, <<Program:?GLuint,Location:?GLint,ValueLen:?GLuint,
(<< <<V1:?GLuint,V2:?GLuint,V3:?GLuint,V4:?GLuint>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
programUniformMatrix2fv(Program,Location,Transpose,Value) ->
- cast(5816, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5817, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3fv(Program,Location,Transpose,Value) ->
- cast(5817, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5818, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4fv(Program,Location,Transpose,Value) ->
- cast(5818, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5819, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat,V13:?GLfloat,V14:?GLfloat,V15:?GLfloat,V16:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float()}].
programUniformMatrix2dv(Program,Location,Transpose,Value) ->
- cast(5819, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5820, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble>> || {V1,V2,V3,V4} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3dv(Program,Location,Transpose,Value) ->
- cast(5820, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5821, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4dv(Program,Location,Transpose,Value) ->
- cast(5821, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5822, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble,V13:?GLdouble,V14:?GLdouble,V15:?GLdouble,V16:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x3fv(Program,Location,Transpose,Value) ->
- cast(5822, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5823, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x2fv(Program,Location,Transpose,Value) ->
- cast(5823, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5824, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x4fv(Program,Location,Transpose,Value) ->
- cast(5824, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5825, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x2fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x2fv(Program,Location,Transpose,Value) ->
- cast(5825, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5826, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x4fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x4fv(Program,Location,Transpose,Value) ->
- cast(5826, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5827, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x3fv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x3fv(Program,Location,Transpose,Value) ->
- cast(5827, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,(length(Value)):?GLuint,
+ ValueLen = length(Value),
+ cast(5828, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:24,ValueLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat,V5:?GLfloat,V6:?GLfloat,V7:?GLfloat,V8:?GLfloat,V9:?GLfloat,V10:?GLfloat,V11:?GLfloat,V12:?GLfloat>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x3dv(Program,Location,Transpose,Value) ->
- cast(5828, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5829, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x2dv(Program,Location,Transpose,Value) ->
- cast(5829, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5830, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble>> || {V1,V2,V3,V4,V5,V6} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix2x4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix2x4dv(Program,Location,Transpose,Value) ->
- cast(5830, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5831, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x2dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x2dv(Program,Location,Transpose,Value) ->
- cast(5831, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5832, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix3x4dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix3x4dv(Program,Location,Transpose,Value) ->
- cast(5832, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5833, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc
%% See {@link programUniform1i/3}
-spec programUniformMatrix4x3dv(Program, Location, Transpose, Value) -> 'ok' when Program :: integer(),Location :: integer(),Transpose :: 0|1,Value :: [{float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float(),float()}].
programUniformMatrix4x3dv(Program,Location,Transpose,Value) ->
- cast(5833, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,(length(Value)):?GLuint,0:32,
+ ValueLen = length(Value),
+ cast(5834, <<Program:?GLuint,Location:?GLint,Transpose:?GLboolean,0:56,ValueLen:?GLuint,0:32,
(<< <<V1:?GLdouble,V2:?GLdouble,V3:?GLdouble,V4:?GLdouble,V5:?GLdouble,V6:?GLdouble,V7:?GLdouble,V8:?GLdouble,V9:?GLdouble,V10:?GLdouble,V11:?GLdouble,V12:?GLdouble>> || {V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12} <- Value>>)/binary>>).
%% @doc Validate a program pipeline object against current GL state
@@ -16144,7 +16280,7 @@ programUniformMatrix4x3dv(Program,Location,Transpose,Value) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glValidateProgramPipeline.xml">external</a> documentation.
-spec validateProgramPipeline(Pipeline) -> 'ok' when Pipeline :: integer().
validateProgramPipeline(Pipeline) ->
- cast(5834, <<Pipeline:?GLuint>>).
+ cast(5835, <<Pipeline:?GLuint>>).
%% @doc Retrieve the info log string from a program pipeline object
%%
@@ -16161,35 +16297,35 @@ validateProgramPipeline(Pipeline) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetProgramPipelineInfoLog.xml">external</a> documentation.
-spec getProgramPipelineInfoLog(Pipeline, BufSize) -> string() when Pipeline :: integer(),BufSize :: integer().
getProgramPipelineInfoLog(Pipeline,BufSize) ->
- call(5835, <<Pipeline:?GLuint,BufSize:?GLsizei>>).
+ call(5836, <<Pipeline:?GLuint,BufSize:?GLsizei>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL1d(Index, X) -> 'ok' when Index :: integer(),X :: float().
vertexAttribL1d(Index,X) ->
- cast(5836, <<Index:?GLuint,0:32,X:?GLdouble>>).
+ cast(5837, <<Index:?GLuint,0:32,X:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL2d(Index, X, Y) -> 'ok' when Index :: integer(),X :: float(),Y :: float().
vertexAttribL2d(Index,X,Y) ->
- cast(5837, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
+ cast(5838, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL3d(Index, X, Y, Z) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float().
vertexAttribL3d(Index,X,Y,Z) ->
- cast(5838, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
+ cast(5839, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble>>).
%% @doc glVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribL.xml">external</a> documentation.
-spec vertexAttribL4d(Index, X, Y, Z, W) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),Z :: float(),W :: float().
vertexAttribL4d(Index,X,Y,Z,W) ->
- cast(5839, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
+ cast(5840, <<Index:?GLuint,0:32,X:?GLdouble,Y:?GLdouble,Z:?GLdouble,W:?GLdouble>>).
%% @equiv vertexAttribL1d(Index,X)
-spec vertexAttribL1dv(Index :: integer(),V) -> 'ok' when V :: {X :: float()}.
@@ -16212,24 +16348,25 @@ vertexAttribL4dv(Index,{X,Y,Z,W}) -> vertexAttribL4d(Index,X,Y,Z,W).
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertexAttribLPointer.xml">external</a> documentation.
-spec vertexAttribLPointer(Index, Size, Type, Stride, Pointer) -> 'ok' when Index :: integer(),Size :: integer(),Type :: enum(),Stride :: integer(),Pointer :: offset()|mem().
vertexAttribLPointer(Index,Size,Type,Stride,Pointer) when is_integer(Pointer) ->
- cast(5840, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
+ cast(5841, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei,Pointer:?GLuint>>);
vertexAttribLPointer(Index,Size,Type,Stride,Pointer) ->
send_bin(Pointer),
- cast(5841, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
+ cast(5842, <<Index:?GLuint,Size:?GLint,Type:?GLenum,Stride:?GLsizei>>).
%% @doc glGetVertexAttribL
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetVertexAttribL.xml">external</a> documentation.
-spec getVertexAttribLdv(Index, Pname) -> {float(),float(),float(),float()} when Index :: integer(),Pname :: enum().
getVertexAttribLdv(Index,Pname) ->
- call(5842, <<Index:?GLuint,Pname:?GLenum>>).
+ call(5843, <<Index:?GLuint,Pname:?GLenum>>).
%% @doc glViewportArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glViewportArrayv.xml">external</a> documentation.
-spec viewportArrayv(First, V) -> 'ok' when First :: integer(),V :: [{float(),float(),float(),float()}].
viewportArrayv(First,V) ->
- cast(5843, <<First:?GLuint,(length(V)):?GLuint,
+ VLen = length(V),
+ cast(5844, <<First:?GLuint,VLen:?GLuint,
(<< <<V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>> || {V1,V2,V3,V4} <- V>>)/binary>>).
%% @doc Set a specified viewport
@@ -16269,20 +16406,21 @@ viewportArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glViewportIndexed.xml">external</a> documentation.
-spec viewportIndexedf(Index, X, Y, W, H) -> 'ok' when Index :: integer(),X :: float(),Y :: float(),W :: float(),H :: float().
viewportIndexedf(Index,X,Y,W,H) ->
- cast(5844, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,W:?GLfloat,H:?GLfloat>>).
+ cast(5845, <<Index:?GLuint,X:?GLfloat,Y:?GLfloat,W:?GLfloat,H:?GLfloat>>).
%% @doc
%% See {@link viewportIndexedf/5}
-spec viewportIndexedfv(Index, V) -> 'ok' when Index :: integer(),V :: {float(),float(),float(),float()}.
viewportIndexedfv(Index,{V1,V2,V3,V4}) ->
- cast(5845, <<Index:?GLuint,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>>).
+ cast(5846, <<Index:?GLuint,V1:?GLfloat,V2:?GLfloat,V3:?GLfloat,V4:?GLfloat>>).
%% @doc glScissorArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorArrayv.xml">external</a> documentation.
-spec scissorArrayv(First, V) -> 'ok' when First :: integer(),V :: [{integer(),integer(),integer(),integer()}].
scissorArrayv(First,V) ->
- cast(5846, <<First:?GLuint,(length(V)):?GLuint,
+ VLen = length(V),
+ cast(5847, <<First:?GLuint,VLen:?GLuint,
(<< <<V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>> || {V1,V2,V3,V4} <- V>>)/binary>>).
%% @doc glScissorIndexe
@@ -16290,21 +16428,22 @@ scissorArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorIndexe.xml">external</a> documentation.
-spec scissorIndexed(Index, Left, Bottom, Width, Height) -> 'ok' when Index :: integer(),Left :: integer(),Bottom :: integer(),Width :: integer(),Height :: integer().
scissorIndexed(Index,Left,Bottom,Width,Height) ->
- cast(5847, <<Index:?GLuint,Left:?GLint,Bottom:?GLint,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5848, <<Index:?GLuint,Left:?GLint,Bottom:?GLint,Width:?GLsizei,Height:?GLsizei>>).
%% @doc glScissorIndexe
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glScissorIndexe.xml">external</a> documentation.
-spec scissorIndexedv(Index, V) -> 'ok' when Index :: integer(),V :: {integer(),integer(),integer(),integer()}.
scissorIndexedv(Index,{V1,V2,V3,V4}) ->
- cast(5848, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
+ cast(5849, <<Index:?GLuint,V1:?GLint,V2:?GLint,V3:?GLint,V4:?GLint>>).
%% @doc glDepthRangeArrayv
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthRangeArrayv.xml">external</a> documentation.
-spec depthRangeArrayv(First, V) -> 'ok' when First :: integer(),V :: [{clamp(),clamp()}].
depthRangeArrayv(First,V) ->
- cast(5849, <<First:?GLuint,0:32,(length(V)):?GLuint,0:32,
+ VLen = length(V),
+ cast(5850, <<First:?GLuint,0:32,VLen:?GLuint,0:32,
(<< <<V1:?GLclampd,V2:?GLclampd>> || {V1,V2} <- V>>)/binary>>).
%% @doc glDepthRangeIndexe
@@ -16312,48 +16451,50 @@ depthRangeArrayv(First,V) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthRangeIndexe.xml">external</a> documentation.
-spec depthRangeIndexed(Index, N, F) -> 'ok' when Index :: integer(),N :: clamp(),F :: clamp().
depthRangeIndexed(Index,N,F) ->
- cast(5850, <<Index:?GLuint,0:32,N:?GLclampd,F:?GLclampd>>).
+ cast(5851, <<Index:?GLuint,0:32,N:?GLclampd,F:?GLclampd>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getFloati_v(Target, Index) -> [float()] when Target :: enum(),Index :: integer().
getFloati_v(Target,Index) ->
- call(5851, <<Target:?GLenum,Index:?GLuint>>).
+ call(5852, <<Target:?GLenum,Index:?GLuint>>).
%% @doc
%% See {@link getBooleanv/1}
-spec getDoublei_v(Target, Index) -> [float()] when Target :: enum(),Index :: integer().
getDoublei_v(Target,Index) ->
- call(5852, <<Target:?GLenum,Index:?GLuint>>).
+ call(5853, <<Target:?GLenum,Index:?GLuint>>).
%% @doc glDebugMessageControlARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDebugMessageControlARB.xml">external</a> documentation.
-spec debugMessageControlARB(Source, Type, Severity, Ids, Enabled) -> 'ok' when Source :: enum(),Type :: enum(),Severity :: enum(),Ids :: [integer()],Enabled :: 0|1.
debugMessageControlARB(Source,Type,Severity,Ids,Enabled) ->
- cast(5853, <<Source:?GLenum,Type:?GLenum,Severity:?GLenum,(length(Ids)):?GLuint,
- (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((length(Ids)) rem 2)*32),Enabled:?GLboolean>>).
+ IdsLen = length(Ids),
+ cast(5854, <<Source:?GLenum,Type:?GLenum,Severity:?GLenum,IdsLen:?GLuint,
+ (<< <<C:?GLuint>> || C <- Ids>>)/binary,0:(((IdsLen) rem 2)*32),Enabled:?GLboolean>>).
%% @doc glDebugMessageInsertARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDebugMessageInsertARB.xml">external</a> documentation.
-spec debugMessageInsertARB(Source, Type, Id, Severity, Buf) -> 'ok' when Source :: enum(),Type :: enum(),Id :: integer(),Severity :: enum(),Buf :: string().
debugMessageInsertARB(Source,Type,Id,Severity,Buf) ->
- cast(5854, <<Source:?GLenum,Type:?GLenum,Id:?GLuint,Severity:?GLenum,(list_to_binary([Buf|[0]]))/binary,0:((8-((length(Buf)+ 1) rem 8)) rem 8)>>).
+ BufLen = length(Buf),
+ cast(5855, <<Source:?GLenum,Type:?GLenum,Id:?GLuint,Severity:?GLenum,(list_to_binary([Buf|[0]]))/binary,0:((8-((BufLen+ 1) rem 8)) rem 8)>>).
%% @doc glGetDebugMessageLogARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetDebugMessageLogARB.xml">external</a> documentation.
-spec getDebugMessageLogARB(Count, Bufsize) -> {integer(),Sources :: [enum()],Types :: [enum()],Ids :: [integer()],Severities :: [enum()],MessageLog :: [string()]} when Count :: integer(),Bufsize :: integer().
getDebugMessageLogARB(Count,Bufsize) ->
- call(5855, <<Count:?GLuint,Bufsize:?GLsizei>>).
+ call(5856, <<Count:?GLuint,Bufsize:?GLsizei>>).
%% @doc glGetGraphicsResetStatusARB
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetGraphicsResetStatusARB.xml">external</a> documentation.
-spec getGraphicsResetStatusARB() -> enum().
getGraphicsResetStatusARB() ->
- call(5856, <<>>).
+ call(5857, <<>>).
%% @doc Draw multiple instances of a range of elements with offset applied to instanced attributes
%%
@@ -16376,7 +16517,7 @@ getGraphicsResetStatusARB() ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawArraysInstancedBaseInstance.xml">external</a> documentation.
-spec drawArraysInstancedBaseInstance(Mode, First, Count, Primcount, Baseinstance) -> 'ok' when Mode :: enum(),First :: integer(),Count :: integer(),Primcount :: integer(),Baseinstance :: integer().
drawArraysInstancedBaseInstance(Mode,First,Count,Primcount,Baseinstance) ->
- cast(5857, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei,Baseinstance:?GLuint>>).
+ cast(5858, <<Mode:?GLenum,First:?GLint,Count:?GLsizei,Primcount:?GLsizei,Baseinstance:?GLuint>>).
%% @doc Draw multiple instances of a set of elements with offset applied to instanced attributes
%%
@@ -16399,10 +16540,10 @@ drawArraysInstancedBaseInstance(Mode,First,Count,Primcount,Baseinstance) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseInstance.xml">external</a> documentation.
-spec drawElementsInstancedBaseInstance(Mode, Count, Type, Indices, Primcount, Baseinstance) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Baseinstance :: integer().
drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance) when is_integer(Indices) ->
- cast(5858, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Baseinstance:?GLuint>>);
+ cast(5859, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Baseinstance:?GLuint>>);
drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance) ->
send_bin(Indices),
- cast(5859, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Baseinstance:?GLuint>>).
+ cast(5860, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Baseinstance:?GLuint>>).
%% @doc Render multiple instances of a set of primitives from array data with a per-element offset
%%
@@ -16423,31 +16564,31 @@ drawElementsInstancedBaseInstance(Mode,Count,Type,Indices,Primcount,Baseinstance
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawElementsInstancedBaseVertexBaseInstance.xml">external</a> documentation.
-spec drawElementsInstancedBaseVertexBaseInstance(Mode, Count, Type, Indices, Primcount, Basevertex, Baseinstance) -> 'ok' when Mode :: enum(),Count :: integer(),Type :: enum(),Indices :: offset()|mem(),Primcount :: integer(),Basevertex :: integer(),Baseinstance :: integer().
drawElementsInstancedBaseVertexBaseInstance(Mode,Count,Type,Indices,Primcount,Basevertex,Baseinstance) when is_integer(Indices) ->
- cast(5860, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>);
+ cast(5861, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Indices:?GLuint,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>);
drawElementsInstancedBaseVertexBaseInstance(Mode,Count,Type,Indices,Primcount,Basevertex,Baseinstance) ->
send_bin(Indices),
- cast(5861, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>).
+ cast(5862, <<Mode:?GLenum,Count:?GLsizei,Type:?GLenum,Primcount:?GLsizei,Basevertex:?GLint,Baseinstance:?GLuint>>).
%% @doc glDrawTransformFeedbackInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackInstance.xml">external</a> documentation.
-spec drawTransformFeedbackInstanced(Mode, Id, Primcount) -> 'ok' when Mode :: enum(),Id :: integer(),Primcount :: integer().
drawTransformFeedbackInstanced(Mode,Id,Primcount) ->
- cast(5862, <<Mode:?GLenum,Id:?GLuint,Primcount:?GLsizei>>).
+ cast(5863, <<Mode:?GLenum,Id:?GLuint,Primcount:?GLsizei>>).
%% @doc glDrawTransformFeedbackStreamInstance
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDrawTransformFeedbackStreamInstance.xml">external</a> documentation.
-spec drawTransformFeedbackStreamInstanced(Mode, Id, Stream, Primcount) -> 'ok' when Mode :: enum(),Id :: integer(),Stream :: integer(),Primcount :: integer().
drawTransformFeedbackStreamInstanced(Mode,Id,Stream,Primcount) ->
- cast(5863, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint,Primcount:?GLsizei>>).
+ cast(5864, <<Mode:?GLenum,Id:?GLuint,Stream:?GLuint,Primcount:?GLsizei>>).
%% @doc glGetInternalformat
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetInternalformat.xml">external</a> documentation.
-spec getInternalformativ(Target, Internalformat, Pname, BufSize) -> [integer()] when Target :: enum(),Internalformat :: enum(),Pname :: enum(),BufSize :: integer().
getInternalformativ(Target,Internalformat,Pname,BufSize) ->
- call(5864, <<Target:?GLenum,Internalformat:?GLenum,Pname:?GLenum,BufSize:?GLsizei>>).
+ call(5865, <<Target:?GLenum,Internalformat:?GLenum,Pname:?GLenum,BufSize:?GLsizei>>).
%% @doc Bind a level of a texture to an image unit
%%
@@ -16509,7 +16650,7 @@ getInternalformativ(Target,Internalformat,Pname,BufSize) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glBindImageTexture.xml">external</a> documentation.
-spec bindImageTexture(Unit, Texture, Level, Layered, Layer, Access, Format) -> 'ok' when Unit :: integer(),Texture :: integer(),Level :: integer(),Layered :: 0|1,Layer :: integer(),Access :: enum(),Format :: enum().
bindImageTexture(Unit,Texture,Level,Layered,Layer,Access,Format) ->
- cast(5865, <<Unit:?GLuint,Texture:?GLuint,Level:?GLint,Layered:?GLboolean,0:24,Layer:?GLint,Access:?GLenum,Format:?GLenum>>).
+ cast(5866, <<Unit:?GLuint,Texture:?GLuint,Level:?GLint,Layered:?GLboolean,0:24,Layer:?GLint,Access:?GLenum,Format:?GLenum>>).
%% @doc Defines a barrier ordering memory transactions
%%
@@ -16636,7 +16777,7 @@ bindImageTexture(Unit,Texture,Level,Layered,Layer,Access,Format) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glMemoryBarrier.xml">external</a> documentation.
-spec memoryBarrier(Barriers) -> 'ok' when Barriers :: integer().
memoryBarrier(Barriers) ->
- cast(5866, <<Barriers:?GLbitfield>>).
+ cast(5867, <<Barriers:?GLbitfield>>).
%% @doc Simultaneously specify storage for all levels of a one-dimensional texture
%%
@@ -16669,7 +16810,7 @@ memoryBarrier(Barriers) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage1D.xml">external</a> documentation.
-spec texStorage1D(Target, Levels, Internalformat, Width) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer().
texStorage1D(Target,Levels,Internalformat,Width) ->
- cast(5867, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei>>).
+ cast(5868, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei>>).
%% @doc Simultaneously specify storage for all levels of a two-dimensional or one-dimensional array texture
%%
@@ -16714,7 +16855,7 @@ texStorage1D(Target,Levels,Internalformat,Width) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage2D.xml">external</a> documentation.
-spec texStorage2D(Target, Levels, Internalformat, Width, Height) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer().
texStorage2D(Target,Levels,Internalformat,Width,Height) ->
- cast(5868, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
+ cast(5869, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei>>).
%% @doc Simultaneously specify storage for all levels of a three-dimensional, two-dimensional array or cube-map array texture
%%
@@ -16757,19 +16898,19 @@ texStorage2D(Target,Levels,Internalformat,Width,Height) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glTexStorage3D.xml">external</a> documentation.
-spec texStorage3D(Target, Levels, Internalformat, Width, Height, Depth) -> 'ok' when Target :: enum(),Levels :: integer(),Internalformat :: enum(),Width :: integer(),Height :: integer(),Depth :: integer().
texStorage3D(Target,Levels,Internalformat,Width,Height,Depth) ->
- cast(5869, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei>>).
+ cast(5870, <<Target:?GLenum,Levels:?GLsizei,Internalformat:?GLenum,Width:?GLsizei,Height:?GLsizei,Depth:?GLsizei>>).
%% @doc glDepthBoundsEXT
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glDepthBoundsEXT.xml">external</a> documentation.
-spec depthBoundsEXT(Zmin, Zmax) -> 'ok' when Zmin :: clamp(),Zmax :: clamp().
depthBoundsEXT(Zmin,Zmax) ->
- cast(5870, <<Zmin:?GLclampd,Zmax:?GLclampd>>).
+ cast(5871, <<Zmin:?GLclampd,Zmax:?GLclampd>>).
%% @doc glStencilClearTagEXT
%%
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/glStencilClearTagEXT.xml">external</a> documentation.
-spec stencilClearTagEXT(StencilTagBits, StencilClearTag) -> 'ok' when StencilTagBits :: integer(),StencilClearTag :: integer().
stencilClearTagEXT(StencilTagBits,StencilClearTag) ->
- cast(5871, <<StencilTagBits:?GLsizei,StencilClearTag:?GLuint>>).
+ cast(5872, <<StencilTagBits:?GLsizei,StencilClearTag:?GLuint>>).
diff --git a/lib/wx/src/gen/glu.erl b/lib/wx/src/gen/glu.erl
index 47d9a83999..f641f41262 100644
--- a/lib/wx/src/gen/glu.erl
+++ b/lib/wx/src/gen/glu.erl
@@ -334,7 +334,9 @@ build3DMipmaps(Target,InternalFormat,Width,Height,Depth,Format,Type,Data) ->
%% See <a href="http://www.opengl.org/sdk/docs/man/xhtml/gluCheckExtension.xml">external</a> documentation.
-spec checkExtension(ExtName, ExtString) -> 0|1 when ExtName :: string(),ExtString :: string().
checkExtension(ExtName,ExtString) ->
- call(5016, <<(list_to_binary([ExtName|[0]]))/binary,0:((8-((length(ExtName)+ 1) rem 8)) rem 8),(list_to_binary([ExtString|[0]]))/binary,0:((8-((length(ExtString)+ 1) rem 8)) rem 8)>>).
+ ExtNameLen = length(ExtName),
+ ExtStringLen = length(ExtString),
+ call(5016, <<(list_to_binary([ExtName|[0]]))/binary,0:((8-((ExtNameLen+ 1) rem 8)) rem 8),(list_to_binary([ExtString|[0]]))/binary,0:((8-((ExtStringLen+ 1) rem 8)) rem 8)>>).
%% @doc Draw a cylinder
%%
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 0ce63d9f71..cfa256fb12 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.7.1
+WX_VSN = 1.8
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 5e0459ec21..9f6b27113e 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -2225,16 +2225,18 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook,
AllAttrs =
case S#xmerl_scanner.default_attrs of
true ->
- [ #xmlAttribute{name = AttName,
- parents = [{Name, Pos} | Parents],
- language = Lang,
- nsinfo = NSI,
- namespace = Namespace,
- value = AttValue,
- normalized = true} ||
- {AttName, AttValue} <- get_default_attrs(S, Name),
- AttValue =/= no_value,
- not lists:keymember(AttName, #xmlAttribute.name, Attrs) ];
+ DefaultAttrs =
+ [ #xmlAttribute{name = AttName,
+ parents = [{Name, Pos} | Parents],
+ language = Lang,
+ nsinfo = NSI,
+ namespace = Namespace,
+ value = AttValue,
+ normalized = true} ||
+ {AttName, AttValue} <- get_default_attrs(S, Name),
+ AttValue =/= no_value,
+ not lists:keymember(AttName, #xmlAttribute.name, Attrs) ],
+ lists:append(Attrs, DefaultAttrs);
false ->
Attrs
end,
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index e97b8c6a4b..cf7c0b7548 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -54,7 +54,8 @@ groups() ->
cpd_expl_provided_DTD]},
{misc, [],
[latin1_alias, syntax_bug1, syntax_bug2, syntax_bug3,
- pe_ref1, copyright, testXSEIF, export_simple1, export]},
+ pe_ref1, copyright, testXSEIF, export_simple1, export,
+ default_attrs_bug]},
{eventp_tests, [], [sax_parse_and_export]},
{ticket_tests, [],
[ticket_5998, ticket_7211, ticket_7214, ticket_7430,
@@ -223,6 +224,21 @@ syntax_bug3(Config) ->
Err -> Err
end.
+default_attrs_bug(Config) ->
+ file:set_cwd(datadir(Config)),
+ Doc = "<!DOCTYPE doc [<!ATTLIST doc b CDATA \"default\">]>\n"
+ "<doc a=\"explicit\"/>",
+ {#xmlElement{attributes = [#xmlAttribute{name = a, value = "explicit"},
+ #xmlAttribute{name = b, value = "default"}]},
+ []
+ } = xmerl_scan:string(Doc, [{default_attrs, true}]),
+ Doc2 = "<!DOCTYPE doc [<!ATTLIST doc b CDATA \"default\">]>\n"
+ "<doc b=\"also explicit\" a=\"explicit\"/>",
+ {#xmlElement{attributes = [#xmlAttribute{name = b, value = "also explicit"},
+ #xmlAttribute{name = a, value = "explicit"}]},
+ []
+ } = xmerl_scan:string(Doc2, [{default_attrs, true}]).
+
pe_ref1(Config) ->
file:set_cwd(datadir(Config)),
{#xmlElement{},[]} = xmerl_scan:file(datadir_join(Config,[misc,"PE_ref1.xml"]),[{validation,true}]).
diff --git a/otp_versions.table b/otp_versions.table
index 793f7bcd28..575a358010 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,5 @@
+OTP-19.2.1 : erts-8.2.1 # asn1-4.0.4 common_test-1.13 compiler-7.0.3 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.2 debugger-4.2.1 dialyzer-3.0.3 diameter-1.12.1 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.2 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.3 ic-4.4.2 inets-6.3.4 jinterface-1.7.1 kernel-5.1.1 megaco-3.18.1 mnesia-4.14.2 observer-2.3 odbc-2.12 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.3 reltool-0.7.2 runtime_tools-1.11 sasl-3.0.2 snmp-5.2.4 ssh-4.4 ssl-8.1 stdlib-3.2 syntax_tools-2.1.1 tools-2.9 typer-0.9.11 wx-1.8 xmerl-1.3.12 :
+OTP-19.2 : common_test-1.13 compiler-7.0.3 crypto-3.7.2 dialyzer-3.0.3 edoc-0.8.1 erl_docgen-0.6.1 erl_interface-3.9.2 erts-8.2 eunit-2.3.2 hipe-3.15.3 inets-6.3.4 kernel-5.1.1 mnesia-4.14.2 observer-2.3 odbc-2.12 parsetools-2.1.4 public_key-1.3 runtime_tools-1.11 sasl-3.0.2 ssh-4.4 ssl-8.1 stdlib-3.2 syntax_tools-2.1.1 tools-2.9 wx-1.8 # asn1-4.0.4 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 debugger-4.2.1 diameter-1.12.1 eldap-1.2.2 et-1.6 gs-1.6.2 ic-4.4.2 jinterface-1.7.1 megaco-3.18.1 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 percept-0.9 reltool-0.7.2 snmp-5.2.4 typer-0.9.11 xmerl-1.3.12 :
OTP-19.1.6 : erts-8.1.1 # asn1-4.0.4 common_test-1.12.3 compiler-7.0.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.1 debugger-4.2.1 dialyzer-3.0.2 diameter-1.12.1 edoc-0.8 eldap-1.2.2 erl_docgen-0.6 erl_interface-3.9.1 et-1.6 eunit-2.3.1 gs-1.6.2 hipe-3.15.2 ic-4.4.2 inets-6.3.3 jinterface-1.7.1 kernel-5.1 megaco-3.18.1 mnesia-4.14.1 observer-2.2.2 odbc-2.11.3 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.3 percept-0.9 public_key-1.2 reltool-0.7.2 runtime_tools-1.10.1 sasl-3.0.1 snmp-5.2.4 ssh-4.3.6 ssl-8.0.3 stdlib-3.1 syntax_tools-2.1 tools-2.8.6 typer-0.9.11 wx-1.7.1 xmerl-1.3.12 :
OTP-19.1.5 : ssh-4.3.6 # asn1-4.0.4 common_test-1.12.3 compiler-7.0.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.1 debugger-4.2.1 dialyzer-3.0.2 diameter-1.12.1 edoc-0.8 eldap-1.2.2 erl_docgen-0.6 erl_interface-3.9.1 erts-8.1 et-1.6 eunit-2.3.1 gs-1.6.2 hipe-3.15.2 ic-4.4.2 inets-6.3.3 jinterface-1.7.1 kernel-5.1 megaco-3.18.1 mnesia-4.14.1 observer-2.2.2 odbc-2.11.3 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.3 percept-0.9 public_key-1.2 reltool-0.7.2 runtime_tools-1.10.1 sasl-3.0.1 snmp-5.2.4 ssl-8.0.3 stdlib-3.1 syntax_tools-2.1 tools-2.8.6 typer-0.9.11 wx-1.7.1 xmerl-1.3.12 :
OTP-19.1.4 : ssh-4.3.5 # asn1-4.0.4 common_test-1.12.3 compiler-7.0.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.1 debugger-4.2.1 dialyzer-3.0.2 diameter-1.12.1 edoc-0.8 eldap-1.2.2 erl_docgen-0.6 erl_interface-3.9.1 erts-8.1 et-1.6 eunit-2.3.1 gs-1.6.2 hipe-3.15.2 ic-4.4.2 inets-6.3.3 jinterface-1.7.1 kernel-5.1 megaco-3.18.1 mnesia-4.14.1 observer-2.2.2 odbc-2.11.3 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.3 percept-0.9 public_key-1.2 reltool-0.7.2 runtime_tools-1.10.1 sasl-3.0.1 snmp-5.2.4 ssl-8.0.3 stdlib-3.1 syntax_tools-2.1 tools-2.8.6 typer-0.9.11 wx-1.7.1 xmerl-1.3.12 :
diff --git a/scripts/run-smoke-tests b/scripts/run-smoke-tests
new file mode 100755
index 0000000000..c2333e7825
--- /dev/null
+++ b/scripts/run-smoke-tests
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -ev
+
+cd $ERL_TOP/release/tests/test_server
+$ERL_TOP/bin/erl -s ts install -s ts smoke_test batch -s init stop
+
+if grep -q '=failed *[1-9]' ct_run.test_server@*/*/run.*/suite.log; then
+ echo "One or more tests failed."
+ exit 1
+fi
diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml
index eee2648f34..e1760d0ded 100644
--- a/system/doc/efficiency_guide/advanced.xml
+++ b/system/doc/efficiency_guide/advanced.xml
@@ -87,15 +87,15 @@
</row>
<row>
<cell>Small Map</cell>
- <cell>4 words + 2 words per entry (key and value) + the size of each key and value pair.</cell>
+ <cell>5 words + the size of all keys and values.</cell>
</row>
<row>
- <cell>Large Map</cell>
+ <cell>Large Map (> 32 keys)</cell>
<cell>
- At least, 2 words + 2 x <c>N</c> words + 2 x log16(<c>N</c>) words +
- the size of each key and value pair, where <c>N</c> is the number of pairs in the Map.
- A large Map is represented as a tree internally where each node in the tree is a
- "sparse tuple" of arity 16.
+ <c>N</c> x <c>F</c> words + the size of all keys and values.<br></br>
+ <c>N</c> is the number of keys in the Map.<br></br>
+ <c>F</c> is a sparsity factor that can vary between 1.6 and 1.8
+ due to the probabilistic nature of the internal HAMT data structure.
</cell>
</row>
<row>
diff --git a/system/doc/reference_manual/code_loading.xml b/system/doc/reference_manual/code_loading.xml
index f6fd2911fa..f5e5e74841 100644
--- a/system/doc/reference_manual/code_loading.xml
+++ b/system/doc/reference_manual/code_loading.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2015</year>
+ <year>2003</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml
index 350bb1d123..5f24473557 100644
--- a/system/doc/reference_manual/macros.xml
+++ b/system/doc/reference_manual/macros.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2015</year>
+ <year>2003</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index ced584ed35..a0ea41cb3b 100644
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -11,7 +11,7 @@
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
-
+
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
@@ -63,7 +63,7 @@
Types consist of, and are built from, a set of predefined types,
for example, <c>integer()</c>, <c>atom()</c>, and <c>pid()</c>.
Predefined types represent a typically infinite set of Erlang terms that
- belong to this type. For example, the type <c>atom()</c> stands for the
+ belong to this type. For example, the type <c>atom()</c> denotes the
set of all Erlang atoms.
</p>
<p>
@@ -131,19 +131,19 @@
| nonempty_improper_list(Type1, Type2) %% Type1 and Type2 as above
| nonempty_list(Type) %% Proper non-empty list
- Map :: map() %% stands for a map of any size
- | #{} %% stands for the empty map
+ Map :: map() %% denotes a map of any size
+ | #{} %% denotes the empty map
| #{PairList}
- Tuple :: tuple() %% stands for a tuple of any size
+ Tuple :: tuple() %% denotes a tuple of any size
| {}
| {TList}
PairList :: Pair
| Pair, PairList
- Pair :: Type := Type %% denotes a pair that must be present
- | Type => Type
+ Pair :: Type := Type %% denotes a mandatory pair
+ | Type => Type %% denotes an optional pair
TList :: Type
| Type, TList
@@ -161,7 +161,7 @@
that <c>M</c> or <c>N</c>, or both, are zero.
</p>
<p>
- Because lists are commonly used, they have shorthand type notations.
+ Because lists are commonly used, they have shorthand type notations.
The types <c>list(T)</c> and <c>nonempty_list(T)</c> have the shorthands
<c>[T]</c> and <c>[T,...]</c>, respectively.
The only difference between the two shorthands is that <c>[T]</c> can be an
@@ -169,14 +169,18 @@
</p>
<p>
Notice that the shorthand for <c>list()</c>, that is, the list of
- elements of unknown type, is <c>[_]</c> (or <c>[any()]</c>), not <c>[]</c>.
+ elements of unknown type, is <c>[_]</c> (or <c>[any()]</c>), not <c>[]</c>.
The notation <c>[]</c> specifies the singleton type for the empty list.
</p>
<p>
The general form of maps is <c>#{PairList}</c>. The key types in
<c>PairList</c> are allowed to overlap, and if they do, the
leftmost pair takes precedence. A map pair has a key in
- <c>PairList</c> if it belongs to this type.
+ <c>PairList</c> if it belongs to this type. A <c>PairList</c> may contain
+ both 'mandatory' and 'optional' pairs where 'mandatory' denotes that
+ a key type, and its associated value type, must be present.
+ In the case of an 'optional' pair it is not required for the key type to
+ be present.
</p>
<p>
Notice that the syntactic representation of <c>map()</c> is
@@ -184,8 +188,8 @@
The notation <c>#{}</c> specifies the singleton type for the empty map.
</p>
<p>
- For convenience, the following types are also built-in.
- They can be thought as predefined aliases for the type unions also shown in
+ For convenience, the following types are also built-in.
+ They can be thought as predefined aliases for the type unions also shown in
the table.
</p>
<table>
@@ -201,37 +205,37 @@
<row>
<cell><c>bitstring()</c></cell><cell><c>&lt;&lt;_:_*1&gt;&gt;</c></cell>
</row>
- <row>
+ <row>
<cell><c>boolean()</c></cell><cell><c>'false' | 'true'</c></cell>
</row>
- <row>
+ <row>
<cell><c>byte()</c></cell><cell><c>0..255</c></cell>
</row>
<row>
<cell><c>char()</c></cell><cell><c>0..16#10ffff</c></cell>
</row>
- <row>
+ <row>
<cell><c>nil()</c></cell><cell><c>[]</c></cell>
</row>
<row>
<cell><c>number()</c></cell><cell><c>integer() | float()</c></cell>
</row>
- <row>
+ <row>
<cell><c>list()</c></cell><cell><c>[any()]</c></cell>
</row>
- <row>
+ <row>
<cell><c>maybe_improper_list()</c></cell><cell><c>maybe_improper_list(any(), any())</c></cell>
</row>
- <row>
+ <row>
<cell><c>nonempty_list()</c></cell><cell><c>nonempty_list(any())</c></cell>
</row>
<row>
<cell><c>string()</c></cell><cell><c>[char()]</c></cell>
</row>
- <row>
+ <row>
<cell><c>nonempty_string()</c></cell><cell><c>[char(),...]</c></cell>
</row>
- <row>
+ <row>
<cell><c>iodata()</c></cell><cell><c>iolist() | binary()</c></cell>
</row>
<row>
@@ -243,7 +247,7 @@
<row>
<cell><c>module()</c></cell><cell><c>atom()</c></cell>
</row>
- <row>
+ <row>
<cell><c>mfa()</c></cell><cell><c>{module(),atom(),arity()}</c></cell>
</row>
<row>
@@ -259,7 +263,7 @@
<cell><c>timeout()</c></cell><cell><c>'infinity' | non_neg_integer()</c></cell>
</row>
<row>
- <cell><c>no_return()</c></cell><cell><c>none()</c></cell>
+ <cell><c>no_return()</c></cell><cell><c>none()</c></cell>
</row>
<tcaption>Built-in types, predefined aliases</tcaption>
</table>
@@ -284,11 +288,11 @@
</row>
<tcaption>Additional built-in types</tcaption>
</table>
-
+
<p>
Users are not allowed to define types with the same names as the
predefined or built-in ones. This is checked by the compiler and
- its violation results in a compilation error.
+ its violation results in a compilation error.
</p>
<note>
<p>
@@ -394,13 +398,13 @@
<pre>
-record(rec, {field1 :: Type1, field2, field3 :: Type3}).</pre>
<p>
- For fields without type annotations, their type defaults to any().
+ For fields without type annotations, their type defaults to any().
That is, the previous example is a shorthand for the following:
</p>
<pre>
-record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).</pre>
<p>
- In the presence of initial values for fields,
+ In the presence of initial values for fields,
the type must be declared after the initialization, as follows:
</p>
<pre>
@@ -409,12 +413,12 @@
The initial values for fields are to be compatible
with (that is, a member of) the corresponding types.
This is checked by the compiler and results in a compilation error
- if a violation is detected.
+ if a violation is detected.
</p>
<note>
<p>Before Erlang/OTP 19, for fields without initial values,
the singleton type <c>'undefined'</c> was added to all declared types.
- In other words, the following two record declarations had identical
+ In other words, the following two record declarations had identical
effects:</p>
<pre>
-record(rec, {f1 = 42 :: integer(),
@@ -430,22 +434,22 @@
</p>
</note>
<p>
- Any record, containing type information or not, once defined,
+ Any record, containing type information or not, once defined,
can be used as a type using the following syntax:
</p>
<pre> #rec{}</pre>
<p>
- In addition, the record fields can be further specified when using
+ In addition, the record fields can be further specified when using
a record type by adding type information about the field
as follows:
</p>
<pre> #rec{some_field :: Type}</pre>
<p>
- Any unspecified fields are assumed to have the type in the original
+ Any unspecified fields are assumed to have the type in the original
record declaration.
</p>
</section>
-
+
<section>
<title>Specifications for Functions</title>
<p>
@@ -459,9 +463,9 @@
else a compilation error occurs.
</p>
<p>
- This form can also be used in header files (.hrl) to declare type
- information for exported functions.
- Then these header files can be included in files that (implicitly or
+ This form can also be used in header files (.hrl) to declare type
+ information for exported functions.
+ Then these header files can be included in files that (implicitly or
explicitly) import these functions.
</p>
<p>
@@ -475,14 +479,14 @@
<pre>
-spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.</pre>
<p>
- A function specification can be overloaded.
+ A function specification can be overloaded.
That is, it can have several types, separated by a semicolon (<c>;</c>):
</p>
<pre>
-spec foo(T1, T2) -> T3
; (T4, T5) -> T6.</pre>
<p>
- A current restriction, which currently results in a warning
+ A current restriction, which currently results in a warning
(not an error) by the compiler, is that the domains of
the argument types cannot overlap.
For example, the following specification results in a warning:
@@ -491,9 +495,9 @@
-spec foo(pos_integer()) -> pos_integer()
; (integer()) -> integer().</pre>
<p>
- Type variables can be used in specifications to specify relations for
- the input and output arguments of a function.
- For example, the following specification defines the type of a
+ Type variables can be used in specifications to specify relations for
+ the input and output arguments of a function.
+ For example, the following specification defines the type of a
polymorphic identity function:
</p>
<pre>
@@ -542,8 +546,8 @@
-spec foo({X, integer()}) -> X when X :: atom()
; ([Y]) -> Y when Y :: number().</pre>
<p>
- Some functions in Erlang are not meant to return;
- either because they define servers or because they are used to
+ Some functions in Erlang are not meant to return;
+ either because they define servers or because they are used to
throw exceptions, as in the following function:
</p>
<pre> my_error(Err) -> erlang:throw({error, Err}).</pre>
@@ -555,4 +559,3 @@
<pre> -spec my_error(term()) -> no_return().</pre>
</section>
</chapter>
-
diff --git a/system/doc/tutorial/c_port.xmlsrc b/system/doc/tutorial/c_port.xmlsrc
index 3c3bc48044..ff0997fb54 100644
--- a/system/doc/tutorial/c_port.xmlsrc
+++ b/system/doc/tutorial/c_port.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2015</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/tutorial/c_portdriver.xmlsrc b/system/doc/tutorial/c_portdriver.xmlsrc
index 933e2395a3..da680642b6 100644
--- a/system/doc/tutorial/c_portdriver.xmlsrc
+++ b/system/doc/tutorial/c_portdriver.xmlsrc
@@ -161,8 +161,8 @@ decode([Int]) -> Int.</pre>
<title>Running the Example</title>
<p><em>Step 1.</em> Compile the C code:</p>
<pre>
-unix> <input>gcc -o exampledrv -fpic -shared complex.c port_driver.c</input>
-windows> <input>cl -LD -MD -Fe exampledrv.dll complex.c port_driver.c</input></pre>
+unix> <input>gcc -o example_drv.so -fpic -shared complex.c port_driver.c</input>
+windows> <input>cl -LD -MD -Fe example_drv.dll complex.c port_driver.c</input></pre>
<p><em>Step 2.</em> Start Erlang and compile the Erlang code:</p>
<pre>
> <input>erl</input>