diff options
Diffstat (limited to 'erts')
58 files changed, 1131 insertions, 2693 deletions
diff --git a/erts/configure.in b/erts/configure.in index 308e1288ba..12dfb9b19b 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -1903,8 +1903,9 @@ fi if test "x$ac_compiler_gnu" = "xyes"; then AC_MSG_CHECKING([if we should add -fno-tree-copyrename to CFLAGS for computed gotos to work properly]) +## tree-copyrename was broken in gcc 4.3 and then removed in gcc 6 AC_TRY_COMPILE([],[ - #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) + #if (__GNUC__ > 4 && __GNUC__ < 6) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) ; #else #error old and ok diff --git a/erts/doc/src/erl_cmd.xml b/erts/doc/src/erl_cmd.xml index 91954b9e7a..eb1e9e2de7 100644 --- a/erts/doc/src/erl_cmd.xml +++ b/erts/doc/src/erl_cmd.xml @@ -678,7 +678,7 @@ produces a crash dump. On Unix systems, sending an emulator process a <c>SIGUSR1</c> signal also forces a crash dump.</p> </item> - <tag><marker id="+dcg"/><c><![CDATA[+rg DecentralizedCounterGroupsLimit]]></c></tag> + <tag><marker id="+dcg"/><c><![CDATA[+dcg DecentralizedCounterGroupsLimit]]></c></tag> <item> <p>Limits the number of decentralized counter groups used by decentralized counters optimized for update operations in the @@ -865,11 +865,6 @@ <c>+IOt</c> are used, <c>+IOPt</c> is ignored. </p> </item> - <tag><c><![CDATA[+l]]></c></tag> - <item> - <p>Enables autoload tracing, displaying information while loading - code.</p> - </item> <tag><c><![CDATA[+L]]></c></tag> <item> <p>Prevents loading information about source filenames and line diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index bcc7bc3e93..d2a1581e35 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -660,7 +660,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, it can only be passed on to API functions. Three types of environments exist:</p> <taglist> - <tag>Process bound environment</tag> + <tag><marker id="proc_bound_env"/>Process bound environment</tag> <item> <p>Passed as the first argument to all NIFs. All function arguments passed to a NIF belong to that environment. The return value from @@ -671,7 +671,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, returns. It is thus useless and dangerous to store pointers to process bound environments between NIF calls.</p> </item> - <tag>Callback environment</tag> + <tag><marker id="callback_env"/>Callback environment</tag> <item> <p>Passed as the first argument to all the non-NIF callback functions (<seecref marker="#load"><c>load</c></seecref>, @@ -685,7 +685,7 @@ int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, returned. Terms may be created in this environment but they will only be accessible during the callback.</p> </item> - <tag>Process independent environment</tag> + <tag><marker id="proc_indep_env"/>Process independent environment</tag> <item> <p>Created by calling <seecref marker="#enif_alloc_env"> <c>enif_alloc_env</c></seecref>. This environment can be @@ -1006,7 +1006,9 @@ typedef struct { <name since="OTP R14B"><ret>ErlNifEnv *</ret><nametext>enif_alloc_env()</nametext></name> <fsummary>Create a new environment.</fsummary> <desc> - <p>Allocates a new process independent environment. The environment can + <p> + Allocates a new <seecref marker="#proc_indep_env">process + independent environment</seecref>. The environment can be used to hold terms that are not bound to any process. Such terms can later be copied to a process environment with <seecref marker="#enif_make_copy"><c>enif_make_copy</c></seecref> or @@ -1253,8 +1255,12 @@ typedef struct { <c>enif_monitor_process</c></seecref>. Argument <c>obj</c> is a pointer to the resource holding the monitor and <c>*mon</c> identifies the monitor.</p> - <p>Argument <c>caller_env</c> is the environment of the calling process - or callback. Must only be NULL if calling from a custom thread.</p> + <p> + Argument <c>caller_env</c> is the environment of the calling thread + (<seecref marker="#proc_bound_env">process bound</seecref> or + <seecref marker="#callback_env">callback</seecref> environment) or + <c>NULL</c> if calling from a custom thread not spawned by ERTS. + </p> <p>Returns <c>0</c> if the monitor was successfully identified and removed. Returns a non-zero value if the monitor could not be identified, which means it was either</p> @@ -2659,8 +2665,12 @@ enif_map_iterator_destroy(env, &iter);</code> <seecref marker="#enif_compare_monitors"><c>enif_compare_monitors</c></seecref>. A monitor is automatically removed when it triggers or when the resource is deallocated.</p> - <p>Argument <c>caller_env</c> is the environment of the calling process - or callback. Must only be NULL if calling from a custom thread.</p> + <p> + Argument <c>caller_env</c> is the environment of the calling thread + (<seecref marker="#proc_bound_env">process bound</seecref> or + <seecref marker="#callback_env">callback</seecref> environment) or + <c>NULL</c> if calling from a custom thread not spawned by ERTS. + </p> <p>Returns <c>0</c> on success, < 0 if no <c>down</c> callback is provided, and > 0 if the process is no longer alive or if <c>target_pid</c> is <seecref marker="#enif_set_pid_undefined"> @@ -3263,7 +3273,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <p>Initializes the <seecref marker="#ErlNifPid"><c>ErlNifPid</c></seecref> variable at <c>*pid</c> to represent the calling process.</p> <p>Returns <c>pid</c> if successful, or NULL if <c>caller_env</c> is not - a <seecref marker="#ErlNifEnv">process bound environment</seecref>.</p> + a <seecref marker="#proc_bound_env">process bound environment</seecref>.</p> </desc> </func> @@ -3275,8 +3285,12 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <p>Sends a message to a process.</p> <taglist> <tag><c>caller_env</c></tag> - <item>The environment of the calling process or callback. Must be <c>NULL</c> - only if calling from a custom thread not spawned by ERTS.</item> + <item> + The environment of the calling thread + (<seecref marker="#proc_bound_env">process bound</seecref> or + <seecref marker="#callback_env">callback</seecref> environment) or + <c>NULL</c> if calling from a custom thread not spawned by ERTS. + </item> <tag><c>*to_pid</c></tag> <item>The pid of the receiving process. The pid is to refer to a process on the local node.</item> @@ -3604,15 +3618,18 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <func> <name since="OTP 20.0"><ret>int</ret> - <nametext>enif_whereis_pid(ErlNifEnv *env, + <nametext>enif_whereis_pid(ErlNifEnv *caller_env, ERL_NIF_TERM name, ErlNifPid *pid)</nametext></name> <fsummary>Looks up a process by its registered name.</fsummary> <desc> <p>Looks up a process by its registered name.</p> <taglist> - <tag><c>env</c></tag> - <item>The environment of the calling process. Must be <c>NULL</c> - only if calling from a created thread.</item> + <tag><c>caller_env</c></tag> + <item>The environment of the calling thread + (<seecref marker="#proc_bound_env">process bound</seecref> or + <seecref marker="#callback_env">callback</seecref> environment) or + <c>NULL</c> if calling from a custom thread not spawned by + ERTS.</item> <tag><c>name</c></tag> <item>The name of a registered process, as an atom.</item> <tag><c>*pid</c></tag> @@ -3632,15 +3649,18 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <func> <name since="OTP 20.0"><ret>int</ret> - <nametext>enif_whereis_port(ErlNifEnv *env, + <nametext>enif_whereis_port(ErlNifEnv *caller_env, ERL_NIF_TERM name, ErlNifPort *port)</nametext></name> <fsummary>Looks up a port by its registered name.</fsummary> <desc> <p>Looks up a port by its registered name.</p> <taglist> - <tag><c>env</c></tag> - <item>The environment of the calling process. Must be <c>NULL</c> - only if calling from a created thread.</item> + <tag><c>caller_env</c></tag> + <item>The environment of the calling thread + (<seecref marker="#proc_bound_env">process bound</seecref> or + <seecref marker="#callback_env">callback</seecref> environment) or + <c>NULL</c> if calling from a custom thread not spawned by + ERTS.</item> <tag><c>name</c></tag> <item>The name of a registered port, as an atom.</item> <tag><c>*port</c></tag> diff --git a/erts/doc/src/escript_cmd.xml b/erts/doc/src/escript_cmd.xml index 47d18c0872..b234b6752c 100644 --- a/erts/doc/src/escript_cmd.xml +++ b/erts/doc/src/escript_cmd.xml @@ -42,7 +42,7 @@ the top <c>bin</c> directory of the standalone system and given <c>.escript</c> as file extension. Further the (built-in) <c>escript</c> program should be copied to the same directory and - given the scripts original name (without the <c>.escript</c> + given the script's original name (without the <c>.escript</c> extension). This will enable use of the bundled Erlang runtime system.</p> @@ -101,7 +101,7 @@ usage: factorial integer</pre> a normal Erlang module. The first line is intended to be the interpreter line, which invokes <c>escript</c>.</p> <p>However, if you invoke the <c>escript</c> as follows, - the contents of the first line does not matter, but it + the contents of the first line do not matter, but it cannot contain Erlang code as it will be ignored:</p> <pre> $ <input>escript factorial 5</input></pre> diff --git a/erts/doc/src/inet_cfg.xml b/erts/doc/src/inet_cfg.xml index 0e2437e33c..7934a6df86 100644 --- a/erts/doc/src/inet_cfg.xml +++ b/erts/doc/src/inet_cfg.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2016</year> + <year>2004</year><year>2020</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -268,6 +268,17 @@ <seeerl marker="kernel:inet_res"><c>inet_res(3)</c></seeerl> will try before giving up. Defaults to 3.</p> </item> + + <tag><c><![CDATA[{servfail_retry_timeout, Time}.]]></c></tag> + <item> + <p><c><![CDATA[Time = non_neg_integer()]]></c></p> + <p>After all name servers have been tried, there is a timeout + before the name servers are tried again. This is to prevent + the server from answering the query with what's in the servfail cache, + <seeerl marker="kernel:inet_res#servfail_retry_timeout"><c>inet_res(3)</c></seeerl>. + Defaults to 1500 milli seconds .</p> + </item> + <tag><c><![CDATA[{inet6, Bool}.]]></c></tag> <item> <p><c><![CDATA[Bool = true | false]]></c></p> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 25b16d6681..29f33ba2d8 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,199 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 11.1.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a bug that could cause some work scheduled for + execution on scheduler threads to be delayed until other + similar work appeared. Beside delaying various cleanup of + internal data structures also the following could be + delayed:</p> <list> <item>Termination of a distribution + controller process</item> <item>Disabling of the + distribution on a node</item> <item>Gathering of memory + allocator information using the <c>instrument</c> + module</item> <item>Enabling, disabling, and gathering of + <c>msacc</c> information</item> <item>Delivery of + <c>'CHANGE'</c> messages when time offset is + monitored</item> <item>A call to + <c>erlang:cancel_timer()</c></item> <item>A call to + <c>erlang:read_timer()</c></item> <item>A call to + <c>erlang:statistics(io | garbage_collection | + scheduler_wall_time)</c></item> <item>A call to + <c>ets:all()</c></item> <item>A call to + <c>erlang:memory()</c></item> <item>A call to + <c>erlang:system_info({allocator | allocator_sizes, + _})</c></item> <item>A call to + <c>erlang:trace_delivered()</c></item> </list> <p>The bug + existed on runtime systems running on all types of + hardware except for x86/x86_64.</p> + <p> + Own Id: OTP-17185</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 11.1.7</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Make windows installer remove write access rights for non + admin users when installing to a non default directory. + Reduces the risk for DLL sideloading, but the user should + always be aware of the access rights for the + installation.</p> + <p> + Own Id: OTP-17097</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 11.1.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The <c>suspend_process()</c> and <c>resume_process()</c> + BIFs did not check their arguments properly which could + cause an emulator crash.</p> + <p> + Own Id: OTP-17080</p> + </item> + <item> + <p> + The runtime system would get into an infinite loop if the + runtime system was started with more than 1023 file + descriptors already open.</p> + <p> + Own Id: OTP-17088 Aux Id: ERIERL-580 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 11.1.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix emulator crash when sending small bit-strings over + Erlang distribution while the connection is being setup.</p> + <p> + The fault was introduced in OTP-23.0</p> + <p> + Own Id: OTP-17083 Aux Id: ERIERL-572 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 11.1.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug which could cause VM crash when a NIF is loaded + at the same time as the Erlang implementation of the NIF + is called. Bug exists since OTP 23.0.</p> + <p> + Own Id: OTP-16859</p> + </item> + <item> + <p> + Fixed <c>enif_make_map_*</c> functions in debug build + when given environment from <c>enif_alloc_env</c>.</p> + <p> + Own Id: OTP-16863 Aux Id: ERL-1352 </p> + </item> + <item> + <p> + Fixed broken configuration option <c>--disable-pie</c>.</p> + <p> + Own Id: OTP-16864</p> + </item> + <item> + <p> + Fixed rare distribution bug in race between received + signal (link/monitor/spawn_request/spawn_reply) and + disconnection. Symptom: VM crash. Since: OTP 21.0.</p> + <p> + Own Id: OTP-16869 Aux Id: ERL-1337 </p> + </item> + <item> + <p>Fixed a performance issue when extremely many items + were stored in the process dictionary. (Fixing this bug + also eliminates a compiler warning emitted by the latest + version of Clang.)</p> + <p> + Own Id: OTP-16888</p> + </item> + <item> + <p> + Remove <c>-ftree-copyrename</c> from flags passed to + compiler when building erts. The flag is not used by + modern gcc's and is not supported by clang.</p> + <p> + Own Id: OTP-16894</p> + </item> + <item> + <p>Modules using complicated nested binary comprehensions + could fail to load.</p> + <p> + Own Id: OTP-16899</p> + </item> + <item> + <p>Fixed a race in <c>file:read_file/1</c> were an + incomplete file could be returned if another OS process + swapped the file out while reading.</p> + <p> + Own Id: OTP-16948 Aux Id: PR-2792 </p> + </item> + <item> + <p>The call <c>list_to_integer("10", true)</c> would + return <c>4</c> instead of raising an exception. Certain + other atoms would also be interpreted as a number + base.</p> + <p> + Own Id: OTP-17030</p> + </item> + <item> + <p> + On macOS 11 (Big Sur), erl would not start if the maximum + number of file descriptors were unlimited (<c>ulimit -n + unlimited</c>).</p> + <p> + Own Id: OTP-17055 Aux Id: ERL-1417 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add manifest to all executables and dynamic libraries.</p> + <p> + Own Id: OTP-17067 Aux Id: PR-2907 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 11.1.3</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1023,6 +1216,118 @@ </section> +<section><title>Erts 10.7.2.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed rare distribution bug in race between received + signal (link/monitor/spawn_request/spawn_reply) and + disconnection. Symptom: VM crash. Since: OTP 21.0.</p> + <p> + Own Id: OTP-16869 Aux Id: ERL-1337 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.7.2.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bugs causing issues when enabling the ERTS internal + allocators on a system built with the undocumented and + unsupported <c>SMALL_MEMORY</c> feature.</p> + <p> + Own Id: OTP-16939</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.7.2.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + inet:setopts([{active,once}]) wakes up IO polling thread + unnecessarily, leading to lock contention and visibly + higher CPU utilization.</p> + <p> + Own Id: OTP-16847 Aux Id: ERL-1301 </p> + </item> + <item> + <p> + The documentation of <c>statistics(run_queue)</c> + erroneously stated that it returns the total length of + all normal run queues when it is the total length of all + normal and dirty CPU run queues that is returned. The + documentation has been updated to reflect the actual + behavior.</p> + <p> + Own Id: OTP-16866 Aux Id: ERL-1355 </p> + </item> + <item> + <p> + Two bugs in the ERTS internal thread wakeup functionality + have been fixed. These bugs mainly hit when all threads + in the system tried to go to sleep. When the bugs were + triggered, certain operations were delayed until a thread + woke up due to some other reason. Most important + operations effected were code loading, persistent term + updates, and memory deallocation.</p> + <p> + Own Id: OTP-16870</p> + </item> + <item> + <p> + Fixed bug in <c>ets:select_replace/2</c> on + <c>compressed</c> tables that could produce faulty + results or VM crash. Bug exists since OTP 20.</p> + <p> + Own Id: OTP-16874 Aux Id: ERL-1356, PR-2763 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + As of OTP 22, the allocator specific memory carrier pools + were replaced by a node global carrier pool. This + unfortunately caused substantial memory fragmentation in + some cases due to long lived data being spread into + carriers used by allocators mainly handling short lived + data.</p> + <p> + A new command line argument <c>+M<S>cp</c> has been + introduced with which one can enable the old behavior as + well as configuring other behaviors for the carrier + pools. In order to configure the old behavior, with + allocator specific carrier pools for all allocators, pass + <c>+Mucp :</c> (including the colon character) as a + command line argument to <c>erl</c> when starting the + Erlang system.</p> + <p> + The default configuration for carrier pools will be + changed to <c>+Mucp :</c> some time in the future, but + not in this patch.</p> + <p> + Own Id: OTP-16856</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.7.2.3</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -2870,6 +3175,53 @@ </section> +<section><title>Erts 10.3.5.14</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The ERTS internal I/O poll implementation could get into + an inconsistent state causing input events to be ignored.</p> + <p> + Own Id: OTP-16780 Aux Id: PR-2701 </p> + </item> + <item> + <p> + The documentation of <c>statistics(run_queue)</c> + erroneously stated that it returns the total length of + all normal run queues when it is the total length of all + normal and dirty CPU run queues that is returned. The + documentation has been updated to reflect the actual + behavior.</p> + <p> + Own Id: OTP-16866 Aux Id: ERL-1355 </p> + </item> + <item> + <p> + Two bugs in the ERTS internal thread wakeup functionality + have been fixed. These bugs mainly hit when all threads + in the system tried to go to sleep. When the bugs were + triggered, certain operations were delayed until a thread + woke up due to some other reason. Most important + operations effected were code loading, persistent term + updates, and memory deallocation.</p> + <p> + Own Id: OTP-16870</p> + </item> + <item> + <p> + Fixed bug in <c>ets:select_replace/2</c> on + <c>compressed</c> tables that could produce faulty + results or VM crash. Bug exists since OTP 20.</p> + <p> + Own Id: OTP-16874 Aux Id: ERL-1356, PR-2763 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.3.5.13</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 5beab81b98..4f1f114eba 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3105,13 +3105,15 @@ BIF_RETTYPE list_to_integer_2(BIF_ALIST_2) int base; i = erts_list_length(BIF_ARG_1); - if (i < 0) - BIF_ERROR(BIF_P, BADARG); - + if (i < 0 || is_not_small(BIF_ARG_2)) { + BIF_ERROR(BIF_P, BADARG); + } + base = signed_val(BIF_ARG_2); - if (base < 2 || base > 36) - BIF_ERROR(BIF_P, BADARG); + if (base < 2 || base > 36) { + BIF_ERROR(BIF_P, BADARG); + } if (erts_list_to_integer(BIF_P, BIF_ARG_1, base, &res, &dummy) != LTI_ALL_INTEGER) { diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 3261fbb5b8..945764d552 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -2016,21 +2016,27 @@ int erts_net_message(Port *prt, from, to); ASSERT(ldp->a.other.item == to); ASSERT(eq(ldp->b.other.item, from)); - code = erts_link_dist_insert(&ldp->a, dep->mld); - ASSERT(code); - if (erts_proc_sig_send_link(NULL, to, &ldp->b)) - break; /* done */ + code = erts_link_dist_insert(&ldp->a, ede.mld); + if (erts_proc_sig_send_link(NULL, to, &ldp->b)) { + if (!code) { + /* Race: connection already down => send link exit */ + erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a, + am_noconnection, NIL); + } + break; /* Done */ + } /* Failed to send signal; cleanup and reply noproc... */ - - code = erts_link_dist_delete(&ldp->a); - ASSERT(code); + if (code) { + code = erts_link_dist_delete(&ldp->a); + ASSERT(code); + } erts_link_release_both(ldp); } code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0); - if (code == ERTS_DSIG_PREP_CONNECTED) { + if (code == ERTS_DSIG_PREP_CONNECTED && ctx.connection_id == conn_id) { code = erts_dsig_send_exit(&ctx, to, from, am_noproc); ASSERT(code == ERTS_DSIG_SEND_OK); } @@ -2105,8 +2111,11 @@ int erts_net_message(Port *prt, mdp = erts_monitor_create(ERTS_MON_TYPE_DIST_PROC, ref, watcher, pid, name); - code = erts_monitor_dist_insert(&mdp->origin, dep->mld); - ASSERT(code); (void)code; + if (!erts_monitor_dist_insert(&mdp->origin, ede.mld)) { + /* Race: connection down => do nothing */ + erts_monitor_release_both(mdp); + break; + } if (erts_proc_sig_send_monitor(&mdp->target, pid)) break; /* done */ @@ -2120,7 +2129,7 @@ int erts_net_message(Port *prt, } code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0); - if (code == ERTS_DSIG_PREP_CONNECTED) { + if (code == ERTS_DSIG_PREP_CONNECTED && ctx.connection_id == conn_id) { code = erts_dsig_send_m_exit(&ctx, watcher, watched, ref, am_noproc); ASSERT(code == ERTS_DSIG_SEND_OK); } @@ -2156,16 +2165,17 @@ int erts_net_message(Port *prt, ; } else if (is_atom(watched)) { - ErtsMonLnkDist *mld = dep->mld; ErtsMonitor *mon; - erts_mtx_lock(&mld->mtx); - - mon = erts_monitor_tree_lookup(mld->orig_name_monitors, ref); - if (mon) - erts_monitor_tree_delete(&mld->orig_name_monitors, mon); - - erts_mtx_unlock(&mld->mtx); + erts_mtx_lock(&ede.mld->mtx); + if (ede.mld->alive) { + mon = erts_monitor_tree_lookup(ede.mld->orig_name_monitors, ref); + if (mon) + erts_monitor_tree_delete(&ede.mld->orig_name_monitors, mon); + } + else + mon = NULL; + erts_mtx_unlock(&ede.mld->mtx); if (mon) erts_proc_sig_send_demonitor(mon); @@ -2554,7 +2564,8 @@ int erts_net_message(Port *prt, } code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0); - if (code == ERTS_DSIG_PREP_CONNECTED) { + if (code == ERTS_DSIG_PREP_CONNECTED + && ctx.connection_id == conn_id) { code = erts_dsig_send_spawn_reply(&ctx, tuple[2], tuple[3], @@ -2572,6 +2583,7 @@ int erts_net_message(Port *prt, so.group_leader = gl; so.mfa = mfa; so.dist_entry = dep; + so.mld = ede.mld; so.edep = edep; so.ede_hfrag = ede_hfrag; so.token = token; @@ -2598,6 +2610,7 @@ int erts_net_message(Port *prt, ErtsLinkData *ldp; ErtsLink *lnk; int monitor; + int link_inserted; Eterm ref, result, flags_term, parent, token; Uint flags; @@ -2619,6 +2632,7 @@ int erts_net_message(Port *prt, ldp = NULL; lnk = NULL; + link_inserted = 0; monitor = 0; ref = tuple[2]; @@ -2660,15 +2674,11 @@ int erts_net_message(Port *prt, if (flags & ERTS_DIST_SPAWN_FLAG_LINK) { /* Successful spawn-link... */ - int code; - ldp = erts_link_create(ERTS_LNK_TYPE_DIST_PROC, result, parent); ASSERT(ldp->a.other.item == parent); ASSERT(eq(ldp->b.other.item, result)); - code = erts_link_dist_insert(&ldp->a, dep->mld); - ASSERT(code); (void)code; - + link_inserted = erts_link_dist_insert(&ldp->a, ede.mld); lnk = &ldp->b; } } @@ -2682,7 +2692,8 @@ int erts_net_message(Port *prt, if (monitor) { code = erts_dsig_prepare(&ctx, dep, NULL, 0, ERTS_DSP_NO_LOCK, 1, 1, 0); - if (code == ERTS_DSIG_PREP_CONNECTED) { + if (code == ERTS_DSIG_PREP_CONNECTED + && ctx.connection_id == conn_id) { code = erts_dsig_send_demonitor(&ctx, parent, result, ref); ASSERT(code == ERTS_DSIG_SEND_OK); @@ -2690,9 +2701,10 @@ int erts_net_message(Port *prt, } if (lnk) { - - code = erts_link_dist_delete(&ldp->a); - ASSERT(code); + if (link_inserted) { + code = erts_link_dist_delete(&ldp->a); + ASSERT(code); + } erts_link_release_both(ldp); } @@ -2706,6 +2718,10 @@ int erts_net_message(Port *prt, dep->mld); } } + else if (lnk && !link_inserted) { + erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a, + am_noconnection, NIL); + } break; } diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 48afa71583..7adab91440 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -354,18 +354,18 @@ type COUNTERS STANDARD SYSTEM erl_bif_counters # Types used by system specific code # -type TEMP_TERM TEMPORARY SYSTEM temp_term -type SHORT_LIVED_TERM SHORT_LIVED SYSTEM short_lived_term -type DRV_TAB LONG_LIVED SYSTEM drv_tab -type DRV_EV_STATE LONG_LIVED SYSTEM driver_event_state -type DRV_SEL_D_STATE FIXED_SIZE SYSTEM driver_select_data_state -type NIF_SEL_D_STATE FIXED_SIZE SYSTEM enif_select_data_state -type POLLSET LONG_LIVED SYSTEM pollset -type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req -type POLL_FDS LONG_LIVED SYSTEM poll_fds +type TEMP_TERM TEMPORARY SYSTEM temp_term +type SHORT_LIVED_TERM SHORT_LIVED SYSTEM short_lived_term +type DRV_TAB LONG_LIVED SYSTEM drv_tab +type DRV_EV_STATE LONG_LIVED SYSTEM driver_event_state +type DRV_SEL_D_STATE FIXED_SIZE SYSTEM driver_select_data_state +type NIF_SEL_D_STATE FIXED_SIZE SYSTEM enif_select_data_state +type POLLSET LONG_LIVED SYSTEM pollset +type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req +type POLL_FDS LONG_LIVED SYSTEM poll_fds type BLOCK_PTHR_DATA LONG_LIVED SYSTEM block_poll_thread_data -type FD_STATUS LONG_LIVED SYSTEM fd_status -type SELECT_FDS LONG_LIVED SYSTEM select_fds +type FD_STATUS LONG_LIVED SYSTEM fd_status +type SELECT_FDS LONG_LIVED SYSTEM select_fds +if unix diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index aac1ff7bfd..e7c649c5a7 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -2071,10 +2071,7 @@ Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value, hp = HAlloc(p, size); res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack); } - DESTROY_ESTACK(stack); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(p); - ERTS_HOLE_CHECK(p); return res; } @@ -2612,8 +2609,6 @@ unroll: HRelease(p, hp_end, hp); not_found: DESTROY_ESTACK(stack); - ERTS_VERIFY_UNUSED_TEMP_ALLOC(p); - ERTS_HOLE_CHECK(p); UnUseTmpHeapNoproc(2); return res; } diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c index 432e895116..a1c5170386 100644 --- a/erts/emulator/beam/erl_monitor_link.c +++ b/erts/emulator/beam/erl_monitor_link.c @@ -544,9 +544,10 @@ erts_mon_link_dist_create(Eterm nodename) return mld; } -void -erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld) +static void +mon_link_dist_destroy(void* vmld) { + ErtsMonLnkDist *mld = (ErtsMonLnkDist*)vmld; ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) == 0); ERTS_ML_ASSERT(!mld->alive); ERTS_ML_ASSERT(!mld->links); @@ -558,6 +559,21 @@ erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld) erts_free(ERTS_ALC_T_ML_DIST, mld); } +void +erts_schedule_mon_link_dist_destruction__(ErtsMonLnkDist *mld) +{ + ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) == 0); + ERTS_ML_ASSERT(!mld->alive); + ERTS_ML_ASSERT(!mld->links); + ERTS_ML_ASSERT(!mld->monitors); + ERTS_ML_ASSERT(!mld->orig_name_monitors); + + erts_schedule_thr_prgr_later_cleanup_op(mon_link_dist_destroy, + mld, + &mld->cleanup_lop, + sizeof(ErtsMonLnkDist)); +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * Monitor Operations * \* */ diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h index 15c0676988..d75bc7999b 100644 --- a/erts/emulator/beam/erl_monitor_link.h +++ b/erts/emulator/beam/erl_monitor_link.h @@ -396,6 +396,11 @@ #include "erl_proc_sig_queue.h" #undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY +#define ERL_THR_PROGRESS_TSD_TYPE_ONLY +#include "erl_thr_progress.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY + + #if defined(DEBUG) || 0 # define ERTS_ML_DEBUG #else @@ -481,7 +486,7 @@ struct ErtsMonLnkNode__ { Uint16 type; }; -typedef struct { +typedef struct ErtsMonLnkDist__ { Eterm nodename; Uint32 connection_id; erts_atomic_t refc; @@ -492,6 +497,7 @@ typedef struct { ErtsMonLnkNode *orig_name_monitors; /* Origin named monitors read-black tree */ ErtsMonLnkNode *dist_pend_spawn_exit; + ErtsThrPrgrLaterOp cleanup_lop; } ErtsMonLnkDist; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ @@ -544,7 +550,7 @@ ERTS_GLB_INLINE void erts_ml_dl_list_delete__(ErtsMonLnkNode **list, ErtsMonLnkNode *ml); ERTS_GLB_INLINE ErtsMonLnkNode *erts_ml_dl_list_first__(ErtsMonLnkNode *list); ERTS_GLB_INLINE ErtsMonLnkNode *erts_ml_dl_list_last__(ErtsMonLnkNode *list); -void erts_mon_link_dist_destroy__(ErtsMonLnkDist *mld); +void erts_schedule_mon_link_dist_destruction__(ErtsMonLnkDist *mld); ERTS_GLB_INLINE void *erts_ml_node_to_main_struct__(ErtsMonLnkNode *mln); /* implementations for globally inlined misc functions... */ @@ -562,7 +568,7 @@ erts_mon_link_dist_dec_refc(ErtsMonLnkDist *mld) { ERTS_ML_ASSERT(erts_atomic_read_nob(&mld->refc) > 0); if (erts_atomic_dec_read_nob(&mld->refc) == 0) - erts_mon_link_dist_destroy__(mld); + erts_schedule_mon_link_dist_destruction__(mld); } ERTS_GLB_INLINE void * @@ -1448,14 +1454,14 @@ erts_monitor_dist_insert(ErtsMonitor *mon, ErtsMonLnkDist *dist) ERTS_ML_ASSERT(!mdep->dist); ERTS_ML_ASSERT(dist); - mdep->dist = dist; - - erts_mon_link_dist_inc_refc(dist); erts_mtx_lock(&dist->mtx); insert = dist->alive; if (insert) { + mdep->dist = dist; + erts_mon_link_dist_inc_refc(dist); + if ((mon->flags & (ERTS_ML_FLG_NAME | ERTS_ML_FLG_TARGET)) == ERTS_ML_FLG_NAME) erts_monitor_tree_insert(&dist->orig_name_monitors, mon); @@ -2346,15 +2352,15 @@ erts_link_dist_insert(ErtsLink *lnk, ErtsMonLnkDist *dist) ERTS_ML_ASSERT(!ldep->dist); ERTS_ML_ASSERT(dist); - ldep->dist = dist; - - erts_mon_link_dist_inc_refc(dist); erts_mtx_lock(&dist->mtx); insert = dist->alive; - if (insert) + if (insert) { + ldep->dist = dist; + erts_mon_link_dist_inc_refc(dist); erts_link_list_insert(&dist->links, lnk); + } erts_mtx_unlock(&dist->mtx); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 83bed11164..3f03243747 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -4605,6 +4605,7 @@ Eterm erts_load_nif(Process *c_p, BeamInstr *I, Eterm filename, Eterm args) static void patch_call_nif_early(ErlNifEntry* entry, struct erl_module_instance* this_mi) { + const BeamInstr call_nif_early = BeamOpCodeAddr(op_call_nif_early); int i; ERTS_LC_ASSERT(erts_has_code_write_permission()); @@ -4627,13 +4628,13 @@ static void patch_call_nif_early(ErlNifEntry* entry, * Code write permission protects against racing breakpoint writes. */ GenericBp* g = ci->u.gen_bp; - g->orig_instr = BeamOpCodeAddr(op_call_nif_early); + g->orig_instr = BeamSetCodeAddr(g->orig_instr, call_nif_early); if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)) continue; } else ASSERT(!BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)); - code_ptr[0] = BeamOpCodeAddr(op_call_nif_early); + code_ptr[0] = BeamSetCodeAddr(code_ptr[0], call_nif_early); } } @@ -4712,12 +4713,12 @@ static void load_nif_2nd_finisher(void* vlib) * Function traced, patch the original instruction word */ GenericBp* g = ci->u.gen_bp; - ASSERT(g->orig_instr == BeamOpCodeAddr(op_call_nif_early)); + ASSERT(BeamIsOpCode(g->orig_instr, op_call_nif_early)); g->orig_instr = BeamOpCodeAddr(op_call_nif_WWW); if (BeamIsOpCode(code_ptr[0], op_i_generic_breakpoint)) continue; } - ASSERT(code_ptr[0] == BeamOpCodeAddr(op_call_nif_early)); + ASSERT(BeamIsOpCode(code_ptr[0], op_call_nif_early)); code_ptr[0] = BeamOpCodeAddr(op_call_nif_WWW); } } diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index ea3b369be2..3c8b1631b4 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1634,6 +1634,11 @@ unset_aux_work_flags(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs) return erts_atomic32_read_band_nob(&ssi->aux_work, ~flgs); } +static ERTS_INLINE erts_aint32_t +unset_aux_work_flags_mb(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs) +{ + return erts_atomic32_read_band_mb(&ssi->aux_work, ~flgs); +} static ERTS_INLINE void haw_chk_later_cleanup_op_wakeup(ErtsAuxWorkData *awdp, ErtsThrPrgrVal val) @@ -1729,9 +1734,7 @@ handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, in if (!waiting && awdp->delayed_wakeup.next > awdp->esdp->reductions) return aux_work; - unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); - - ERTS_THR_MEMORY_BARRIER; + unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); max_jix = awdp->delayed_wakeup.jix; awdp->delayed_wakeup.jix = -1; @@ -1855,7 +1858,7 @@ handle_misc_aux_work(ErtsAuxWorkData *awdp, { ErtsThrQ_t *q = &misc_aux_work_queues[awdp->sched_id].q; - unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MISC); + unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_MISC); while (1) { erts_misc_aux_work_t *mawp = erts_thr_q_dequeue(q); if (!mawp) @@ -1957,7 +1960,7 @@ handle_async_ready(ErtsAuxWorkData *awdp, ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); - unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY); + unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY); if (erts_check_async_ready(awdp->async_ready.queue)) { if (set_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY) & ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN) { @@ -2013,8 +2016,8 @@ handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); - unset_aux_work_flags(ssi, (ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM - | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC)); + unset_aux_work_flags_mb(ssi, (ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM + | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC)); aux_work &= ~(ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC); res = erts_alloc_fix_alloc_shrink(awdp->sched_id, aux_work); @@ -2062,7 +2065,7 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waitin ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); - unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD); + unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_DD); ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_ALLOC); erts_alloc_scheduler_handle_delayed_dealloc((void *) awdp->esdp, &need_thr_progress, @@ -2158,7 +2161,7 @@ handle_canceled_timers(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waitin ASSERT(!awdp->esdp || !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp)); - unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_CNCLD_TMRS); + unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_CNCLD_TMRS); erts_handle_canceled_timers((void *) awdp->esdp, &need_thr_progress, &wakeup, @@ -2328,7 +2331,7 @@ handle_debug_wait_completed(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int w awdp->debug.wait_completed.callback = NULL; awdp->debug.wait_completed.arg = NULL; - unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED); + unset_aux_work_flags_mb(ssi, ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED); return aux_work & ~ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED; } @@ -2464,7 +2467,7 @@ int erts_halt_code; static ERTS_INLINE erts_aint32_t handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { - unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS); + unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS); ERTS_RUNQ_FLGS_SET(awdp->esdp->run_queue, ERTS_RUNQ_FLG_HALTING); if (erts_atomic32_dec_read_acqb(&erts_halt_progress) == 0) { @@ -2559,7 +2562,7 @@ handle_yield(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) static ERTS_INLINE erts_aint32_t handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { - unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK); + unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK); erts_mseg_cache_check(); return aux_work & ~ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK; } @@ -2570,7 +2573,7 @@ handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiti static ERTS_INLINE erts_aint32_t handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { - unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO); + unset_aux_work_flags_mb(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO); setup_aux_work_timer(awdp->esdp); return aux_work & ~ERTS_SSI_AUX_WORK_SET_TMO; } @@ -8699,6 +8702,9 @@ erts_internal_suspend_process_2(BIF_ALIST_2) if (BIF_P->common.id == BIF_ARG_1) BIF_RET(am_badarg); /* We are not allowed to suspend ourselves */ + if (!is_internal_pid(BIF_ARG_1)) + BIF_RET(am_badarg); + if (is_not_nil(BIF_ARG_2)) { /* Parse option list */ Eterm arg = BIF_ARG_2; @@ -8847,6 +8853,9 @@ resume_process_1(BIF_ALIST_1) if (BIF_P->common.id == BIF_ARG_1) BIF_ERROR(BIF_P, BADARG); + if (!is_internal_pid(BIF_ARG_1)) + BIF_ERROR(BIF_P, BADARG); + mon = erts_monitor_tree_lookup(ERTS_P_MONITORS(BIF_P), BIF_ARG_1); if (!mon) { @@ -12209,9 +12218,11 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). ErtsLinkData *ldp; ldp = erts_link_create(ERTS_LNK_TYPE_DIST_PROC, parent_id, p->common.id); - code = erts_link_dist_insert(&ldp->a, so->dist_entry->mld); - ASSERT(code); erts_link_tree_insert(&ERTS_P_LINKS(p), &ldp->b); + if (!erts_link_dist_insert(&ldp->a, so->mld)) { + erts_proc_sig_send_link_exit(NULL, THE_NON_VALUE, &ldp->a, + am_noconnection, NIL); + } } if (so->flags & SPO_MONITOR) { @@ -12219,9 +12230,12 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). mdp = erts_monitor_create(ERTS_MON_TYPE_DIST_PROC, spawn_ref, parent_id, p->common.id, NIL); - code = erts_monitor_dist_insert(&mdp->origin, so->dist_entry->mld); - ASSERT(code); (void)code; - erts_monitor_tree_insert(&ERTS_P_MONITORS(p), &mdp->target); + if (erts_monitor_dist_insert(&mdp->origin, so->mld)) { + erts_monitor_tree_insert(&ERTS_P_MONITORS(p), &mdp->target); + } + else { + erts_monitor_release_both(mdp); + } } if (have_seqtrace(token)) { diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 8dfa5b1bbb..d89a00714f 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1387,6 +1387,7 @@ typedef struct { Eterm group_leader; Eterm mfa; DistEntry *dist_entry; + ErtsMonLnkDist *mld; /* copied from dist_entry->mld */ ErtsDistExternal *edep; ErlHeapFragment *ede_hfrag; Eterm token; diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c index 64ee483079..248da52db5 100644 --- a/erts/emulator/beam/erl_process_dict.c +++ b/erts/emulator/beam/erl_process_dict.c @@ -1052,7 +1052,7 @@ static unsigned int next_array_size(unsigned int need) 1342177280UL, 2684354560UL }; - int hi = sizeof(tab) / sizeof(Uint) - 1; + int hi = sizeof(tab) / sizeof(tab[0]) - 1; int lo = 1; int cur = 4; diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 1a29904f5e..72edff0c22 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -883,6 +883,7 @@ erts_prepare_dist_ext(ErtsDistExternal *edep, edep->heap_size = -1; edep->flags = 0; edep->dep = dep; + edep->mld = dep->mld; edep->connection_id = conn_id; edep->data->ext_endp = ext+size; edep->data->binp = binp; @@ -3838,7 +3839,7 @@ hopefull_bit_binary(TTBEncodeContext* ctx, byte **epp, Binary *pb_val, Eterm pb_ /* copy trailing bits into new hopefull data element */ ep = begin_hopefull_data(ctx, ep); - *ep = 0; + *ep = 0; /* Clear the bit in the byte */ copy_binary_to_buffer(ep, 0, bytes + sz, bitoffs, bitsize); ep++; @@ -5241,10 +5242,13 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, + bin_size); } else if (dflags & DFLAG_PENDING_CONNECT) { + /* This is the odd case when we have an un-aligned bit-string + during a pending connect. */ Uint csz = result - ctx->last_result; ASSERT(dflags & DFLAG_BIT_BINARIES); /* potentially multiple elements leading up to binary */ - vlen += csz/MAX_SYSIOVEC_IOVLEN; + vlen += (csz + MAX_SYSIOVEC_IOVLEN - 1)/MAX_SYSIOVEC_IOVLEN; + vlen++; /* hopefull prolog */ /* * Size for hopefull prolog is max of diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h index 4d8f0bdd29..937dc532f6 100644 --- a/erts/emulator/beam/external.h +++ b/erts/emulator/beam/external.h @@ -144,6 +144,7 @@ typedef struct erl_dist_external { Uint32 flags; Uint32 connection_id; ErtsDistExternalData *data; + struct ErtsMonLnkDist__ *mld; /* copied from DistEntry.mld */ ErtsAtomTranslationTable attab; } ErtsDistExternal; diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index ed0b240d8a..14afdd8553 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1356,6 +1356,9 @@ bs_append Fail Size Extra Live Unit Bin Flags Dst => \ bs_private_append Fail Size Unit Bin Flags Dst => \ i_bs_private_append Fail Unit Size Bin Dst +i_bs_private_append Fail Unit Size Bin Dst=y => \ + i_bs_private_append Fail Unit Size Bin x | move x Dst + bs_init_writable i_bs_append j? I t? t s xy diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c index fce4fc3c90..d26be2bc3e 100644 --- a/erts/emulator/nifs/common/prim_file_nif.c +++ b/erts/emulator/nifs/common/prim_file_nif.c @@ -1266,12 +1266,16 @@ static ERL_NIF_TERM read_file_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); - } else if((posix_errno = efile_read_info(&path, 1, &info))) { - return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_open(&path, EFILE_MODE_READ, efile_resource_type, &d))) { return posix_error_to_tuple(env, posix_errno); } + /* read_file() wants to know the file size, so retrieve it now from the + open file handle. In theory, efile_read_handle_info() may fail with + ENOTSUP, fall back to the "unknown size" logic if that happens. */ + if (efile_read_handle_info(d, &info) != 0) { + info.size = 0; + } posix_errno = read_file(d, info.size, &result); erts_atomic32_set_acqb(&d->state, EFILE_STATE_CLOSED); diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 4e5918d1be..9f0c82dc4b 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -646,12 +646,13 @@ int erts_poll_new_table_len(int old_len, int need_len) } else { new_len = old_len; + if (new_len < ERTS_FD_TABLE_MIN_LENGTH) + new_len = ERTS_FD_TABLE_MIN_LENGTH; do { if (new_len < ERTS_FD_TABLE_EXP_THRESHOLD) new_len *= 2; else new_len += ERTS_FD_TABLE_EXP_THRESHOLD; - } while (new_len < need_len); } ASSERT(new_len >= need_len); @@ -2062,6 +2063,21 @@ ERTS_POLL_EXPORT(erts_poll_init)(int *concurrent_updates) max_fds = OPEN_MAX; #endif + if (max_fds < 0 && errno == 0) { + /* On macOS 11 and higher, it possible to have an unlimited + * number of open files per process. ERTS will need an actual + * limit, though, so we will set it to a largish value. The + * number below is the hard number of file descriptors per + * process as returned by `sysctl kern.maxfilesperproc`, which + * seems to be the limit in practice. + * + * Note: The size of the port table will be based on max_fds, + * so we don't want to set it to a huge value such as + * MAX_INT. + */ + max_fds = 24576; + } + #if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE) && \ !defined(_DARWIN_UNLIMITED_SELECT) if (max_fds > FD_SETSIZE) diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index b00ba287e2..4c64494ac0 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -52,10 +52,6 @@ #include <fcntl.h> #include <time.h> #include <sys/timeb.h> -#pragma comment(linker,"/manifestdependency:\"type='win32' "\ - "name='Microsoft.Windows.Common-Controls' "\ - "version='6.0.0.0' processorArchitecture='*' "\ - "publicKeyToken='6595b64144ccf1df' language='*'\"") #define WIN32_LEAN_AND_MEAN #include <windows.h> diff --git a/erts/emulator/test/bs_bincomp_SUITE.erl b/erts/emulator/test/bs_bincomp_SUITE.erl index c481e93e41..2dcebc2ef9 100644 --- a/erts/emulator/test/bs_bincomp_SUITE.erl +++ b/erts/emulator/test/bs_bincomp_SUITE.erl @@ -112,7 +112,14 @@ mixed(Config) when is_list(Config) -> [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>], [2,3,3,4,4,5,5,6] = [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2]], - ok. + + %% OTP-16899: Nested binary comprehensions would fail to load. + <<0,1,0,2,0,3,99>> = mixed_nested([1,2,3]), + + ok. + +mixed_nested(L) -> + << << << << E:16 >> || E <- L >> || true >>/binary, 99:(id(8))>>. %% OTP-8179: Call tracing on binary comprehensions would cause a crash. tracing(Config) when is_list(Config) -> @@ -148,3 +155,8 @@ tracer(Parent, N) -> tracer(Parent, N+1) end end. + +%%% Common utilities. + +id(I) -> + I. diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index d945023f61..4982d979ec 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -75,7 +75,6 @@ system_limit/1, hopefull_data_encoding/1, hopefull_export_fun_bug/1, - mk_hopefull_data/0, huge_iovec/1]). %% Internal exports. @@ -2604,7 +2603,6 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) -> false = rpc:call(BouncerNode, erts_debug, set_internal_state, [remove_hopefull_dflags, true]) end, - HData = mk_hopefull_data(), Tester = self(), R1 = make_ref(), R2 = make_ref(), @@ -2613,10 +2611,13 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) -> Proxy = spawn_link(ProxyNode, fun () -> register(bouncer, self()), + %% We create the data on the proxy node in order + %% to create the correct sub binaries + HData = mk_hopefull_data(R1, Tester), %% Verify same result between this node and tester Tester ! [R1, HData], %% Test when connection has not been setup yet - Bouncer ! {Tester, [R2, HData]}, + Bouncer ! {Tester, [R2, HData]}, Sync = make_ref(), Bouncer ! {self(), Sync}, receive Sync -> ok end, @@ -2624,17 +2625,18 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) -> Bouncer ! {Tester, [R3, HData]}, receive after infinity -> ok end end), - receive - [R1, HData1] -> - Hdata = HData1 - end, + HData = + receive + [R1, HData1] -> + HData1 + end, receive [R2, HData2] -> case Fallback of false -> HData = HData2; true -> - check_hopefull_fallback_data(Hdata, HData2) + check_hopefull_fallback_data(HData, HData2) end end, receive @@ -2643,7 +2645,7 @@ test_hopefull_data_encoding(Config, Fallback) when is_list(Config) -> false -> HData = HData3; true -> - check_hopefull_fallback_data(Hdata, HData3) + check_hopefull_fallback_data(HData, HData3) end end, unlink(Proxy), @@ -2661,32 +2663,54 @@ bounce_loop() -> end, bounce_loop(). -mk_hopefull_data() -> +mk_hopefull_data(RemoteRef, RemotePid) -> HugeBs = list_to_bitstring([lists:duplicate(12*1024*1024, 85), <<6:6>>]), <<_:1/bitstring,HugeBs2/bitstring>> = HugeBs, - lists:flatten([mk_hopefull_data(list_to_binary(lists:seq(1,255))), - 1234567890, HugeBs, fun gurka:banan/3, fun erlang:node/1, - self(), fun erlang:self/0, - mk_hopefull_data(list_to_binary(lists:seq(1,32))), an_atom, - fun lists:reverse/1, make_ref(), HugeBs2, - fun blipp:blapp/7]). + mk_hopefull_data(list_to_binary(lists:seq(1,255))) ++ + [1234567890, HugeBs, fun gurka:banan/3, fun erlang:node/1, + RemotePid, self(), fun erlang:self/0] ++ + mk_hopefull_data(list_to_binary(lists:seq(1,32))) ++ + [an_atom, + fun lists:reverse/1, RemoteRef, make_ref(), HugeBs2, + fun blipp:blapp/7]. mk_hopefull_data(BS) -> BSsz = bit_size(BS), - [lists:map(fun (Offset) -> - <<_:Offset/bitstring, NewBs/bitstring>> = BS, - NewBs - end, lists:seq(1, 16)), - lists:map(fun (Offset) -> - <<NewBs:Offset/bitstring, _/bitstring>> = BS, - NewBs - end, lists:seq(BSsz-16, BSsz-1)), - lists:map(fun (Offset) -> - PreOffset = Offset rem 16, - <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS, - NewBs - end, lists:seq(BSsz-32, BSsz-17))]. - + lists:concat( + [lists:map(fun (Offset) -> + <<NewBs:Offset/bitstring, _/bitstring>> = BS, + NewBs + end, lists:seq(1, 16)), + lists:map(fun (Offset) -> + <<_:Offset/bitstring, NewBs/bitstring>> = BS, + NewBs + end, lists:seq(1, 16)), + lists:map(fun (Offset) -> + <<NewBs:Offset/bitstring, _/bitstring>> = BS, + NewBs + end, lists:seq(BSsz-16, BSsz-1)), + lists:map(fun (Offset) -> + PreOffset = Offset rem 16, + <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS, + NewBs + end, lists:seq(BSsz-32, BSsz-17)), + lists:map(fun (Offset) -> + <<NewBs:Offset/bitstring, _/bitstring>> = BS, + [NewBs] + end, lists:seq(1, 16)), + lists:map(fun (Offset) -> + <<_:Offset/bitstring, NewBs/bitstring>> = BS, + [NewBs] + end, lists:seq(1, 16)), + lists:map(fun (Offset) -> + <<NewBs:Offset/bitstring, _/bitstring>> = BS, + [NewBs] + end, lists:seq(BSsz-16, BSsz-1)), + lists:map(fun (Offset) -> + PreOffset = Offset rem 16, + <<_:PreOffset/bitstring, NewBs:Offset/bitstring, _/bitstring>> = BS, + [NewBs] + end, lists:seq(BSsz-32, BSsz-17))]). check_hopefull_fallback_data([], []) -> ok; @@ -2696,6 +2720,8 @@ check_hopefull_fallback_data([X|Xs],[Y|Ys]) -> chk_hopefull_fallback(Binary, FallbackBinary) when is_binary(Binary) -> Binary = FallbackBinary; +chk_hopefull_fallback([BitStr], [{Bin, BitSize}]) when is_bitstring(BitStr) -> + chk_hopefull_fallback(BitStr, {Bin, BitSize}); chk_hopefull_fallback(BitStr, {Bin, BitSize}) when is_bitstring(BitStr) -> true = is_binary(Bin), true = is_integer(BitSize), diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index 95cae93225..ddbade85c5 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -82,6 +82,8 @@ consume_timeslice/1, env/1, poll_pipe/1, + lots_of_used_fds_on_boot/1, + lots_of_used_fds_on_boot_slave/1, z_test/1]). -export([bin_prefix/2]). @@ -159,7 +161,9 @@ groups() -> [a_test, use_fallback_pollset, bad_fd_in_pollset, fd_change, steal_control, smp_select, - driver_select_use, z_test]}, + driver_select_use, + lots_of_used_fds_on_boot, + z_test]}, {ioq_exit, [], [ioq_exit_ready_input, ioq_exit_ready_output, ioq_exit_timeout, ioq_exit_ready_async, @@ -1859,6 +1863,79 @@ driver_select_use0(Config) -> ok = erl_ddll:stop(), ok. +lots_of_used_fds_on_boot(Config) -> + case os:type() of + {unix, _} -> lots_of_used_fds_on_boot_test(Config); + _ -> {skipped, "Unix only test"} + end. + +lots_of_used_fds_on_boot_test(Config) -> + %% Start a node in a wrapper which have lots of fds + %% open. This used to hang the whole VM at boot in + %% an eternal loop trying to figure out how to size + %% arrays in erts_poll() implementation. + Name = lots_of_used_fds_on_boot, + HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end, + atom_to_list(node())), + FullName = list_to_atom(atom_to_list(Name) ++ HostSuffix), + Pa = filename:dirname(code:which(?MODULE)), + Prog = case catch init:get_argument(progname) of + {ok,[[P]]} -> P; + _ -> exit(no_progname_argument_found) + end, + NameSw = case net_kernel:longnames() of + false -> "-sname "; + true -> "-name "; + _ -> exit(not_distributed_node) + end, + {ok, Pwd} = file:get_cwd(), + NameStr = atom_to_list(Name), + DataDir = proplists:get_value(data_dir, Config), + Wrapper = filename:join(DataDir, "lots_of_fds_used_wrapper"), + CmdLine = Wrapper ++ " " ++ Prog ++ " -noshell -noinput " + ++ NameSw ++ " " ++ NameStr ++ " " + ++ "-pa " ++ Pa ++ " " + ++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr ++ " " + ++ "-setcookie " ++ atom_to_list(erlang:get_cookie()) ++ " " + ++ "-s " ++ atom_to_list(?MODULE) ++ " lots_of_used_fds_on_boot_slave " + ++ atom_to_list(node()), + io:format("Starting node ~p: ~s~n", [FullName, CmdLine]), + net_kernel:monitor_nodes(true), + Port = case open_port({spawn, CmdLine}, [exit_status]) of + Prt when is_port(Prt) -> + Prt; + OPError -> + exit({failed_to_start_node, {open_port_error, OPError}}) + end, + receive + {Port, {exit_status, 17}} -> + {skip, "Cannot open enough fds to test this"}; + {Port, {exit_status, Error}} -> + exit({failed_to_start_node, {exit_status, Error}}); + {nodeup, FullName} -> + io:format("~p connected!~n", [FullName]), + FullName = rpc:call(FullName, erlang, node, []), + rpc:cast(FullName, erlang, halt, []), + receive + {Port, {exit_status, 0}} -> + ok; + {Port, {exit_status, Error}} -> + exit({unexpected_exit_status, Error}) + after 5000 -> + exit(missing_exit_status) + end + after 5000 -> + exit(connection_timeout) + end. + +lots_of_used_fds_on_boot_slave([Master]) -> + erlang:monitor_node(Master, true), + receive + {nodedown, Master} -> + erlang:halt() + end, + ok. + thread_mseg_alloc_cache_clean(Config) when is_list(Config) -> case {erlang:system_info(threads), erlang:system_info({allocator,mseg_alloc}), diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src index bcabaa689d..77cbd34fb1 100644 --- a/erts/emulator/test/driver_SUITE_data/Makefile.src +++ b/erts/emulator/test/driver_SUITE_data/Makefile.src @@ -1,3 +1,7 @@ +CC = @CC@ +LD = @LD@ +CFLAGS = @CFLAGS@ @DEFS@ +CROSSLDFLAGS = @CROSSLDFLAGS@ MISC_DRVS = outputv_drv@dll@ \ timer_drv@dll@ \ @@ -30,7 +34,15 @@ VSN_MISMATCH_DRVS = zero_extended_marker_garb_drv@dll@ \ smaller_major_vsn_drv@dll@ \ smaller_minor_vsn_drv@dll@ -all: $(MISC_DRVS) $(SYS_INFO_DRVS) $(VSN_MISMATCH_DRVS) +PROGS = lots_of_fds_used_wrapper@exe@ + +all: $(MISC_DRVS) $(SYS_INFO_DRVS) $(VSN_MISMATCH_DRVS) $(PROGS) + +lots_of_fds_used_wrapper@exe@: lots_of_fds_used_wrapper@obj@ + $(LD) $(CROSSLDFLAGS) -o lots_of_fds_used_wrapper lots_of_fds_used_wrapper@obj@ @LIBS@ + +lots_of_fds_used_wrapper@obj@: lots_of_fds_used_wrapper.c + $(CC) -c -o lots_of_fds_used_wrapper@obj@ $(CFLAGS) lots_of_fds_used_wrapper.c @SHLIB_RULES@ diff --git a/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c b/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c new file mode 100644 index 0000000000..34d84827d5 --- /dev/null +++ b/erts/emulator/test/driver_SUITE_data/lots_of_fds_used_wrapper.c @@ -0,0 +1,61 @@ +#if !defined(__WIN32__) +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#endif + +int +main(int argc, char *argv[]) +{ +#if !defined(__WIN32__) + + char **exec_argv; + int fds[12000]; + int max = sizeof(fds)/sizeof(fds[0]); + int i; + + /* Open a bit more than 1024 file descriptors... */ + for (i = 0; i < max; i++) { + fds[i] = open("/dev/null", 0, O_WRONLY); + if (fds[i] < 0) { + if (i < 1200) + return 17; /* Not enough fds for the test... */ + max = i; + break; + } + } + + /* + * Close some of the latest fds to give room for + * the emulators usage... + */ + for (i = max-150; i < max; i++) + close(fds[i]); + + if (argc < 2) + return 1; + + /* + * Ensure NULL pointer after last argument... + */ + exec_argv = malloc(sizeof(char *)*argc); + if (!exec_argv) + return 2; + + for (i = 0; i < argc-1; i++) { + /* printf("arg=%d: %s\n", i, argv[i+1]); */ + exec_argv[i] = argv[i+1]; + } + exec_argv[i] = NULL; + + execvp(exec_argv[0], exec_argv); + + perror("Failed to exec"); + +#endif + + return 3; +} diff --git a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c index 685cda3e07..b69d75c31d 100644 --- a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c +++ b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c @@ -47,6 +47,10 @@ #include <windows.h> #endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + #include <errno.h> #include "erl_driver.h" diff --git a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c index 56183c9484..503d8b902c 100644 --- a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c +++ b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c @@ -18,6 +18,10 @@ * %CopyrightEnd% */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + #include "erl_driver.h" #define THR_MSG_BLAST_NO_PROCS 10 diff --git a/erts/emulator/test/esock_misc/esock_iow_client.erl b/erts/emulator/test/esock_misc/esock_iow_client.erl deleted file mode 100644 index 3e48a8f300..0000000000 --- a/erts/emulator/test/esock_misc/esock_iow_client.erl +++ /dev/null @@ -1,94 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2020-2020. All 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% -%% - -%% --------------------------------------------------------------------- -%% -%% Writes small messages to a socket, until counters wrap! -%% -%% --------------------------------------------------------------------- - --module(esock_iow_client). - --export([start/1]). - --define(LIB, esock_iow_lib). --define(LIMIT, 100000). - --define(MSG, <<"abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz" - "abcdefghijklmnopqrstuvxyz">>). - - -%% --------------------------------------------------------------------- - -start(ServerPort) -> - Domain = inet, - ?LIB:iprint("open"), - {ok, S} = socket:open(Domain, stream, tcp), - ?LIB:iprint("iow"), - ok = socket:setopt(S, otp, iow, true), - ?LIB:iprint("bind"), - LocalSA = #{family => Domain, - addr => {147,214,93,147}}, - {ok, _} = socket:bind(S, LocalSA), - ?LIB:iprint("connect (to ~w)", [ServerPort]), - ServerSA = LocalSA#{port => ServerPort}, - ok = socket:connect(S, ServerSA), - ?LIB:iprint("connected - now await begin"), - case socket:recv(S, 0, infinity) of - {ok, <<"begin">>} -> - ?LIB:iprint("begin"), - loop(S, 0); - {error, Reason} -> - ?LIB:eprint("failed receive begin: ~p", [Reason]) - end. - -loop(S, N) -> - ok = socket:send(S, ?MSG), - NextN = receive - {'$socket', S, counter_wrap, Cnt} -> - ?LIB:iprint("Counter ~w wrapped", [Cnt]), - N + 1; - Any -> - ?LIB:iprint("Received: ~n ~p~n", [Any]), - N + 1 - after 1 -> - if (N < ?LIMIT) -> - N+1; - true -> - ?LIB:iprint("Counters:" - "~s", [?LIB:format_counters(cnts(S))]), - 0 - end - end, - loop(S, NextN). - - -cnts(S) -> - #{counters := Cnts} = socket:info(S), - Cnts. - diff --git a/erts/emulator/test/esock_misc/esock_iow_lib.erl b/erts/emulator/test/esock_misc/esock_iow_lib.erl deleted file mode 100644 index 6fc1365dca..0000000000 --- a/erts/emulator/test/esock_misc/esock_iow_lib.erl +++ /dev/null @@ -1,123 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2020-2020. All 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(esock_iow_lib). - --export([ - format_counters/1, format_counters/2, format_counters/3, - iprint/1, iprint/2, - eprint/1, eprint/2, - f/2, - fts/0, fts/1 - ]). - - -%% --------------------------------------------------------------------- - -format_counters(Counters) -> - format_counters(traffic, Counters). - -format_counters(Type, Counters) when (Type =:= listen) orelse (Type =:= traffic) -> - format_counters(" ", Type, Counters). - -format_counters(Prefix, traffic, Counters) -> - ReadByte = proplists:get_value(read_byte, Counters, -1), - ReadFails = proplists:get_value(read_fails, Counters, -1), - ReadPkg = proplists:get_value(read_pkg, Counters, -1), - ReadPkgMax = proplists:get_value(read_pkg_max, Counters, -1), - ReadTries = proplists:get_value(read_tries, Counters, -1), - ReadWaits = proplists:get_value(read_waits, Counters, -1), - WriteByte = proplists:get_value(write_byte, Counters, -1), - WriteFails = proplists:get_value(write_fails, Counters, -1), - WritePkg = proplists:get_value(write_pkg, Counters, -1), - WritePkgMax = proplists:get_value(write_pkg_max, Counters, -1), - WriteTries = proplists:get_value(write_tries, Counters, -1), - WriteWaits = proplists:get_value(write_waits, Counters, -1), - f("~n~sNumber Of Read Bytes: ~p" - "~n~sNumber Of Read Fails: ~p" - "~n~sNumber Of Read Packages: ~p" - "~n~sNumber Of Read Tries: ~p" - "~n~sNumber Of Read Waits: ~p" - "~n~sMax Read Package Size: ~p" - "~n~sNumber Of Write Bytes: ~p" - "~n~sNumber Of Write Fails: ~p" - "~n~sNumber Of Write Packages: ~p" - "~n~sNumber Of Write Tries: ~p" - "~n~sNumber Of Write Waits: ~p" - "~n~sMax Write Package Size: ~p", - [Prefix, ReadByte, - Prefix, ReadFails, - Prefix, ReadPkg, - Prefix, ReadTries, - Prefix, ReadWaits, - Prefix, ReadPkgMax, - Prefix, WriteByte, - Prefix, WriteFails, - Prefix, WritePkg, - Prefix, WriteTries, - Prefix, WriteWaits, - Prefix, WritePkgMax]); - -format_counters(Prefix, listen, Counters) -> - AccSuccess = proplists:get_value(acc_success, Counters, -1), - AccFails = proplists:get_value(acc_fails, Counters, -1), - AccTries = proplists:get_value(acc_tries, Counters, -1), - AccWaits = proplists:get_value(acc_waits, Counters, -1), - f("~n~sNumber Of Successful Accepts: ~p" - "~n~sNumber Of Failed Accepts: ~p" - "~n~sNumber Of Accept Attempts: ~p" - "~n~sNumber Of Accept Waits: ~p", - [Prefix, AccSuccess, - Prefix, AccFails, - Prefix, AccTries, - Prefix, AccWaits]). - -%% --------------------------------------------------------------------- - -iprint(F) -> - iprint(F, []). - -iprint(F, A) -> - print("INFO", F, A). - -eprint(F) -> - iprint(F, []). - -eprint(F, A) -> - print("ERROR", F, A). - -print(Pre, F, A) -> - io:format("*** ~s *** ~s ~n" ++ F ++ "~n~n", [Pre, fts() | A]). - - -f(F, A) -> - lists:flatten(io_lib:format(F, A)). - - -ts() -> - os:timestamp(). - -fts() -> - fts(ts()). - -fts({_N1, _N2, N3} = TS) -> - {_Date, Time} = calendar:now_to_local_time(TS), - {Hour,Min,Sec} = Time, - f("~.2.0w:~.2.0w:~.2.0w.4~w", [Hour, Min, Sec, round(N3/1000)]). diff --git a/erts/emulator/test/esock_misc/esock_iow_server.erl b/erts/emulator/test/esock_misc/esock_iow_server.erl deleted file mode 100644 index 4b364a6ca6..0000000000 --- a/erts/emulator/test/esock_misc/esock_iow_server.erl +++ /dev/null @@ -1,83 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2020-2020. All 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% -%% - -%% --------------------------------------------------------------------- -%% -%% Reads small messages to a socket, until counters wrap! -%% -%% --------------------------------------------------------------------- - --module(esock_iow_server). - --export([start/0]). - --define(LIB, esock_iow_lib). --define(LIMIT, 100000). - - -%% --------------------------------------------------------------------- - -start() -> - Domain = inet, - ?LIB:iprint("open"), - {ok, LSock} = socket:open(Domain, stream, tcp), - ?LIB:iprint("iow"), - ok = socket:setopt(LSock, otp, iow, true), - ?LIB:iprint("bind"), - LocalSA = #{family => Domain, - addr => {147,214,93,147}}, - {ok, LPort} = socket:bind(LSock, LocalSA), - ?LIB:iprint("listen port: ~p", [LPort]), - ?LIB:iprint("make listen socket"), - ok = socket:listen(LSock), - ?LIB:iprint("accept"), - {ok, CSock} = socket:accept(LSock), - ok = socket:send(CSock, <<"begin">>), - loop(CSock, 0). - -loop(S, N) -> - case socket:recv(S) of - {ok, _} when (N < ?LIMIT) -> - flush(S), - loop(S, N+1); - {ok, _} -> - ?LIB:iprint("Counters:" - "~s", [?LIB:format_counters(cnts(S))]), - flush(S), - loop(S, 0); - {error, Reason} -> - ?LIB:eprint("failed receive: ~p", [Reason]) - end. - - -cnts(S) -> - #{counters := Cnts} = socket:info(S), - Cnts. - -flush(S) -> - receive - {'$socket', S, counter_wrap, Cnt} -> - ?LIB:iprint("Counter ~w wrapped", [Cnt]); - Any -> - ?LIB:iprint("Received: ~n ~p~n", [Any]) - after 0 -> - ok - end. - diff --git a/erts/emulator/test/esock_misc/socket_client.erl b/erts/emulator/test/esock_misc/socket_client.erl deleted file mode 100644 index 891f7e67ab..0000000000 --- a/erts/emulator/test/esock_misc/socket_client.erl +++ /dev/null @@ -1,538 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2020. All 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(socket_client). - --export([ - start/1, start/2, start/5, start/6, - start_tcp/1, start_tcp/2, start_tcp/3, - start_tcp4/1, start_tcp4/2, start_tcp6/1, start_tcp6/2, - start_udp/1, start_udp/2, start_udp/3, - start_udp4/1, start_udp4/2, start_udp6/1, start_udp6/2 - ]). - --define(LIB, socket_lib). - --record(client, {socket, verbose = true, msg = true, type, dest, msg_id = 1}). - -start(Port) -> - start(Port, 1). - -start(Port, Num) -> - start_tcp(Port, Num). - -start_tcp(Port) -> - start_tcp(Port, 1). - -start_tcp(Port, Num) -> - start_tcp4(Port, Num). - -start_tcp4(Port) -> - start_tcp4(Port, 1). - -start_tcp4(Port, Num) -> - start(inet, stream, tcp, Port, Num). - -start_tcp6(Port) -> - start_tcp6(Port, 1). - -start_tcp6(Port, Num) -> - start(inet6, stream, tcp, Port, Num). - -start_tcp(Addr, Port, Num) when (size(Addr) =:= 4) andalso - is_integer(Num) andalso - (Num > 0) -> - start(inet, stream, tcp, Addr, Port, Num); -start_tcp(Addr, Port, Num) when (size(Addr) =:= 8) andalso - is_integer(Num) andalso - (Num > 0) -> - start(inet6, stream, tcp, Addr, Port, Num). - - -start_udp(Port) -> - start_udp(Port, 1). - -start_udp(Port, Num) -> - start_udp4(Port, Num). - -start_udp4(Port) -> - start_udp4(Port, 1). - -start_udp4(Port, Num) -> - start(inet, dgram, udp, Port, Num). - -start_udp6(Port) -> - start_udp6(Port, 1). - -start_udp6(Port, Num) -> - start(inet6, dgram, udp, Port, Num). - -start_udp(Addr, Port, Num) when (size(Addr) =:= 4) -> - start(inet, dgram, udp, Addr, Port, Num); -start_udp(Addr, Port, Num) when (size(Addr) =:= 8) -> - start(inet6, dgram, udp, Addr, Port, Num). - - -start(Domain, Type, Proto, Port, Num) - when is_integer(Port) andalso is_integer(Num) -> - start(Domain, Type, Proto, which_addr(Domain), Port, Num); - -start(Domain, Type, Proto, Addr, Port) -> - start(Domain, Type, Proto, Addr, Port, 1). - -start(Domain, Type, Proto, Addr, Port, 1 = Num) -> - start(Domain, Type, Proto, Addr, Port, Num, true); -start(Domain, Type, Proto, Addr, Port, Num) - when is_integer(Num) andalso (Num > 1) -> - start(Domain, Type, Proto, Addr, Port, Num, false). - -start(Domain, Type, Proto, Addr, Port, Num, Verbose) -> - put(sname, "starter"), - Clients = start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose), - await_clients(Clients). - -start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose) -> - start_clients(Num, 1, Domain, Type, Proto, Addr, Port, Verbose, []). - -start_clients(Num, ID, Domain, Type, Proto, Addr, Port, Verbose, Acc) - when (Num > 0) -> - StartClient = fun() -> - start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) - end, - {Pid, _} = spawn_monitor(StartClient), - ?LIB:sleep(500), - i("start client ~w", [ID]), - start_clients(Num-1, ID+1, Domain, Type, Proto, Addr, Port, Verbose, [Pid|Acc]); -start_clients(_, _, _, _, _, _, _, _, Acc) -> - i("all client(s) started"), - lists:reverse(Acc). - -await_clients([]) -> - i("all clients done"); -await_clients(Clients) -> - receive - {'DOWN', _MRef, process, Pid, _Reason} -> - case lists:delete(Pid, Clients) of - Clients2 when (Clients2 =/= Clients) -> - i("client ~p done", [Pid]), - await_clients(Clients2); - _ -> - await_clients(Clients) - end - end. - - -start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) -> - put(sname, ?LIB:f("client[~w]", [ID])), - SA = #{family => Domain, - addr => Addr, - port => Port}, - %% The way we use tos only works because we - %% send so few messages (a new value for every - %% message). - tos_init(), - do_start(Domain, Type, Proto, SA, Verbose). - -do_start(Domain, stream = Type, Proto, SA, Verbose) -> - try do_init(Domain, Type, Proto) of - Sock -> - connect(Sock, SA), - maybe_print_start_info(Verbose, Sock, Type), - %% Give the server some time... - ?LIB:sleep(5000), - %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type, - verbose = Verbose}) - catch - throw:E -> - e("Failed initiate: " - "~n Error: ~p", [E]) - end; -do_start(Domain, dgram = Type, Proto, SA, Verbose) -> - try do_init(Domain, Type, Proto) of - Sock -> - maybe_print_start_info(Verbose, Sock, Type), - %% Give the server some time... - ?LIB:sleep(5000), - %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type, - dest = SA, - verbose = Verbose}) - catch - throw:E -> - e("Failed initiate: " - "~n Error: ~p", [E]) - end. - -maybe_print_start_info(true = _Verbose, Sock, stream = _Type) -> - {ok, Name} = socket:sockname(Sock), - {ok, Peer} = socket:peername(Sock), - {ok, Domain} = socket:getopt(Sock, socket, domain), - {ok, Type} = socket:getopt(Sock, socket, type), - {ok, Proto} = socket:getopt(Sock, socket, protocol), - {ok, OOBI} = socket:getopt(Sock, socket, oobinline), - {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf), - {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf), - {ok, Linger} = socket:getopt(Sock, socket, linger), - {ok, MTU} = socket:getopt(Sock, ip, mtu), - {ok, MTUDisc} = socket:getopt(Sock, ip, mtu_discover), - {ok, MALL} = socket:getopt(Sock, ip, multicast_all), - {ok, MIF} = socket:getopt(Sock, ip, multicast_if), - {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), - {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - i("connected: " - "~n From: ~p" - "~n To: ~p" - "~nwhen" - "~n (socket) Domain: ~p" - "~n (socket) Type: ~p" - "~n (socket) Protocol: ~p" - "~n (socket) OOBInline: ~p" - "~n (socket) SndBuf: ~p" - "~n (socket) RcvBuf: ~p" - "~n (socket) Linger: ~p" - "~n (ip) MTU: ~p" - "~n (ip) MTU Discovery: ~p" - "~n (ip) Multicast ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n => wait some", - [Name, Peer, - Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - RecvTOS]); -maybe_print_start_info(true = _Verbose, Sock, dgram = _Type) -> - {ok, Domain} = socket:getopt(Sock, socket, domain), - {ok, Type} = socket:getopt(Sock, socket, type), - {ok, Proto} = socket:getopt(Sock, socket, protocol), - {ok, OOBI} = socket:getopt(Sock, socket, oobinline), - {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf), - {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf), - {ok, Linger} = socket:getopt(Sock, socket, linger), - {ok, MALL} = socket:getopt(Sock, ip, multicast_all), - {ok, MIF} = socket:getopt(Sock, ip, multicast_if), - {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), - {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl), - i("initiated when: " - "~n (socket) Domain: ~p" - "~n (socket) Type: ~p" - "~n (socket) Protocol: ~p" - "~n (socket) OOBInline: ~p" - "~n (socket) SndBuf: ~p" - "~n (socket) RcvBuf: ~p" - "~n (socket) Linger: ~p" - "~n (ip) Multicast ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n (ip) RecvTTL: ~p" - "~n => wait some", - [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MALL, MIF, MLoop, MTTL, - RecvTOS, RecvTTL]); -maybe_print_start_info(_Verbose, _Sock, _Type) -> - ok. - - -do_init(Domain, stream = Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - i("try (socket) bind"), - case socket:bind(Sock, any) of - {ok, _P} -> - ok = socket:setopt(Sock, socket, timestamp, true), - ok = socket:setopt(Sock, ip, tos, mincost), - ok = socket:setopt(Sock, ip, recvtos, true), - Sock; - {error, BReason} -> - throw({bind, BReason}) - end; -do_init(Domain, dgram = Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - case socket:bind(Sock, any) of - {ok, _} -> - ok = socket:setopt(Sock, socket, timestamp, true), - ok = socket:setopt(Sock, ip, tos, mincost), - ok = socket:setopt(Sock, ip, recvtos, true), - ok = socket:setopt(Sock, ip, recvttl, true), - Sock; - {error, BReason} -> - throw({bind, BReason}) - end. - - -which_addr(Domain) -> - Iflist = case inet:getifaddrs() of - {ok, IFL} -> - IFL; - {error, Reason} -> - throw({inet,getifaddrs,Reason}) - end, - which_addr(Domain, Iflist). - - -connect(Sock, SA) -> - i("try (socket) connect to:" - "~n ~p", [SA]), - case socket:connect(Sock, SA) of - ok -> - ok; - {error, Reason} -> - e("connect failure: " - "~n ~p", [Reason]), - exit({connect, Reason}) - end. - - -send_loop(#client{msg_id = N} = C) when (N =< 10) -> - i("try send request ~w", [N]), - Req = ?LIB:enc_req_msg(N, "hejsan"), - case send(C, Req) of - ok -> - i("request ~w sent - now try read answer", [N]), - case recv(C) of - {ok, {Source, Msg}} -> - if - (C#client.verbose =:= true) -> - i("received ~w bytes of data~s", - [size(Msg), case Source of - undefined -> ""; - _ -> ?LIB:f(" from:~n ~p", [Source]) - end]); - true -> - i("received ~w bytes", [size(Msg)]) - end, - case ?LIB:dec_msg(Msg) of - {reply, N, Reply} -> - if - (C#client.verbose =:= true) -> - i("received reply ~w: ~p", [N, Reply]); - true -> - i("received reply ~w", [N]) - end, - ?LIB:sleep(500), % Just to spread it out a bit - send_loop(C#client{msg_id = N+1}) - end; - {error, RReason} -> - e("Failed recv response for request ~w: " - "~n ~p", [N, RReason]), - exit({failed_recv, RReason}) - end; - {error, SReason} -> - e("Failed send request ~w: " - "~n ~p", [N, SReason]), - exit({failed_send, SReason}) - end; -send_loop(Client) -> - sock_close(Client). - -sock_close(#client{socket = Sock, verbose = true}) -> - i("we are done - close the socket when: " - "~n ~p", [socket:info()]), - ok = socket:close(Sock), - i("we are done - socket closed when: " - "~n ~p", [socket:info()]); -sock_close(#client{socket = Sock}) -> - i("we are done"), - ok = socket:close(Sock). - - - -send(#client{socket = Sock, type = stream}, Msg) -> - socket:send(Sock, Msg); -send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> - %% i("try send to: " - %% "~n ~p", [Dest]), - %% ok = socket:setopt(Sock, otp, debug, true), - TOS = tos_next(), - ok = socket:setopt(Sock, ip, tos, TOS), - case socket:sendto(Sock, Msg, Dest) of - ok = OK -> - OK; - {error, _} = ERROR -> - ERROR - end. - -recv(#client{socket = Sock, type = stream, msg = false}) -> - case socket:recv(Sock) of - {ok, Msg} -> - {ok, {undefined, Msg}}; - {error, _} = ERROR -> - ERROR - end; -recv(#client{socket = Sock, verbose = Verbose, type = stream, msg = true}) -> - case socket:recvmsg(Sock) of - %% An iov of length 1 is an simplification... - {ok, #{addr := undefined = Source, - iov := [Msg], - ctrl := CMsgHdrs, - flags := Flags}} -> - if - (Verbose =:= true) -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]); - true -> - ok - end, - {ok, {Source, Msg}}; - {error, _} = ERROR -> - ERROR - end; -recv(#client{socket = Sock, type = dgram, msg = false}) -> - socket:recvfrom(Sock); -recv(#client{socket = Sock, verbose = Verbose, type = dgram, msg = true}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Msg], - ctrl := CMsgHdrs, - flags := Flags}} -> - if - (Verbose =:= true) -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]); - true -> - ok - end, - {ok, {Source, Msg}}; - {error, _} = ERROR -> - ERROR - end. - - - -which_addr(_Domain, []) -> - throw(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -which_addr(Domain, [_|IFL]) -> - which_addr(Domain, IFL). - -which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> - Addr; -which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - - -%% --- - -%% enc_req_msg(N, Data) -> -%% enc_msg(?REQ, N, Data). - -%% enc_rep_msg(N, Data) -> -%% enc_msg(?REP, N, Data). - -%% enc_msg(Type, N, Data) when is_list(Data) -> -%% enc_msg(Type, N, list_to_binary(Data)); -%% enc_msg(Type, N, Data) -%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> -%% <<Type:32/integer, N:32/integer, Data/binary>>. - -%% dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) -> -%% {request, N, Data}; -%% dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) -> -%% {reply, N, Data}. - - -%% --- - -%% sleep(T) -> -%% receive after T -> ok end. - - -%% --- - -%% formated_timestamp() -> -%% format_timestamp(os:timestamp()). - -%% format_timestamp(Now) -> -%% N2T = fun(N) -> calendar:now_to_local_time(N) end, -%% format_timestamp(Now, N2T, true). - -%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> -%% FormatExtra = ".~.2.0w", -%% ArgsExtra = [N3 div 10000], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); -%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> -%% FormatExtra = "", -%% ArgsExtra = [], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> -%% {Date, Time} = N2T(N), -%% {YYYY,MM,DD} = Date, -%% {Hour,Min,Sec} = Time, -%% FormatDate = -%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, -%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), -%% lists:flatten(FormatDate). - - -%% --- - -tos_init() -> - put(tos, 1). - -tos_next() -> - case get(tos) of - TOS when (TOS < 100) -> - put(tos, TOS + 1), - TOS; - _ -> - put(tos, 1), - 1 - end. - - -%% --- - -e(F, A) -> - ?LIB:e(F, A). - -i(F) -> - ?LIB:i(F). - -i(F, A) -> - ?LIB:i(F, A). - diff --git a/erts/emulator/test/esock_misc/socket_lib.erl b/erts/emulator/test/esock_misc/socket_lib.erl deleted file mode 100644 index e401a3195c..0000000000 --- a/erts/emulator/test/esock_misc/socket_lib.erl +++ /dev/null @@ -1,133 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2020. All 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(socket_lib). - --export([ - sleep/1, - req/0, rep/0, - enc_req_msg/2, enc_rep_msg/2, - enc_msg/3, dec_msg/1, - request/3, reply/4, - f/2, - i/1, i/2, - e/2 - ]). - - --define(REQ, 0). --define(REP, 1). - - -%% --- - -sleep(T) -> - receive after T -> ok end. - - -%% --- - -req() -> ?REQ. -rep() -> ?REP. - -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). - -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). - -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <<Type:32/integer, N:32/integer, Data/binary>>. - -dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) -> - {request, N, Data}; -dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) -> - {reply, N, Data}. - - -%% --- - -request(Tag, Pid, Request) -> - Ref = make_ref(), - Pid ! {Tag, self(), Ref, Request}, - receive - {Tag, Pid, Ref, Reply} -> - Reply - end. - -reply(Tag, Pid, Ref, Reply) -> - Pid ! {Tag, self(), Ref, Reply}. - - -%% --- - -f(F, A) -> - lists:flatten(io_lib:format(F, A)). - - -%% --- - -e(F, A) -> - p("<ERROR> " ++ F, A). - -i(F) -> - i(F, []). -i(F, A) -> - p("*** " ++ F, A). - -p(F, A) -> - p(get(sname), F, A). - -p(SName, F, A) -> - io:format("[~s,~p][~s] " ++ F ++ "~n", - [SName,self(),formated_timestamp()|A]). - - -%% --- - -formated_timestamp() -> - format_timestamp(os:timestamp()). - -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). - -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). - - diff --git a/erts/emulator/test/esock_misc/socket_server.erl b/erts/emulator/test/esock_misc/socket_server.erl deleted file mode 100644 index 161ea17027..0000000000 --- a/erts/emulator/test/esock_misc/socket_server.erl +++ /dev/null @@ -1,954 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2020. All 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(socket_server). - --export([ - start/0, start/5, - start_tcp/0, start_tcp/1, start_tcp/3, - start_tcp4/0, start_tcp4/1, start_tcp4/2, - start_tcp6/0, start_tcp6/1, start_tcp6/2, - start_udp/0, start_udp/1, start_udp/3, - start_udp4/0, start_udp4/1, start_udp4/2, - start_udp6/0, start_udp6/1, start_udp6/2, - start_sctp/0, start_sctp/1 - ]). - --define(LIB, socket_lib). - --record(manager, {socket, msg, peek, acceptors, handler_id, handlers}). --record(acceptor, {id, socket, manager, - atimeout = 5000}). --record(handler, {socket, peek, msg, type, manager, - stimeout = 5000, rtimeout = 5000}). - --define(NUM_ACCEPTORS, 5). - -start() -> - start_tcp(). - -start_tcp() -> - start_tcp4(). - -start_tcp(Peek) -> - start_tcp4(Peek). - -start_tcp4() -> - start_tcp4(false). - -start_tcp4(Peek) -> - start_tcp4(false, Peek). - -start_tcp4(UseMsg, Peek) -> - start_tcp(inet, UseMsg, Peek). - -start_tcp6() -> - start_tcp6(false). - -start_tcp6(Peek) -> - start_tcp6(false, Peek). - -start_tcp6(UseMsg, Peek) -> - start_tcp(inet6, UseMsg, Peek). - -start_tcp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> - start(Domain, stream, tcp, UseMsg, Peek). - -start_udp() -> - start_udp4(). - -start_udp(Peek) -> - start_udp4(Peek). - -start_udp4() -> - start_udp4(false). - -start_udp4(Peek) -> - start_udp4(false, Peek). - -start_udp4(UseMsg, Peek) -> - start_udp(inet, UseMsg, Peek). - -start_udp6() -> - start_udp6(false, false). - -start_udp6(Peek) -> - start_udp6(false, Peek). - -start_udp6(UseMsg, Peek) -> - start_udp(inet6, UseMsg, Peek). - -start_udp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> - start(Domain, dgram, udp, UseMsg, Peek). - - -start_sctp() -> - start_sctp(inet). - -start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) -> - start(Domain, seqpacket, sctp, true, false). - -start(Domain, Type, Proto, UseMsg, Peek) -> - put(sname, "starter"), - i("try start manager"), - {Pid, MRef} = manager_start(Domain, Type, Proto, UseMsg, Peek), - i("manager (~p) started", [Pid]), - loop(Pid, MRef). - -loop(Pid, MRef) -> - receive - {'DOWN', MRef, process, Pid, Reason} -> - i("manager process exited: " - "~n ~p", [Reason]), - ok - end. - - -%% ========================================================================= - -manager_start(Domain, Type, Proto, UseMsg, Peek) -> - spawn_monitor(fun() -> manager_init(Domain, Type, Proto, UseMsg, Peek) end). - -manager_start_handler(Pid, Sock) -> - manager_request(Pid, {start_handler, Sock}). - -manager_stop(Pid, Reason) -> - manager_request(Pid, {stop, Reason}). - -manager_request(Pid, Request) -> - ?LIB:request(manager, Pid, Request). - -manager_reply(Pid, Ref, Reply) -> - ?LIB:reply(manager, Pid, Ref, Reply). - - -manager_init(Domain, Type, Proto, UseMsg, Peek) -> - put(sname, "manager"), - do_manager_init(Domain, Type, Proto, UseMsg, Peek). - -do_manager_init(Domain, stream = Type, Proto, UseMsg, Peek) -> - i("try start acceptor(s)"), - {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto), - manager_loop(#manager{socket = Sock, - msg = UseMsg, - peek = Peek, - acceptors = Acceptors, - handler_id = 1, - handlers = []}); -do_manager_init(Domain, dgram = Type, Proto, UseMsg, Peek) -> - i("try open socket"), - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - F = fun(X) -> case socket:getopt(Sock, socket, X) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - i("socket opened (~s,~s,~s): " - "~n broadcast: ~s" - "~n dontroute: ~s" - "~n keepalive: ~s" - "~n reuseaddr: ~s" - "~n linger: ~s" - "~n debug: ~s" - "~n prio: ~s" - "~n rcvbuf: ~s" - "~n rcvtimeo: ~s" - "~n sndbuf: ~s" - "~n sndtimeo: ~s" - "~n => try find (local) address", - [F(domain), F(type), F(protocol), - F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger), - F(debug), F(priority), - F(rcvbuf), F(rcvtimeo), F(sndbuf), F(sndtimeo)]), - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => Addr}, - i("try bind to: " - "~n ~p", [Addr]), - case socket:bind(Sock, SA) of - {ok, _P} -> - ok; - {error, BReason} -> - throw({bind, BReason}) - end, - i("bound to: " - "~n ~s" - "~n => try start handler", - [case socket:sockname(Sock) of - {ok, Name} -> f("~p", [Name]); - {error, R} -> f("error: ~p", [R]) - end]), - case handler_start(1, Sock, UseMsg, Peek) of - {ok, {Pid, MRef}} -> - i("handler (~p) started", [Pid]), - handler_continue(Pid), - manager_loop(#manager{peek = Peek, - msg = UseMsg, - handler_id = 2, % Just in case - handlers = [{1, Pid, MRef}]}); - {error, SReason} -> - e("Failed starting handler: " - "~n ~p", [SReason]), - exit({failed_start_handler, SReason}) - end; - {error, OReason} -> - e("Failed open socket: " - "~n ~p", [OReason]), - exit({failed_open_socket, OReason}) - end; -do_manager_init(Domain, seqpacket = Type, sctp = Proto, _UseMsg, _Peek) -> - %% This is as far as I have got with SCTP at the moment... - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - i("(sctp) socket opened: " - "~n ~p", [Sock]), - EXP = fun(_Desc, Expect, Expect) -> - Expect; - (Desc, Expect, Actual) -> - e("Unexpected result ~w: " - "~n Expect: ~p" - "~n Actual: ~p", [Desc, Expect, Actual]), - exit({Desc, Expect, Actual}) - end, - GO = fun(O) -> case socket:getopt(Sock, sctp, O) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - %% ok = socket:setopt(Sock, otp, debug, true), - - i("Miscellaneous options: " - "~n associnfo: ~s" - "~n autoclose: ~s" - "~n disable-fragments: ~s" - "~n initmsg: ~s" - "~n maxseg: ~s" - "~n nodelay: ~s" - "~n rtoinfo: ~s", - [GO(associnfo), - GO(autoclose), - GO(disable_fragments), - GO(initmsg), - GO(maxseg), - GO(nodelay), - GO(rtoinfo)]), - - Events = #{data_in => true, - association => true, - address => true, - send_failure => true, - peer_error => true, - shutdown => true, - partial_delivery => true, - adaptation_layer => true, - authentication => true, - sender_dry => true}, - EXP(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)), - EXP(close_socket, ok, socket:close(Sock)); - {error, Reason} -> - exit({failed_open, Reason}) - end; -do_manager_init(Domain, raw = Type, Proto, UseMsg, Peek) when is_integer(Proto) -> - do_manager_init(Domain, Type, {raw, Proto}, UseMsg, Peek); -do_manager_init(Domain, raw = Type, Proto, _UseMsg, _Peek) -> - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - i("(sctp) socket opened: " - "~n ~p", [Sock]), - socket:close(Sock); - {error, Reason} -> - exit({failed_open, Reason}) - end. - - - -manager_stream_init(Domain, Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - F = fun(X) -> case socket:getopt(Sock, socket, X) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - i("(socket) open (~s,~s,~s): " - "~n debug: ~s" - "~n prio: ~s" - "~n => try find (local) address", - [F(domain), F(type), F(protocol), F(debug), F(priority)]), - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => Addr}, - i("found: " - "~n ~p" - "~n => try (socket) bind", [Addr]), - %% ok = socket:setopt(Sock, otp, debug, true), - %% ok = socket:setopt(Sock, socket, debug, 1), %% must have rights!! - Port = case socket:bind(Sock, SA) of - {ok, P} -> - %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!! - %% ok = socket:setopt(Sock, otp, debug, false), - P; - {error, BReason} -> - throw({bind, BReason}) - end, - i("bound to: " - "~n ~p" - "~n => try (socket) listen (acceptconn: ~s)", - [Port, F(acceptconn)]), - case socket:listen(Sock) of - ok -> - i("listening (acceptconn: ~s)", - [F(acceptconn)]), - manager_stream_init(Sock, 1, ?NUM_ACCEPTORS, []); - {error, LReason} -> - throw({listen, LReason}) - end. - -which_addr(Domain) -> - Iflist = case inet:getifaddrs() of - {ok, IFL} -> - IFL; - {error, Reason} -> - throw({inet,getifaddrs,Reason}) - end, - which_addr(Domain, Iflist). - -which_addr(_Domain, []) -> - throw(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -which_addr(Domain, [_|IFL]) -> - which_addr(Domain, IFL). - -which_addr2(_, []) -> - throw(no_address); -which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> - Addr; -which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - - -manager_stream_init(Sock, ID, NumAcceptors, Acc) - when (NumAcceptors > 0) -> - i("try start acceptor"), - case acceptor_start(Sock, ID) of - {ok, {Pid, MRef}} -> - i("acceptor ~w (~p) started", [ID, Pid]), - ?LIB:sleep(2000), - manager_stream_init(Sock, ID+1, NumAcceptors-1, - [{ID, Pid, MRef}|Acc]); - {error, Reason} -> - exit({failed_starting_acceptor, Reason}) - end; -manager_stream_init(Sock, _ID, 0, Acc) -> - %% Req = {kill_acceptor, length(Acc)}, % Last in the queue - %% Req = {kill_acceptor, 3}, % In the "middle" of the queue - %% Req = {kill_acceptor, 2}, % The first in the queue - %% Req = {kill_acceptor, 1}, % Current acceptor - %% Msg = {manager, self(), make_ref(), Req}, - %% erlang:send_after(timer:seconds(10), self(), Msg), - {Sock, lists:reverse(Acc)}. - - -manager_loop(M) -> - receive - {'DOWN', MRef, process, Pid, Reason} -> - M2 = manager_handle_down(M, MRef, Pid, Reason), - manager_loop(M2); - - {manager, Pid, Ref, Request} -> - M2 = manager_handle_request(M, Pid, Ref, Request), - manager_loop(M2) - end. - - -manager_handle_down(#manager{acceptors = Acceptors, - handlers = Handlers} = M, MRef, Pid, Reason) -> - case lists:keysearch(Pid, 2, Acceptors) of - {value, {ID, Pid, MRef}} when (Reason =:= normal) -> - i("acceptor ~w exited (normally)", [ID]), - case lists:keydelete(Pid, 2, Acceptors) of - [] -> - %% We are done - i("the last acceptor - we are done"), - exit(normal); - Acceptors2 -> - M#manager{acceptors = Acceptors2} - end; - {value, {ID, Pid, MRef}} -> - e("acceptor ~w crashed: " - "~n ~p", [ID, Reason]), - exit({acceptor_died, Reason}); - - false -> %% handler! - if - (Reason =/= normal) -> - e("handler ~p died: " - "~n ~p", [Pid, Reason]); - true -> - i("handler ~p terminated", [Pid]) - end, - Handlers2 = lists:keydelete(Pid, 2, Handlers), - M#manager{handlers = Handlers2} - end. - - -manager_handle_request(#manager{peek = Peek, - msg = UseMsg, - handler_id = HID, - handlers = Handlers} = M, Pid, Ref, - {start_handler, Sock}) -> - i("try start handler (~w)", [HID]), - case handler_start(HID, Sock, UseMsg, Peek) of - {ok, {HPid, HMRef}} -> - i("handler ~w started", [HID]), - manager_reply(Pid, Ref, {ok, HPid}), - M#manager{handler_id = HID+1, - handlers = [{HID, HPid, HMRef}|Handlers]}; - {error, Reason} = ERROR -> - e("Failed starting new handler: " - "~n Sock: ~p" - "~n Reason: ~p", [Sock, Reason]), - manager_reply(Pid, Ref, ERROR), - M - end; -manager_handle_request(#manager{socket = Sock, - acceptors = [{AID, APid, AMRef}]} = M, _Pid, _Ref, - {kill_acceptor, AID}) -> - i("try kill (only remeining) acceptor ~w", [AID]), - socket:setopt(Sock, otp, debug, true), - manager_stop_acceptor(APid, AMRef, AID, kill), - M#manager{acceptors = []}; -manager_handle_request(#manager{socket = Sock, - acceptors = Acceptors} = M, _Pid, _Ref, - {kill_acceptor, AID}) -> - i("try kill acceptor ~w", [AID]), - case lists:keysearch(AID, 1, Acceptors) of - {value, {AID, APid, AMRef}} -> - socket:setopt(Sock, otp, debug, true), - manager_stop_acceptor(APid, AMRef, AID, kill), - Acceptors2 = lists:keydelete(AID, 1, Acceptors), - M#manager{acceptors = Acceptors2}; - false -> - e("no such acceptor"), - M - end; -manager_handle_request(#manager{acceptors = Acceptors, - handlers = Handlers}, Pid, Ref, - {stop, Reason}) -> - i("stop"), - manager_reply(Pid, Ref, ok), - manager_stop_handlers(Handlers, Reason), - manager_stop_acceptors(Acceptors, Reason), - i("stopped", []), - exit(Reason). - -manager_stop_acceptors(Acceptors, Reason) -> - lists:foreach(fun({ID,P,M}) -> - manager_stop_acceptor(P, M, ID, Reason) - end, Acceptors). - -manager_stop_acceptor(Pid, MRef, ID, Reason) -> - i("try stop acceptor ~w (~p): ~p", [ID, Pid, Reason]), - erlang:demonitor(MRef, [flush]), - acceptor_stop(Pid, Reason), - ok. - -manager_stop_handlers(Handlers, Reason) -> - lists:foreach(fun({ID,P,M}) -> - manager_stop_handler(P, M, ID, Reason) - end, Handlers). - -manager_stop_handler(Pid, MRef, ID, Reason) -> - i("try stop handler ~w (~p): ~p", [ID, Pid, Reason]), - erlang:demonitor(MRef, [flush]), - handler_stop(Pid, Reason), - ok. - - - -%% ========================================================================= - -acceptor_start(Sock, ID) -> - Self = self(), - A = {Pid, _} = spawn_monitor(fun() -> - acceptor_init(Self, Sock, ID) - end), - receive - {acceptor, Pid, ok} -> - {ok, A}; - {acceptor, Pid, {error, _} = Error} -> - exit(Pid, kill), % Just in case - Error; - {'DOWN', _MRef, process, Pid, Reason} -> - {error, {crashed, Reason}} - end. - -acceptor_stop(Pid, _Reason) -> - %% acceptor_request(Pid, {stop, Reason}). - exit(Pid, kill). - -%% acceptor_request(Pid, Request) -> -%% request(acceptor, Pid, Request). - -%% acceptor_reply(Pid, Ref, Reply) -> -%% reply(acceptor, Pid, Ref, Reply). - - -acceptor_init(Manager, Sock, ID) -> - put(sname, f("acceptor[~w]", [ID])), - Manager ! {acceptor, self(), ok}, - %% ok = socket:setopt(Sock, otp, debug, true), - acceptor_loop(#acceptor{id = ID, - manager = Manager, - socket = Sock}). - -acceptor_loop(#acceptor{socket = LSock, atimeout = Timeout} = A) -> - i("try accept"), - case socket:accept(LSock, Timeout) of - {ok, Sock} -> - i("accepted: " - "~n ~p" - "~nwhen" - "~n ~p", [Sock, socket:info()]), - case acceptor_handle_accept_success(A, Sock) of - ok -> - acceptor_loop(A); - {error, Reason} -> - e("Failed starting handler: " - "~n ~p", [Reason]), - socket:close(Sock), - exit({failed_starting_handler, Reason}) - end; - {error, timeout} -> - i("timeout"), - acceptor_loop(A); - {error, Reason} -> - e("accept failure: " - "~n ~p", [Reason]), - exit({accept, Reason}) - end. - -acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> - i("try start handler for peer" - "~n ~p", [case socket:peername(Sock) of - {ok, Peer} -> Peer; - {error, _} = E -> E - end]), - case manager_start_handler(Manager, Sock) of - {ok, Pid} -> - i("handler (~p) started - now change 'ownership'", [Pid]), - case socket:setopt(Sock, otp, controlling_process, Pid) of - ok -> - %% Normally we should have a msgs collection here - %% (of messages we receive before the control was - %% handled over to Handler), but since we don't - %% have active implemented yet... - i("new handler (~p) now controlling process", [Pid]), - handler_continue(Pid), - ok; - {error, _} = ERROR -> - exit(Pid, kill), - ERROR - end; - {error, Reason2} -> - e("failed starting handler: " - "~n (new) Socket: ~p" - "~n Reason: ~p", [Sock, Reason2]), - exit({failed_starting_handler, Reason2}) - end. - - - -%% ========================================================================= - -handler_start(ID, Sock, UseMsg, Peek) -> - Self = self(), - H = {Pid, _} = spawn_monitor(fun() -> - handler_init(Self, ID, UseMsg, Peek, Sock) - end), - receive - {handler, Pid, ok} -> - {ok, H}; - {handler, Pid, {error, _} = ERROR} -> - exit(Pid, kill), % Just in case - ERROR - end. - -handler_stop(Pid, _Reason) -> - %% handler_request(Pid, {stop, Reason}). - exit(Pid, kill). - -handler_continue(Pid) -> - handler_request(Pid, continue). - -handler_request(Pid, Request) -> - ?LIB:request(handler, Pid, Request). - -handler_reply(Pid, Ref, Reply) -> - ?LIB:reply(handler, Pid, Ref, Reply). - - -handler_init(Manager, ID, Msg, Peek, Sock) -> - put(sname, f("handler:~w", [ID])), - i("starting"), - Manager ! {handler, self(), ok}, - receive - {handler, Pid, Ref, continue} -> - i("got continue"), - handler_reply(Pid, Ref, ok), - G = fun(L, O) -> case socket:getopt(Sock, L, O) of - {ok, Val} -> - f("~p", [Val]); - {error, R} when is_atom(R) -> - f("error: ~w", [R]); - {error, {T, R}} when is_atom(T) -> - f("error: ~w, ~p", [T, R]); - {error, R} -> - f("error: ~p", [R]) - end - end, - GSO = fun(O) -> G(socket, O) end, - GIP4 = fun(O) -> G(ip, O) end, - GIP6 = fun(O) -> G(ipv6, O) end, - {ok, Domain} = socket:getopt(Sock, socket, domain), - {ok, Type} = socket:getopt(Sock, socket, type), - {ok, Proto} = socket:getopt(Sock, socket, protocol), - B2D = GSO(bindtodevice), - RA = GSO(reuseaddr), - RP = GSO(reuseport), - OOBI = GSO(oobinline), - RcvBuf = GSO(rcvbuf), - RcvLW = GSO(rcvlowat), - RcvTO = GSO(rcvtimeo), - SndBuf = GSO(sndbuf), - SndLW = GSO(sndlowat), - SndTO = GSO(sndtimeo), - Linger = GSO(linger), - Timestamp = GSO(timestamp), - FreeBind = GIP4(freebind), - MTU = GIP4(mtu), - MTUDisc = GIP4(mtu_discover), - MALL = GIP4(multicast_all), - MIF4 = GIP4(multicast_if), - MLoop4 = GIP4(multicast_loop), - MTTL = GIP4(multicast_ttl), - NF = GIP4(nodefrag), % raw only - PktInfo = GIP4(pktinfo), % dgram only - RecvErr4 = GIP4(recverr), - RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) - RecvOPTS = GIP4(recvopts), % Not stream - RecvOrigDstAddr = GIP4(recvorigdstaddr), - RecvTOS = GIP4(recvtos), - RecvTTL = GIP4(recvttl), % not stream - RetOpts = GIP4(retopts), % not stream - SendSrcAddr = GIP4(sendsrcaddr), - TOS = GIP4(tos), - Transparent = GIP4(transparent), - TTL = GIP4(ttl), - MHops = GIP6(multicast_hops), - MIF6 = GIP6(multicast_if), % Only dgram and raw - MLoop6 = GIP6(multicast_loop), - RecvErr6 = GIP6(recverr), - RecvPktInfo = GIP6(recvpktinfo), - RtHdr = GIP6(rthdr), - AuthHdr = GIP6(authhdr), - HopLimit = GIP6(hoplimit), - HopOpts = GIP6(hopopts), - DstOpts = GIP6(dstopts), - FlowInfo = GIP6(flowinfo), - UHops = GIP6(unicast_hops), - i("got continue when: " - "~n (socket) Domain: ~p" - "~n (socket) Type: ~p" - "~n (socket) Protocol: ~p" - "~n (socket) Reuse Address: ~s" - "~n (socket) Reuse Port: ~s" - "~n (socket) Bind To Device: ~s" - "~n (socket) OOBInline: ~s" - "~n (socket) RcvBuf: ~s" - "~n (socket) RcvLW: ~s" - "~n (socket) RcvTO: ~s" - "~n (socket) SndBuf: ~s" - "~n (socket) SndLW: ~s" - "~n (socket) SndTO: ~s" - "~n (socket) Linger: ~s" - "~n (socket) Timestamp: ~s" - "~n (ip) FreeBind: ~s" - "~n (ip) MTU: ~s" - "~n (ip) MTU Discovery: ~s" - "~n (ip) Multicast ALL: ~s" - "~n (ip) Multicast IF: ~s" - "~n (ip) Multicast Loop: ~s" - "~n (ip) Multicast TTL: ~s" - "~n (ip) Node Frag: ~s" - "~n (ip) Pkt Info: ~s" - "~n (ip) Recv Err: ~s" - "~n (ip) Recv IF: ~s" - "~n (ip) Recv OPTS: ~s" - "~n (ip) Recv Orig Dst Addr: ~s" - "~n (ip) Recv TOS: ~s" - "~n (ip) Recv TTL: ~s" - "~n (ip) Ret Opts: ~s" - "~n (ip) Send Src Addr: ~s" - "~n (ip) TOS: ~s" - "~n (ip) Transparent: ~s" - "~n (ip) TTL: ~s" - "~n (ipv6) Multicast Hops: ~s" - "~n (ipv6) Multicast IF: ~s" - "~n (ipv6) Multicast Loop: ~s" - "~n (ipv6) Recv Err: ~s" - "~n (ipv6) Recv Pkt Info: ~s" - "~n (ipv6) RT Hdr: ~s" - "~n (ipv6) Auth Hdr: ~s" - "~n (ipv6) Hop Limit: ~s" - "~n (ipv6) Hop Opts: ~s" - "~n (ipv6) Dst Opts: ~s" - "~n (ipv6) Flow Info: ~s" - "~n (ipv6) Unicast Hops: ~s", - [Domain, Type, Proto, - RA, RP, B2D, OOBI, - RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, - Linger, Timestamp, - FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, PktInfo,RecvErr4, - RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts, - SendSrcAddr, TOS, Transparent, TTL, - MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, - RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, - UHops]), - - %% ok = socket:setopt(Sock, otp, debug, true), - %% case socket:getopt(Sock, 0, {13, int}) of - %% {ok, Val} -> - %% i("PktOpts ok: ~p", [Val]); - %% {error, Reason} -> - %% e("PktOpts err: ~p", [Reason]) - %% end, - %% ok = socket:setopt(Sock, otp, debug, false), - SSO = fun(O, V) -> soso(Sock, O, V) end, - SIP4 = - fun(O, V) -> - if - (Type =:= dgram) -> - ok = soip(Sock, O, V); - true -> - ok - end - end, - SSO(timestamp, true), - SIP4(pktinfo, true), - ok = soip(Sock, recvtos, true), - SIP4(recvttl, true), - ok = soip(Sock, recvorigdstaddr, true), - - handler_loop(#handler{msg = Msg, - peek = Peek, - manager = Manager, - type = Type, - socket = Sock}) - end. - -so(Sock, Lvl, Opt, Val) -> - ok = socket:setopt(Sock, Lvl, Opt, Val). - -soso(Sock, Opt, Val) -> - so(Sock, socket, Opt, Val). - -soip(Sock, Opt, Val) -> - so(Sock, ip, Opt, Val). - -%% soipv6(Sock, Opt, Val) -> -%% so(Sock, ipv6, Opt, Val). - -handler_loop(H) -> - i("try read message"), - case recv(H) of - {ok, {Source, Msg}} -> - i("received ~w bytes of data~s", - [size(Msg), case Source of - undefined -> ""; - _ -> f(" from:~n ~p", [Source]) - end]), - case ?LIB:dec_msg(Msg) of - {request, N, Req} -> - i("received request ~w: " - "~n ~p", [N, Req]), - Reply = ?LIB:enc_rep_msg(N, "hoppsan"), - case send(H, Reply, Source) of - ok -> - i("successfully sent reply ~w", [N]), - handler_loop(H); - {error, SReason} -> - e("failed sending reply ~w:" - "~n ~p", [N, SReason]), - exit({failed_sending_reply, SReason}) - end - end; - - {error, closed} -> - i("closed when" - "~n ~p", [socket:info()]), - exit(normal); - - {error, RReason} -> - e("failed reading request: " - "~n ~p", [RReason]), - exit({failed_reading_request, RReason}) - end. - - -recv(#handler{peek = true, socket = Sock, type = stream}) -> - peek_recv(Sock); -recv(#handler{socket = Sock, msg = true, type = stream}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := undefined = Source, - iov := [Data], - ctrl := CMsgHdrs, - flags := Flags}} -> - i("received message: " - "~n CMsgHdrs: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), - {ok, {Source, Data}}; - {ok, X} -> - e("received *unexpected* message: " - "~n ~p", [X]), - {error, {unexpected, X}}; - {error, _} = ERROR -> - ERROR - end; -recv(#handler{socket = Sock, msg = true, type = dgram}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Data], - ctrl := CMsgHdrs, - flags := Flags}} -> - i("received message: " - "~n CMsgHdrs: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), - {ok, {Source, Data}}; - {ok, X} -> - {error, {unexpected, X}}; - {error, _} = ERROR -> - ERROR - end; -recv(#handler{peek = false, socket = Sock, type = stream}) -> - do_recv(Sock); -recv(#handler{peek = Peek, socket = Sock, type = dgram}) - when (Peek =:= true) -> - %% ok = socket:setopt(Sock, otp, debug, true), - RES = peek_recvfrom(Sock, 5), - %% ok = socket:setopt(Sock, otp, debug, false), - RES; -recv(#handler{peek = Peek, socket = Sock, type = dgram}) - when (Peek =:= false) -> - %% ok = socket:setopt(Sock, otp, debug, true), - socket:recvfrom(Sock). - -do_recv(Sock) -> - case socket:recv(Sock) of - {ok, Msg} -> - {ok, {undefined, Msg}}; - {error, _} = ERROR -> - ERROR - end. - -peek_recv(Sock) -> - i("try peek on the message type (expect request)"), - Type = ?LIB:req(), - case socket:recv(Sock, 4, [peek]) of - {ok, <<Type:32>>} -> - i("was request - do proper recv"), - do_recv(Sock); - {error, _} = ERROR -> - ERROR - end. - -peek_recvfrom(Sock, BufSz) -> - i("try peek recvfrom with buffer size ~w", [BufSz]), - case socket:recvfrom(Sock, BufSz, [peek]) of - {ok, {_Source, Msg}} when (BufSz =:= size(Msg)) -> - %% i("we filled the buffer: " - %% "~n ~p", [Msg]), - %% It *may not* fit => try again with double size - peek_recvfrom(Sock, BufSz*2); - {ok, _} -> - %% It fits => read for real - i("we did *not* fill the buffer - do the 'real' read"), - socket:recvfrom(Sock); - {error, _} = ERROR -> - ERROR - end. - - -send(#handler{socket = Sock, msg = true, type = stream, stimeout = Timeout}, - Msg, _) -> - CMsgHdr = #{level => ip, type => tos, data => reliability}, - CMsgHdrs = [CMsgHdr], - MsgHdr = #{iov => [Msg], ctrl => CMsgHdrs}, - %% socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr, Timeout), - %% socket:setopt(Sock, otp, debug, false), - Res; -send(#handler{socket = Sock, type = stream, stimeout = Timeout}, Msg, _) -> - socket:send(Sock, Msg, Timeout); -send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout}, - Msg, Dest) -> - CMsgHdr = #{level => ip, type => tos, data => reliability}, - CMsgHdrs = [CMsgHdr], - MsgHdr = #{addr => Dest, - ctrl => CMsgHdrs, - iov => [Msg]}, - %% ok = socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr, Timeout), - %% ok = socket:setopt(Sock, otp, debug, false), - Res; -send(#handler{socket = Sock, type = dgram, stimeout = Timeout}, Msg, Dest) -> - socket:sendto(Sock, Msg, Dest, Timeout). - -%% filler() -> -%% list_to_binary(lists:duplicate(2048, " FILLER ")). - - - -%% ========================================================================= - -f(F, A) -> - ?LIB:f(F, A). - -e(F) -> - e(F, []). -e(F, A) -> - ?LIB:e(F, A). - -i(F) -> - ?LIB:i(F). - -i(F, A) -> - ?LIB:i(F, A). - diff --git a/erts/emulator/test/esock_ttest/.gitignore b/erts/emulator/test/esock_ttest/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/erts/emulator/test/esock_ttest/.gitignore +++ /dev/null diff --git a/erts/emulator/test/esock_ttest/esock-ttest b/erts/emulator/test/esock_ttest/esock-ttest deleted file mode 100755 index 2ded557484..0000000000 --- a/erts/emulator/test/esock_ttest/esock-ttest +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env escript - -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2019. All 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% -%% - -%% ========================================================================== -%% -%% This is a simple wrapper escript on top of the socket ttest program(s). -%% The idea is to make it simple to run in a normal shell (bash). -%% -%% ========================================================================== - --define(SECS(I), timer:seconds(I)). - --define(CLIENT_MSG_1_MAX_OUTSTANDING, 100). --define(CLIENT_MSG_2_MAX_OUTSTANDING, 10). --define(CLIENT_MSG_3_MAX_OUTSTANDING, 1). - -main(Args) -> - State = process_args(Args), - exec(State), - ok. - -usage(ErrorString) when is_list(ErrorString) -> - eprint(ErrorString), - usage(), - erlang:halt(0). - -usage() -> - io:format("usage: ~s [options]" - "~n" - "~n This erlang script is used to start the (e)socket ttest " - "~n units (server or client)." - "~n" - "~n options: " - "~n --help Display this info and exit. " - "~n --server [server-options] Start a server. " - "~n There are no mandatory server options." - "~n --client client-options Start a client" - "~n Some client options are mandatory and" - "~n others optional." - "~n --domain <domain> local | inet | inet6" - "~n Which domain to use." - "~n Only valid for server." - "~n Defaults to: inet" - "~n --async Asynchronous mode (Timeout = nowait)" - "~n This option is only valid for transport = sock." - "~n Also, its only used when active =/= false." - "~n --active <active> boolean() | once." - "~n Valid for both client and server." - "~n Defaults to: false" - "~n --transport <transport> Which transport to use: gen|sock[:plain|msg]" - "~n gen: gen_tcp" - "~n sock: socket" - "~n plain: recv/send (default)" - "~n msg: recvmsg/sendmsg" - "~n Defaults to: sock:plain" - "~n --scon <addr>:<port>|<path> Server info." - "~n The address part is in the standard form:" - "~n \"a.b.c.d\"." - "~n <path> is used for Unix Domain sockets (local)." - "~n Only valid, and mandatory, for client." - "~n --msg-id <1|2|3> Choose which message to use during the test." - "~n Basically: " - "~n 1: small" - "~n 2: medium" - "~n 3: large" - "~n Defaults to: 1" - "~n --max-outstanding <Num> How many messages to send before waiting for" - "~n a reply." - "~n Valid only for client." - "~n Defaults to: " - "~n MsgID 1: 100" - "~n MsgID 2: 10" - "~n MsgID 3: 1" - "~n --runtime <Time> Time of the test in seconds." - "~n Only valid for client." - "~n Mandatory." - "~n Defaults to: 60 (seconds)" - "~n" - "~n" - "~n", - [scriptname()]), - ok. - -process_args(["--help"|_]) -> - usage(); -process_args(["--server"|ServerArgs]) -> - process_server_args(ServerArgs); -process_args(["--client"|ClientArgs]) -> - process_client_args(ClientArgs); -process_args(Args) -> - usage(f("Invalid Args: " - "~n ~p", [Args])). - - -process_server_args(Args) -> - Defaults = #{role => server, - domain => inet, - async => false, - active => false, - transport => {sock, plain}}, - process_server_args(Args, Defaults). - -process_server_args([], State) -> - State; - -process_server_args(["--domain", Domain|Args], State) - when ((Domain =:= "local") orelse - (Domain =:= "inet") orelse - (Domain =:= "inet6")) -> - process_server_args(Args, State#{domain => list_to_atom(Domain)}); - -process_server_args(["--async"|Args], State) -> - process_server_args(Args, State#{async => true}); - -process_server_args(["--active", Active|Args], State) - when ((Active =:= "false") orelse - (Active =:= "once") orelse - (Active =:= "true")) -> - process_server_args(Args, State#{active => list_to_atom(Active)}); - -process_server_args(["--transport", "gen" | Args], State) -> - process_server_args(Args, State#{transport => gen}); -process_server_args(["--transport", "sock" | Args], State) -> - process_server_args(Args, State#{transport => {sock, plain}}); -process_server_args(["--transport", "sock:plain" | Args], State) -> - process_server_args(Args, State#{transport => {sock, plain}}); -process_server_args(["--transport", "sock:msg" | Args], State) -> - process_server_args(Args, State#{transport => {sock, msg}}); - -process_server_args([Arg|_], _State) -> - usage(f("Invalid Server arg: ~s", [Arg])). - - -process_client_args(Args) -> - Defaults = #{role => client, - async => false, - active => false, - transport => {sock, plain}, - %% Will cause error if not provided - %% Should be "addr:port or string() - server => undefined, - msg_id => 1, - %% Will be filled in based on msg_id if not provided - max_outstanding => undefined, - runtime => ?SECS(60)}, - process_client_args(Args, Defaults). - -process_client_args([], State) -> - process_client_args_ensure_max_outstanding(State); - -process_client_args(["--async"|Args], State) -> - process_client_args(Args, State#{async => true}); - -process_client_args(["--active", Active|Args], State) - when (Active =:= "false") orelse - (Active =:= "once") orelse - (Active =:= "true") -> - process_client_args(Args, State#{active => list_to_atom(Active)}); - -process_client_args(["--transport", "gen" | Args], State) -> - process_client_args(Args, State#{transport => gen}); -process_client_args(["--transport", "sock" | Args], State) -> - process_client_args(Args, State#{transport => {sock, plain}}); -process_client_args(["--transport", "sock:plain" | Args], State) -> - process_client_args(Args, State#{transport => {sock, plain}}); -process_client_args(["--transport", "sock:msg" | Args], State) -> - process_client_args(Args, State#{transport => {sock, msg}}); - -process_client_args(["--msg-id", MsgID|Args], State) - when ((MsgID =:= "1") orelse - (MsgID =:= "2") orelse - (MsgID =:= "3")) -> - process_client_args(Args, State#{msg_id => list_to_integer(MsgID)}); - -process_client_args(["--max-outstanding", Max|Args], State) -> - try list_to_integer(Max) of - I when (I > 0) -> - process_client_args(Args, State#{max_outstanding => I}); - _ -> - usage(f("Invalid Max Outstanding: ~s", [Max])) - catch - _:_:_ -> - usage(f("Invalid Max Outstanding: ~s", [Max])) - end; - -process_client_args(["--scon", Server|Args], State) -> - case string:split(Server, ":", trailing) of - [AddrStr,PortStr] -> - Addr = case inet:parse_address(AddrStr) of - {ok, A} -> - A; - {error, _} -> - usage(f("Invalid Server Address: ~s", [AddrStr])) - end, - Port = try list_to_integer(PortStr) of - I when (I > 0) -> - I; - _ -> - usage(f("Invalid Server Port: ~s", [PortStr])) - catch - _:_:_ -> - usage(f("Invalid Server Port: ~s", [PortStr])) - end, - process_client_args(Args, State#{server => {Addr, Port}}); - [Path] -> - process_client_args(Args, State#{server => Path}); - _ -> - usage(f("Invalid Server: ~s", [Server])) - end; - -process_client_args(["--runtime", T|Args], State) -> - try list_to_integer(T) of - I when (I > 0) -> - process_client_args(Args, State#{runtime => ?SECS(I)}); - _ -> - usage(f("Invalid Run Time: ~s", [T])) - catch - _:_:_ -> - usage(f("Invalid Run Time: ~s", [T])) - end; - -process_client_args([Arg|_], _State) -> - usage(f("Invalid Client arg: ~s", [Arg])). - - -process_client_args_ensure_max_outstanding( - #{msg_id := 1, - max_outstanding := undefined} = State) -> - State#{max_outstanding => ?CLIENT_MSG_1_MAX_OUTSTANDING}; -process_client_args_ensure_max_outstanding( - #{msg_id := 2, - max_outstanding := undefined} = State) -> - State#{max_outstanding => ?CLIENT_MSG_2_MAX_OUTSTANDING}; -process_client_args_ensure_max_outstanding( - #{msg_id := 3, - max_outstanding := undefined} = State) -> - State#{max_outstanding => ?CLIENT_MSG_3_MAX_OUTSTANDING}; -process_client_args_ensure_max_outstanding( - #{msg_id := MsgID, - max_outstanding := MaxOutstanding} = State) - when ((MsgID =:= 1) orelse - (MsgID =:= 2) orelse - (MsgID =:= 3)) andalso - (is_integer(MaxOutstanding) andalso (MaxOutstanding > 0)) -> - State; -process_client_args_ensure_max_outstanding( - #{msg_id := MsgID, - max_outstanding := MaxOutstanding}) -> - usage(f("Invalid Msg ID (~w) and Max Outstanding (~w)", - [MsgID, MaxOutstanding])). - - - -%% ========================================================================== - -exec(#{role := server, - domain := Domain, - active := Active, - transport := gen}) - when (Domain =:= inet) orelse (Domain =:= inet6) -> - case socket_test_ttest_tcp_server_gen:start(Domain, Active) of - {ok, {Pid, _}} -> - MRef = erlang:monitor(process, Pid), - receive - {'DOWN', MRef, process, Pid, Info} -> - Info - end; - {error, Reason} -> - eprint(f("Failed starting server: " - "~n ~p", [Reason])), - error - end; -exec(#{role := server, - domain := Domain, - async := Async, - active := Active, - transport := {sock, Method}}) -> - case socket_test_ttest_tcp_server_socket:start(Method, Domain, Async, Active) of - {ok, {Pid, _}} -> - MRef = erlang:monitor(process, Pid), - receive - {'DOWN', MRef, process, Pid, Info} -> - Info - end; - {error, Reason} -> - eprint(f("Failed starting server: " - "~n ~p", [Reason])), - error - end; - -exec(#{role := client, - server := undefined}) -> - usage("Mandatory option 'server' not provided"); -exec(#{role := client, - server := {_Addr, _Port} = ServerInfo, - active := Active, - transport := gen, - msg_id := MsgID, - max_outstanding := MaxOutstanding, - runtime := RunTime}) -> - case socket_test_ttest_tcp_client_gen:start(true, - ServerInfo, - Active, - MsgID, MaxOutstanding, - RunTime) of - {ok, Pid} -> - MRef = erlang:monitor(process, Pid), - receive - {'DOWN', MRef, process, Pid, Info} -> - Info - end; - {error, Reason} -> - eprint(f("Failed starting server: " - "~n ~p", [Reason])), - error - end; -exec(#{role := client, - server := ServerInfo, - async := Async, - active := Active, - transport := {sock, Method}, - msg_id := MsgID, - max_outstanding := MaxOutstanding, - runtime := RunTime}) -> - case socket_test_ttest_tcp_client_socket:start(true, - Async, - Active, - Method, - ServerInfo, - MsgID, MaxOutstanding, - RunTime) of - {ok, Pid} -> - MRef = erlang:monitor(process, Pid), - receive - {'DOWN', MRef, process, Pid, Info} -> - Info - end; - {error, Reason} -> - eprint(f("Failed starting server: " - "~n ~p", [Reason])), - error - end; -exec(_) -> - usage("Unexpected option combo"), - ok. - - - -%% ========================================================================== - -f(F, A) -> - socket_test_ttest_lib:format(F, A). - -eprint(ErrorString) when is_list(ErrorString) -> - print("<ERROR> " ++ ErrorString ++ "~n", []). - -print(F, A) -> - io:format(F ++ "~n", A). - -scriptname() -> - FullName = escript:script_name(), - filename:basename(FullName). - diff --git a/erts/emulator/test/esock_ttest/esock-ttest-client b/erts/emulator/test/esock_ttest/esock-ttest-client deleted file mode 100755 index 5ae05d03b8..0000000000 --- a/erts/emulator/test/esock_ttest/esock-ttest-client +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh - -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2019-2019. All 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% -# - -# -# This is just a simple convenience wrapper to the esock-ttest. -# That means that there are some options not available here. -# - -EMU=$ERL_TOP/erts/emulator -EMU_TEST=$EMU/test -ESOCK_TTEST=$EMU_TEST/esock_ttest - -RUNTIME=30 -# RUNTIME=60 -# RUNTIME=600 - -if [ $# = 3 ]; then - MSGID=$1 - SERVER_INFO=$2:$3 - - ITERATIONS="\ - gen false $MSGID - gen true $MSGID - gen once $MSGID - sock false $MSGID --async - sock true $MSGID --async - sock once $MSGID --async" - -else - if [ $# = 2 ]; then - MSGID=$1 - SERVER_INFO=$2 - - ITERATIONS="\ - sock false $MSGID --async - sock true $MSGID --async - sock once $MSGID --async" - - else - echo "Invalid number of args" - exit 1; - fi -fi - - -# --------------------------------------------------------------------------- - -# For when we have figured out how to configure local for gen_tcp... - -#ITERATIONS="\ -# gen false $MSGID -# gen true $MSGID -# gen once $MSGID -# sock false $MSGID -# sock true $MSGID -# sock once $MSGID" - -# --------------------------------------------------------------------------- - -echo "$ITERATIONS" | - while read TRANSPORT ACTIVE MSG_ID ASYNC; do - - echo "" - echo "=========== transport = $TRANSPORT, active = $ACTIVE, msg-id = $MSG_ID ===========" - # The /dev/null at the end is necessary because erlang "does things" with stdin - # and this case would cause the 'while read' to "fail" so that we only would - # loop one time - $ESOCK_TTEST/esock-ttest --client --transport $TRANSPORT $ASYNC --active $ACTIVE --msg-id $MSG_ID --scon $SERVER_INFO --runtime $RUNTIME </dev/null - echo "" - - done - - diff --git a/erts/emulator/test/esock_ttest/esock-ttest-server-gen b/erts/emulator/test/esock_ttest/esock-ttest-server-gen deleted file mode 100755 index c29184772e..0000000000 --- a/erts/emulator/test/esock_ttest/esock-ttest-server-gen +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2019-2019. All 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% -# - -EMU=$ERL_TOP/erts/emulator -EMU_TEST=$EMU/test -ESOCK_TTEST=$EMU_TEST/esock_ttest - -if [ $# = 1 ]; then - ACTIVE="--active $1" -fi - -$ESOCK_TTEST/esock-ttest --server --transport gen $ACTIVE - diff --git a/erts/emulator/test/esock_ttest/esock-ttest-server-sock b/erts/emulator/test/esock_ttest/esock-ttest-server-sock deleted file mode 100755 index c443d42e64..0000000000 --- a/erts/emulator/test/esock_ttest/esock-ttest-server-sock +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2019-2019. All 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% -# - -EMU=$ERL_TOP/erts/emulator -EMU_TEST=$EMU/test -ESOCK_TTEST=$EMU_TEST/esock_ttest - -# $1 - async - boolean() -# $2 - active - once | boolean() -# [$3 - domain - inet (default) | inet6 | local] -if [ $# -ge 2 ]; then - - async=$1 - active=$2 - - if [ $async = true ]; then - ASYNC="--async" - else - ASYNC= - fi - - ACTIVE="--active $active" - - if [ $# = 3 ]; then - DOMAIN="--domain $3" - fi - - -else - echo "<ERROR> Missing args: async and active" - echo "" - exit 1 -fi - - -$ESOCK_TTEST/esock-ttest --server $DOMAIN $ASYNC --transport sock $ACTIVE - diff --git a/erts/emulator/test/estone_SUITE_data/estone_cat.c b/erts/emulator/test/estone_SUITE_data/estone_cat.c index a34bda4384..cbdf3db6c9 100644 --- a/erts/emulator/test/estone_SUITE_data/estone_cat.c +++ b/erts/emulator/test/estone_SUITE_data/estone_cat.c @@ -12,9 +12,11 @@ #include <fcntl.h> #include <errno.h> -main(argc, argv) -int argc; -char *argv[]; +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +int main(int argc, char* argv[]) { char buf[16384]; int n; diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c index 46ee8b5540..6f662ae514 100644 --- a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c +++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c @@ -39,6 +39,7 @@ #include <errno.h> #include <stdio.h> +#include <string.h> static int fail(const char *file, int line, const char *function, const char *assertion); diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 273d9b1543..2cc3b8db32 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1434,6 +1434,21 @@ maps(Config) when is_list(Config) -> end, {1,#{}}), + M5 = lists:foldl(fun(N, MapIn) -> + {1, #{N := value}=MapOut} = make_map_put_nif(MapIn, N, value), + MapOut + end, + #{}, + lists:seq(1,40)), + M6 = lists:foldl(fun(N, MapIn) -> + {1, MapOut} = make_map_remove_nif(MapIn, N), + ok = maps:get(N, MapOut, ok), + MapOut + end, + M5, + lists:seq(1,40)), + true = (M6 =:= #{}), + has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]), verify_tmpmem(TmpMem), diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index a6ed6ae15f..93708fa99c 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2123,6 +2123,19 @@ static ERL_NIF_TERM make_map_put_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER { ERL_NIF_TERM map_out = enif_make_atom(env, "undefined"); int ret = enif_make_map_put(env, argv[0], argv[1], argv[2], &map_out); + + /* build same map in dynamic env */ + ErlNifEnv* dynenv = enif_alloc_env(); + ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined"); + int ret2 = enif_make_map_put(dynenv, + enif_make_copy(dynenv, argv[0]), + enif_make_copy(dynenv, argv[1]), + enif_make_copy(dynenv, argv[2]), + &map_out2); + if (ret != ret2 || !enif_is_identical(map_out, map_out2)) + map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1); + enif_free_env(dynenv); + return enif_make_tuple2(env, enif_make_int(env,ret), map_out); } static ERL_NIF_TERM get_map_value_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -2136,12 +2149,37 @@ static ERL_NIF_TERM make_map_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_ { ERL_NIF_TERM map_out = enif_make_atom(env, "undefined"); int ret = enif_make_map_update(env, argv[0], argv[1], argv[2], &map_out); + + /* build same map in dynamic env */ + ErlNifEnv* dynenv = enif_alloc_env(); + ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined"); + int ret2 = enif_make_map_update(dynenv, + enif_make_copy(dynenv, argv[0]), + enif_make_copy(dynenv, argv[1]), + enif_make_copy(dynenv, argv[2]), + &map_out2); + if (ret != ret2 || !enif_is_identical(map_out, map_out2)) + map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1); + enif_free_env(dynenv); + return enif_make_tuple2(env, enif_make_int(env,ret), map_out); } static ERL_NIF_TERM make_map_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM map_out = enif_make_atom(env, "undefined"); int ret = enif_make_map_remove(env, argv[0], argv[1], &map_out); + + /* build same map in dynamic env */ + ErlNifEnv* dynenv = enif_alloc_env(); + ERL_NIF_TERM map_out2 = enif_make_atom(env, "undefined"); + int ret2 = enif_make_map_remove(dynenv, + enif_make_copy(dynenv, argv[0]), + enif_make_copy(dynenv, argv[1]), + &map_out2); + if (ret != ret2 || !enif_is_identical(map_out, map_out2)) + map_out = enif_make_string(env, "dynenv failure", ERL_NIF_LATIN1); + enif_free_env(dynenv); + return enif_make_tuple2(env, enif_make_int(env,ret), map_out); } @@ -3345,15 +3383,15 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ret = enif_make_resource(env, ioq); enif_release_resource(ioq); return ret; - } else if (enif_is_identical(argv[0], enif_make_atom(env, "inspect"))) { + } else if (argc >= 2 && enif_is_identical(argv[0], enif_make_atom(env, "inspect"))) { ErlNifIOVec vec, *iovec = NULL; int i, iovcnt; ERL_NIF_TERM *elems, tail, list; ErlNifEnv *myenv = NULL; - if (enif_is_identical(argv[2], enif_make_atom(env, "use_stack"))) + if (argv >= 3 && enif_is_identical(argv[2], enif_make_atom(env, "use_stack"))) iovec = &vec; - if (enif_is_identical(argv[3], enif_make_atom(env, "use_env"))) + if (argc >= 4 && enif_is_identical(argv[3], enif_make_atom(env, "use_env"))) myenv = env; if (!enif_inspect_iovec(myenv, ~(size_t)0, argv[1], &tail, &iovec)) return enif_make_badarg(env); @@ -3378,13 +3416,13 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) list = enif_make_list_from_array(env, elems, iovcnt); enif_free(elems); return list; - } else { + } else if (argc >= 2) { unsigned skip; if (!enif_get_resource(env, argv[1], ioq_resource_type, (void**)&ioq) || !ioq->q) return enif_make_badarg(env); - if (enif_is_identical(argv[0], enif_make_atom(env, "example"))) { + if (argc == 3 && enif_is_identical(argv[0], enif_make_atom(env, "example"))) { #ifndef __WIN32__ int fd[2], res = 0, cnt = 0; ERL_NIF_TERM tail; @@ -3434,7 +3472,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) enif_ioq_destroy(ioq->q); ioq->q = NULL; return enif_make_atom(env, "false"); - } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqv"))) { + } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqv"))) { ErlNifIOVec vec, *iovec = &vec; ERL_NIF_TERM tail; @@ -3446,7 +3484,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return enif_make_badarg(env); return enif_make_atom(env, "true"); - } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqb"))) { + } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqb"))) { ErlNifBinary bin; if (!enif_get_uint(env, argv[3], &skip) || !enif_inspect_binary(env, argv[2], &bin)) @@ -3456,7 +3494,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return enif_make_badarg(env); return enif_make_atom(env, "true"); - } else if (enif_is_identical(argv[0], enif_make_atom(env, "enqbraw"))) { + } else if (argc >= 4 && enif_is_identical(argv[0], enif_make_atom(env, "enqbraw"))) { ErlNifBinary bin; ErlNifBinary localbin; int i; @@ -3480,7 +3518,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } return enif_make_atom(env, "false"); - } else if (enif_is_identical(argv[0], enif_make_atom(env, "peek"))) { + } else if (argc >= 3 && enif_is_identical(argv[0], enif_make_atom(env, "peek"))) { int iovlen, num, i, off = 0; SysIOVec *iov = enif_ioq_peek(ioq->q, &iovlen); ErlNifBinary bin; @@ -3496,7 +3534,7 @@ static ERL_NIF_TERM ioq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } return enif_make_binary(env, &bin); - } else if (enif_is_identical(argv[0], enif_make_atom(env, "deq"))) { + } else if (argc >= 3 && enif_is_identical(argv[0], enif_make_atom(env, "deq"))) { int num; size_t sz; ErlNifUInt64 sz64; diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index 6b834705cf..fded36431e 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -544,7 +544,7 @@ t_string_to_integer(Config) when is_list(Config) -> test_sti(268435455), test_sti(-268435455), - % Interesting values around 2-pows, such as MIN_SMALL and MAX_SMALL. + %% Interesting values around 2-pows, such as MIN_SMALL and MAX_SMALL. lists:foreach(fun(Bits) -> N = 1 bsl Bits, test_sti(N - 1), @@ -553,11 +553,11 @@ t_string_to_integer(Config) when is_list(Config) -> end, lists:seq(16, 130)), - %% Bignums. + %% Bignums test_sti(123456932798748738738,16), test_sti(list_to_integer(lists:duplicate(2000, $1))), - %% unalign string + %% Unaligned string Str = <<"10">>, UnalignStr = <<0:3, (id(Str))/binary, 0:5>>, <<_:3, SomeStr:2/binary, _:5>> = id(UnalignStr), @@ -568,32 +568,39 @@ t_string_to_integer(Config) when is_list(Config) -> {'EXIT', {badarg, _}} = (catch binary_to_integer(Value)), {'EXIT', {badarg, _}} = - (catch erlang:list_to_integer(Value)) + (catch list_to_integer(Value)) end,[atom,1.2,0.0,[$1,[$2]]]), - % Default base error cases + %% Default base error cases lists:foreach(fun(Value) -> {'EXIT', {badarg, _}} = - (catch erlang:binary_to_integer( - list_to_binary(Value))), + (catch binary_to_integer(list_to_binary(Value))), {'EXIT', {badarg, _}} = - (catch erlang:list_to_integer(Value)) + (catch list_to_integer(Value)) end,["1.0"," 1"," -1","","+"]), - % Custom base error cases + %% Custom base error cases lists:foreach(fun({Value,Base}) -> {'EXIT', {badarg, _}} = - (catch binary_to_integer( - list_to_binary(Value),Base)), + (catch binary_to_integer(list_to_binary(Value), Base)), {'EXIT', {badarg, _}} = - (catch erlang:list_to_integer(Value,Base)) - end,[{" 1",1},{" 1",37},{"2",2},{"B",11},{"b",11},{":", 16}, - {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16}, - {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16}, - {"111z11111111",16}]), - - %% log2 calculation overflow bug in do_integer_to_list (OTP-12624) - %% Would crash with segv + (catch list_to_integer(Value, Base)) + end, + [{" 1",1},{" 1",37},{"2",2},{"B",11},{"b",11},{":", 16}, + {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16}, + {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16}, + {"111z11111111",16}, + %% Untagging atoms at the beginning of atom.names + %% would produce a base in the valid range. + {"10",true}, %Base 4 + {"10",'_'}, %Base 8 + {"10",nonode@nohost}, %Base 12 + {"10",'$end_of_table'}, %Base 16 + {"10",''} %Base 20 + ]), + + %% log2 calculation overflow bug in do_integer_to_list (OTP-12624). + %% Would crash with segementation fault. 0 = list_to_integer(lists:duplicate(10000000,$0)), ok. diff --git a/erts/emulator/test/port_bif_SUITE_data/port_test.c b/erts/emulator/test/port_bif_SUITE_data/port_test.c index 923ab99ccc..ef6d12dc93 100644 --- a/erts/emulator/test/port_bif_SUITE_data/port_test.c +++ b/erts/emulator/test/port_bif_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> @@ -32,7 +33,7 @@ exit(1); \ } -#define MAIN(argc, argv) main(argc, argv) +#define MAIN(argc, argv) int main(argc, argv) extern int errno; diff --git a/erts/emulator/test/trace_SUITE_data/slow_drv.c b/erts/emulator/test/trace_SUITE_data/slow_drv.c index 4f7c93a69e..e7c1eb2125 100644 --- a/erts/emulator/test/trace_SUITE_data/slow_drv.c +++ b/erts/emulator/test/trace_SUITE_data/slow_drv.c @@ -3,6 +3,12 @@ #endif #include <stdio.h> +#include <string.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + #include "erl_driver.h" typedef struct _erl_drv_data { diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab index a000b9d415..78b6fba254 100755 --- a/erts/emulator/utils/make_driver_tab +++ b/erts/emulator/utils/make_driver_tab @@ -52,6 +52,7 @@ while (@ARGV) { if ( $d =~ /^.*\.a$/ ) { $d = basename $d; $d =~ s/\.a$//; # strip .a + $d =~ s/\.gprof$//; # strip .gprof if ($mode == 1) { push(@static_drivers, $d); } diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard index 3d6b4b50d3..a029ea7d37 100644 --- a/erts/emulator/valgrind/suppress.standard +++ b/erts/emulator/valgrind/suppress.standard @@ -277,7 +277,36 @@ obj:*/ssleay.* Memcheck:Addr8 fun:RC4 } - +{ +Crypto internal... loading gives expected errors when curves are tried. But including <openssl/err.h> and removing them triggers compiler errors on Windows +Memcheck:Leak +fun:malloc +... +fun:valid_curve +fun:init_curves +fun:init_curve_types +fun:init_algorithms_types +fun:initialize +fun:load +fun:erts_load_nif +fun:process_main +fun:sched_thread_func +} +{ +Crypto internal.. loading pecularities revisited +Memcheck:Leak +fun:malloc +fun:CRYPTO_malloc +fun:lh_new +... +fun:ecdh_check +fun:ECDH_compute_key +fun:ecdh_compute_key_nif +fun:process_main +fun:sched_thread_func +fun:thr_wrapper +fun:start_thread +} { Prebuilt constant terms in os_info_init (PossiblyLost) Memcheck:Leak diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 59dcf700d7..9dba684cbb 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -1199,10 +1199,10 @@ usage_aux(void) #endif "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] " "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] " - "[+C MODE] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] " - "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] " + "[+C MODE] [+dcg DECENTRALIZED_COUNTER_GROUPS_LIMIT] [+h HEAP_SIZE_OPTION] " + "[+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] " "[+R COMPAT_REL] " - "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] " + "[+r] [+rg READER_GROUPS_LIMIT] [+s<SUBSWITCH> SCHEDULER_OPTION] " "[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] " "[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] " "[+T LEVEL] [+V] [+v] " diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index 9ed887c3d4..f440b6a882 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -646,6 +646,67 @@ define etp-atom-1 end +define etp-string-to-atom +# Args: (char*) null-terminated +# +# Non-reentrant + + set $etp_i = 0 + set $etp_h = ((UWord)0) + while (($arg0)[$etp_i]) != 0 + set $etp_c = (unsigned char)(($arg0)[$etp_i]) + + if $etp_c & 0x80 + printf "Non ASCII atoms not implemented\n" + loop_break + end + + set $etp_h = ($etp_h << 4) + $etp_c + set $etp_g = $etp_h & 0xf0000000 + if $etp_g != 0 + set $etp_h ^= ($etp_g >> 24) + set $etp_h ^= $etp_g + end + set $etp_i++ + end + + # hash_get_slot + set $etp_h ^= $etp_h >> erts_atom_table.htable.shift + if $etp_arch64 + set $etp_h = (11400714819323198485UL * $etp_h) >> erts_atom_table.htable.shift + else + set $etp_h = (2654435769UL * $etp_h) >> erts_atom_table.htable.shift + end + set $etp_p = (Atom*)erts_atom_table.htable.bucket[$etp_h] + + # search hash bucket list + while $etp_p + set $etp_i = 0 + while $etp_i < $etp_p->len && ($arg0)[$etp_i] + if $etp_p->name[$etp_i] != ($arg0)[$etp_i] + loop_break + end + set $etp_i++ + end + if $etp_i == $etp_p->len && ($arg0)[$etp_i] == 0 + loop_break + end + set $etp_p = (Atom*)$etp_p->slot.bucket.next + end + if $etp_p + print ($etp_p->slot.index << 6) | (2 << 2) | 3 + else + printf "Can't find atom\n" + end +end + +document etp-string-to-atom +%---------------------------------------- +% etp-string-to-atom (char*) +% +% Ex: etp-string-to-atom "erlang" +%---------------------------------------- +end define etp-char-1 # Args: int char, int quote_char @@ -1093,6 +1154,92 @@ document etp-mfa %--------------------------------------------------------------------------- end +define etp-export-get + # Args: Eterm Eterm Uint + + set $etp_h = (((Eterm)$arg0 >> 6) * ((Eterm)$arg1 >> 6)) ^ (Uint)$arg2 + + #hash_get_slot + set $etp_t = &export_tables[the_active_code_index.counter].htable + set $etp_h ^= $etp_h >> $etp_t->shift + if $etp_arch64 + set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift + else + set $etp_h = (2654435769UL * $etp_h) >> $etp_t->shift + end + + set $etp_p = (struct export_entry*) $etp_t->bucket[$etp_h] + while $etp_p + if $etp_p->ep->info.mfa.module == $arg0 && $etp_p->ep->info.mfa.function == $arg1 && $etp_p->ep->info.mfa.arity == $arg2 + loop_break + end + set $etp_p = (struct export_entry*) $etp_p->slot.bucket.next + end + if $etp_p + print $etp_p->ep + else + printf "Can't find export entry\n" + end +end + +document etp-export-get +%--------------------------------------------------------- +% etp-export-get module function arity +% +% Lookup and print pointer to Export entry. +% Example: +% (gdb) etp-string-to-atom "erlang" +% $1 = 13323 +% (gdb) etp-string-to-atom "self" +% $2 = 47115 +% (gdb) etp-export-get 13323 47115 0 +% $3 = (Export *) 0x7f53caf1f358 +%--------------------------------------------------------- +end + +define etp-module-get + # Args: Eterm + + set $etp_ix = ((Eterm)$arg0 >> 6) + set $etp_h = $etp_ix + + #hash_get_slot + set $etp_t = &module_tables[the_active_code_index.counter].htable + set $etp_h ^= $etp_h >> $etp_t->shift + if $etp_arch64 + set $etp_h = (11400714819323198485UL * $etp_h) >> $etp_t->shift + else + set $etp_h = (2654435769UL * $etp_h) >> $etp_t->shift + end + + set $etp_p = (Module*) $etp_t->bucket[$etp_h] + while $etp_p + if $etp_p->module == $etp_ix + loop_break + end + set $etp_p = (Module*) $etp_p->slot.bucket.next + end + if $etp_p + print $etp_p + else + printf "Can't find module entry\n" + end +end + +document etp-module-get +%--------------------------------------------------------- +% etp-module-get module +% +% Lookup and print pointer to Module entry. +% Example: +% (gdb) etp-string-to-atom "erlang" +% $1 = 13323 +% (gdb) etp-module-get 13323 +% $2 = (Module *) 0x7f53caf1f358 +%--------------------------------------------------------- +end + + define etp-cp-func-info-1 # Args: Eterm cp # diff --git a/erts/etc/win32/erl.c b/erts/etc/win32/erl.c index 7cbd0d027c..e960fb1238 100644 --- a/erts/etc/win32/erl.c +++ b/erts/etc/win32/erl.c @@ -17,10 +17,7 @@ * * %CopyrightEnd% */ -#pragma comment(linker,"/manifestdependency:\"type='win32' "\ - "name='Microsoft.Windows.Common-Controls' "\ - "version='6.0.0.0' processorArchitecture='*' "\ - "publicKeyToken='6595b64144ccf1df' language='*'\"") + #include <windows.h> #include <stdio.h> #include <stdlib.h> diff --git a/erts/etc/win32/manifest.xml b/erts/etc/win32/manifest.xml new file mode 100644 index 0000000000..eea364c9e9 --- /dev/null +++ b/erts/etc/win32/manifest.xml @@ -0,0 +1,17 @@ +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" + processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"> + </assemblyIdentity> + </dependentAssembly> + </dependency> + <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2"> + <ms_asmv2:security> + <ms_asmv2:requestedPrivileges> + <ms_asmv2:requestedExecutionLevel level="AsInvoker" uiAccess="false"></ms_asmv2:requestedExecutionLevel> + </ms_asmv2:requestedPrivileges> + </ms_asmv2:security> + </ms_asmv2:trustInfo> +</assembly> diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index 5a79101b5d..907a64b89c 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -144,7 +144,21 @@ SubSection /e "Erlang" SecErlang Section "Development" SecErlangDev
SectionIn 1 RO
+ SetOutPath "$INSTDIR"
+ +; Don't let Users nor Autenticated Users group create new files +; Avoid dll injection when installing to non /Program Files/ dirs + + StrCmp $INSTDIR $InstallDir cp_files
+ ; Remove ANY inherited access control + ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /inheritance:r' SW_HIDE
+ ; Grant Admin full control + ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-5-32-544:(OI)(CI)F' SW_HIDE
+ ; Grant Normal Users read+execute control + ExecShellWait "open" "$SYSDIR\icacls.exe" '"$INSTDIR" /grant:r *S-1-1-0:(OI)(CI)RX' SW_HIDE
+
+cp_files:
File "${TESTROOT}\Install.ini"
File "${TESTROOT}\Install.exe"
SetOutPath "$INSTDIR\releases"
diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c index c0bb92793e..defa654ad8 100644 --- a/erts/etc/win32/win_erlexec.c +++ b/erts/etc/win32/win_erlexec.c @@ -22,11 +22,6 @@ * Most of this only used when beam is run as a separate process. */ -#pragma comment(linker,"/manifestdependency:\"type='win32' "\ - "name='Microsoft.Windows.Common-Controls' "\ - "version='6.0.0.0' processorArchitecture='*' "\ - "publicKeyToken='6595b64144ccf1df' language='*'\"") - #include <windows.h> #include <winuser.h> #include <wincon.h> diff --git a/erts/etc/win32/wsl_tools/vc/ld.sh b/erts/etc/win32/wsl_tools/vc/ld.sh index fc115bec8c..a16c502cea 100755 --- a/erts/etc/win32/wsl_tools/vc/ld.sh +++ b/erts/etc/win32/wsl_tools/vc/ld.sh @@ -177,11 +177,16 @@ RES=$? CMANIFEST=`w32_path.sh -u $MANIFEST` -if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then - # Add stuff to manifest to turn off "virtualization" +if [ -f "$CMANIFEST" ]; then + ## Add stuff to manifest to turn off "virtualization" sed -n -i '1h;1!H;${;g;s,<trustInfo.*</trustInfo>.,,g;p;}' $CMANIFEST 2>/dev/null sed -i "s/<\/assembly>/ <ms_asmv2:trustInfo xmlns:ms_asmv2=\"urn:schemas-microsoft-com:asm.v2\">\n <ms_asmv2:security>\n <ms_asmv2:requestedPrivileges>\n <ms_asmv2:requestedExecutionLevel level=\"AsInvoker\" uiAccess=\"false\"\/>\n <\/ms_asmv2:requestedPrivileges>\n <\/ms_asmv2:security>\n <\/ms_asmv2:trustInfo>\n<\/assembly>/" $CMANIFEST 2>/dev/null +else + CMANIFEST=$ERL_TOP/erts/etc/win32/manifest.xml + MANIFEST=`w32_path.sh -d $CMANIFEST` +fi +if [ "$RES" = "0" ]; then eval mt.exe -nologo -manifest "$MANIFEST" -outputresource:"$OUTPUTRES" >>/tmp/link.exe.${p}.1 2>>/tmp/link.exe.${p}.2 RES=$? if [ "$RES" != "0" ]; then @@ -192,7 +197,6 @@ if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then echo "If you get this error, make sure Windows Defender AND Windows Search is disabled">>/tmp/link.exe.${p}.1 rm -f "$CREMOVE" fi - rm -f "$CMANIFEST" fi # This works around some strange behaviour diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in index 70ff666ed3..bb43d51d97 100644 --- a/erts/lib_src/Makefile.in +++ b/erts/lib_src/Makefile.in @@ -44,6 +44,7 @@ ERLANG_OSTYPE=@ERLANG_OSTYPE@ OMIT_FP=false CFLAGS=$(subst O2,O3, @CFLAGS@) +LDFLAGS=@LDFLAGS@ ifeq ($(TYPE),debug) CFLAGS=@DEBUG_CFLAGS@ -DDEBUG diff --git a/erts/vsn.mk b/erts/vsn.mk index 7582350755..cc7958578f 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 11.1.3 +VSN = 11.1.8 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |