diff options
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 Binary files differindex 48e8f80f79..fbea0b152b 100644 --- a/bootstrap/lib/compiler/ebin/beam_bsm.beam +++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex 044ed03d93..163d9b8432 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex 3ba8d92655..f3bbc3401c 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam 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 Binary files differindex e4f06a8278..c52a159368 100644 --- a/bootstrap/lib/stdlib/ebin/gen_statem.beam +++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam Binary files differindex 2c0eb8a742..c72dd5c717 100644 --- a/bootstrap/lib/stdlib/ebin/ms_transform.beam +++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam 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 Binary files differindex 64d1a70e61..d91b5ed079 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam Binary files differindex 4406a82a36..d6c987178b 100644 --- a/erts/preloaded/ebin/erl_tracer.beam +++ b/erts/preloaded/ebin/erl_tracer.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex fbbfefa462..72898e6d8a 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam Binary files differindex 6956eee740..21463a2286 100644 --- a/erts/preloaded/ebin/erts_code_purger.beam +++ b/erts/preloaded/ebin/erts_code_purger.beam diff --git a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam Binary files differindex a7ac116c05..423f33b99a 100644 --- a/erts/preloaded/ebin/erts_dirty_process_code_checker.beam +++ b/erts/preloaded/ebin/erts_dirty_process_code_checker.beam diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex 2a7bfb8b86..4f81b5089d 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam Binary files differindex 71f3c2ec8c..0926cf1f95 100644 --- a/erts/preloaded/ebin/erts_literal_area_collector.beam +++ b/erts/preloaded/ebin/erts_literal_area_collector.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 74a0184818..c8db150d64 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex b601c048b3..dc29a3eaad 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam Binary files differindex 77909b01f0..a50a628a27 100644 --- a/erts/preloaded/ebin/prim_eval.beam +++ b/erts/preloaded/ebin/prim_eval.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 5bbbaf14d5..6bf3c7313c 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 1a573ce297..bae6291d87 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 6afeb454d6..134497411f 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 4c48742344..34c342371b 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam 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) -> 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) -> 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) -> 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) -> 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) -> ok</name> + <name>pal(Category, Importance, Format, FormatArgs, Opts) -> 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) -> 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) -> 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) -> 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) -> 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) -> ok</name> + <name>print(Category, Importance, Format, FormatArgs, Opts) -> 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: <pre>~s</pre>", [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 Binary files differdeleted file mode 100644 index 0b90c08a9a..0000000000 --- a/lib/observer/priv/crashdump_viewer/collapsd.gif +++ /dev/null diff --git a/lib/observer/priv/crashdump_viewer/exploded.gif b/lib/observer/priv/crashdump_viewer/exploded.gif Binary files differdeleted file mode 100644 index e3ab5ca2e9..0000000000 --- a/lib/observer/priv/crashdump_viewer/exploded.gif +++ /dev/null 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><<_:_*1>></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> |