@@ -1,5 +1,23 @@
2010-06-16 Richard Henderson <rth@redhat.com>
+ * method-wbetl.cc (wbetl_dispatch::trycommit): Discard changes
+ that overlap the libitm stack.
+ * barrier.tpl: Mark incoming stack.
+ * beginend.cc (_ITM_rollbackTransaction, _ITM_abortTransaction,
+ _ITM_commitTransaction, _ITM_commitTransactionEH): Likewise.
+ * clone.cc (_ITM_getTMCloneOrIrrevocable): Likewise.
+ * memcpy.cc, memset.cc: Likewise.
+ * method-serial.cc (_ITM_changeTransactionMode): Likewise.
+ * config/generic/tls.h (gtm_thread): Add stack_top member.
+ (gtm_stack_top, set_gtm_stack_top, struct gtm_stack_marker): New.
+ * libitm_i.h (gtm_mask_stack): Declare.
+ * config/generic/tls.cc: New file.
+ * Makefile.am (libitm_la_SOURCES): Add it.
+ (AM_CXXFLAGS): Turn off exceptions.
+ * Makefile.in: Rebuild.
+
+2010-06-16 Richard Henderson <rth@redhat.com>
+
* alloc.cc (struct gtm_alloc_action): Move definition ...
* libitm_i.h: ... here.
(class gtm_transaction): Declare new and delete.
@@ -18,7 +18,7 @@ vpath % $(strip $(search_path))
AM_CPPFLAGS = $(addprefix -I, $(search_path))
AM_CFLAGS = $(XCFLAGS)
-AM_CXXFLAGS = -std=gnu++0x -fno-rtti $(XCFLAGS) $(abi_version)
+AM_CXXFLAGS = -std=gnu++0x -fno-exceptions -fno-rtti $(XCFLAGS) $(abi_version)
AM_CCASFLAGS = $(XCFLAGS)
AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS)
@@ -32,8 +32,8 @@ libitm_version_script =
endif
libitm_version_info = -version-info $(libtool_VERSION)
-## Force link with C, not C++. For now, while we're using C++ we don't
-## want or need libstdc++.
+# Force link with C, not C++. For now, while we're using C++ we don't
+# want or need libstdc++.
libitm_la_LINK = $(LINK)
libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \
-no-undefined
@@ -42,7 +42,7 @@ libitm_la_SOURCES = \
aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc barrier.cc beginend.cc \
clone.cc cacheline.cc cachepage.cc eh_cpp.cc local.cc memcpy.cc \
memset.cc query.cc retry.cc rwlock.cc useraction.cc util.cc \
- sjlj.S method-serial.cc method-readonly.cc method-wbetl.cc
+ sjlj.S tls.cc method-serial.cc method-readonly.cc method-wbetl.cc
if ARCH_X86
libitm_la_SOURCES += x86_sse.cc x86_avx.cc
@@ -94,15 +94,16 @@ libitm_la_LIBADD =
am__libitm_la_SOURCES_DIST = aatree.cc alloc.cc alloc_c.cc \
alloc_cpp.cc barrier.cc beginend.cc clone.cc cacheline.cc \
cachepage.cc eh_cpp.cc local.cc memcpy.cc memset.cc query.cc \
- retry.cc rwlock.cc useraction.cc util.cc sjlj.S \
+ retry.cc rwlock.cc useraction.cc util.cc sjlj.S tls.cc \
method-serial.cc method-readonly.cc method-wbetl.cc x86_sse.cc \
x86_avx.cc
@ARCH_X86_TRUE@am__objects_1 = x86_sse.lo x86_avx.lo
am_libitm_la_OBJECTS = aatree.lo alloc.lo alloc_c.lo alloc_cpp.lo \
barrier.lo beginend.lo clone.lo cacheline.lo cachepage.lo \
eh_cpp.lo local.lo memcpy.lo memset.lo query.lo retry.lo \
- rwlock.lo useraction.lo util.lo sjlj.lo method-serial.lo \
- method-readonly.lo method-wbetl.lo $(am__objects_1)
+ rwlock.lo useraction.lo util.lo sjlj.lo tls.lo \
+ method-serial.lo method-readonly.lo method-wbetl.lo \
+ $(am__objects_1)
libitm_la_OBJECTS = $(am_libitm_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -339,7 +340,7 @@ fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude
libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include
AM_CPPFLAGS = $(addprefix -I, $(search_path))
AM_CFLAGS = $(XCFLAGS)
-AM_CXXFLAGS = -std=gnu++0x -fno-rtti $(XCFLAGS) $(abi_version)
+AM_CXXFLAGS = -std=gnu++0x -fno-exceptions -fno-rtti $(XCFLAGS) $(abi_version)
AM_CCASFLAGS = $(XCFLAGS)
AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS)
toolexeclib_LTLIBRARIES = libitm.la
@@ -347,6 +348,9 @@ nodist_toolexeclib_HEADERS = libitm.spec
@LIBITM_BUILD_VERSIONED_SHLIB_FALSE@libitm_version_script =
@LIBITM_BUILD_VERSIONED_SHLIB_TRUE@libitm_version_script = -Wl,--version-script,$(top_srcdir)/libitm.map
libitm_version_info = -version-info $(libtool_VERSION)
+
+# Force link with C, not C++. For now, while we're using C++ we don't
+# want or need libstdc++.
libitm_la_LINK = $(LINK)
libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \
-no-undefined
@@ -354,7 +358,7 @@ libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \
libitm_la_SOURCES = aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc \
barrier.cc beginend.cc clone.cc cacheline.cc cachepage.cc \
eh_cpp.cc local.cc memcpy.cc memset.cc query.cc retry.cc \
- rwlock.cc useraction.cc util.cc sjlj.S method-serial.cc \
+ rwlock.cc useraction.cc util.cc sjlj.S tls.cc method-serial.cc \
method-readonly.cc method-wbetl.cc $(am__append_1)
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -474,6 +478,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retry.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwlock.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sjlj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/useraction.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_avx.Plo@am__quote@
@@ -122,11 +122,17 @@ void do_write (T *ptr, T val, gtm_dispatch::lock_type lock)
#define ITM_READ(T, LOCK) \
_ITM_TYPE_##T ITM_REGPARM _ITM_##LOCK##T (const _ITM_TYPE_##T *ptr) \
- { return do_read (ptr, gtm_dispatch::LOCK); }
+ { \
+ gtm_stack_marker marker; \
+ return do_read (ptr, gtm_dispatch::LOCK); \
+ }
#define ITM_WRITE(T, LOCK) \
void ITM_REGPARM _ITM_##LOCK##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \
- { do_write (ptr, val, gtm_dispatch::LOCK); }
+ { \
+ gtm_stack_marker marker; \
+ do_write (ptr, val, gtm_dispatch::LOCK); \
+ }
#define ITM_BARRIERS(T) \
ITM_READ(T, R) \
@@ -84,7 +84,6 @@ GTM::gtm_transaction::operator delete(void *tx)
thr->free_tx[idx] = tx;
}
-
uint32_t
GTM::gtm_transaction::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
{
@@ -162,6 +161,8 @@ _ITM_rollbackTransaction (void)
assert ((tx->prop & pr_hasNoAbort) == 0);
assert ((tx->state & gtm_transaction::STATE_ABORTING) == 0);
+ gtm_stack_marker marker;
+
tx->rollback ();
tx->state |= gtm_transaction::STATE_ABORTING;
}
@@ -178,6 +179,8 @@ _ITM_abortTransaction (_ITM_abortReason reason)
if (tx->state & gtm_transaction::STATE_IRREVOCABLE)
abort ();
+ gtm_stack_marker marker;
+
tx->rollback ();
gtm_disp()->fini ();
@@ -251,6 +254,8 @@ void ITM_REGPARM
_ITM_commitTransaction(void)
{
gtm_transaction *tx = gtm_tx();
+ gtm_stack_marker marker;
+
if (!tx->trycommit_and_finalize ())
tx->restart (RESTART_VALIDATE_COMMIT);
}
@@ -259,6 +264,8 @@ void ITM_REGPARM
_ITM_commitTransactionEH(void *exc_ptr)
{
gtm_transaction *tx = gtm_tx();
+ gtm_stack_marker marker;
+
if (!tx->trycommit_and_finalize ())
{
tx->eh_in_flight = exc_ptr;
@@ -92,7 +92,9 @@ _ITM_getTMCloneOrIrrevocable (void *ptr)
if (ret)
return ret;
+ gtm_stack_marker marker;
gtm_tx()->serialirr_mode ();
+
return ptr;
}
new file mode 100644
@@ -0,0 +1,76 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+ Contributed by Richard Henderson <rth@redhat.com>.
+
+ This file is part of the GNU Transactional Memory Library (libitm).
+
+ Libitm is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "libitm_i.h"
+
+namespace GTM HIDDEN {
+
+// Filter out any updates that overlap the libitm stack, as defined by
+// TOP (entry point to library) and BOT (below current function). This
+// definition should be fine for all stack-grows-down architectures.
+
+gtm_cacheline_mask __attribute__((noinline))
+gtm_mask_stack(gtm_cacheline *line, gtm_cacheline_mask mask)
+{
+ void *top = gtm_stack_top();
+ void *bot = __builtin_dwarf_cfa();
+
+ // We must have come through an entry point that set TOP.
+ assert (top != NULL);
+
+ if (line + 1 < bot)
+ {
+ // Since we don't have the REAL stack boundaries for this thread,
+ // we cannot know if this is a dead write to a stack address below
+ // the current function or if it is write to another VMA. In either
+ // case allowing the write should not affect correctness.
+ }
+ else if (line >= top)
+ {
+ // A valid write to an address in an outer stack frame, or a write
+ // to another VMA.
+ }
+ else
+ {
+ uintptr_t diff = (uintptr_t)top - (uintptr_t)line;
+ if (diff >= CACHELINE_SIZE)
+ {
+ // The write is either fully within the proscribed area, or the tail
+ // of the cacheline overlaps the proscribed area. Assume that all
+ // stacks are at least cacheline aligned and declare the head of the
+ // cacheline dead.
+ mask = 0;
+ }
+ else
+ {
+ // The head of the cacheline is within the proscribed area, but the
+ // tail of the cacheline is live. Eliminate the dead writes.
+ mask &= (gtm_cacheline_mask)-1 << diff;
+ }
+ }
+
+ return mask;
+}
+
+} // namespace GTM
@@ -40,6 +40,10 @@ struct gtm_thread
// if the target provides some efficient mechanism for storing this.
gtm_dispatch *disp;
#endif
+#ifndef HAVE_ARCH_GTM_THREAD_STACK_TOP
+ // The top of stack on entry to the STM library.
+ void *stack_top;
+#endif
// The maximum number of free gtm_transaction structs to be kept.
// This number must be greater than 1 in order for transaction abort
@@ -67,24 +71,35 @@ extern __thread gtm_thread _gtm_thr;
#ifndef HAVE_ARCH_GTM_THREAD
// If the target does not provide optimized access to the thread-local
// data, simply access the TLS variable defined above.
-static inline void setup_gtm_thr(void) { }
-static inline gtm_thread *gtm_thr(void) { return &_gtm_thr; }
+static inline void setup_gtm_thr() { }
+static inline gtm_thread *gtm_thr() { return &_gtm_thr; }
#endif
#ifndef HAVE_ARCH_GTM_THREAD_TX
// If the target does not provide optimized access to the currently
// active transaction, simply access via GTM_THR.
-static inline gtm_transaction * gtm_tx(void) { return gtm_thr()->tx; }
+static inline gtm_transaction * gtm_tx() { return gtm_thr()->tx; }
static inline void set_gtm_tx(gtm_transaction *x) { gtm_thr()->tx = x; }
#endif
#ifndef HAVE_ARCH_GTM_THREAD_DISP
// If the target does not provide optimized access to the currently
// active dispatch table, simply access via GTM_THR.
-static inline gtm_dispatch * gtm_disp(void) { return gtm_thr()->disp; }
+static inline gtm_dispatch * gtm_disp() { return gtm_thr()->disp; }
static inline void set_gtm_disp(gtm_dispatch *x) { gtm_thr()->disp = x; }
#endif
+#ifndef HAVE_ARCH_GTM_THREAD_STACK_TOP
+static inline void *gtm_stack_top() { return gtm_thr()->stack_top; }
+static inline void set_gtm_stack_top(void *t) { gtm_thr()->stack_top = t; }
+#endif
+
+struct gtm_stack_marker
+{
+ gtm_stack_marker(void *t = __builtin_dwarf_cfa()) { set_gtm_stack_top (t); }
+ ~gtm_stack_marker() { set_gtm_stack_top (0); }
+};
+
} // namespace GTM
#endif // LIBITM_TLS_H
@@ -285,6 +285,8 @@ extern gtm_dispatch *dispatch_wbetl();
extern gtm_dispatch *dispatch_readonly();
extern gtm_dispatch *dispatch_serial();
+extern gtm_cacheline_mask gtm_mask_stack(gtm_cacheline *, gtm_cacheline_mask);
+
} // namespace GTM
#endif // LIBITM_I_H
@@ -302,11 +302,13 @@ do_memmove (uintptr_t idst, uintptr_t isrc, size_t size,
#define ITM_MEM_DEF(NAME, READ, WRITE) \
void ITM_REGPARM _ITM_memcpy##NAME(void *dst, const void *src, size_t size) \
{ \
+ gtm_stack_marker marker; \
do_memcpy ((uintptr_t)dst, (uintptr_t)src, size, \
gtm_dispatch::WRITE, gtm_dispatch::READ); \
} \
void ITM_REGPARM _ITM_memmove##NAME(void *dst, const void *src, size_t size) \
{ \
+ gtm_stack_marker marker; \
do_memmove ((uintptr_t)dst, (uintptr_t)src, size, \
gtm_dispatch::WRITE, gtm_dispatch::READ); \
}
@@ -69,7 +69,10 @@ do_memset(uintptr_t idst, int c, size_t size, gtm_dispatch::lock_type W)
#define ITM_MEM_DEF(WRITE) \
void ITM_REGPARM _ITM_memset##WRITE(void *dst, int c, size_t size) \
-{ do_memset ((uintptr_t)dst, c, size, gtm_dispatch::WRITE); }
+{ \
+ gtm_stack_marker marker; \
+ do_memset ((uintptr_t)dst, c, size, gtm_dispatch::WRITE); \
+}
ITM_MEM_DEF(W)
ITM_MEM_DEF(WaR)
@@ -117,6 +117,7 @@ GTM::gtm_transaction::serialirr_mode ()
void ITM_REGPARM
_ITM_changeTransactionMode (_ITM_transactionState state)
{
+ gtm_stack_marker marker;
assert (state == modeSerialIrrevocable);
gtm_tx()->serialirr_mode ();
}
@@ -426,8 +426,13 @@ wbetl_dispatch::trycommit ()
for (size_t i = 0; i < n; ++i)
{
w_entry *w = &m_wset_entries[i];
- gtm_cacheline::copy_mask (w->addr, w->value,
- *gtm_cacheline_page::mask_for_page_line (w->value));
+ gtm_cacheline_mask mask
+ = *gtm_cacheline_page::mask_for_page_line (w->value);
+
+ /* Filter out any updates that overlap the libitm stack. */
+ mask = gtm_mask_stack (w->addr, mask);
+
+ gtm_cacheline::copy_mask (w->addr, w->value, mask);
}
/* Only emit barrier after all cachelines are copied. */