aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in32
-rw-r--r--erts/doc/src/erl.xml26
-rw-r--r--erts/doc/src/erl_nif.xml4
-rw-r--r--erts/doc/src/erlang.xml128
-rw-r--r--erts/emulator/Makefile.in2
-rw-r--r--erts/emulator/beam/atom.c2
-rw-r--r--erts/emulator/beam/atom.names2
-rw-r--r--erts/emulator/beam/beam_bif_load.c1
-rw-r--r--erts/emulator/beam/beam_load.c4
-rw-r--r--erts/emulator/beam/erl_bif_binary.c22
-rw-r--r--erts/emulator/beam/erl_bif_info.c29
-rw-r--r--erts/emulator/beam/erl_db.c4
-rw-r--r--erts/emulator/beam/erl_db_hash.c2
-rw-r--r--erts/emulator/beam/erl_fun.c2
-rw-r--r--erts/emulator/beam/erl_init.c16
-rw-r--r--erts/emulator/beam/erl_node_tables.c4
-rw-r--r--erts/emulator/beam/erl_process.c62
-rw-r--r--erts/emulator/beam/erl_process.h2
-rw-r--r--erts/emulator/beam/export.c2
-rw-r--r--erts/emulator/beam/register.c2
-rw-r--r--erts/emulator/beam/time.c62
-rw-r--r--erts/emulator/drivers/common/inet_drv.c68
-rw-r--r--erts/emulator/hipe/hipe_amd64_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_arm_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_bif1.c49
-rw-r--r--erts/emulator/hipe/hipe_ppc_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_sparc_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_x86_glue.S6
-rw-r--r--erts/emulator/hipe/hipe_x86_signal.c9
-rw-r--r--erts/emulator/sys/common/erl_mseg.c8
-rw-r--r--erts/emulator/sys/unix/sys_float.c23
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c5
-rw-r--r--erts/emulator/test/port_SUITE.erl10
-rw-r--r--erts/emulator/test/port_SUITE_data/Makefile.src2
-rw-r--r--erts/emulator/test/port_SUITE_data/dead_port.c102
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl133
-rw-r--r--erts/etc/common/erlexec.c1
-rw-r--r--erts/include/internal/ethr_mutex.h8
-rw-r--r--erts/include/internal/gcc/ethr_atomic.h9
-rw-r--r--erts/lib_src/common/ethr_mutex.c80
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin50392 -> 50384 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin24324 -> 24316 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin44352 -> 44348 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1436 -> 1428 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin30544 -> 30536 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin57272 -> 57268 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22440 -> 22428 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin10620 -> 10612 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl4
-rw-r--r--erts/test/Makefile9
-rw-r--r--erts/test/autoimport_SUITE.erl163
-rw-r--r--erts/test/autoimport_SUITE_data/dummy.txt19
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
index 7b824f1ab4..222809e662 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 3cab91b722..65c7369b76 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 9f88ddd51e..f1b54b7fcb 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 4c9cc9675b..abf17bcb0e 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 9a4904b6a1..a3f300268f 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index ac336c1b2d..a777971b32 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index c57d37725e..0fe38a1fb2 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 6b14d3fd66..7108bf44d0 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
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