aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/aclocal.m495
-rw-r--r--erts/doc/src/erlang.xml2
-rw-r--r--erts/doc/src/match_spec.xml52
-rw-r--r--erts/emulator/Makefile.in14
-rw-r--r--erts/emulator/beam/bif.c48
-rw-r--r--erts/emulator/beam/bif.tab2
-rw-r--r--erts/emulator/beam/erl_init.c53
-rw-r--r--erts/emulator/beam/erl_port_task.c8
-rw-r--r--erts/emulator/beam/erl_threads.h14
-rw-r--r--erts/emulator/beam/erl_trace.c4
-rw-r--r--erts/emulator/beam/global.h4
-rw-r--r--erts/emulator/beam/io.c26
-rw-r--r--erts/emulator/beam/register.c37
-rw-r--r--erts/emulator/beam/sys.h2
-rw-r--r--erts/emulator/drivers/win32/win_efile.c3
-rw-r--r--erts/emulator/sys/common/erl_poll.c58
-rw-r--r--erts/emulator/sys/unix/erl9_start.c130
-rw-r--r--erts/emulator/sys/win32/erl_poll.c65
-rw-r--r--erts/emulator/sys/win32/sys.c6
-rw-r--r--erts/emulator/test/binary_SUITE.erl10
-rw-r--r--erts/include/internal/ethread.h66
-rw-r--r--erts/include/internal/ethread_header_config.h.in23
-rw-r--r--erts/include/internal/gcc/ethr_atomic.h164
-rw-r--r--erts/include/internal/gcc/ethread.h30
-rw-r--r--erts/include/internal/i386/atomic.h20
-rw-r--r--erts/include/internal/ppc32/atomic.h11
-rw-r--r--erts/include/internal/sparc32/atomic.h14
-rw-r--r--erts/include/internal/tile/atomic.h2
-rw-r--r--erts/lib_src/Makefile.in2
-rw-r--r--erts/lib_src/common/ethread.c37
30 files changed, 613 insertions, 389 deletions
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 3d935b7295..61244c7cd3 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -512,6 +512,8 @@ dnl
AC_DEFUN(LM_CHECK_THR_LIB,
[
+NEED_NPTL_PTHREAD_H=no
+
dnl win32?
AC_MSG_CHECKING([for native win32 threads])
if test "X$host_os" = "Xwin32"; then
@@ -585,7 +587,9 @@ dnl On ofs1 the '-pthread' switch should be used
fi
if test $nptl = yes; then
need_nptl_incldir=no
- AC_CHECK_HEADER(nptl/pthread.h, need_nptl_incldir=yes)
+ AC_CHECK_HEADER(nptl/pthread.h,
+ [need_nptl_incldir=yes
+ NEED_NPTL_PTHREAD_H=yes])
if test $need_nptl_incldir = yes; then
# Ahh...
nptl_path="$C_INCLUDE_PATH:$CPATH"
@@ -799,6 +803,11 @@ case "$THR_LIB_NAME" in
AC_DEFINE(ETHR_HAVE_MIT_PTHREAD_H, 1, \
[Define if the pthread.h header file is in pthread/mit directory.]))
+ if test $NEED_NPTL_PTHREAD_H = yes; then
+ AC_DEFINE(ETHR_NEED_NPTL_PTHREAD_H, 1, \
+[Define if you need the <nptl/pthread.h> header file.])
+ fi
+
AC_CHECK_HEADER(sys/time.h, \
AC_DEFINE(ETHR_HAVE_SYS_TIME_H, 1, \
[Define if you have the <sys/time.h> header file.]))
@@ -826,23 +835,70 @@ case "$THR_LIB_NAME" in
AC_CHECK_FUNC(pthread_spin_lock, \
AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \
[Define if you have the pthread_spin_lock function.]))
- test "$force_linux_pthread_rwlocks" = "yes" || {
- force_linux_pthread_rwlocks=no
- }
- case "$force_linux_pthread_rwlocks-$host_os" in
- no-linux*) # Writers may get starved
- # TODO: write a test that tests the implementation
- ;;
- *)
- AC_CHECK_FUNC(pthread_rwlock_init, \
- AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_INIT, 1, \
-[Define if you have a pthread_rwlock implementation that can be used.]))
- ;;
- esac
+
+ have_pthread_rwlock_init=no
+ AC_CHECK_FUNC(pthread_rwlock_init, [have_pthread_rwlock_init=yes])
+ if test $have_pthread_rwlock_init = yes; then
+
+ AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_INIT, 1, \
+[Define if you have a pthread_rwlock implementation that can be used.])
+
+ ethr_have_pthread_rwlockattr_setkind_np=no
+ AC_CHECK_FUNC(pthread_rwlockattr_setkind_np,
+ [ethr_have_pthread_rwlockattr_setkind_np=yes])
+
+ if test $ethr_have_pthread_rwlockattr_setkind_np = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP, 1, \
+[Define if you have the pthread_rwlockattr_setkind_np() function.])
+
+ AC_MSG_CHECKING([for PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP])
+ ethr_pthread_rwlock_writer_nonrecursive_initializer_np=no
+ AC_TRY_LINK([
+ #if defined(ETHR_NEED_NPTL_PTHREAD_H)
+ #include <nptl/pthread.h>
+ #elif defined(ETHR_HAVE_MIT_PTHREAD_H)
+ #include <pthread/mit/pthread.h>
+ #elif defined(ETHR_HAVE_PTHREAD_H)
+ #include <pthread.h>
+ #endif
+ ],
+ [
+ pthread_rwlockattr_t *attr;
+ return pthread_rwlockattr_setkind_np(attr,
+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ ],
+ [ethr_pthread_rwlock_writer_nonrecursive_initializer_np=yes])
+ AC_MSG_RESULT([$ethr_pthread_rwlock_writer_nonrecursive_initializer_np])
+ if test $ethr_pthread_rwlock_writer_nonrecursive_initializer_np = yes; then
+ AC_DEFINE(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 1, \
+[Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock attribute.])
+ fi
+ fi
+ fi
+
+
+
AC_CHECK_FUNC(pthread_attr_setguardsize, \
AC_DEFINE(ETHR_HAVE_PTHREAD_ATTR_SETGUARDSIZE, 1, \
[Define if you have the pthread_attr_setguardsize function.]))
+ AC_MSG_CHECKING([for GCC atomic operations])
+ ethr_have_gcc_atomic_ops=no
+ AC_TRY_LINK([],
+ [
+ long res;
+ volatile long val;
+ res = __sync_val_compare_and_swap(&val, (long) 1, (long) 0);
+ res = __sync_add_and_fetch(&val, (long) 1);
+ res = __sync_sub_and_fetch(&val, (long) 1);
+ res = __sync_fetch_and_and(&val, (long) 1);
+ res = __sync_fetch_and_or(&val, (long) 1);
+ ],
+ [ethr_have_native_atomics=yes
+ ethr_have_gcc_atomic_ops=yes])
+ AC_MSG_RESULT([$ethr_have_gcc_atomic_ops])
+ test $ethr_have_gcc_atomic_ops = yes && AC_DEFINE(ETHR_HAVE_GCC_ATOMIC_OPS, 1, [Define if you have gcc atomic operations])
+
dnl Restore LIBS
LIBS=$saved_libs
dnl restore CPPFLAGS
@@ -873,6 +929,17 @@ if test "X$disable_native_ethr_impls" = "Xyes"; then
AC_DEFINE(ETHR_DISABLE_NATIVE_IMPLS, 1, [Define if you want to disable native ethread implementations])
fi
+AC_ARG_ENABLE(prefer-gcc-native-ethr-impls,
+ AS_HELP_STRING([--enable-prefer-gcc-native-ethr-impls],
+ [enable prefer gcc native ethread implementations]),
+[ case "$enableval" in
+ yes) enable_prefer_gcc_native_ethr_impls=yes ;;
+ *) enable_prefer_gcc_native_ethr_impls=no ;;
+ esac ], enable_prefer_gcc_native_ethr_impls=no)
+
+test $enable_prefer_gcc_native_ethr_impls = yes &&
+ AC_DEFINE(ETHR_PREFER_GCC_NATIVE_IMPLS, 1, [Define if you prefer gcc native ethread implementations])
+
AC_DEFINE(ETHR_HAVE_ETHREAD_DEFINES, 1, \
[Define if you have all ethread defines])
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index e683f161f1..c3c0dd77d7 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -407,7 +407,7 @@ iolist() = [char() | binary() | iolist()]
</desc>
</func>
<func>
- <name>erlang:binary_to_term(Binary, Opts) -> term()</name>
+ <name>binary_to_term(Binary, Opts) -> term()</name>
<fsummary>Decode an Erlang external term format binary</fsummary>
<type>
<v>Opts = [safe]</v>
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index d6492198ca..f0390c9db8 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -60,7 +60,7 @@
<section>
<title>Grammar</title>
- <p>A match_spec can be described in this <em>informal</em> grammar:</p>
+ <p>A match_spec used in tracing can be described in this <em>informal</em> grammar:</p>
<list type="bulleted">
<item>MatchExpression ::= [ MatchFunction, ... ]
</item>
@@ -117,6 +117,52 @@
<c><![CDATA[display]]></c> | <c><![CDATA[caller]]></c> | <c><![CDATA[set_tcw]]></c> |
<c><![CDATA[silent]]></c></item>
</list>
+
+ <p>A match_spec used in ets can be described in this <em>informal</em> grammar:</p>
+ <list type="bulleted">
+ <item>MatchExpression ::= [ MatchFunction, ... ]
+ </item>
+ <item>MatchFunction ::= { MatchHead, MatchConditions, MatchBody }
+ </item>
+ <item>MatchHead ::= MatchVariable | <c><![CDATA['_']]></c> | { MatchHeadPart, ... }
+ </item>
+ <item>MatchHeadPart ::= term() | MatchVariable | <c><![CDATA['_']]></c></item>
+ <item>MatchVariable ::= '$&lt;number&gt;'
+ </item>
+ <item>MatchConditions ::= [ MatchCondition, ...] | <c><![CDATA[[]]]></c></item>
+ <item>MatchCondition ::= { GuardFunction } |
+ { GuardFunction, ConditionExpression, ... }
+ </item>
+ <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_constant]]></c> |
+ <c><![CDATA[is_float]]></c> | <c><![CDATA[is_integer]]></c> | <c><![CDATA[is_list]]></c> |
+ <c><![CDATA[is_number]]></c> | <c><![CDATA[is_pid]]></c> | <c><![CDATA[is_port]]></c> |
+ <c><![CDATA[is_reference]]></c> | <c><![CDATA[is_tuple]]></c> | <c><![CDATA[is_binary]]></c> |
+ <c><![CDATA[is_function]]></c> | <c><![CDATA[is_record]]></c> | <c><![CDATA[is_seq_trace]]></c> |
+ <c><![CDATA['and']]></c> | <c><![CDATA['or']]></c> | <c><![CDATA['not']]></c> | <c><![CDATA['xor']]></c> |
+ <c><![CDATA[andalso]]></c> | <c><![CDATA[orelse]]></c></item>
+ <item>ConditionExpression ::= ExprMatchVariable | { GuardFunction } |
+ { GuardFunction, ConditionExpression, ... } | TermConstruct
+ </item>
+ <item>ExprMatchVariable ::= MatchVariable (bound in the MatchHead) |
+ <c><![CDATA['$_']]></c> | <c><![CDATA['$$']]></c></item>
+ <item>TermConstruct = {{}} | {{ ConditionExpression, ... }} |
+ <c><![CDATA[[]]]></c> | [ConditionExpression, ...] | NonCompositeTerm | Constant
+ </item>
+ <item>NonCompositeTerm ::= term() (not list or tuple)
+ </item>
+ <item>Constant ::= {<c><![CDATA[const]]></c>, term()}
+ </item>
+ <item>GuardFunction ::= BoolFunction | <c><![CDATA[abs]]></c> |
+ <c><![CDATA[element]]></c> | <c><![CDATA[hd]]></c> | <c><![CDATA[length]]></c> | <c><![CDATA[node]]></c> |
+ <c><![CDATA[round]]></c> | <c><![CDATA[size]]></c> | <c><![CDATA[tl]]></c> | <c><![CDATA[trunc]]></c> |
+ <c><![CDATA['+']]></c> | <c><![CDATA['-']]></c> | <c><![CDATA['*']]></c> | <c><![CDATA['div']]></c> |
+ <c><![CDATA['rem']]></c> | <c><![CDATA['band']]></c> | <c><![CDATA['bor']]></c> | <c><![CDATA['bxor']]></c> |
+ <c><![CDATA['bnot']]></c> | <c><![CDATA['bsl']]></c> | <c><![CDATA['bsr']]></c> | <c><![CDATA['>']]></c> |
+ <c><![CDATA['>=']]></c> | <c><![CDATA['<']]></c> | <c><![CDATA['=<']]></c> | <c><![CDATA['=:=']]></c> |
+ <c><![CDATA['==']]></c> | <c><![CDATA['=/=']]></c> | <c><![CDATA['/=']]></c> | <c><![CDATA[self]]></c> |
+ <c><![CDATA[get_tcw]]></c></item>
+ <item>MatchBody ::= [ ConditionExpression, ... ]</item>
+ </list>
</section>
<section>
@@ -453,8 +499,8 @@
<section>
<title>Differences between match specifications in ETS and tracing</title>
<p>ETS match specifications are there to produce a return
- value. Usually the expression contains one single
- <c><![CDATA[ActionTerm]]></c> which defines the return value without having
+ value. Usually the <c><![CDATA[MatchBody]]></c> contains one single
+ <c><![CDATA[ConditionExpression]]></c> which defines the return value without having
any side effects. Calls with side effects are not allowed in the
ETS context.</p>
<p>When tracing there is no return value to produce, the
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index d767194d4d..eca6121a1e 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -341,7 +341,6 @@ ERLANG_OSTYPE = @ERLANG_OSTYPE@
ENABLE_ALLOC_TYPE_VARS += @ERLANG_OSTYPE@
-EMULATOR_EXECUTABLE_SAE = beam_evm$(TF_MARKER)
EMULATOR_EXECUTABLE_ELIB = beam.elib$(TF_MARKER)
ifeq ($(TARGET), win32)
EMULATOR_EXECUTABLE = beam$(TF_MARKER).dll
@@ -406,7 +405,7 @@ endif
@set -e ; cd zlib && $(MAKE) clean
@set -e ; cd pcre && $(MAKE) clean
-.PHONY: all sae zlib pcre clean
+.PHONY: all zlib pcre clean
docs:
@@ -640,10 +639,6 @@ $(BINDIR)/$(CS_EXECUTABLE): $(CS_SRC)
$(OBJDIR)/%.elib.o: beam/%.c
$(CC) $(ELIB_FLAGS) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
-# Disable vfork() for sae (then we don't need the child_setup program)
-$(OBJDIR)/sys_sae.o: sys/$(ERLANG_OSTYPE)/sys.c
- $(CC) -DDISABLE_VFORK=1 $(CFLAGS) $(INCLUDES) -c $< -o $@
-
$(OBJDIR)/%.kp.o: sys/common/%.c
$(CC) -DERTS_KERNEL_POLL_VERSION $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@
@@ -689,8 +684,6 @@ endif
INIT_OBJS = $(OBJDIR)/erl_main.o $(PRELOAD)
-INIT_OBJS_SAE = $(OBJDIR)/erl9_start.o
-
EMU_OBJS = \
$(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \
$(OBJDIR)/beam_load.o $(OBJDIR)/beam_bif_load.o \
@@ -826,7 +819,6 @@ endif
BASE_OBJS = $(RUN_OBJS) $(EMU_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS)
OBJS = $(BASE_OBJS) $(DRV_OBJS)
-OBJS_SAE = $(subst sys.o,sys_sae.o,$(OBJS))
ELIB_C_FILES = beam/elib_malloc.c \
beam/elib_memmove.c \
@@ -933,10 +925,6 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE_ELIB): $(INIT_OBJS) $(OBJS_ELIB) $(DEPLIBS)
$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE_ELIB) \
$(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS_ELIB) $(LIBS)
-$(BINDIR)/$(EMULATOR_EXECUTABLE_SAE): $(INIT_OBJS_SAE) $(OBJS_SAE) $(DEPLIBS)
- $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE_SAE) \
- $(LDFLAGS) $(DEXPORT) $(INIT_OBJS_SAE) $(OBJS_SAE) $(LIBS)
-
endif
#
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 85bf584337..10cc2e9003 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4143,54 +4143,6 @@ void erts_init_bif(void)
await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3);
}
-BIF_RETTYPE blocking_read_file_1(BIF_ALIST_1)
-{
- Eterm bin;
- Eterm* hp;
- byte *buff;
- int i, buff_size;
- FILE *file;
- struct stat file_info;
- char *filename = NULL;
- size_t size;
-
- i = list_length(BIF_ARG_1);
- if (i < 0) {
- BIF_ERROR(BIF_P, BADARG);
- }
- filename = erts_alloc(ERTS_ALC_T_TMP, i + 1);
- if (intlist_to_buf(BIF_ARG_1, filename, i) != i)
- erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__);
- filename[i] = '\0';
-
- hp = HAlloc(BIF_P, 3);
-
- file = fopen(filename, "r");
- if(file == NULL){
- erts_free(ERTS_ALC_T_TMP, (void *) filename);
- BIF_RET(TUPLE2(hp, am_error, am_nofile));
- }
-
- stat(filename, &file_info);
- erts_free(ERTS_ALC_T_TMP, (void *) filename);
-
- buff_size = file_info.st_size;
- buff = (byte *) erts_alloc_fnf(ERTS_ALC_T_TMP, buff_size);
- if (!buff) {
- fclose(file);
- BIF_RET(TUPLE2(hp, am_error, am_allocator));
- }
- size = fread(buff, 1, buff_size, file);
- fclose(file);
- if (size < 0)
- size = 0;
- else if (size > buff_size)
- size = (size_t) buff_size;
- bin = new_binary(BIF_P, buff, (int) size);
- erts_free(ERTS_ALC_T_TMP, (void *) buff);
-
- BIF_RET(TUPLE2(hp, am_ok, bin));
-}
#ifdef HARDDEBUG
/*
You'll need this line in bif.tab to be able to use this debug bif
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 9feb302a3d..38e2dd77d3 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -686,8 +686,6 @@ bif 'erl.system.code':make_stub_module/3 ebif_code_make_stub_module_3
bif code:is_module_native/1
bif 'erl.system.code':is_native/1 ebif_code_is_native_1 code_is_module_native_1
-bif erlang:blocking_read_file/1
-
#
# New Bifs in R9C.
#
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index f2e71ae98d..2ee802cf3e 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -336,59 +336,6 @@ init_shared_memory(int argc, char **argv)
#endif
}
-
-/*
- * Create the very first process.
- */
-
-void
-erts_first_process(Eterm modname, void* code, unsigned size, int argc, char** argv)
-{
- int i;
- Eterm args;
- Eterm pid;
- Eterm* hp;
- Process parent;
- Process* p;
- ErlSpawnOpts so;
-
- if (erts_find_function(modname, am_start, 1) == NULL) {
- char sbuf[256];
- Atom* ap;
-
- ap = atom_tab(atom_val(modname));
- memcpy(sbuf, ap->name, ap->len);
- sbuf[ap->len] = '\0';
- erl_exit(5, "No function %s:start/1\n", sbuf);
- }
-
- /*
- * We need a dummy parent process to be able to call erl_create_process().
- */
- erts_init_empty_process(&parent);
- hp = HAlloc(&parent, argc*2 + 4);
- args = NIL;
- for (i = argc-1; i >= 0; i--) {
- int len = sys_strlen(argv[i]);
- args = CONS(hp, new_binary(&parent, (byte*)argv[i], len), args);
- hp += 2;
- }
- args = CONS(hp, new_binary(&parent, code, size), args);
- hp += 2;
- args = CONS(hp, args, NIL);
-
- so.flags = 0;
- pid = erl_create_process(&parent, modname, am_start, args, &so);
- p = process_tab[internal_pid_index(pid)];
- p->group_leader = pid;
-
- erts_cleanup_empty_process(&parent);
-}
-
-/*
- * XXX Old way of starting. Hopefully soon obsolete.
- */
-
static void
erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** argv)
{
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 0b6bb0d8e9..967a14f0d1 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -969,11 +969,11 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
erts_port_release(pp);
#else
{
- long refc = erts_smp_atomic_dectest(&pp->refc);
+ long refc;
+ erts_smp_mtx_unlock(pp->lock);
+ refc = erts_smp_atomic_dectest(&pp->refc);
ASSERT(refc >= 0);
- if (refc > 0)
- erts_smp_mtx_unlock(pp->lock);
- else {
+ if (refc == 0) {
erts_smp_runq_unlock(runq);
erts_port_cleanup(pp); /* Might aquire runq lock */
erts_smp_runq_lock(runq);
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index d635916dd8..21f85bd045 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2001-2009. All Rights Reserved.
- *
+ *
+ * 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%
*/
@@ -34,6 +34,8 @@
#include "erl_lock_count.h"
#include "erl_term.h"
+#define ERTS_THR_MEMORY_BARRIER ETHR_MEMORY_BARRIER
+
#ifdef ERTS_ENABLE_LOCK_COUNT
#define erts_mtx_lock(L) erts_mtx_lock_x(L, __FILE__, __LINE__)
#define erts_spin_lock(L) erts_spin_lock_x(L, __FILE__, __LINE__)
@@ -122,6 +124,8 @@ __decl_noreturn void __noreturn erts_thr_fatal_error(int, char *);
#else /* #ifdef USE_THREADS */
+#define ERTS_THR_MEMORY_BARRIER
+
#define ERTS_THR_OPTS_DEFAULT_INITER 0
typedef int erts_thr_opts_t;
typedef int erts_thr_init_data_t;
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 8addfcf5ad..381a182e39 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1941,11 +1941,13 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
Eterm* hp;
int need;
+ ERTS_SMP_LC_ASSERT((erts_proc_lc_my_proc_locks(t_p) != 0) || erts_is_system_blocked(0));
if (is_internal_port(t_p->tracer_proc)) {
#define LOCAL_HEAP_SIZE (5+5)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+
hp = local_heap;
mess = TUPLE4(hp, am_trace, t_p->id, what, data);
hp += 5;
@@ -2727,6 +2729,8 @@ trace_port(Port *t_p, Eterm what, Eterm data) {
Eterm mess;
Eterm* hp;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p) || erts_is_system_blocked(0));
+
if (is_internal_port(t_p->tracer_proc)) {
#define LOCAL_HEAP_SIZE (5+5)
DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index a7990e1799..d5d63631ff 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1192,12 +1192,11 @@ erts_smp_port_unlock(Port *prt)
{
#ifdef ERTS_SMP
long refc;
+ erts_smp_mtx_unlock(prt->lock);
refc = erts_smp_atomic_dectest(&prt->refc);
ASSERT(refc >= 0);
if (refc == 0)
erts_port_cleanup(prt);
- else
- erts_smp_mtx_unlock(prt->lock);
#endif
}
@@ -1720,7 +1719,6 @@ int erts_print_system_version(int to, void *arg, Process *c_p);
* Interface to erl_init
*/
void erl_init(void);
-void erts_first_process(Eterm modname, void* code, unsigned size, int argc, char** argv);
#define seq_trace_output(token, msg, type, receiver, process) \
seq_trace_output_generic((token), (msg), (type), (receiver), (process), NIL)
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 10f1082039..68625801cf 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -280,10 +280,36 @@ erts_test_next_port(int set, Uint next)
return res;
}
+
+static void port_cleanup(Port *prt);
+
+#ifdef ERTS_SMP
+
+static void
+sched_port_cleanup(void *vprt)
+{
+ Port *prt = (Port *) vprt;
+ erts_smp_mtx_lock(prt->lock);
+ port_cleanup(prt);
+}
+
+#endif
+
void
erts_port_cleanup(Port *prt)
{
#ifdef ERTS_SMP
+ if (erts_smp_mtx_trylock(prt->lock) == EBUSY)
+ erts_schedule_misc_op(sched_port_cleanup, (void *) prt);
+ else
+#endif
+ port_cleanup(prt);
+}
+
+void
+port_cleanup(Port *prt)
+{
+#ifdef ERTS_SMP
Uint32 port_specific;
erts_smp_mtx_t *mtx;
#endif
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index 964c10a380..900ebcbbf7 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -476,8 +476,9 @@ int erts_unregister_name(Process *c_p,
* on c_prt.
*/
- if (!c_p)
+ if (!c_p) {
c_p_locks = 0;
+ }
current_c_p_locks = c_p_locks;
restart:
@@ -489,9 +490,15 @@ int erts_unregister_name(Process *c_p,
if (is_non_value(name)) {
/* Unregister current process name */
ASSERT(c_p);
- if (c_p->reg)
+#ifdef ERTS_SMP
+ if (current_c_p_locks != c_p_locks) {
+ erts_smp_proc_lock(c_p, c_p_locks);
+ current_c_p_locks = c_p_locks;
+ }
+#endif
+ if (c_p->reg) {
r.name = c_p->reg->name;
- else {
+ } else {
/* Name got unregistered while main lock was released */
res = 0;
goto done;
@@ -533,24 +540,25 @@ int erts_unregister_name(Process *c_p,
}
} else if (rp->p) {
- Process* p = rp->p;
+
#ifdef ERTS_SMP
erts_proc_safelock(c_p,
current_c_p_locks,
c_p_locks,
rp->p,
- 0,
+ (c_p == rp->p) ? current_c_p_locks : 0,
ERTS_PROC_LOCK_MAIN);
current_c_p_locks = c_p_locks;
#endif
- p->reg = NULL;
+ rp->p->reg = NULL;
+ if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) {
+ trace_proc(c_p, rp->p, am_unregister, r.name);
+ }
#ifdef ERTS_SMP
- if (rp->p != c_p)
+ if (rp->p != c_p) {
erts_smp_proc_unlock(rp->p, ERTS_PROC_LOCK_MAIN);
-#endif
- if (IS_TRACED_FL(p, F_TRACE_PROCS)) {
- trace_proc(c_p, p, am_unregister, r.name);
}
+#endif
}
hash_erase(&process_reg, (void*) &r);
res = 1;
@@ -560,14 +568,17 @@ int erts_unregister_name(Process *c_p,
reg_write_unlock();
if (c_prt != port) {
- if (port)
+ if (port) {
erts_smp_port_unlock(port);
- if (c_prt)
+ }
+ if (c_prt) {
erts_smp_port_lock(c_prt);
+ }
}
#ifdef ERTS_SMP
- if (c_p && !current_c_p_locks)
+ if (c_p && !current_c_p_locks) {
erts_smp_proc_lock(c_p, c_p_locks);
+ }
#endif
return res;
}
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 0f20d36167..ca87d3d70f 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -648,7 +648,7 @@ extern char *erts_sys_ddll_error(int code);
/*
- * System interfaces for startup/sae code (functions found in respective sys.c)
+ * System interfaces for startup.
*/
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index d5f2b79706..24b6fb30dc 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -689,7 +689,8 @@ Sint64* pSize; /* Where to store the size of the file. */
if (flags & EFILE_MODE_APPEND) {
crFlags = OPEN_ALWAYS;
}
- fd = CreateFile(name, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ fd = CreateFile(name, access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL);
/*
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index d268547e1a..09fb6337f7 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -130,13 +130,18 @@
#define ERTS_POLLSET_IS_POLLED(PS) \
((int) erts_smp_atomic_read(&(PS)->polled))
-#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) \
- ((int) erts_smp_atomic_xchg(&(PS)->woken, (long) 1))
-#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \
- erts_smp_atomic_set(&(PS)->woken, (long) 1)
-#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \
- erts_smp_atomic_set(&(PS)->woken, (long) 0)
-#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \
+#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) set_poller_woken_chk((PS))
+#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \
+do { \
+ ERTS_THR_MEMORY_BARRIER; \
+ erts_smp_atomic_set(&(PS)->woken, (long) 1); \
+} while (0)
+#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \
+do { \
+ erts_smp_atomic_set(&(PS)->woken, (long) 0); \
+ ERTS_THR_MEMORY_BARRIER; \
+} while (0)
+#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \
((int) erts_smp_atomic_read(&(PS)->woken))
#else
@@ -194,13 +199,18 @@
#else
-#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) \
- ((int) erts_smp_atomic_xchg(&(PS)->interrupt, (long) 0))
-#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \
- erts_smp_atomic_set(&(PS)->interrupt, (long) 0)
-#define ERTS_POLLSET_SET_INTERRUPTED(PS) \
- erts_smp_atomic_set(&(PS)->interrupt, (long) 1)
-#define ERTS_POLLSET_IS_INTERRUPTED(PS) \
+#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) unset_interrupted_chk((PS))
+#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \
+do { \
+ erts_smp_atomic_set(&(PS)->interrupt, (long) 0); \
+ ERTS_THR_MEMORY_BARRIER; \
+} while (0)
+#define ERTS_POLLSET_SET_INTERRUPTED(PS) \
+do { \
+ ERTS_THR_MEMORY_BARRIER; \
+ erts_smp_atomic_set(&(PS)->interrupt, (long) 1); \
+} while (0)
+#define ERTS_POLLSET_IS_INTERRUPTED(PS) \
((int) erts_smp_atomic_read(&(PS)->interrupt))
#endif
@@ -336,16 +346,30 @@ struct ErtsPollSet_ {
#endif
};
-#if ERTS_POLL_ASYNC_INTERRUPT_SUPPORT && !defined(ERTS_SMP)
-
static ERTS_INLINE int
unset_interrupted_chk(ErtsPollSet ps)
{
+ int res;
+#if ERTS_POLL_ASYNC_INTERRUPT_SUPPORT && !defined(ERTS_SMP)
/* This operation isn't atomic, but we have no need at all for an
atomic operation here... */
- int res = ps->interrupt;
+ res = ps->interrupt;
ps->interrupt = 0;
+#else
+ res = (int) erts_smp_atomic_xchg(&ps->interrupt, (long) 0);
+ ERTS_THR_MEMORY_BARRIER;
+#endif
return res;
+
+}
+
+#ifdef ERTS_SMP
+
+static ERTS_INLINE int
+set_poller_woken_chk(ErtsPollSet ps)
+{
+ ERTS_THR_MEMORY_BARRIER;
+ return (int) erts_smp_atomic_xchg(&ps->woken, (long) 1);
}
#endif
diff --git a/erts/emulator/sys/unix/erl9_start.c b/erts/emulator/sys/unix/erl9_start.c
deleted file mode 100644
index 578062d7e2..0000000000
--- a/erts/emulator/sys/unix/erl9_start.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2009. 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 HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include "sys.h"
-#include "erl_vm.h"
-#include "global.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-/*
- * XXX This is a temporary dummy to make sys.c happy until we'll rewrite it.
- */
-unsigned preloaded_size_ring0 = 1;
-unsigned char preloaded_ring0[1] = {0};
-
-Preload pre_loaded[] = {
- {"ring0", 1, preloaded_ring0},
- {0, 0, 0}
-};
-
-int
-main(int argc, char** argv)
-{
- char sbuf[1024];
- struct {
- void* p;
- int sz;
- } bins[2];
- int bin_num = 0;
- FILE* fp;
- char* progname = argv[0];
- char* eq;
-
- argv++, argc--;
-
- if (argc > 0 && argv[0][0] == '-') {
- argv++, argc--;
- }
- if (argc < 1) {
- abort();
- }
- if ((fp = fopen(argv[0], "r")) == NULL) {
- abort();
- }
-
- /* Needs to be called before any memory allocation */
- erts_short_init();
-
- while (fgets(sbuf, sizeof sbuf, fp)) {
- if (sbuf[0] == '#') {
- continue; /* Comment */
- } else if (sbuf[0] == 'e' && strncmp("exec", sbuf, 4) == 0) {
- continue; /* Comment ;-) */
- } else if ((eq = strchr(sbuf, '=')) != NULL) {
- char* val;
- char* p = strchr(sbuf, '\n');
- if (p) {
- *p = '\0';
- }
- *eq = '\0';
- val = erts_read_env(sbuf);
- if (val == NULL) {
- *eq = '=';
- erts_sys_putenv(sbuf, eq - &sbuf[0]);
- }
- erts_free_read_env(val);
- } else if (sbuf[0] == ':' && '0' <= sbuf[1] && sbuf[1] <= '9') {
- int load_size = atoi(sbuf+1);
- void* bin;
-
- bin = malloc(load_size);
- if (fread(bin, 1, load_size, fp) != load_size) {
- abort();
- }
- bins[bin_num].p = bin;
- bins[bin_num].sz = load_size;
- bin_num++;
- } else if (strcmp(sbuf, "--end--\n") == 0) {
- int rval;
- Eterm mod = NIL;
- char *val;
-
- fclose(fp);
-
- if (bin_num != 2) {
- abort();
- }
-
- val = erts_read_env("ERLBREAKHANDLER");
- if (val) {
- init_break_handler();
- }
- erts_free_read_env(val);
-
- if ((rval = erts_load_module(NULL, 0, NIL, &mod, bins[0].p, bins[0].sz)) < 0) {
- fprintf(stderr, "%s: Load of initial module failed: %d\n",
- progname, rval);
- abort();
- }
- erts_first_process(mod, bins[1].p, bins[1].sz, argc, argv);
- free(bins[0].p);
- free(bins[1].p);
- process_main();
- abort();
- } else {
- fprintf(stderr, "%s: bad line: %s\n", progname, sbuf);
- abort();
- }
- }
- abort();
-}
diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c
index d816cc2c07..a766fe9575 100644
--- a/erts/emulator/sys/win32/erl_poll.c
+++ b/erts/emulator/sys/win32/erl_poll.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2007-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2007-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 HAVE_CONFIG_H
@@ -304,24 +304,51 @@ struct ErtsPollSet_ {
erts_smp_atomic_set(&(PS)->polled, (long) 0)
#define ERTS_POLLSET_IS_POLLED(PS) \
((int) erts_smp_atomic_read(&(PS)->polled))
-#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) \
- ((int) erts_smp_atomic_xchg(&(PS)->woken, (long) 1))
-#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \
- erts_smp_atomic_set(&(PS)->woken, (long) 1)
-#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \
- erts_smp_atomic_set(&(PS)->woken, (long) 0)
-#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \
+
+#define ERTS_POLLSET_SET_POLLER_WOKEN_CHK(PS) set_poller_woken_chk((PS))
+#define ERTS_POLLSET_SET_POLLER_WOKEN(PS) \
+do { \
+ ERTS_THR_MEMORY_BARRIER; \
+ erts_smp_atomic_set(&(PS)->woken, (long) 1); \
+} while (0)
+#define ERTS_POLLSET_UNSET_POLLER_WOKEN(PS) \
+do { \
+ erts_smp_atomic_set(&(PS)->woken, (long) 0); \
+ ERTS_THR_MEMORY_BARRIER; \
+} while (0)
+#define ERTS_POLLSET_IS_POLLER_WOKEN(PS) \
((int) erts_smp_atomic_read(&(PS)->woken))
-#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) \
- ((int) erts_smp_atomic_xchg(&(PS)->interrupt, (long) 0))
-#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \
- erts_smp_atomic_set(&(PS)->interrupt, (long) 0)
-#define ERTS_POLLSET_SET_INTERRUPTED(PS) \
- erts_smp_atomic_set(&(PS)->interrupt, (long) 1)
-#define ERTS_POLLSET_IS_INTERRUPTED(PS) \
+#define ERTS_POLLSET_UNSET_INTERRUPTED_CHK(PS) unset_interrupted_chk((PS))
+#define ERTS_POLLSET_UNSET_INTERRUPTED(PS) \
+do { \
+ erts_smp_atomic_set(&(PS)->interrupt, (long) 0); \
+ ERTS_THR_MEMORY_BARRIER; \
+} while (0)
+#define ERTS_POLLSET_SET_INTERRUPTED(PS) \
+do { \
+ ERTS_THR_MEMORY_BARRIER; \
+ erts_smp_atomic_set(&(PS)->interrupt, (long) 1); \
+} while (0)
+#define ERTS_POLLSET_IS_INTERRUPTED(PS) \
((int) erts_smp_atomic_read(&(PS)->interrupt))
+static ERTS_INLINE int
+unset_interrupted_chk(ErtsPollSet ps)
+{
+ int res = (int) erts_smp_atomic_xchg(&ps->interrupt, (long) 0);
+ ERTS_THR_MEMORY_BARRIER;
+ return res;
+
+}
+
+static ERTS_INLINE int
+set_poller_woken_chk(ErtsPollSet ps)
+{
+ ERTS_THR_MEMORY_BARRIER;
+ return (int) erts_smp_atomic_xchg(&ps->woken, (long) 1);
+}
+
#else
#define ERTS_POLLSET_LOCK(PS)
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index 65719a91d6..d3921a14f8 100644
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -3010,12 +3010,6 @@ erts_sys_pre_init(void)
erts_sys_env_init();
}
-/*
- * the last two only used for standalone erlang
- * they should are used by sae_main in beam dll to
- * enable standalone execution via erl_api-routines
- */
-
void noinherit_std_handle(DWORD type)
{
HANDLE h = GetStdHandle(type);
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 7ecc31aa29..77d2579848 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -438,11 +438,11 @@ terms(Config) when is_list(Config) ->
ok
end,
Term = binary_to_term(Bin),
- Term = erlang:binary_to_term(Bin, [safe]),
+ Term = binary_to_term(Bin, [safe]),
Unaligned = make_unaligned_sub_binary(Bin),
Term = binary_to_term(Unaligned),
- Term = erlang:binary_to_term(Unaligned, []),
- Term = erlang:binary_to_term(Bin, [safe]),
+ Term = binary_to_term(Unaligned, []),
+ Term = binary_to_term(Bin, [safe]),
BinC = erlang:term_to_binary(Term, [compressed]),
Term = binary_to_term(BinC),
true = size(BinC) =< size(Bin),
@@ -542,7 +542,7 @@ bad_bin_to_term(BadBin) ->
{'EXIT',{badarg,_}} = (catch binary_to_term(BadBin)).
bad_bin_to_term(BadBin,Opts) ->
- {'EXIT',{badarg,_}} = (catch erlang:binary_to_term(BadBin,Opts)).
+ {'EXIT',{badarg,_}} = (catch binary_to_term(BadBin,Opts)).
safe_binary_to_term2(doc) -> "Test safety options for binary_to_term/2";
safe_binary_to_term2(Config) when is_list(Config) ->
@@ -553,7 +553,7 @@ safe_binary_to_term2(Config) when is_list(Config) ->
BadRef = <<131,114,0,3,BadHostAtom/binary,0,<<0,0,0,255>>/binary,
Empty/binary,Empty/binary>>,
?line bad_bin_to_term(BadRef, [safe]), % good ref, with a bad atom
- ?line fullsweep_after = erlang:binary_to_term(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
+ ?line fullsweep_after = binary_to_term(<<131,100,0,15,"fullsweep_after">>, [safe]), % should be a good atom
BadExtFun = <<131,113,100,0,4,98,108,117,101,100,0,4,109,111,111,110,97,3>>,
?line bad_bin_to_term(BadExtFun, [safe]),
ok.
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index 934a79c6f9..4e7a38cd5c 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2004-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%
*/
@@ -375,6 +375,12 @@ ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
#define ETHR_HAVE_OPTIMIZED_LOCKS 1
+#define ETHR_MEMORY_BARRIER \
+do { \
+ volatile LONG x___ = 0; \
+ (void) _InterlockedCompareExchange(&x___, (LONG) 1, (LONG) 0); \
+} while (0)
+
typedef struct {
volatile LONG value;
} ethr_atomic_t;
@@ -688,25 +694,33 @@ ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
#endif
/* For CPU-optimised atomics, spinlocks, and rwlocks. */
-#if !defined(ETHR_DISABLE_NATIVE_IMPLS) && defined(__GNUC__)
-# if ETHR_SIZEOF_PTR == 4
-# if defined(__i386__)
-# include "i386/ethread.h"
-# elif (defined(__powerpc__) || defined(__ppc__)) && !defined(__powerpc64__)
-# include "ppc32/ethread.h"
-# elif defined(__sparc__)
-# include "sparc32/ethread.h"
-# elif defined(__tile__)
-# include "tile/ethread.h"
+#if !defined(ETHR_DISABLE_NATIVE_IMPLS)
+# if defined(__GNUC__)
+# if defined(ETHR_PREFER_GCC_NATIVE_IMPLS)
+# include "gcc/ethread.h"
# endif
-# elif ETHR_SIZEOF_PTR == 8
-# if defined(__x86_64__)
-# include "x86_64/ethread.h"
-# elif defined(__sparc__) && defined(__arch64__)
-# include "sparc64/ethread.h"
+# ifndef ETHR_HAVE_NATIVE_ATOMICS
+# if ETHR_SIZEOF_PTR == 4
+# if defined(__i386__)
+# include "i386/ethread.h"
+# elif (defined(__powerpc__)||defined(__ppc__))&&!defined(__powerpc64__)
+# include "ppc32/ethread.h"
+# elif defined(__sparc__)
+# include "sparc32/ethread.h"
+# elif defined(__tile__)
+# include "tile/ethread.h"
+# endif
+# elif ETHR_SIZEOF_PTR == 8
+# if defined(__x86_64__)
+# include "x86_64/ethread.h"
+# elif defined(__sparc__) && defined(__arch64__)
+# include "sparc64/ethread.h"
+# endif
+# endif
+# include "gcc/ethread.h"
# endif
# endif
-#endif /* !defined(ETHR_DISABLE_NATIVE_IMPLS) && defined(__GNUC__) */
+#endif /* !defined(ETHR_DISABLE_NATIVE_IMPLS) */
#ifdef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
# undef ETHR_HAVE_NATIVE_ATOMICS
@@ -1124,8 +1138,14 @@ ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
*/
#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
-#define ETHR_ATOMIC_ADDR_BITS 4
-#define ETHR_ATOMIC_ADDR_SHIFT 3
+/*
+ * ETHR_MEMORY_BARRIER orders between locked and atomic accesses only,
+ * i.e. when this atomic fallback is used a noop is sufficient.
+ */
+#define ETHR_MEMORY_BARRIER
+
+#define ETHR_ATOMIC_ADDR_BITS 10
+#define ETHR_ATOMIC_ADDR_SHIFT 6
typedef struct {
union {
diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in
index e5b4946a53..c9fd87c2f6 100644
--- a/erts/include/internal/ethread_header_config.h.in
+++ b/erts/include/internal/ethread_header_config.h.in
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2004-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%
*/
@@ -50,6 +50,19 @@
/* Define if you have a pthread_rwlock implementation that can be used */
#undef ETHR_HAVE_PTHREAD_RWLOCK_INIT
+/* Define if you have the pthread_rwlockattr_setkind_np() function. */
+#undef ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP
+
+/* Define if you have the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP rwlock
+ attribute. */
+#undef ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+
+/* Define if you have gcc atomic operations */
+#undef ETHR_HAVE_GCC_ATOMIC_OPS
+
+/* Define if you prefer gcc native ethread implementations */
+#undef ETHR_PREFER_GCC_NATIVE_IMPLS
+
/* Define if you want to turn on extra sanity checking in the ethread library */
#undef ETHR_XCHK
diff --git a/erts/include/internal/gcc/ethr_atomic.h b/erts/include/internal/gcc/ethr_atomic.h
new file mode 100644
index 0000000000..775030c8d5
--- /dev/null
+++ b/erts/include/internal/gcc/ethr_atomic.h
@@ -0,0 +1,164 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 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%
+ */
+
+/*
+ * Description: Native atomics ethread support using gcc's builtins
+ * Author: Rickard Green
+ */
+
+#ifndef ETHR_GCC_ATOMIC_H__
+#define ETHR_GCC_ATOMIC_H__
+
+#if !defined(ETHR_HAVE_NATIVE_ATOMICS) && defined(ETHR_HAVE_GCC_ATOMIC_OPS)
+#define ETHR_HAVE_NATIVE_ATOMICS 1
+
+#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__)
+# undef ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+# define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
+#endif
+
+typedef struct {
+ volatile long counter;
+} ethr_native_atomic_t;
+
+
+/*
+ * According to the documentation this is what we want:
+ * #define ETHR_MEMORY_BARRIER __sync_synchronize()
+ * However, __sync_synchronize() is known to erroneously be
+ * 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.
+ */
+#define ETHR_MEMORY_BARRIER \
+do { \
+ volatile long x___ = 0; \
+ (void) __sync_val_compare_and_swap(&x___, (long) 0, (long) 1); \
+} while (0)
+
+#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
+
+static ETHR_INLINE void
+ethr_native_atomic_set(ethr_native_atomic_t *var, long value)
+{
+#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+ var->counter = value;
+#else
+ /*
+ * Unfortunately no __sync_store() or similar exist in the gcc atomic
+ * op interface. We therefore have to simulate it this way...
+ */
+ long act = 0, exp;
+ do {
+ exp = act;
+ act = __sync_val_compare_and_swap(&var->counter, exp, value);
+ } while (act != exp);
+#endif
+}
+
+#define ethr_native_atomic_init ethr_native_atomic_set
+
+static ETHR_INLINE long
+ethr_native_atomic_read(ethr_native_atomic_t *var)
+{
+#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
+ return var->counter;
+#else
+ /*
+ * Unfortunately no __sync_fetch() or similar exist in the gcc atomic
+ * op interface. We therefore have to simulate it this way...
+ */
+ return __sync_add_and_fetch(&var->counter, (long) 0);
+#endif
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_add(ethr_native_atomic_t *var, long incr)
+{
+ (void) __sync_add_and_fetch(&var->counter, incr);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_add_return(ethr_native_atomic_t *var, long incr)
+{
+ return __sync_add_and_fetch(&var->counter, incr);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_inc(ethr_native_atomic_t *var)
+{
+ (void) __sync_add_and_fetch(&var->counter, (long) 1);
+}
+
+static ETHR_INLINE void
+ethr_native_atomic_dec(ethr_native_atomic_t *var)
+{
+ (void) __sync_sub_and_fetch(&var->counter, (long) 1);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_inc_return(ethr_native_atomic_t *var)
+{
+ return __sync_add_and_fetch(&var->counter, (long) 1);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_dec_return(ethr_native_atomic_t *var)
+{
+ return __sync_sub_and_fetch(&var->counter, (long) 1);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_and_retold(ethr_native_atomic_t *var, long mask)
+{
+ return __sync_fetch_and_and(&var->counter, mask);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_or_retold(ethr_native_atomic_t *var, long mask)
+{
+ return (long) __sync_fetch_and_or(&var->counter, mask);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_cmpxchg(ethr_native_atomic_t *var, long new, long old)
+{
+ return __sync_val_compare_and_swap(&var->counter, old, new);
+}
+
+static ETHR_INLINE long
+ethr_native_atomic_xchg(ethr_native_atomic_t *var, long new)
+{
+ long exp, act = 0;
+ do {
+ exp = act;
+ act = __sync_val_compare_and_swap(&var->counter, exp, new);
+ } while (act != exp);
+ return act;
+}
+
+#endif
+
+#endif
+
+#endif
diff --git a/erts/include/internal/gcc/ethread.h b/erts/include/internal/gcc/ethread.h
new file mode 100644
index 0000000000..bb378e31e0
--- /dev/null
+++ b/erts/include/internal/gcc/ethread.h
@@ -0,0 +1,30 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 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%
+ */
+
+/*
+ * Description: Native atomic ethread support when using gcc
+ * Author: Rickard Green
+ */
+
+#ifndef ETHREAD_GCC_H__
+#define ETHREAD_GCC_H__
+
+#include "ethr_atomic.h"
+
+#endif
diff --git a/erts/include/internal/i386/atomic.h b/erts/include/internal/i386/atomic.h
index 3291ad38e5..90b4c5f773 100644
--- a/erts/include/internal/i386/atomic.h
+++ b/erts/include/internal/i386/atomic.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-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%
*/
@@ -32,6 +32,16 @@ typedef struct {
volatile long counter;
} ethr_native_atomic_t;
+#ifdef __x86_64__
+#define ETHR_MEMORY_BARRIER __asm__ __volatile__("mfence" : : : "memory")
+#else
+#define ETHR_MEMORY_BARRIER \
+do { \
+ volatile long x___ = 0; \
+ __asm__ __volatile__("lock; incl %0" : "=m"(x___) : "m"(x___) : "memory"); \
+} while (0)
+#endif
+
#ifdef ETHR_TRY_INLINE_FUNCS
#ifdef __x86_64__
diff --git a/erts/include/internal/ppc32/atomic.h b/erts/include/internal/ppc32/atomic.h
index fa701c6a92..105d874995 100644
--- a/erts/include/internal/ppc32/atomic.h
+++ b/erts/include/internal/ppc32/atomic.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-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%
*/
@@ -32,6 +32,7 @@ typedef struct {
volatile int counter;
} ethr_native_atomic_t;
+#define ETHR_MEMORY_BARRIER __asm__ __volatile__("sync" : : : "memory")
#ifdef ETHR_TRY_INLINE_FUNCS
diff --git a/erts/include/internal/sparc32/atomic.h b/erts/include/internal/sparc32/atomic.h
index d6fdc6b2a4..8fde449a52 100644
--- a/erts/include/internal/sparc32/atomic.h
+++ b/erts/include/internal/sparc32/atomic.h
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2005-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%
*/
@@ -28,6 +28,10 @@ typedef struct {
volatile long counter;
} ethr_native_atomic_t;
+#define ETHR_MEMORY_BARRIER \
+ __asm__ __volatile__("membar #LoadLoad|#LoadStore|#StoreLoad|#StoreStore\n" \
+ : : : "memory")
+
#ifdef ETHR_TRY_INLINE_FUNCS
#if defined(__arch64__)
diff --git a/erts/include/internal/tile/atomic.h b/erts/include/internal/tile/atomic.h
index 59a9250e7c..5e4c7ac9fe 100644
--- a/erts/include/internal/tile/atomic.h
+++ b/erts/include/internal/tile/atomic.h
@@ -32,6 +32,8 @@ typedef struct {
volatile long counter;
} ethr_native_atomic_t;
+#define ETHR_MEMORY_BARRIER __insn_mf()
+
#ifdef ETHR_TRY_INLINE_FUNCS
static ETHR_INLINE void
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 49f5b1f048..e7caac8072 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -447,7 +447,7 @@ INTERNAL_RELEASE_INCLUDES= \
$(ERTS_INCL_INT)/erl_misc_utils.h \
$(ERTS_INCL_INT)/erl_errno.h
-INTERNAL_X_RELEASE_INCLUDE_DIRS= i386 x86_64 ppc32 sparc32 sparc64 tile
+INTERNAL_X_RELEASE_INCLUDE_DIRS= i386 x86_64 ppc32 sparc32 sparc64 tile gcc
INTERNAL_RELEASE_LIBS= \
../lib/internal/README \
diff --git a/erts/lib_src/common/ethread.c b/erts/lib_src/common/ethread.c
index eb4d0cad20..9c88233934 100644
--- a/erts/lib_src/common/ethread.c
+++ b/erts/lib_src/common/ethread.c
@@ -1,19 +1,19 @@
/*
* %CopyrightBegin%
- *
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
- *
+ *
+ * Copyright Ericsson AB 2004-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%
*/
@@ -269,6 +269,11 @@ static ethr_mutex no_ethrs_mtx;
#warning "Cannot enforce fork-safety"
#endif
+#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
+static pthread_rwlockattr_t write_pref_attr_data;
+static pthread_rwlockattr_t *write_pref_attr;
+#endif
+
/*
* ----------------------------------------------------------------------------
* Static functions
@@ -525,6 +530,24 @@ ethr_init(ethr_init_data *id)
}
#endif
+#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
+#if defined(ETHR_HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) \
+ && defined(ETHR_HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)
+ res = pthread_rwlockattr_init(&write_pref_attr_data);
+ if (res != 0)
+ goto error;
+ res = pthread_rwlockattr_setkind_np(
+ &write_pref_attr_data,
+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ if (res != 0)
+ goto error;
+ write_pref_attr = &write_pref_attr_data;
+#else
+ write_pref_attr = NULL;
+#endif
+#endif
+
+
return 0;
error:
@@ -1060,7 +1083,7 @@ ethr_rwmutex_init(ethr_rwmutex *rwmtx)
}
rwmtx->initialized = ETHR_RWMUTEX_INITIALIZED;
#endif
- return pthread_rwlock_init(&rwmtx->pt_rwlock, NULL);
+ return pthread_rwlock_init(&rwmtx->pt_rwlock, write_pref_attr);
}
int
@@ -3193,7 +3216,7 @@ ethr_rwmutex_tryrlock(ethr_rwmutex *rwmtx)
res = ethr_mutex_trylock__(&rwmtx->mtx);
if (res != 0)
return res;
- if (!rwmtx->waiting_writers) {
+ if (rwmtx->waiting_writers) {
res = ethr_mutex_unlock__(&rwmtx->mtx);
if (res == 0)
return EBUSY;