diff options
Diffstat (limited to 'erts')
52 files changed, 874 insertions, 252 deletions
diff --git a/erts/configure.in b/erts/configure.in index 6b494ef127..8c6f2ac076 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -1788,6 +1788,9 @@ AC_CHECK_FUNCS([fdatasync]) dnl Find which C libraries are required to use fdatasync AC_SEARCH_LIBS(fdatasync, [rt]) +AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h) +AC_CHECK_FUNCS([getifaddrs]) + dnl ---------------------------------------------------------------------- dnl Checks for features/quirks in the system that affects Erlang. dnl ---------------------------------------------------------------------- @@ -2673,7 +2676,7 @@ static __inline__ int check_fpe(double f) * Implement SIGFPE handler based on CPU/OS combination */ -#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__i386__) || defined(__x86_64__))) || (defined(__OpenBSD__) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__)) +#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__i386__) || defined(__x86_64__))) || ((defined(__OpenBSD__) || defined(__NetBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__)) #if defined(__linux__) && defined(__i386__) #if !defined(X86_FXSR_MAGIC) @@ -2787,6 +2790,11 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc) struct fxsave64 *fxsave = uc->sc_fpstate; fxsave->fx_mxcsr = 0x1F80; fxsave->fx_fsw &= ~0xFF; +#elif defined(__NetBSD__) && defined(__x86_64__) + mcontext_t *mc = &uc->uc_mcontext; + struct fxsave64 *fxsave = (struct fxsave64 *)&mc->__fpregs; + fxsave->fx_mxcsr = 0x1F80; + fxsave->fx_fsw &= ~0xFF; #elif defined(__sun__) && defined(__x86_64__) mcontext_t *mc = &uc->uc_mcontext; struct fpchip_state *fpstate = &mc->fpregs.fp_reg_set.fpchip_state; @@ -3419,7 +3427,6 @@ AC_SUBST(SSL_LINK_WITH_KERBEROS) AC_SUBST(STATIC_KERBEROS_LIBS) AC_SUBST(SSL_LINK_WITH_ZLIB) AC_SUBST(STATIC_ZLIB_LIBS) -AC_SUBST(OPENSSL_CMD) std_ssl_locations="/usr/local /usr/sfw /opt/local /usr /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl" @@ -3611,25 +3618,7 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in SSL_DYNAMIC_ONLY=yes fi SSL_BINDIR="$rdir/bin" -dnl Should one use EXEEXT or ac_exeext? - if test -f "$erl_xcomp_sysroot$SSL_BINDIR/openssl$EXEEXT"; then - if test "$cross_compiling" = "yes"; then - dnl Cannot test it; hope it is working... - OPENSSL_CMD="$erl_xcomp_sysroot$SSL_BINDIR/openssl$EXEEXT" - else - if "$SSL_BINDIR/openssl$EXEEXT" version > /dev/null 2>&1; then - OPENSSL_CMD="$SSL_BINDIR/openssl$EXEEXT" - else - is_real_ssl=no - fi - fi - else - is_real_ssl=no - fi if test "x$is_real_ssl" = "xyes" ; then - if test "$MIXED_CYGWIN" = "yes"; then - OPENSSL_CMD=`cygpath -s -m "$OPENSSL_CMD"` 2> /dev/null - fi SSL_INCLUDE="-I$dir/include" old_CPPFLAGS=$CPPFLAGS CPPFLAGS=$SSL_INCLUDE @@ -3692,7 +3681,6 @@ dnl Should one use EXEEXT or ac_exeext? SSL_RUNTIME_LIB="/usr/lib" SSL_LIB="$erl_xcomp_sysroot/usr/lib" SSL_BINDIR="/usr/sbin" - OPENSSL_CMD="$SSL_BINDIR/openssl" dnl OpenBSD requires us to link with -L and -l SSL_DYNAMIC_ONLY="yes" fi @@ -3778,7 +3766,6 @@ dnl so it is - be adoptable SSL_DYNAMIC_ONLY=yes fi SSL_INCLUDE="-I$with_ssl/include" - OPENSSL_CMD="$with_ssl/bin/openssl" SSL_APP=ssl CRYPTO_APP=crypto SSH_APP=ssh @@ -4175,7 +4162,6 @@ dnl ../lib/ic/c_src/$host/Makefile:../lib/ic/c_src/Makefile.in ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in - ../lib/ssl/examples/certs/$host/Makefile:../lib/ssl/examples/certs/Makefile.in ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in ../lib/orber/c_src/$host/Makefile:../lib/orber/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index f477280a6f..e36d0adb0d 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -831,14 +831,28 @@ <p>For more information, see <seealso marker="erlang#system_flag_cpu_topology">erlang:system_flag(cpu_topology, CpuTopology)</seealso>.</p> </item> + <tag><marker id="+swt"><c>+swt very_low|low|medium|high|very_high</c></marker></tag> + <item> + <p>Set scheduler wakeup threshold. Default is <c>medium</c>. + The threshold determines when to wake up sleeping schedulers + when more work than can be handled by currently awake schedulers + exist. A low threshold will cause earlier wakeups, and a high + threshold will cause later wakeups. Early wakeups will + distribute work over multiple schedulers faster, but work will + more easily bounce between schedulers. + </p> + <p><em>NOTE:</em> This flag may be removed or changed at any time + without prior notice. + </p> + </item> + <tag><marker id="sched_thread_stack_size"><c><![CDATA[+sss size]]></c></marker></tag> + <item> + <p>Suggested stack size, in kilowords, for scheduler threads. + Valid range is 4-8192 kilowords. The default stack size + is OS dependent.</p> + </item> </taglist> </item> - <tag><marker id="sched_thread_stack_size"><c><![CDATA[+sss size]]></c></marker></tag> - <item> - <p>Suggested stack size, in kilowords, for scheduler threads. - Valid range is 4-8192 kilowords. The default stack size - is OS dependent.</p> - </item> <tag><marker id="+t"><c><![CDATA[+t size]]></c></marker></tag> <item> <p>Set the maximum number of atoms the VM can handle. Default is 1048576.</p> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 8e4d8130f5..27887cbdf6 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2009</year> + <year>2001</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -1130,7 +1130,7 @@ typedef enum { </funcs> <section> <title>SEE ALSO</title> - <p><seealso marker="erlang#load_nif-2">load_nif(3)</seealso></p> + <p><seealso marker="erlang#load_nif-2">erlang:load_nif/2</seealso></p> </section> </cref> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 1eec45e0f3..59ac3dc66c 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -80,7 +80,7 @@ iolist() = [char() | binary() | iolist()] </desc> </func> <func> - <name>adler32(Data) -> int()</name> + <name>erlang:adler32(Data) -> int()</name> <fsummary>Compute adler32 checksum</fsummary> <type> <v>Data = iodata()</v> @@ -90,7 +90,7 @@ iolist() = [char() | binary() | iolist()] </desc> </func> <func> - <name>adler32(OldAdler, Data) -> int()</name> + <name>erlang:adler32(OldAdler, Data) -> int()</name> <fsummary>Compute adler32 checksum</fsummary> <type> <v>OldAdler = int()</v> @@ -102,17 +102,17 @@ iolist() = [char() | binary() | iolist()] <c>Data</c>.</p> <p>The following code:</p> <code> - X = adler32(Data1), - Y = adler32(X,Data2). + X = erlang:adler32(Data1), + Y = erlang:adler32(X,Data2). </code> <p>- would assign the same value to <c>Y</c> as this would:</p> <code> - Y = adler32([Data1,Data2]). + Y = erlang:adler32([Data1,Data2]). </code> </desc> </func> <func> - <name>adler32_combine(FirstAdler, SecondAdler, SecondSize) -> int()</name> + <name>erlang:adler32_combine(FirstAdler, SecondAdler, SecondSize) -> int()</name> <fsummary>Combine two adler32 checksums</fsummary> <type> <v>FirstAdler = SecondAdler = int()</v> @@ -124,14 +124,14 @@ iolist() = [char() | binary() | iolist()] the second checksum to be known.</p> <p>The following code:</p> <code> - Y = adler32(Data1), - Z = adler32(Y,Data2). + Y = erlang:adler32(Data1), + Z = erlang:adler32(Y,Data2). </code> <p>- would assign the same value to <c>Z</c> as this would:</p> <code> - X = adler32(Data1), - Y = adler32(Data2), - Z = adler32_combine(X,Y,iolist_size(Data2)). + X = erlang:adler32(Data1), + Y = erlang:adler32(Data2), + Z = erlang:adler32_combine(X,Y,iolist_size(Data2)). </code> </desc> </func> @@ -147,7 +147,7 @@ iolist() = [char() | binary() | iolist()] <c>Tuple1</c>, and contains the elements in <c>Tuple1</c> followed by <c>Term</c> as the last element. Semantically equivalent to - <c>list_to_tuple(tuple_to_list(Tuple ++ [Term])</c>, but much + <c>list_to_tuple(tuple_to_list(Tuple) ++ [Term])</c>, but much faster.</p> <pre> > <input>erlang:append_element({one, two}, three).</input> @@ -553,7 +553,7 @@ false</pre> </desc> </func> <func> - <name>crc32(Data) -> int()</name> + <name>erlang:crc32(Data) -> int()</name> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> <type> <v>Data = iodata()</v> @@ -563,7 +563,7 @@ false</pre> </desc> </func> <func> - <name>crc32(OldCrc, Data) -> int()</name> + <name>erlang:crc32(OldCrc, Data) -> int()</name> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> <type> <v>OldCrc = int()</v> @@ -575,17 +575,17 @@ false</pre> <c>Data</c>.</p> <p>The following code:</p> <code> - X = crc32(Data1), - Y = crc32(X,Data2). + X = erlang:crc32(Data1), + Y = erlang:crc32(X,Data2). </code> <p>- would assign the same value to <c>Y</c> as this would:</p> <code> - Y = crc32([Data1,Data2]). + Y = erlang:crc32([Data1,Data2]). </code> </desc> </func> <func> - <name>crc32_combine(FirstCrc, SecondCrc, SecondSize) -> int()</name> + <name>erlang:crc32_combine(FirstCrc, SecondCrc, SecondSize) -> int()</name> <fsummary>Combine two crc32 (IEEE 802.3) checksums</fsummary> <type> <v>FirstCrc = SecondCrc = int()</v> @@ -597,14 +597,14 @@ false</pre> the second checksum to be known.</p> <p>The following code:</p> <code> - Y = crc32(Data1), - Z = crc32(Y,Data2). + Y = erlang:crc32(Data1), + Z = erlang:crc32(Y,Data2). </code> <p>- would assign the same value to <c>Z</c> as this would:</p> <code> - X = crc32(Data1), - Y = crc32(Data2), - Z = crc32_combine(X,Y,iolist_size(Data2)). + X = erlang:crc32(Data1), + Y = erlang:crc32(Data2), + Z = erlang:crc32_combine(X,Y,iolist_size(Data2)). </code> </desc> </func> @@ -624,7 +624,7 @@ false</pre> </desc> </func> <func> - <name>decode_packet(Type,Bin,Options) -> {ok,Packet,Rest} | {more,Length} | {error,Reason}</name> + <name>erlang:decode_packet(Type,Bin,Options) -> {ok,Packet,Rest} | {more,Length} | {error,Reason}</name> <fsummary>Extracts a protocol packet from a binary</fsummary> <type> <v>Bin = binary()</v> @@ -760,7 +760,7 @@ false</pre> </desc> </func> <func> - <name>erlang:demonitor(MonitorRef) -> true</name> + <name>demonitor(MonitorRef) -> true</name> <fsummary>Stop monitoring</fsummary> <type> <v>MonitorRef = reference()</v> @@ -768,10 +768,10 @@ false</pre> <desc> <p>If <c>MonitorRef</c> is a reference which the calling process obtained by calling - <seealso marker="#monitor/2">erlang:monitor/2</seealso>, + <seealso marker="#monitor/2">monitor/2</seealso>, this monitoring is turned off. If the monitoring is already turned off, nothing happens.</p> - <p>Once <c>erlang:demonitor(MonitorRef)</c> has returned it is + <p>Once <c>demonitor(MonitorRef)</c> has returned it is guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message due to the monitor will be placed in the callers message queue in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message @@ -779,10 +779,10 @@ false</pre> the call, though. Therefore, in most cases, it is advisable to remove such a <c>'DOWN'</c> message from the message queue after monitoring has been stopped. - <seealso marker="#demonitor/2">erlang:demonitor(MonitorRef, [flush])</seealso> can be used instead of - <c>erlang:demonitor(MonitorRef)</c> if this cleanup is wanted.</p> + <seealso marker="#demonitor/2">demonitor(MonitorRef, [flush])</seealso> can be used instead of + <c>demonitor(MonitorRef)</c> if this cleanup is wanted.</p> <note> - <p>Prior to OTP release R11B (erts version 5.5) <c>erlang:demonitor/1</c> + <p>Prior to OTP release R11B (erts version 5.5) <c>demonitor/1</c> behaved completely asynchronous, i.e., the monitor was active until the "demonitor signal" reached the monitored entity. This had one undesirable effect, though. You could never know when @@ -800,7 +800,7 @@ false</pre> </desc> </func> <func> - <name>erlang:demonitor(MonitorRef, OptionList) -> true|false</name> + <name>demonitor(MonitorRef, OptionList) -> true|false</name> <fsummary>Stop monitoring</fsummary> <type> <v>MonitorRef = reference()</v> @@ -812,8 +812,8 @@ false</pre> <p>The returned value is <c>true</c> unless <c>info</c> is part of <c>OptionList</c>. </p> - <p><c>erlang:demonitor(MonitorRef, [])</c> is equivalent to - <seealso marker="#demonitor/1">erlang:demonitor(MonitorRef)</seealso>.</p> + <p><c>demonitor(MonitorRef, [])</c> is equivalent to + <seealso marker="#demonitor/1">demonitor(MonitorRef)</seealso>.</p> <p>Currently the following <c>Option</c>s are valid:</p> <taglist> <tag><c>flush</c></tag> @@ -821,11 +821,11 @@ false</pre> <p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message, if there is one, from the callers message queue after monitoring has been stopped.</p> - <p>Calling <c>erlang:demonitor(MonitorRef, [flush])</c> + <p>Calling <c>demonitor(MonitorRef, [flush])</c> is equivalent to the following, but more efficient:</p> <code type="none"> - erlang:demonitor(MonitorRef), + demonitor(MonitorRef), receive {_, MonitorRef, _, _, _} -> true @@ -863,7 +863,7 @@ false</pre> </note> <p>Failure: <c>badarg</c> if <c>OptionList</c> is not a list, or if <c>Option</c> is not a valid option, or the same failure as for - <seealso marker="#demonitor/1">erlang:demonitor/1</seealso></p> + <seealso marker="#demonitor/1">demonitor/1</seealso></p> </desc> </func> <func> @@ -944,7 +944,7 @@ b</pre> </desc> </func> <func> - <name>erlang:error(Reason)</name> + <name>error(Reason)</name> <fsummary>Stop execution with a given reason</fsummary> <type> <v>Reason = term()</v> @@ -957,7 +957,7 @@ b</pre> function first). Since evaluating this function causes the process to terminate, it has no return value.</p> <pre> -> <input>catch erlang:error(foobar).</input> +> <input>catch error(foobar).</input> {'EXIT',{foobar,[{erl_eval,do_apply,5}, {erl_eval,expr,5}, {shell,exprs,6}, @@ -966,7 +966,7 @@ b</pre> </desc> </func> <func> - <name>erlang:error(Reason, Args)</name> + <name>error(Reason, Args)</name> <fsummary>Stop execution with a given reason</fsummary> <type> <v>Reason = term()</v> @@ -1483,7 +1483,7 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:integer_to_list(Integer, Base) -> string()</name> + <name>integer_to_list(Integer, Base) -> string()</name> <fsummary>Text representation of an integer</fsummary> <type> <v>Integer = int()</v> @@ -1493,7 +1493,7 @@ os_prompt%</pre> <p>Returns a string which corresponds to the text representation of <c>Integer</c> in base <c>Base</c>.</p> <pre> -> <input>erlang:integer_to_list(1023, 16).</input> +> <input>integer_to_list(1023, 16).</input> "3FF"</pre> </desc> </func> @@ -1932,7 +1932,7 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:list_to_integer(String, Base) -> int()</name> + <name>list_to_integer(String, Base) -> int()</name> <fsummary>Convert from text representation to an integer</fsummary> <type> <v>String = string()</v> @@ -1942,7 +1942,7 @@ os_prompt%</pre> <p>Returns an integer whose text representation in base <c>Base</c> is <c>String</c>.</p> <pre> -> <input>erlang:list_to_integer("3FF", 16).</input> +> <input>list_to_integer("3FF", 16).</input> 1023</pre> <p>Failure: <c>badarg</c> if <c>String</c> contains a bad representation of an integer.</p> @@ -2034,16 +2034,18 @@ os_prompt%</pre> <v>Text = string()</v> </type> <desc> - <warning> - <p>This BIF is still an experimental feature. The interface - may be changed in any way in future releases.</p><p>In - R13B03 the return value on failure was + <note> + <p>In releases older than OTP R14B, NIFs were an + experimental feature. Versions of OTP older than R14B might + have different and possibly incompatible NIF semantics and + interfaces. For example, in R13B03 the return value on + failure was <c>{error,Reason,Text}</c>.</p> - </warning> + </note> <p>Loads and links a dynamic library containing native implemented functions (NIFs) for a module. <c>Path</c> is a file path to the sharable object/dynamic library file minus - the OS-dependant file extension (.so for Unix and .ddl for + the OS-dependent file extension (.so for Unix and .dll for Windows). See <seealso marker="erl_nif">erl_nif</seealso> on how to implement a NIF library.</p> <p><c>LoadInfo</c> can be any term. It will be passed on to @@ -2486,7 +2488,7 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:monitor(Type, Item) -> MonitorRef</name> + <name>monitor(Type, Item) -> MonitorRef</name> <fsummary>Start monitoring</fsummary> <type> <v>Type = process</v> @@ -2522,7 +2524,7 @@ os_prompt%</pre> <note> <p>When a process is monitored by registered name, the process that has the registered name at the time when - <c>erlang:monitor/2</c> is called will be monitored. + <c>monitor/2</c> is called will be monitored. The monitor will not be effected, if the registered name is unregistered.</p> </note> @@ -2556,20 +2558,20 @@ os_prompt%</pre> </item> </taglist> <note> - <p>If/when <c>erlang:monitor/2</c> is extended (e.g. to + <p>If/when <c>monitor/2</c> is extended (e.g. to handle other item types than <c>process</c>), other possible values for <c>Object</c>, and <c>Info</c> in the <c>'DOWN'</c> message will be introduced.</p> </note> <p>The monitoring is turned off either when the <c>'DOWN'</c> message is sent, or when - <seealso marker="#demonitor/1">erlang:demonitor/1</seealso> + <seealso marker="#demonitor/1">demonitor/1</seealso> is called.</p> <p>If an attempt is made to monitor a process on an older node (where remote process monitoring is not implemented or one where remote process monitoring by registered name is not implemented), the call fails with <c>badarg</c>.</p> - <p>Making several calls to <c>erlang:monitor/2</c> for the same + <p>Making several calls to <c>monitor/2</c> for the same <c>Item</c> is not an error; it results in as many, completely independent, monitorings.</p> <note> @@ -3897,11 +3899,11 @@ os_prompt%</pre> <tag><c>{monitored_by, Pids}</c></tag> <item> <p>A list of pids that are monitoring the process (with - <c>erlang:monitor/2</c>).</p> + <c>monitor/2</c>).</p> </item> <tag><c>{monitors, Monitors}</c></tag> <item> - <p>A list of monitors (started by <c>erlang:monitor/2</c>) + <p>A list of monitors (started by <c>monitor/2</c>) that are active for the process. For a local process monitor or a remote process monitor by pid, the list item is <c>{process, Pid}</c>, and for a remote process @@ -4090,7 +4092,7 @@ os_prompt%</pre> terminate, it has no return value - unless the arguments are invalid, in which case the function <em>returns the error reason</em>, that is <c>badarg</c>. If you want to be really sure not to return you can call - <c>erlang:error(erlang:raise(Class, Reason, Stacktrace))</c> + <c>error(erlang:raise(Class, Reason, Stacktrace))</c> and hope to distinguish exceptions later.</p> </desc> </func> @@ -4691,7 +4693,7 @@ true</pre> <tag><c>monitor</c></tag> <item> <p>Monitor the new process (just like - <seealso marker="#monitor/2">erlang:monitor/2</seealso> does).</p> + <seealso marker="#monitor/2">monitor/2</seealso> does).</p> </item> <tag><c>{priority, Level}</c></tag> <item> @@ -5456,6 +5458,16 @@ true</pre> <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, Alloc})</seealso>. </p> </item> + <tag><c>build_type</c></tag> + <item> + <p>Returns an atom describing the build type of the runtime + system. This is normally the atom <c>opt</c> for optimized. + Other possible return values are <c>debug</c>, <c>purify</c>, + <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, + <c>gprof</c>, and <c>lcnt</c>. Possible return values + may be added and/or removed at any time without prior notice. + </p> + </item> <tag><c>c_compiler_used</c></tag> <item> <p>Returns a two-tuple describing the C compiler used when diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index ed0d1b3fa6..903abe6f5c 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -74,7 +74,7 @@ else ifeq ($(TYPE),gcov) PURIFY = TYPEMARKER = .gcov -TYPE_FLAGS = @DEBUG_CFLAGS@ -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= +TYPE_FLAGS = @DEBUG_CFLAGS@ -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= ifneq ($(findstring solaris,$(TARGET)),solaris) LIBS += -lgcov endif diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c index 6b3c106a97..b97705ed96 100644 --- a/erts/emulator/beam/atom.c +++ b/erts/emulator/beam/atom.c @@ -303,7 +303,7 @@ init_atom_table(void) HashFunctions f; int i; Atom a; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 0815cdbc7f..327620772f 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -119,6 +119,7 @@ atom bsl atom bsr atom bsr_anycrlf atom bsr_unicode +atom build_type atom busy_dist_port atom busy_port atom call @@ -378,6 +379,7 @@ atom old_heap_size atom on_load atom open atom open_error +atom opt atom or atom ordered_set atom orelse diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 4fc271d41c..6ae9736141 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -337,7 +337,6 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) ep->code[0] == BIF_ARG_1 && ep->code[4] != 0) { ep->address = (void *) ep->code[4]; - ep->code[3] = 0; ep->code[4] = 0; } } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 74777e4c26..df5602b040 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1379,8 +1379,10 @@ read_code_header(LoaderState* stp) stp->ci = MI_FUNCTIONS + stp->num_functions + 1; stp->code[MI_ATTR_PTR] = 0; + stp->code[MI_ATTR_SIZE] = 0; stp->code[MI_ATTR_SIZE_ON_HEAP] = 0; stp->code[MI_COMPILE_PTR] = 0; + stp->code[MI_COMPILE_SIZE] = 0; stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; stp->code[MI_NUM_BREAKPOINTS] = 0; @@ -5199,8 +5201,10 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_NUM_FUNCTIONS] = n; code[MI_ATTR_PTR] = 0; + code[MI_ATTR_SIZE] = 0; code[MI_ATTR_SIZE_ON_HEAP] = 0; code[MI_COMPILE_PTR] = 0; + code[MI_COMPILE_SIZE] = 0; code[MI_COMPILE_SIZE_ON_HEAP] = 0; code[MI_NUM_BREAKPOINTS] = 0; code[MI_ON_LOAD_FUNCTION_PTR] = 0; diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index 024ff2a684..b6a445c55c 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -555,8 +555,12 @@ static void ac_init_find_all(ACFindAllState *state, ACTrie *act, Sint startpos, static void ac_restore_find_all(ACFindAllState *state, char *buff) { memcpy(state,buff,sizeof(ACFindAllState)); - state->out = erts_alloc(ERTS_ALC_T_TMP, sizeof(FindallData) * (state->allocated)); - memcpy(state->out,buff+sizeof(ACFindAllState),sizeof(FindallData)*state->m); + if (state->allocated > 0) { + state->out = erts_alloc(ERTS_ALC_T_TMP, sizeof(FindallData) * (state->allocated)); + memcpy(state->out,buff+sizeof(ACFindAllState),sizeof(FindallData)*state->m); + } else { + state->out = NULL; + } } static void ac_serialize_find_all(ACFindAllState *state, char *buff) @@ -828,10 +832,14 @@ static void bm_init_find_all(BMFindAllState *state, Sint startpos, Uint len) static void bm_restore_find_all(BMFindAllState *state, char *buff) { memcpy(state,buff,sizeof(BMFindAllState)); - state->out = erts_alloc(ERTS_ALC_T_TMP, sizeof(FindallData) * - (state->allocated)); - memcpy(state->out,buff+sizeof(BMFindAllState), - sizeof(FindallData)*state->m); + if (state->allocated > 0) { + state->out = erts_alloc(ERTS_ALC_T_TMP, sizeof(FindallData) * + (state->allocated)); + memcpy(state->out,buff+sizeof(BMFindAllState), + sizeof(FindallData)*state->m); + } else { + state->out = NULL; + } } static void bm_serialize_find_all(BMFindAllState *state, char *buff) @@ -1128,7 +1136,7 @@ static int do_binary_match(Process *p, Eterm subject, Uint hsstart, Uint hsend, ret = am_nomatch; } else if (acr == AC_RESTART) { int x = (sizeof(state) / sizeof(Eterm)) + - !!(sizeof(BMFindFirstState) % sizeof(Eterm)); + !!(sizeof(ACFindFirstState) % sizeof(Eterm)); #ifdef HARDDEBUG erts_printf("Trap ac!\n"); #endif diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index dace5b9297..40d8dc097c 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -1955,6 +1955,35 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) : am_enabled); } #endif + } else if (BIF_ARG_1 == am_build_type) { +#if defined(DEBUG) + ERTS_DECL_AM(debug); + BIF_RET(AM_debug); +#elif defined(PURIFY) + ERTS_DECL_AM(purify); + BIF_RET(AM_purify); +#elif defined(QUANTIFY) + ERTS_DECL_AM(quantify); + BIF_RET(AM_quantify); +#elif defined(PURECOV) + ERTS_DECL_AM(purecov); + BIF_RET(AM_purecov); +#elif defined(ERTS_GCOV) + ERTS_DECL_AM(gcov); + BIF_RET(AM_gcov); +#elif defined(VALGRIND) + ERTS_DECL_AM(valgrind); + BIF_RET(AM_valgrind); +#elif defined(GPROF) + ERTS_DECL_AM(gprof); + BIF_RET(AM_gprof); +#elif defined(ERTS_ENABLE_LOCK_COUNT) + ERTS_DECL_AM(lcnt); + BIF_RET(AM_lcnt); +#else + BIF_RET(am_opt); +#endif + BIF_RET(res); } else if (BIF_ARG_1 == am_allocated_areas) { res = erts_allocated_areas(NULL, NULL, BIF_P); BIF_RET(res); diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index b0369a402b..52d5f86ee0 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -265,7 +265,7 @@ static ERTS_INLINE void db_init_lock(DbTable* tb, int use_frequent_read_lock, char *rwname, char* fixname) { #ifdef ERTS_SMP - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; if (use_frequent_read_lock) rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; #endif @@ -2746,7 +2746,7 @@ void init_db(void) size_t size; #ifdef ERTS_SMP - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 5abd2e50fa..fa707f4eed 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -623,7 +623,7 @@ int db_create_hash(Process *p, DbTable *tbl) erts_smp_atomic_init(&tb->is_resizing, 0); #ifdef ERTS_SMP if (tb->common.type & DB_FINE_LOCKED) { - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; int i; if (tb->common.type & DB_FREQ_READ) rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c index 5dce5ad262..84869f12d6 100644 --- a/erts/emulator/beam/erl_fun.c +++ b/erts/emulator/beam/erl_fun.c @@ -55,7 +55,7 @@ void erts_init_fun_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 14bd10b42c..4ae656a3ad 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -512,6 +512,8 @@ void erts_usage(void) erts_fprintf(stderr, " u|ns|ts|ps|s|nnts|nnps|tnnps|db\n"); erts_fprintf(stderr, "-sct cput set cpu topology,\n"); erts_fprintf(stderr, " see the erl(1) documentation for more info.\n"); + erts_fprintf(stderr, "-swt val set scheduler wakeup threshold, valid values are:\n"); + erts_fprintf(stderr, " very_low|low|medium|high|very_high.\n"); erts_fprintf(stderr, "-sss size suggested stack size in kilo words for scheduler threads,\n"); erts_fprintf(stderr, " valid range is [%d-%d]\n", ERTS_SCHED_THREAD_MIN_STACK_SIZE, @@ -1176,10 +1178,20 @@ erl_start(int argc, char **argv) } else if (sys_strcmp("mrq", sub_param) == 0) use_multi_run_queue = 1; - else if (sys_strcmp("srq", sub_param) == 0) - use_multi_run_queue = 0; else if (sys_strcmp("nsp", sub_param) == 0) erts_use_sender_punish = 0; + else if (sys_strcmp("srq", sub_param) == 0) + use_multi_run_queue = 0; + else if (sys_strcmp("wt", sub_param) == 0) { + arg = get_arg(sub_param+2, argv[i+1], &i); + if (erts_sched_set_wakeup_limit(arg) != 0) { + erts_fprintf(stderr, "scheduler wakeup threshold: %s\n", + arg); + erts_usage(); + } + VERBOSE(DEBUG_SYSTEM, + ("scheduler wakup threshold: %s\n", arg)); + } else if (has_prefix("ss", sub_param)) { /* suggested stack size (Kilo Words) for scheduler threads */ arg = get_arg(sub_param+2, argv[i+1], &i); diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index e430b4ad77..d0b08bf72e 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -80,7 +80,7 @@ dist_table_alloc(void *dep_tmpl) Eterm chnl_nr; Eterm sysname; DistEntry *dep; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; if(((DistEntry *) dep_tmpl) == erts_this_dist_entry) @@ -710,7 +710,7 @@ erts_set_this_node(Eterm sysname, Uint creation) void erts_init_node_tables(void) { - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; HashFunctions f; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 761096e9ad..901167a315 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -54,7 +54,12 @@ (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT) #define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0 -#define ERTS_WAKEUP_OTHER_LIMIT (100*CONTEXT_REDS/2) +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS) +#define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10) + #define ERTS_WAKEUP_OTHER_DEC 10 #define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10) @@ -112,6 +117,8 @@ Uint erts_no_schedulers; Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES; Uint erts_process_tab_index_mask; +static int wakeup_other_limit; + #ifdef ERTS_SMP Uint erts_max_main_threads; #endif @@ -2373,7 +2380,27 @@ void erts_early_init_scheduling(void) { early_cpu_bind_init(); + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; +} + +int +erts_sched_set_wakeup_limit(char *str) +{ + if (sys_strcmp(str, "very_high") == 0) + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH; + else if (sys_strcmp(str, "high") == 0) + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH; + else if (sys_strcmp(str, "medium") == 0) + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM; + else if (sys_strcmp(str, "low") == 0) + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_LOW; + else if (sys_strcmp(str, "very_low") == 0) + wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW; + else + return EINVAL; + return 0; } + void erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) @@ -4009,7 +4036,7 @@ signal_schedulers_bind_change(erts_cpu_topology_t *cpudata, int size) int s_ix = 1; int cpu_ix; - if (cpu_bind_order != ERTS_CPU_BIND_NONE) { + if (cpu_bind_order != ERTS_CPU_BIND_NONE && size) { cpu_bind_order_sort(cpudata, size, cpu_bind_order, 1); @@ -5523,7 +5550,6 @@ late_cpu_bind_init(void) erts_cpu_topology_t *cpudata; int cpudata_size; create_tmp_cpu_topology_copy(&cpudata, &cpudata_size); - ASSERT(cpudata); signal_schedulers_bind_change(cpudata, cpudata_size); destroy_tmp_cpu_topology_copy(cpudata); } @@ -5538,23 +5564,29 @@ erts_update_cpu_info(void) if (changed) { erts_cpu_topology_t *cpudata; int cpudata_size; - erts_free(ERTS_ALC_T_CPUDATA, system_cpudata); - system_cpudata_size = erts_get_cpu_topology_size(erts_cpuinfo); - system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA, - (sizeof(erts_cpu_topology_t) - * system_cpudata_size)); - - if (!erts_get_cpu_topology(erts_cpuinfo, system_cpudata) - || ERTS_INIT_CPU_TOPOLOGY_OK != verify_topology(system_cpudata, - system_cpudata_size)) { + if (system_cpudata) erts_free(ERTS_ALC_T_CPUDATA, system_cpudata); + + system_cpudata_size = erts_get_cpu_topology_size(erts_cpuinfo); + if (!system_cpudata_size) system_cpudata = NULL; - system_cpudata_size = 0; + else { + system_cpudata = erts_alloc(ERTS_ALC_T_CPUDATA, + (sizeof(erts_cpu_topology_t) + * system_cpudata_size)); + + if (!erts_get_cpu_topology(erts_cpuinfo, system_cpudata) + || (ERTS_INIT_CPU_TOPOLOGY_OK + != verify_topology(system_cpudata, + system_cpudata_size))) { + erts_free(ERTS_ALC_T_CPUDATA, system_cpudata); + system_cpudata = NULL; + system_cpudata_size = 0; + } } create_tmp_cpu_topology_copy(&cpudata, &cpudata_size); - ASSERT(cpudata); signal_schedulers_bind_change(cpudata, cpudata_size); destroy_tmp_cpu_topology_copy(cpudata); } @@ -7164,7 +7196,7 @@ Process *schedule(Process *p, int calls) if (rq->wakeup_other < 0) rq->wakeup_other = 0; } - else if (rq->wakeup_other < ERTS_WAKEUP_OTHER_LIMIT) + else if (rq->wakeup_other < wakeup_other_limit) rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC; else { if (erts_common_run_queue) { diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index e49710a7ed..4365e409e5 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1038,6 +1038,8 @@ ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); int erts_proclist_same(ErtsProcList *, Process *); +int erts_sched_set_wakeup_limit(char *str); + #ifdef DEBUG void erts_dbg_multi_scheduling_return_trap(Process *, Eterm); #endif diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 5e81a2d624..5bc402fe22 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -109,7 +109,7 @@ void init_export_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c index c9bb7bbe91..26d64887d0 100644 --- a/erts/emulator/beam/register.c +++ b/erts/emulator/beam/register.c @@ -145,7 +145,7 @@ static void reg_free(RegProc *obj) void init_register_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_THR_OPTS_DEFAULT_INITER; + erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index a07d6a5327..53d39aef0e 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -83,24 +83,8 @@ #define ASSERT_NO_LOCKED_LOCKS #endif +static erts_smp_mtx_t tiw_lock; -#if defined(ERTS_TIMER_THREAD) || 1 -/* I don't yet know why, but using a mutex instead of a spinlock - or spin-based rwlock avoids excessive delays at startup. */ -static erts_smp_rwmtx_t tiw_lock; -#define tiw_read_lock() erts_smp_rwmtx_rlock(&tiw_lock) -#define tiw_read_unlock() erts_smp_rwmtx_runlock(&tiw_lock) -#define tiw_write_lock() erts_smp_rwmtx_rwlock(&tiw_lock) -#define tiw_write_unlock() erts_smp_rwmtx_rwunlock(&tiw_lock) -#define tiw_init_lock() erts_smp_rwmtx_init(&tiw_lock, "timer_wheel") -#else -static erts_smp_rwlock_t tiw_lock; -#define tiw_read_lock() erts_smp_read_lock(&tiw_lock) -#define tiw_read_unlock() erts_smp_read_unlock(&tiw_lock) -#define tiw_write_lock() erts_smp_write_lock(&tiw_lock) -#define tiw_write_unlock() erts_smp_write_unlock(&tiw_lock) -#define tiw_init_lock() erts_smp_rwlock_init(&tiw_lock, "timer_wheel") -#endif /* BEGIN tiw_lock protected variables ** @@ -224,10 +208,10 @@ int next_time(void) { int ret; - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); (void)do_time_update(); ret = next_time_internal(); - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return ret; } #endif @@ -241,7 +225,7 @@ static ERTS_INLINE void bump_timer_internal(long dt) /* PRE: tiw_lock is write-l /* no need to bump the position if there aren't any timeouts */ if (tiw_nto == 0) { - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return; } @@ -278,7 +262,7 @@ static ERTS_INLINE void bump_timer_internal(long dt) /* PRE: tiw_lock is write-l } tiw_pos = keep_pos; - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); /* Call timedout timers callbacks */ while (timeout_head) { @@ -299,13 +283,13 @@ static ERTS_INLINE void bump_timer_internal(long dt) /* PRE: tiw_lock is write-l #if defined(ERTS_TIMER_THREAD) static void timer_thread_bump_timer(void) { - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); bump_timer_internal(do_time_reset()); } #else void bump_timer(long dt) /* dt is value from do_time */ { - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); bump_timer_internal(dt); } #endif @@ -324,7 +308,7 @@ static int timer_thread_setup_delay(SysTimeval *rem_time) long elapsed; int ticks; - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); elapsed = do_time_update(); ticks = next_time_internal(); if (ticks == -1) /* timer queue empty */ @@ -336,7 +320,7 @@ static int timer_thread_setup_delay(SysTimeval *rem_time) rem_time->tv_sec = ticks / 1000; rem_time->tv_usec = 1000 * (ticks % 1000); ticks_end = ticks; - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return ticks; } @@ -399,7 +383,7 @@ init_time(void) if timer thread is enabled */ itime = erts_init_time_sup(); - tiw_init_lock(); + erts_smp_mtx_init(&tiw_lock, "timer_wheel"); tiw = (ErlTimer**) erts_alloc(ERTS_ALC_T_TIMER_WHEEL, TIW_SIZE * sizeof(ErlTimer*)); @@ -451,9 +435,9 @@ erl_set_timer(ErlTimer* p, ErlTimeoutProc timeout, ErlCancelProc cancel, void* arg, Uint t) { erts_deliver_time(); - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); if (p->active) { /* XXX assert ? */ - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return; } p->timeout = timeout; @@ -461,7 +445,7 @@ erl_set_timer(ErlTimer* p, ErlTimeoutProc timeout, ErlCancelProc cancel, p->arg = arg; p->active = 1; insert_timer(p, t); - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); #if defined(ERTS_SMP) && !defined(ERTS_TIMER_THREAD) if (t <= (Uint) LONG_MAX) erts_sys_schedule_interrupt_timed(1, (long) t); @@ -474,9 +458,9 @@ erl_cancel_timer(ErlTimer* p) ErlTimer *tp; ErlTimer **prev; - tiw_write_lock(); + erts_smp_mtx_lock(&tiw_lock); if (!p->active) { /* allow repeated cancel (drivers) */ - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return; } /* find p in linked list at slot p->slot and remove it */ @@ -489,17 +473,17 @@ erl_cancel_timer(ErlTimer* p) p->slot = p->count = 0; p->active = 0; if (p->cancel != NULL) { - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); (*p->cancel)(p->arg); } else { - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); } return; } else { prev = &tp->next; } } - tiw_write_unlock(); + erts_smp_mtx_unlock(&tiw_lock); } /* @@ -514,10 +498,10 @@ time_left(ErlTimer *p) Uint left; long dt; - tiw_read_lock(); + erts_smp_mtx_lock(&tiw_lock); if (!p->active) { - tiw_read_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return 0; } @@ -531,7 +515,7 @@ time_left(ErlTimer *p) else left -= dt; - tiw_read_unlock(); + erts_smp_mtx_unlock(&tiw_lock); return left * itime; } @@ -543,7 +527,7 @@ void p_slpq() int i; ErlTimer* p; - tiw_read_lock(); + erts_smp_mtx_lock(&tiw_lock); /* print the whole wheel, starting at the current position */ erts_printf("\ntiw_pos = %d tiw_nto %d\n", tiw_pos, tiw_nto); @@ -565,7 +549,7 @@ void p_slpq() } } - tiw_read_unlock(); + erts_smp_mtx_unlock(&tiw_lock); } #endif /* DEBUG */ diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 059288d1cb..3de48194fb 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -48,6 +48,12 @@ #include <sys/uio.h> #endif +#ifdef HAVE_NET_IF_DL_H +#include <net/if_dl.h> +#endif +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -2168,7 +2174,7 @@ static int http_error_inetdrv(void* arg, const char* buf, int len) ErlDrvTermData spec[19]; if (desc->inet.active == INET_PASSIVE) { - /* {inet_async,S,Ref,{error,{http_error,Line}}} */ + /* {inet_async,S,Ref,{ok,{http_error,Line}}} */ int req; int aid; ErlDrvTermData caller; @@ -2178,7 +2184,7 @@ static int http_error_inetdrv(void* arg, const char* buf, int len) i = LOAD_ATOM(spec, i, am_inet_async); i = LOAD_PORT(spec, i, desc->inet.dport); i = LOAD_INT(spec, i, aid); - i = LOAD_ATOM(spec, i, am_error); + i = LOAD_ATOM(spec, i, am_ok); i = LOAD_ATOM(spec, i, am_http_error); i = http_load_string(desc, spec, i, buf, len); i = LOAD_TUPLE(spec, i, 2); @@ -3905,7 +3911,7 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, INTERFACE_INFO* ifp; long namaddr; - if ((len == 0) || ((namlen = buf[0]) > len)) + if ((len == 0) || ((namlen = get_int8(buf)) > len)) goto error; if (parse_addr(buf+1, namlen, &namaddr) < 0) goto error; @@ -4089,6 +4095,10 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) } +/* FIXME: temporary hack */ +#ifndef IFHWADDRLEN +#define IFHWADDRLEN 6 +#endif static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, char** rbuf, int rsize) @@ -4099,11 +4109,11 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, struct ifreq ifreq; int namlen; - if ((len == 0) || ((namlen = buf[0]) > len)) + if ((len == 0) || ((namlen = get_int8(buf)) > len)) goto error; sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); sys_memcpy(ifreq.ifr_name, buf+1, - (namlen > IFNAMSIZ) ? IFNAMSIZ : namlen); + (namlen >= IFNAMSIZ) ? IFNAMSIZ-1 : namlen); buf += (namlen+1); len -= (namlen+1); sptr = sbuf; @@ -4128,6 +4138,32 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, /* raw memcpy (fix include autoconf later) */ sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN); sptr += IFHWADDRLEN; +#elif defined(HAVE_GETIFADDRS) + struct ifaddrs *ifa, *ifp; + int found = 0; + + if (getifaddrs(&ifa) == -1) + goto error; + + for (ifp = ifa; ifp; ifp = ifp->ifa_next) { + if ((ifp->ifa_addr->sa_family == AF_LINK) && + (sys_strcmp(ifp->ifa_name, ifreq.ifr_name) == 0)) { + found = 1; + break; + } + } + + if (found == 0) { + freeifaddrs(ifa); + break; + } + + buf_check(sptr, s_end, 1+IFHWADDRLEN); + *sptr++ = INET_IFOPT_HWADDR; + sys_memcpy(sptr, ((struct sockaddr_dl *)ifp->ifa_addr)->sdl_data + + ((struct sockaddr_dl *)ifp->ifa_addr)->sdl_nlen, IFHWADDRLEN); + freeifaddrs(ifa); + sptr += IFHWADDRLEN; #endif break; } @@ -4240,10 +4276,6 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, return ctl_error(EINVAL, rbuf, rsize); } -/* FIXME: temporary hack */ -#ifndef IFHWADDRLEN -#define IFHWADDRLEN 6 -#endif static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, char** rbuf, int rsize) @@ -4252,11 +4284,11 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, int namlen; char* b_end = buf + len; - if ((len == 0) || ((namlen = buf[0]) > len)) + if ((len == 0) || ((namlen = get_int8(buf)) > len)) goto error; sys_memset(ifreq.ifr_name, '\0', IFNAMSIZ); sys_memcpy(ifreq.ifr_name, buf+1, - (namlen > IFNAMSIZ) ? IFNAMSIZ : namlen); + (namlen >= IFNAMSIZ) ? IFNAMSIZ-1 : namlen); buf += (namlen+1); len -= (namlen+1); @@ -5032,8 +5064,8 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) } case INET_OPT_LINGER: { - CHKLEN(curr, ASSOC_ID_LEN + 2 + 4); - arg.lin.l_onoff = get_int16 (curr); curr += 2; + CHKLEN(curr, 2*4); + arg.lin.l_onoff = get_int32 (curr); curr += 4; arg.lin.l_linger = get_int32 (curr); curr += 4; proto = SOL_SOCKET; @@ -6193,6 +6225,10 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, struct sctp_sndrcvinfo sri; unsigned int sz = sizeof(sri); + if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL); + sri.sinfo_assoc_id = GET_ASSOC_ID(buf); + buf += ASSOC_ID_LEN; + buflen -= ASSOC_ID_LEN; if (sock_getopt(desc->s, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, &sri, &sz) < 0) continue; /* Fill in the response: */ @@ -6847,13 +6883,13 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, if (len < 2) return ctl_error(EINVAL, rbuf, rsize); - n = buf[0]; buf++; len--; + n = get_int8(buf); buf++; len--; if (n >= len) /* the = sign makes the test inklude next length byte */ return ctl_error(EINVAL, rbuf, rsize); memcpy(namebuf, buf, n); namebuf[n] = '\0'; len -= n; buf += n; - n = buf[0]; buf++; len--; + n = get_int8(buf); buf++; len--; if (n > len) return ctl_error(EINVAL, rbuf, rsize); memcpy(protobuf, buf, n); @@ -6876,7 +6912,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, port = get_int16(buf); port = sock_htons(port); buf += 2; - n = buf[0]; buf++; len -= 3; + n = get_int8(buf); buf++; len -= 3; if (n > len) return ctl_error(EINVAL, rbuf, rsize); memcpy(protobuf, buf, n); diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S index 83b7b0397b..ede762aae0 100644 --- a/erts/emulator/hipe/hipe_amd64_glue.S +++ b/erts/emulator/hipe/hipe_amd64_glue.S @@ -346,6 +346,8 @@ nbif_3_gc_after_bif: subq $(16-8), %rsp movq P, %rdi movq %rax, %rsi + xorl %edx, %edx # Pass NULL in regs + xorl %ecx, %ecx # Pass 0 in arity call CSYM(erts_gc_after_bif_call) addq $(16-8), %rsp movl $0, P_NARITY(P) # Note: narity is a 32-bit field diff --git a/erts/emulator/hipe/hipe_arm_glue.S b/erts/emulator/hipe/hipe_arm_glue.S index 5d626a5f69..2bce01954e 100644 --- a/erts/emulator/hipe/hipe_arm_glue.S +++ b/erts/emulator/hipe/hipe_arm_glue.S @@ -311,6 +311,8 @@ nbif_3_gc_after_bif: str TEMP_LR, [P, #P_NRA] str NSP, [P, #P_NSP] mov TEMP_LR, lr + mov r3, #0 /* Pass 0 in arity */ + mov r2, #0 /* Pass NULL in regs */ mov r1, r0 mov r0, P bl erts_gc_after_bif_call diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c index 5188950e17..8f43811537 100644 --- a/erts/emulator/hipe/hipe_bif1.c +++ b/erts/emulator/hipe/hipe_bif1.c @@ -876,22 +876,44 @@ BIF_RETTYPE hipe_bifs_misc_timer_clear_0(BIF_ALIST_0) * + The fallback, which is the same as {X,_} = runtime(statistics). */ +static double fallback_get_hrvtime(void) +{ + unsigned long ms_user; + + elapsed_time_both(&ms_user, NULL, NULL, NULL); + return (double)ms_user; +} + #if USE_PERFCTR #include "hipe_perfctr.h" -static int hrvtime_is_open; -#define hrvtime_is_started() hrvtime_is_open +static int hrvtime_started; /* 0: closed, +1: perfctr, -1: fallback */ +#define hrvtime_is_started() (hrvtime_started != 0) static void start_hrvtime(void) { if (hipe_perfctr_hrvtime_open() >= 0) - hrvtime_is_open = 1; + hrvtime_started = 1; + else + hrvtime_started = -1; } -#define get_hrvtime() hipe_perfctr_hrvtime_get() -#define stop_hrvtime() hipe_perfctr_hrvtime_close() +static void stop_hrvtime(void) +{ + if (hrvtime_started > 0) + hipe_perfctr_hrvtime_close(); + hrvtime_started = 0; +} -#else +static double get_hrvtime(void) +{ + if (hrvtime_started > 0) + return hipe_perfctr_hrvtime_get(); + else + return fallback_get_hrvtime(); +} + +#else /* !USE_PERFCTR */ /* * Fallback, if nothing better exists. @@ -902,15 +924,9 @@ static void start_hrvtime(void) #define hrvtime_is_started() 1 #define start_hrvtime() do{}while(0) #define stop_hrvtime() do{}while(0) +#define get_hrvtime() fallback_get_hrvtime() -static double get_hrvtime(void) -{ - unsigned long ms_user; - elapsed_time_both(&ms_user, NULL, NULL, NULL); - return (double)ms_user; -} - -#endif /* hrvtime support */ +#endif /* !USE_PERFCTR */ BIF_RETTYPE hipe_bifs_get_hrvtime_0(BIF_ALIST_0) { @@ -918,11 +934,8 @@ BIF_RETTYPE hipe_bifs_get_hrvtime_0(BIF_ALIST_0) Eterm res; FloatDef f; - if (!hrvtime_is_started()) { + if (!hrvtime_is_started()) start_hrvtime(); - if (!hrvtime_is_started()) - BIF_RET(NIL); /* arity 0 BIFs may not fail */ - } f.fd = get_hrvtime(); hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT); res = make_float(hp); diff --git a/erts/emulator/hipe/hipe_ppc_glue.S b/erts/emulator/hipe/hipe_ppc_glue.S index 97b07353f9..0651963294 100644 --- a/erts/emulator/hipe/hipe_ppc_glue.S +++ b/erts/emulator/hipe/hipe_ppc_glue.S @@ -476,6 +476,8 @@ CSYM(nbif_3_gc_after_bif): STORE TEMP_LR, P_NRA(P) STORE NSP, P_NSP(P) mflr TEMP_LR + li r6, 0 /* Pass 0 in arity */ + li r5, 0 /* Pass NULL in regs */ mr r4, r3 mr r3, P bl CSYM(erts_gc_after_bif_call) diff --git a/erts/emulator/hipe/hipe_sparc_glue.S b/erts/emulator/hipe/hipe_sparc_glue.S index d1af5c43f5..73cefd4896 100644 --- a/erts/emulator/hipe/hipe_sparc_glue.S +++ b/erts/emulator/hipe/hipe_sparc_glue.S @@ -333,6 +333,8 @@ nbif_3_gc_after_bif: st TEMP_RA, [P+P_NRA] st NSP, [P+P_NSP] mov RA, TEMP_RA + mov 0, %o3 /* Pass 0 in arity */ + mov 0, %o2 /* Pass NULL in regs */ mov %o0, %o1 call erts_gc_after_bif_call mov P, %o0 /* delay slot */ diff --git a/erts/emulator/hipe/hipe_x86_glue.S b/erts/emulator/hipe/hipe_x86_glue.S index 2f7dff39f5..43392111fe 100644 --- a/erts/emulator/hipe/hipe_x86_glue.S +++ b/erts/emulator/hipe/hipe_x86_glue.S @@ -320,11 +320,13 @@ nbif_3_gc_after_bif: .align 4 .gc_after_bif: movl %edx, P_NARITY(P) - subl $(16-4), %esp + subl $(32-4), %esp movl P, (%esp) movl %eax, 4(%esp) + movl $0, 8(%esp) # Pass NULL in regs + movl $0, 12(%esp) # Pass 0 in arity call CSYM(erts_gc_after_bif_call) - addl $(16-4), %esp + addl $(32-4), %esp movl $0, P_NARITY(P) ret diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c index a4fff4ce31..0c61e7bf96 100644 --- a/erts/emulator/hipe/hipe_x86_signal.c +++ b/erts/emulator/hipe/hipe_x86_signal.c @@ -195,7 +195,7 @@ static void do_init(void) #define INIT() do { if (!init_done()) do_init(); } while (0) #endif /* __DARWIN__ */ -#if !defined(__GLIBC__) && !defined(__DARWIN__) +#if !defined(__GLIBC__) && !defined(__DARWIN__) && !defined(__NetBSD__) /* * Assume Solaris/x86 2.8. * There is a number of sigaction() procedures in libc: @@ -231,6 +231,7 @@ static void do_init(void) #define INIT() do { if (!init_done()) do_init(); } while (0) #endif /* not glibc or darwin */ +#if !defined(__NetBSD__) /* * This is our wrapper for sigaction(). sigaction() can be called before * hipe_signal_init() has been executed, especially when threads support @@ -253,7 +254,7 @@ static int my_sigaction(int signum, const struct sigaction *act, struct sigactio } return __next_sigaction(signum, act, oldact); } - +#endif /* * This overrides the C library's core sigaction() procedure, catching * all its internal calls. @@ -268,7 +269,7 @@ int __SIGACTION(int signum, const struct sigaction *act, struct sigaction *oldac /* * This catches the application's own sigaction() calls. */ -#if !defined(__DARWIN__) +#if !defined(__DARWIN__) && !defined(__NetBSD__) int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { return my_sigaction(signum, act, oldact); @@ -326,7 +327,9 @@ void hipe_signal_init(void) struct sigaction sa; int i; +#ifndef __NetBSD__ INIT(); +#endif hipe_sigaltstack_init(); diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index 1c4c37b01a..b1ee165489 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -382,6 +382,14 @@ mseg_recreate(void *old_seg, Uint old_size, Uint new_size) new_seg = (void *) pmremap((void *) old_seg, (size_t) old_size, (size_t) new_size); +#elif defined(__NetBSD__) + new_seg = (void *) mremap((void *) old_seg, + (size_t) old_size, + NULL, + (size_t) new_size, + 0); + if (new_seg == (void *) MAP_FAILED) + new_seg = NULL; #else new_seg = (void *) mremap((void *) old_seg, (size_t) old_size, diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index 5a682ab045..6e9376b0f3 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -476,7 +476,7 @@ static int mask_fpe(void) #endif -#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || (defined(__OpenBSD__) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__)) +#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || ((defined(__NetBSD__) || defined(__OpenBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__)) #if defined(__linux__) && defined(__i386__) #if !defined(X86_FXSR_MAGIC) @@ -519,6 +519,10 @@ static int mask_fpe(void) #define mc_pc(mc) ((mc)->mc_rip) #elif defined(__FreeBSD__) && defined(__i386__) #define mc_pc(mc) ((mc)->mc_eip) +#elif defined(__NetBSD__) && defined(__x86_64__) +#define mc_pc(mc) ((mc)->__gregs[_REG_RIP]) +#elif defined(__NetBSD__) && defined(__i386__) +#define mc_pc(mc) ((mc)->__gregs[_REG_EIP]) #elif defined(__OpenBSD__) && defined(__x86_64__) #define mc_pc(mc) ((mc)->sc_rip) #elif defined(__sun__) && defined(__x86_64__) @@ -610,6 +614,23 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc) struct env87 *env87 = &savefpu->sv_87.sv_env; env87->en_sw &= ~0xFF; } +#elif defined(__NetBSD__) && defined(__x86_64__) + mcontext_t *mc = &uc->uc_mcontext; + struct fxsave64 *fxsave = (struct fxsave64 *)&mc->__fpregs; + pc = mc_pc(mc); + fxsave->fx_mxcsr = 0x1F80; + fxsave->fx_fsw &= ~0xFF; +#elif defined(__NetBSD__) && defined(__i386__) + mcontext_t *mc = &uc->uc_mcontext; + pc = mc_pc(mc); + if (uc->uc_flags & _UC_FXSAVE) { + struct envxmm *envxmm = (struct envxmm *)&mc->__fpregs; + envxmm->en_mxcsr = 0x1F80; + envxmm->en_sw &= ~0xFF; + } else { + struct env87 *env87 = (struct env87 *)&mc->__fpregs; + env87->en_sw &= ~0xFF; + } #elif defined(__OpenBSD__) && defined(__x86_64__) struct fxsave64 *fxsave = uc->sc_fpstate; pc = mc_pc(uc); diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 5384a32f21..8489124966 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1029,8 +1029,11 @@ static ERL_NIF_TERM make_term_list0(struct make_term_info* mti, int n) static ERL_NIF_TERM make_term_resource(struct make_term_info* mti, int n) { void* resource = enif_alloc_resource(mti->resource_type, 10); + ERL_NIF_TERM term; fill(resource, 10, n); - return enif_make_resource(mti->dst_env, resource); + term = enif_make_resource(mti->dst_env, resource); + enif_release_resource(resource); + return term; } static ERL_NIF_TERM make_term_new_binary(struct make_term_info* mti, int n) { diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index 77fa75b78f..a7476ca9bb 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -2305,7 +2305,11 @@ load_driver(Dir, Driver) -> close_deaf_port(doc) -> ["Send data to port program that does not read it, then close port."]; close_deaf_port(suite) -> []; close_deaf_port(Config) when is_list(Config) -> - Port = open_port({spawn,"sleep 999999"},[]), - erlang:port_command(Port,"Hello, can you hear me!?!?"), - port_close(Port), + ?line Dog = test_server:timetrap(test_server:seconds(100)), + ?line DataDir = ?config(data_dir, Config), + ?line DeadPort = os:find_executable("dead_port", DataDir), + + ?line Port = open_port({spawn,DeadPort++" 60"},[]), + ?line erlang:port_command(Port,"Hello, can you hear me!?!?"), + ?line port_close(Port), ok. diff --git a/erts/emulator/test/port_SUITE_data/Makefile.src b/erts/emulator/test/port_SUITE_data/Makefile.src index d97b37c9ae..ff822ae720 100644 --- a/erts/emulator/test/port_SUITE_data/Makefile.src +++ b/erts/emulator/test/port_SUITE_data/Makefile.src @@ -3,7 +3,7 @@ LD = @LD@ CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@ CROSSLDFLAGS = @CROSSLDFLAGS@ -PROGS = port_test@exe@ echo_args@exe@ +PROGS = port_test@exe@ echo_args@exe@ dead_port@exe@ DRIVERS = echo_drv@dll@ exit_drv@dll@ failure_drv@dll@ all: $(PROGS) $(DRIVERS) port_test.@EMULATOR@ diff --git a/erts/emulator/test/port_SUITE_data/dead_port.c b/erts/emulator/test/port_SUITE_data/dead_port.c new file mode 100644 index 0000000000..6fa77112be --- /dev/null +++ b/erts/emulator/test/port_SUITE_data/dead_port.c @@ -0,0 +1,102 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef VXWORKS +#include <vxWorks.h> +#include <taskVarLib.h> +#include <taskLib.h> +#include <sysLib.h> +#include <string.h> +#include <ioLib.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifndef __WIN32__ +#include <unistd.h> + +#ifdef VXWORKS +#include "reclaim.h" +#include <sys/times.h> +#else +#include <sys/time.h> +#endif + +#define O_BINARY 0 +#define _setmode(fd, mode) +#endif + +#ifdef __WIN32__ +#include "windows.h" +#include "winbase.h" +#endif + + +#ifdef VXWORKS +#define MAIN(argc, argv) port_test(argc, argv) +#else +#define MAIN(argc, argv) main(argc, argv) +#endif + + +extern int errno; + +static void delay(unsigned ms); + + +MAIN(argc, argv) +int argc; +char *argv[]; +{ + int x; + if (argc < 2) { + fprintf(stderr,"Usage %s <seconds>\n",argv[0]); + return 1; + } + if ((x = atoi(argv[1])) <= 0) { + fprintf(stderr,"Usage %s <seconds>\n",argv[0]); + return 1; + } + delay(x*1000); + return 0; +} + +static void +delay(unsigned ms) +{ +#ifdef VXWORKS + taskDelay((sysClkRateGet() * ms) / 1000); +#else +#ifdef __WIN32__ + Sleep(ms); +#else + struct timeval t; + t.tv_sec = ms/1000; + t.tv_usec = (ms % 1000) * 1000; + + select(0, NULL, NULL, NULL, &t); +#endif +#endif +} diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index 4f4458802c..06442bfad6 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -47,6 +47,7 @@ scheduler_bind/1, scheduler_bind_types/1, cpu_topology/1, + update_cpu_info/1, sct_cmd/1, sbt_cmd/1, scheduler_suspend/1, @@ -249,6 +250,7 @@ bound_loop(NS, N, M, Sched) -> scheduler_bind(suite) -> [scheduler_bind_types, cpu_topology, + update_cpu_info, sct_cmd, sbt_cmd]. @@ -772,6 +774,137 @@ cpu_topology_cmdline_test(Config, Topology, Cmd) -> ?line stop_node(Node), ?line ok. +update_cpu_info(Config) when is_list(Config) -> + ?line OldOnline = erlang:system_info(schedulers_online), + ?line OldAff = get_affinity_mask(), + ?line ?t:format("START - Affinity mask: ~p - Schedulers online: ~p - Scheduler bindings: ~p~n", + [OldAff, OldOnline, erlang:system_info(scheduler_bindings)]), + ?line case {erlang:system_info(logical_processors_available), OldAff} of + {Avail, _} when Avail == unknown; OldAff == unknown -> + %% Nothing much to test; just a smoke test + case erlang:system_info(update_cpu_info) of + unchanged -> ?line ok; + changed -> ?line ok + end; + _ -> + try + ?line adjust_schedulers_online(), + case erlang:system_info(schedulers_online) of + 1 -> + %% Nothing much to test; just a smoke test + ?line ok; + Onln0 -> + %% unset least significant bit + ?line Aff = (OldAff band (OldAff - 1)), + ?line set_affinity_mask(Aff), + ?line Onln1 = Onln0 - 1, + ?line case adjust_schedulers_online() of + {Onln0, Onln1} -> + ?line Onln1 = erlang:system_info(schedulers_online), + ?line receive after 500 -> ok end, + ?line ?t:format("TEST - Affinity mask: ~p - Schedulers online: ~p - Scheduler bindings: ~p~n", + [Aff, Onln1, erlang:system_info(scheduler_bindings)]), + ?line unchanged = adjust_schedulers_online(), + ?line ok; + Fail -> + ?line ?t:fail(Fail) + end + end + after + set_affinity_mask(OldAff), + adjust_schedulers_online(), + erlang:system_flag(schedulers_online, OldOnline), + receive after 500 -> ok end, + ?t:format("END - Affinity mask: ~p - Schedulers online: ~p - Scheduler bindings: ~p~n", + [get_affinity_mask(), + erlang:system_info(schedulers_online), + erlang:system_info(scheduler_bindings)]) + end + end. + +adjust_schedulers_online() -> + case erlang:system_info(update_cpu_info) of + unchanged -> + unchanged; + changed -> + Avail = erlang:system_info(logical_processors_available), + {erlang:system_flag(schedulers_online, Avail), Avail} + end. + +read_affinity(Data) -> + Exp = "pid " ++ os:getpid() ++ "'s current affinity mask", + case string:tokens(Data, ":") of + [Exp, DirtyAffinityStr] -> + AffinityStr = string:strip(string:strip(DirtyAffinityStr, + both, $ ), + both, $\n), + case catch erlang:list_to_integer(AffinityStr, 16) of + Affinity when is_integer(Affinity) -> + Affinity; + _ -> + bad + end; + _ -> + bad + end. + +get_affinity_mask(Port, Status, Affinity) when Status == unknown; + Affinity == unknown -> + receive + {Port,{data, Data}} -> + get_affinity_mask(Port, Status, read_affinity(Data)); + {Port,{exit_status,S}} -> + get_affinity_mask(Port, S, Affinity) + end; +get_affinity_mask(Port, Status, bad) -> + unknown; +get_affinity_mask(Port, Status, Affinity) -> + Affinity. + +get_affinity_mask() -> + case ?t:os_type() of + {unix, linux} -> + case catch open_port({spawn, "taskset -p " ++ os:getpid()}, + [exit_status]) of + Port when is_port(Port) -> + get_affinity_mask(Port, unknown, unknown); + _ -> + unknown + end; + _ -> + unknown + end. + +set_affinity_mask(Port, unknown) -> + receive + {Port,{data, _}} -> + set_affinity_mask(Port, unknown); + {Port,{exit_status,Status}} -> + set_affinity_mask(Port, Status) + end; +set_affinity_mask(Port, Status) -> + receive + {Port,{data, _}} -> + set_affinity_mask(Port, unknown) + after 0 -> + Status + end. + +set_affinity_mask(Mask) -> + Cmd = lists:flatten(["taskset -p ", + io_lib:format("~.16b", [Mask]), + " ", + os:getpid()]), + case catch open_port({spawn, Cmd}, [exit_status]) of + Port when is_port(Port) -> + case set_affinity_mask(Port, unknown) of + 0 -> ok; + _ -> exit(failed_to_set_affinity) + end; + _ -> + exit(failed_to_set_affinity) + end. + sct_cmd(Config) when is_list(Config) -> ?line Topology = ?TOPOLOGY_A_TERM, ?line OldRelFlags = clear_erl_rel_flags(), diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 76ce0a7e3c..c1fc2aebee 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -120,6 +120,7 @@ static char *plusM_other_switches[] = { static char *pluss_val_switches[] = { "bt", "ct", + "wt", "ss", NULL }; diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h index 4ce3e75c78..8d9d5e3d08 100644 --- a/erts/include/internal/ethr_mutex.h +++ b/erts/include/internal/ethr_mutex.h @@ -346,7 +346,9 @@ do { \ #ifdef ETHR_USE_OWN_MTX_IMPL__ -#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT 1000 +#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_MAX 2000 +#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_BASE 800 +#define ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_INC 50 #define ETHR_MTX_DEFAULT_AUX_SPINCOUNT 50 #define ETHR_CND_DEFAULT_MAIN_SPINCOUNT 0 @@ -443,7 +445,9 @@ ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx) #ifdef ETHR_USE_OWN_RWMTX_IMPL__ -#define ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT 1000 +#define ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_MAX 2000 +#define ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_BASE 800 +#define ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_INC 50 #define ETHR_RWMTX_DEFAULT_AUX_SPINCOUNT 50 #else /* pthread_rwlock */ diff --git a/erts/include/internal/gcc/ethr_atomic.h b/erts/include/internal/gcc/ethr_atomic.h index 5fe6e23477..e8e529dd48 100644 --- a/erts/include/internal/gcc/ethr_atomic.h +++ b/erts/include/internal/gcc/ethr_atomic.h @@ -31,7 +31,7 @@ #define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0 /* Enable immediate read/write on platforms where we know it is safe */ #if defined(__i386__) || defined(__x86_64__) || defined(__sparc__) \ - || defined(__powerpc__) || defined(__ppc__) + || defined(__powerpc__) || defined(__ppc__) || defined(__mips__) # undef ETHR_IMMED_ATOMIC_SET_GET_SAFE__ # define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1 #endif @@ -48,13 +48,18 @@ typedef struct { * a noop on at least some platforms with some gcc versions. * This has suposedly been fixed in some gcc version, but we * don't know from which version. Therefore, we use the - * workaround implemented below on all gcc versions. + * workaround implemented below on all gcc versions except + * for gcc 4.2 or above for MIPS, where it's been verified. */ +#if defined(__mips__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +#define ETHR_MEMORY_BARRIER __sync_synchronize() +#else #define ETHR_MEMORY_BARRIER \ do { \ volatile long x___ = 0; \ (void) __sync_val_compare_and_swap(&x___, (long) 0, (long) 1); \ } while (0) +#endif #define ETHR_READ_DEPEND_MEMORY_BARRIER ETHR_MEMORY_BARRIER #if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__) diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c index aac0d44a32..78323b62a3 100644 --- a/erts/lib_src/common/ethr_mutex.c +++ b/erts/lib_src/common/ethr_mutex.c @@ -35,7 +35,7 @@ #define ETHR_SPIN_WITH_WAITERS 1 -#define ETHR_MTX_MAX_FLGS_SPIN 1000 +#define ETHR_MTX_MAX_FLGS_SPIN 10 #ifdef ETHR_USE_OWN_RWMTX_IMPL__ static int default_rwmtx_main_spincount; @@ -90,7 +90,7 @@ ethr_mutex_lib_init(int cpu_conf) no_spin = cpu_conf == 1; #ifdef ETHR_USE_OWN_MTX_IMPL__ - default_mtx_main_spincount = ETHR_MTX_DEFAULT_MAIN_SPINCOUNT; + default_mtx_main_spincount = ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_BASE; default_mtx_aux_spincount = ETHR_MTX_DEFAULT_AUX_SPINCOUNT; default_cnd_main_spincount = ETHR_CND_DEFAULT_MAIN_SPINCOUNT; default_cnd_aux_spincount = ETHR_CND_DEFAULT_AUX_SPINCOUNT; @@ -98,7 +98,7 @@ ethr_mutex_lib_init(int cpu_conf) #ifdef ETHR_USE_OWN_RWMTX_IMPL__ - default_rwmtx_main_spincount = ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT; + default_rwmtx_main_spincount = ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_BASE; default_rwmtx_aux_spincount = ETHR_RWMTX_DEFAULT_AUX_SPINCOUNT; #else @@ -146,7 +146,21 @@ static int main_threads_array_size = 0; int ethr_mutex_lib_late_init(int no_reader_groups, int no_main_threads) { + +#ifdef ETHR_USE_OWN_MTX_IMPL__ + default_mtx_main_spincount += (no_main_threads + * ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_INC); + if (default_mtx_main_spincount > ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_MAX) + default_mtx_main_spincount = ETHR_MTX_DEFAULT_MAIN_SPINCOUNT_MAX; +#endif + #ifdef ETHR_USE_OWN_RWMTX_IMPL__ + + default_rwmtx_main_spincount += (no_main_threads + * ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_INC); + if (default_rwmtx_main_spincount > ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_MAX) + default_rwmtx_main_spincount = ETHR_RWMTX_DEFAULT_MAIN_SPINCOUNT_MAX; + reader_groups_array_size = (no_reader_groups <= 1 ? 1 : no_reader_groups + 1); @@ -593,24 +607,31 @@ initial_spincount(struct ethr_mutex_base_ *mtxb) static ETHR_INLINE int update_spincount(struct ethr_mutex_base_ *mtxb, ethr_ts_event *tse, - int *start_scnt, + int *scnt_state, int *scnt) { - int sscnt = *start_scnt; - if (sscnt < 0) { - *scnt = ((tse->iflgs & ETHR_TS_EV_MAIN_THR) - ? mtxb->main_scnt - : mtxb->aux_scnt); - *scnt -= ETHR_MTX_MAX_FLGS_SPIN; + int state = *scnt_state; + if (state <= 0) { + /* Here state is max spincount to do on event negated */ + *scnt = -state; } else { + /* Here state is initial spincount made on flags */ *scnt = ((tse->iflgs & ETHR_TS_EV_MAIN_THR) ? mtxb->main_scnt : mtxb->aux_scnt); - *scnt -= sscnt; - if (*scnt > 0 && sscnt < ETHR_MTX_MAX_FLGS_SPIN) { - *scnt = ETHR_MTX_MAX_FLGS_SPIN - sscnt; - *start_scnt = -1; + if (*scnt <= state) + *scnt = 0; + else { + if (*scnt <= ETHR_MTX_MAX_FLGS_SPIN) + *scnt_state = 0; /* No spin on event */ + else { + /* Spin on event after... */ + *scnt_state = -1*(*scnt - ETHR_MTX_MAX_FLGS_SPIN); + /* ... we have spun on flags */ + *scnt = ETHR_MTX_MAX_FLGS_SPIN; + } + *scnt -= state; return 0; } } @@ -619,8 +640,7 @@ update_spincount(struct ethr_mutex_base_ *mtxb, int check_readers_array(ethr_rwmutex *rwmtx, int start_rix, - int length, - int pre_check); + int length); static ETHR_INLINE void write_lock_wait(struct ethr_mutex_base_ *mtxb, @@ -666,8 +686,7 @@ write_lock_wait(struct ethr_mutex_base_ *mtxb, } res = check_readers_array(rwmtx, freq_read_start_ix, - freq_read_size, - 1); + freq_read_size); scnt--; if (res == 0) { act = ethr_atomic_read(&mtxb->flgs); @@ -708,7 +727,6 @@ write_lock_wait(struct ethr_mutex_base_ *mtxb, act = ethr_atomic_read(&mtxb->flgs); scnt--; } - ETHR_ASSERT(scnt >= 0); exp = act; @@ -985,7 +1003,6 @@ enqueue_mtx(ethr_mutex *mtx, ethr_ts_event *tse_start, ethr_ts_event *tse_end) int ethr_cond_init_opt(ethr_cond *cnd, ethr_cond_opt *opt) { - int res; #if ETHR_XCHK if (!cnd) { ETHR_ASSERT(0); @@ -1085,7 +1102,6 @@ ethr_cond_signal(ethr_cond *cnd) void ethr_cond_broadcast(ethr_cond *cnd) { - int res; int got_all; ethr_ts_event *tse; ETHR_ASSERT(!ethr_not_inited__); @@ -1153,7 +1169,6 @@ ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx) { int woken; int scnt; - int res; void *udata = NULL; ethr_ts_event *tse; @@ -1466,17 +1481,11 @@ multiple_w_waiters(ethr_rwmutex *rwmtx) int check_readers_array(ethr_rwmutex *rwmtx, int start_rix, - int length, - int pre_check) + int length) { int ix = start_rix; -#ifndef ETHR_READ_MEMORY_BARRIER_IS_FULL - if (pre_check) - ETHR_READ_MEMORY_BARRIER; - else -#endif - ETHR_MEMORY_BARRIER; + ETHR_MEMORY_BARRIER; do { long act = rwmutex_freqread_rdrs_read(rwmtx, ix); @@ -1559,7 +1568,7 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx, ethr_leave_ts_event(tse_tmp); if (check_before_try) { - res = check_readers_array(rwmtx, six, length, 1); + res = check_readers_array(rwmtx, six, length); if (res == EBUSY) return try_write_lock ? EBUSY : 0; } @@ -1597,7 +1606,7 @@ rwmutex_try_complete_runlock(ethr_rwmutex *rwmtx, } } - res = check_readers_array(rwmtx, six, length, 0); + res = check_readers_array(rwmtx, six, length); if (res == EBUSY) { act = ethr_atomic_dec_read(&rwmtx->mtxb.flgs); if (act & ETHR_RWMTX_R_MASK__) @@ -1691,7 +1700,7 @@ rwmutex_normal_rlock_wait(ethr_rwmutex *rwmtx, #endif while (act & (ETHR_RWMTX_W_FLG__|ETHR_RWMTX_W_WAIT_FLG__)) { - if (scnt == 0) { + if (scnt >= 0) { tse = ethr_get_ts_event(); if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) { event_wait(&rwmtx->mtxb, tse, scnt, @@ -1708,7 +1717,6 @@ rwmutex_normal_rlock_wait(ethr_rwmutex *rwmtx, scnt--; } exp = act; - ETHR_ASSERT(scnt >= 0); #ifdef ETHR_RLOCK_WITH_INC_DEC act = ethr_atomic_inc_read(&rwmtx->mtxb.flgs); @@ -1749,7 +1757,7 @@ rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx, act = ethr_atomic_read(&rwmtx->mtxb.flgs); while (act & ~(ETHR_RWMTX_R_FLG__|ETHR_RWMTX_R_WAIT_FLG__)) { - if (scnt == 0) { + if (scnt >= 0) { if (update_spincount(&rwmtx->mtxb, tse, &start_scnt, &scnt)) { event_wait(&rwmtx->mtxb, tse, scnt, ETHR_RWMTX_R_WAIT_FLG__, 1, 1); @@ -1765,8 +1773,6 @@ rwmutex_freqread_rlock_wait(ethr_rwmutex *rwmtx, scnt--; } - ETHR_ASSERT(scnt >= 0); - rwmutex_freqread_rdrs_inc(rwmtx, tse); ETHR_MEMORY_BARRIER; diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex 7b824f1ab4..222809e662 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 3cab91b722..65c7369b76 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 9f88ddd51e..f1b54b7fcb 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 4c9cc9675b..abf17bcb0e 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 9a4904b6a1..a3f300268f 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex ac336c1b2d..a777971b32 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex c57d37725e..0fe38a1fb2 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 6b14d3fd66..7108bf44d0 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 0feb591efb..91d39c6a73 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1206,7 +1206,7 @@ type_opt_1(sctp_default_send_param) -> timetolive = [uint32,0], tsn = [], cumtsn = [], - assoc_id = [sctp_assoc_id,0]}}]; + assoc_id = [[sctp_assoc_id,0]]}}]; %% for SCTP_OPT_EVENTS type_opt_1(sctp_events) -> [{record,#sctp_event_subscribe{ diff --git a/erts/test/Makefile b/erts/test/Makefile index 796403e182..94458da019 100644 --- a/erts/test/Makefile +++ b/erts/test/Makefile @@ -28,6 +28,7 @@ EBIN = . # ---------------------------------------------------- MODULES= \ + autoimport_SUITE \ erlc_SUITE \ install_SUITE \ nt_SUITE \ @@ -38,12 +39,14 @@ MODULES= \ erlexec_SUITE \ z_SUITE +ERL_XML = $(ERL_TOP)/erts/doc/src/erlang.xml +ERL_XML_TARGET = autoimport_SUITE_data/erlang.xml ERL_FILES= $(MODULES:%=%.erl) TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -EXTRA_FILES = install_SUITE_data/install_bin +EXTRA_FILES = install_SUITE_data/install_bin $(ERL_XML_TARGET) # ---------------------------------------------------- # Release directory specification @@ -65,6 +68,10 @@ install_SUITE_data/install_bin: ../../make/install_bin rm -f $@ cp -p $< $@ +$(ERL_XML_TARGET): $(ERL_XML) + rm -f $@ + cp -p $< $@ + clean: rm -f $(TARGET_FILES) $(EXTRA_FILES) rm -f core *~ diff --git a/erts/test/autoimport_SUITE.erl b/erts/test/autoimport_SUITE.erl new file mode 100644 index 0000000000..2430dac78d --- /dev/null +++ b/erts/test/autoimport_SUITE.erl @@ -0,0 +1,163 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%% Purpose: Test erlang.xml re autoimports +-module(autoimport_SUITE). + +-include_lib("test_server/include/test_server.hrl"). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,autoimports/1]). +-define(TEST_TIMEOUT, ?t:seconds(180)). + +all(suite) -> [autoimports]. + +init_per_testcase(_Func, Config) -> + Dog = test_server:timetrap(?TEST_TIMEOUT), + [{watchdog, Dog} | Config]. + +fin_per_testcase(_Func, Config) -> + Dog = ?config(watchdog, Config), + catch test_server:timetrap_cancel(Dog), + ok. + + +autoimports(suite) -> + []; +autoimports(doc) -> + ["Check that erlang.xml documents autoimports correctly"]; +autoimports(Config) when is_list(Config) -> + ?line XML = filename:join([?config(data_dir,Config),"erlang.xml"]), + ?line case xml(XML) of + [] -> + ok; + List -> + lists:foreach(fun({[],F,A}) -> + io:format("erlang:~s/~p is wrongly " + "documented as ~s/~p~n", + [F,A,F,A]); + ({"erlang",F,A}) -> + io:format("~s/~p is wrongly " + "documented as " + "erlang:~s/~p~n", + [F,A,F,A]) + end,List), + ?t:fail({wrong_autoimports,List}) + end. + +%% +%% Ugly chunk of code to heuristically analyze the erlang.xml +%% documentation file. Don't view this as an example... +%% + +xml(XMLFile) -> + {ok,File} = file:open(XMLFile,[read]), + DocData = xloop(file:read_line(File),File), + file:close(File), + analyze(DocData). + +xloop({ok,Line},File) -> + case re:run(Line,"\\<name\\>",[{capture,none}]) of + nomatch -> + xloop(file:read_line(File),File); + match -> + X = re:replace(Line,"\\).*",")",[{return,list}]), + Y = re:replace(X,".*\\>","",[{return,list}]), + Mod = get_module(Y), + Rest1 = fstrip(Mod++":",Y), + Func = get_function(Rest1), + Rest2 = fstrip(Func++"(", Rest1), + Argc = count_args(Rest2,1,0,false), + [{Mod,Func,Argc} | + xloop(file:read_line(File),File)] + end; +xloop(_,_) -> + []. + +analyze([{[],Func,Arity}|T]) -> + case erl_internal:bif(list_to_atom(Func),Arity) of + true -> + analyze(T); + false -> + [{[],Func,Arity} | + analyze(T)] + end; +analyze([{"erlang",Func,Arity}|T]) -> + case erl_internal:bif(list_to_atom(Func),Arity) of + true -> + [{"erlang",Func,Arity}|analyze(T)]; + false -> + analyze(T) + end; +analyze([_|T]) -> + analyze(T); +analyze([]) -> + []. + + +count_args([],_,N,false) -> + N; +count_args([],_,N,true) -> + N+1; +count_args(_,0,N,true) -> + N+1; +count_args(_,0,N,false) -> + N; +count_args([Par|T],Level,N,Got) when (Par =:= 40) or + (Par =:= 123) or (Par =:= 91) -> + count_args(T,Level+1,N,(Level =:= 1) or Got); +count_args([41|T],1,N,true) -> + count_args(T,0,N+1,false); +count_args([Par|T],Level,N, Got) when (Par =:= 41) or + (Par =:= 125) or (Par =:= 93) -> + count_args(T,Level-1,N,Got); +count_args([$,|T],1,N,true) -> + count_args(T,1,N+1,false); +count_args([$ |T],A,B,C) -> + count_args(T,A,B,C); +count_args([_|T],1,N,_) -> + count_args(T,1,N,true); +count_args([_|T],A,B,C) -> + count_args(T,A,B,C). + +fstrip([],X) -> + X; +fstrip(_,[]) -> + []; +fstrip([H|T1],[H|T2]) -> + fstrip(T1,T2); +fstrip(_,L) -> + L. + +get_module(X) -> + get_module(X,[]). +get_module([],_) -> + []; +get_module([$:|_],Acc) -> + lists:reverse(Acc); +get_module([40|_],_) -> %( + []; +get_module([H|T],Acc) -> + get_module(T,[H|Acc]). + +get_function(X) -> + get_function(X,[]). +get_function([],_) -> + []; +get_function([40|_],Acc) -> %( + lists:reverse(Acc); +get_function([H|T],Acc) -> + get_function(T,[H|Acc]). diff --git a/erts/test/autoimport_SUITE_data/dummy.txt b/erts/test/autoimport_SUITE_data/dummy.txt new file mode 100644 index 0000000000..972643e527 --- /dev/null +++ b/erts/test/autoimport_SUITE_data/dummy.txt @@ -0,0 +1,19 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% Purpouse: Dummy |