@@ -27,7 +27,7 @@
namespace GTM HIDDEN {
void
-gtm_transaction::record_allocation (void *ptr, void (*free_fn)(void *))
+gtm_thread::record_allocation (void *ptr, void (*free_fn)(void *))
{
uintptr_t iptr = (uintptr_t) ptr;
@@ -40,7 +40,7 @@ gtm_transaction::record_allocation (void *ptr, void (*free_fn)(void *))
}
void
-gtm_transaction::forget_allocation (void *ptr, void (*free_fn)(void *))
+gtm_thread::forget_allocation (void *ptr, void (*free_fn)(void *))
{
uintptr_t iptr = (uintptr_t) ptr;
@@ -116,7 +116,7 @@ commit_allocations_1 (uintptr_t key, gtm_alloc_action *a, void *cb_data)
REVERT_P is true if instead of committing the allocations, we want
to roll them back (and vice versa). */
void
-gtm_transaction::commit_allocations (bool revert_p,
+gtm_thread::commit_allocations (bool revert_p,
aa_tree<uintptr_t, gtm_alloc_action>* parent)
{
if (parent)
@@ -35,7 +35,7 @@ _ITM_malloc (size_t sz)
{
void *r = malloc (sz);
if (r)
- gtm_tx()->record_allocation (r, free);
+ gtm_thr()->record_allocation (r, free);
return r;
}
@@ -45,7 +45,7 @@ _ITM_calloc (size_t nm, size_t sz)
{
void *r = calloc (nm, sz);
if (r)
- gtm_tx()->record_allocation (r, free);
+ gtm_thr()->record_allocation (r, free);
return r;
}
@@ -54,7 +54,7 @@ void
_ITM_free (void *ptr)
{
if (ptr)
- gtm_tx()->forget_allocation (ptr, free);
+ gtm_thr()->forget_allocation (ptr, free);
}
/* Forget any internal references to PTR. */
@@ -83,7 +83,7 @@ _ZGTtnwX (size_t sz)
{
void *r = _ZnwX (sz);
if (r)
- gtm_tx()->record_allocation (r, _ZdlPv);
+ gtm_thr()->record_allocation (r, _ZdlPv);
return r;
}
@@ -93,7 +93,7 @@ _ZGTtnwXRKSt9nothrow_t (size_t sz, c_nothrow_p nt)
{
void *r = _ZnwXRKSt9nothrow_t (sz, nt);
if (r)
- gtm_tx()->record_allocation (r, del_opnt);
+ gtm_thr()->record_allocation (r, del_opnt);
return r;
}
@@ -103,7 +103,7 @@ _ZGTtnaX (size_t sz)
{
void *r = _ZnaX (sz);
if (r)
- gtm_tx()->record_allocation (r, _ZdaPv);
+ gtm_thr()->record_allocation (r, _ZdaPv);
return r;
}
@@ -113,7 +113,7 @@ _ZGTtnaXRKSt9nothrow_t (size_t sz, c_nothrow_p nt)
{
void *r = _ZnaXRKSt9nothrow_t (sz, nt);
if (r)
- gtm_tx()->record_allocation (r, del_opvnt);
+ gtm_thr()->record_allocation (r, del_opvnt);
return r;
}
@@ -122,7 +122,7 @@ void
_ZGTtdlPv (void *ptr)
{
if (ptr)
- gtm_tx()->forget_allocation (ptr, _ZdlPv);
+ gtm_thr()->forget_allocation (ptr, _ZdlPv);
}
/* Wrap: operator delete (void *ptr, const std::nothrow_t&) */
@@ -130,7 +130,7 @@ void
_ZGTtdlPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED)
{
if (ptr)
- gtm_tx()->forget_allocation (ptr, del_opnt);
+ gtm_thr()->forget_allocation (ptr, del_opnt);
}
/* Wrap: operator delete[] (void *ptr) */
@@ -138,7 +138,7 @@ void
_ZGTtdaPv (void *ptr)
{
if (ptr)
- gtm_tx()->forget_allocation (ptr, _ZdaPv);
+ gtm_thr()->forget_allocation (ptr, _ZdaPv);
}
/* Wrap: operator delete[] (void *ptr, const std::nothrow_t&) */
@@ -146,7 +146,7 @@ void
_ZGTtdaPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED)
{
if (ptr)
- gtm_tx()->forget_allocation (ptr, del_opvnt);
+ gtm_thr()->forget_allocation (ptr, del_opvnt);
}
} // extern "C"
@@ -27,9 +27,12 @@
using namespace GTM;
-__thread gtm_thread GTM::_gtm_thr;
-gtm_rwlock GTM::gtm_transaction::serial_lock;
-gtm_transaction *GTM::gtm_transaction::list_of_tx = 0;
+#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP)
+extern __thread gtm_thread_tls _gtm_thr_tls;
+#endif
+
+gtm_rwlock GTM::gtm_thread::serial_lock;
+gtm_thread *GTM::gtm_thread::list_of_threads = 0;
gtm_stmlock GTM::gtm_stmlock_array[LOCK_ARRAY_SIZE];
gtm_version GTM::gtm_clock;
@@ -40,71 +43,91 @@ uint64_t GTM::gtm_spin_count_var = 1000;
static _ITM_transactionId_t global_tid;
// Provides a on-thread-exit callback used to release per-thread data.
-static pthread_key_t tx_release_key;
-static pthread_once_t tx_release_once = PTHREAD_ONCE_INIT;
+static pthread_key_t thr_release_key;
+static pthread_once_t thr_release_once = PTHREAD_ONCE_INIT;
/* Allocate a transaction structure. */
-
void *
-GTM::gtm_transaction::operator new (size_t s)
+GTM::gtm_thread::operator new (size_t s)
{
void *tx;
- assert(s == sizeof(gtm_transaction));
+ assert(s == sizeof(gtm_thread));
- tx = xmalloc (sizeof (gtm_transaction), true);
- memset (tx, 0, sizeof (gtm_transaction));
+ tx = xmalloc (sizeof (gtm_thread), true);
+ memset (tx, 0, sizeof (gtm_thread));
return tx;
}
/* Free the given transaction. Raises an error if the transaction is still
in use. */
-
void
-GTM::gtm_transaction::operator delete(void *tx)
+GTM::gtm_thread::operator delete(void *tx)
{
free(tx);
}
static void
-thread_exit_handler(void *dummy __attribute__((unused)))
+thread_exit_handler(void *)
{
- gtm_transaction *tx = gtm_tx();
- if (tx)
- {
- if (tx->nesting > 0)
- GTM_fatal("Thread exit while a transaction is still active.");
+ gtm_thread *thr = gtm_thr();
+ if (thr)
+ delete thr;
+ set_gtm_thr(0);
+}
+
+static void
+thread_exit_init()
+{
+ if (pthread_key_create(&thr_release_key, thread_exit_handler))
+ GTM_fatal("Creating thread release TLS key failed.");
+}
- // Deregister this transaction.
- gtm_transaction::serial_lock.write_lock ();
- gtm_transaction **prev = >m_transaction::list_of_tx;
- for (; *prev; prev = &(*prev)->next_tx)
+
+GTM::gtm_thread::~gtm_thread()
+{
+ if (nesting > 0)
+ GTM_fatal("Thread exit while a transaction is still active.");
+
+ // Deregister this transaction.
+ serial_lock.write_lock ();
+ gtm_thread **prev = &list_of_threads;
+ for (; *prev; prev = &(*prev)->next_thread)
+ {
+ if (*prev == this)
{
- if (*prev == tx)
- {
- *prev = (*prev)->next_tx;
- break;
- }
+ *prev = (*prev)->next_thread;
+ break;
}
- gtm_transaction::serial_lock.write_unlock ();
-
- delete tx;
- set_gtm_tx(NULL);
}
- if (pthread_setspecific(tx_release_key, NULL))
- GTM_fatal("Setting tx release TLS key failed.");
+ serial_lock.write_unlock ();
}
-static void
-thread_exit_init()
+GTM::gtm_thread::gtm_thread ()
{
- if (pthread_key_create(&tx_release_key, thread_exit_handler))
- GTM_fatal("Creating tx release TLS key failed.");
+ // This object's memory has been set to zero by operator new, so no need
+ // to initialize any of the other primitive-type members that do not have
+ // constructors.
+ shared_state = ~(typeof shared_state)0;
+
+ // Register this transaction with the list of all threads' transactions.
+ serial_lock.write_lock ();
+ next_thread = list_of_threads;
+ list_of_threads = this;
+ serial_lock.write_unlock ();
+
+ if (pthread_once(&thr_release_once, thread_exit_init))
+ GTM_fatal("Initializing thread release TLS key failed.");
+ // Any non-null value is sufficient to trigger destruction of this
+ // transaction when the current thread terminates.
+ if (pthread_setspecific(thr_release_key, this))
+ GTM_fatal("Setting thread release TLS key failed.");
}
+
#ifndef HAVE_64BIT_SYNC_BUILTINS
static pthread_mutex_t global_tid_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
@@ -118,11 +141,11 @@ static inline uint32_t choose_code_path(uint32_t prop, abi_dispatch *disp)
}
uint32_t
-GTM::gtm_transaction::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
+GTM::gtm_thread::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
{
static const _ITM_transactionId_t tid_block_size = 1 << 16;
- gtm_transaction *tx;
+ gtm_thread *tx;
abi_dispatch *disp;
uint32_t ret;
@@ -133,24 +156,13 @@ GTM::gtm_transaction::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
if (unlikely(prop & pr_undoLogCode))
GTM_fatal("pr_undoLogCode not supported");
- tx = gtm_tx();
+ tx = gtm_thr();
if (unlikely(tx == NULL))
{
- tx = new gtm_transaction;
- set_gtm_tx(tx);
-
- // Register this transaction with the list of all threads' transactions.
- serial_lock.write_lock ();
- tx->next_tx = list_of_tx;
- list_of_tx = tx;
- serial_lock.write_unlock ();
-
- if (pthread_once(&tx_release_once, thread_exit_init))
- GTM_fatal("Initializing tx release TLS key failed.");
- // Any non-null value is sufficient to trigger releasing of this
- // transaction when the current thread terminates.
- if (pthread_setspecific(tx_release_key, tx))
- GTM_fatal("Setting tx release TLS key failed.");
+ // Create the thread object. The constructor will also set up automatic
+ // deletion on thread termination.
+ tx = new gtm_thread();
+ set_gtm_thr(tx);
}
if (tx->nesting > 0)
@@ -272,7 +284,7 @@ GTM::gtm_transaction::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
void
-GTM::gtm_transaction_cp::save(gtm_transaction* tx)
+GTM::gtm_transaction_cp::save(gtm_thread* tx)
{
// Save everything that we might have to restore on restarts or aborts.
jb = tx->jb;
@@ -288,7 +300,7 @@ GTM::gtm_transaction_cp::save(gtm_transaction* tx)
}
void
-GTM::gtm_transaction_cp::commit(gtm_transaction* tx)
+GTM::gtm_transaction_cp::commit(gtm_thread* tx)
{
// Restore state that is not persistent across commits. Exception handling,
// information, nesting level, and any logs do not need to be restored on
@@ -302,7 +314,7 @@ GTM::gtm_transaction_cp::commit(gtm_transaction* tx)
void
-GTM::gtm_transaction::rollback (gtm_transaction_cp *cp)
+GTM::gtm_thread::rollback (gtm_transaction_cp *cp)
{
abi_disp()->rollback (cp);
@@ -351,12 +363,12 @@ GTM::gtm_transaction::rollback (gtm_transaction_cp *cp)
void ITM_REGPARM
_ITM_abortTransaction (_ITM_abortReason reason)
{
- gtm_transaction *tx = gtm_tx();
+ gtm_thread *tx = gtm_thr();
assert (reason == userAbort);
assert ((tx->prop & pr_hasNoAbort) == 0);
- if (tx->state & gtm_transaction::STATE_IRREVOCABLE)
+ if (tx->state & gtm_thread::STATE_IRREVOCABLE)
abort ();
// If the current method does not support closed nesting, we are nested, and
@@ -388,10 +400,10 @@ _ITM_abortTransaction (_ITM_abortReason reason)
// Aborting an outermost transaction finishes execution of the whole
// transaction. Therefore, reset transaction state.
- if (tx->state & gtm_transaction::STATE_SERIAL)
- gtm_transaction::serial_lock.write_unlock ();
+ if (tx->state & gtm_thread::STATE_SERIAL)
+ gtm_thread::serial_lock.write_unlock ();
else
- gtm_transaction::serial_lock.read_unlock (tx);
+ gtm_thread::serial_lock.read_unlock (tx);
tx->state = 0;
GTM_longjmp (&tx->jb, a_abortTransaction | a_restoreLiveVariables,
@@ -400,7 +412,7 @@ _ITM_abortTransaction (_ITM_abortReason reason)
}
bool
-GTM::gtm_transaction::trycommit ()
+GTM::gtm_thread::trycommit ()
{
nesting--;
@@ -434,10 +446,10 @@ GTM::gtm_transaction::trycommit ()
// TODO can release SI mode before committing user actions? If so,
// we can release before ensuring privatization safety too.
- if (state & gtm_transaction::STATE_SERIAL)
- gtm_transaction::serial_lock.write_unlock ();
+ if (state & gtm_thread::STATE_SERIAL)
+ gtm_thread::serial_lock.write_unlock ();
else
- gtm_transaction::serial_lock.read_unlock (this);
+ gtm_thread::serial_lock.read_unlock (this);
state = 0;
return true;
@@ -446,7 +458,7 @@ GTM::gtm_transaction::trycommit ()
}
void ITM_NORETURN
-GTM::gtm_transaction::restart (gtm_restart_reason r)
+GTM::gtm_thread::restart (gtm_restart_reason r)
{
// Roll back to outermost transaction. Do not reset transaction state because
// we will continue executing this transaction.
@@ -461,7 +473,7 @@ GTM::gtm_transaction::restart (gtm_restart_reason r)
void ITM_REGPARM
_ITM_commitTransaction(void)
{
- gtm_transaction *tx = gtm_tx();
+ gtm_thread *tx = gtm_thr();
if (!tx->trycommit ())
tx->restart (RESTART_VALIDATE_COMMIT);
}
@@ -469,7 +481,7 @@ _ITM_commitTransaction(void)
void ITM_REGPARM
_ITM_commitTransactionEH(void *exc_ptr)
{
- gtm_transaction *tx = gtm_tx();
+ gtm_thread *tx = gtm_thr();
if (!tx->trycommit ())
{
tx->eh_in_flight = exc_ptr;
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Transactional Memory Library (libitm).
@@ -82,7 +82,7 @@ _ITM_getTMCloneOrIrrevocable (void *ptr)
if (ret)
return ret;
- gtm_tx()->serialirr_mode ();
+ gtm_thr()->serialirr_mode ();
return ptr;
}
@@ -125,17 +125,17 @@ class ExcludeTransaction
public:
ExcludeTransaction()
{
- gtm_transaction *tx = gtm_tx();
- do_lock = !(tx && (tx->state & gtm_transaction::STATE_SERIAL));
+ gtm_thread *tx = gtm_thr();
+ do_lock = !(tx && (tx->state & gtm_thread::STATE_SERIAL));
if (do_lock)
- gtm_transaction::serial_lock.write_lock ();
+ gtm_thread::serial_lock.write_lock ();
}
~ExcludeTransaction()
{
if (do_lock)
- gtm_transaction::serial_lock.write_unlock ();
+ gtm_thread::serial_lock.write_unlock ();
}
};
@@ -33,7 +33,7 @@ namespace GTM HIDDEN {
gtm_cacheline_mask __attribute__((noinline))
gtm_mask_stack(gtm_cacheline *line, gtm_cacheline_mask mask)
{
- void *top = gtm_tx()->jb.cfa;
+ void *top = gtm_thr()->jb.cfa;
void *bot = __builtin_dwarf_cfa();
// We must have come through an entry point that set TOP.
@@ -27,53 +27,37 @@
namespace GTM HIDDEN {
-// All thread-local data required by the entire library.
-struct gtm_thread
+#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP)
+// Provides a single place to store all this libraries thread-local data.
+struct gtm_thread_tls
{
-#ifndef HAVE_ARCH_GTM_THREAD_TX
+#ifndef HAVE_ARCH_GTM_THREAD
// The currently active transaction. Elided if the target provides
// some efficient mechanism for storing this.
- gtm_transaction *tx;
+ gtm_thread *thr;
#endif
#ifndef HAVE_ARCH_GTM_THREAD_DISP
// The dispatch table for the STM implementation currently in use. Elided
// if the target provides some efficient mechanism for storing this.
abi_dispatch *disp;
#endif
-
- // The value returned by _ITM_getThreadnum to identify this thread.
- // ??? At present, this is densely allocated beginning with 1 and
- // we don't bother filling in this value until it is requested.
- // Which means that the value returned is, as far as the user is
- // concerned, essentially arbitrary. We wouldn't need this at all
- // if we knew that pthread_t is integral and fits into an int.
- // ??? Consider using gettid on Linux w/ NPTL. At least that would
- // be a value meaningful to the user.
- int thread_num;
};
-// Don't access this variable directly; use the functions below.
-extern __thread gtm_thread _gtm_thr;
+extern __thread gtm_thread_tls _gtm_thr_tls;
+#endif
#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 gtm_thread *setup_gtm_thr() { return &_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() { return gtm_thr()->tx; }
-static inline void set_gtm_tx(gtm_transaction *x) { gtm_thr()->tx = x; }
+static inline gtm_thread *gtm_thr() { return &_gtm_thr_tls.thr; }
+static inline void set_gtm_thr(gtm_thread *x) { _gtm_thr_tls.thr = 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 abi_dispatch * abi_disp() { return gtm_thr()->disp; }
-static inline void set_abi_disp(abi_dispatch *x) { gtm_thr()->disp = x; }
+static inline abi_dispatch * abi_disp() { return _gtm_thr_tls.disp; }
+static inline void set_abi_disp(abi_dispatch *x) { _gtm_thr_tls.disp = x; }
#endif
} // namespace GTM
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Transactional Memory Library (libitm).
@@ -50,7 +50,7 @@ gtm_rwlock::~gtm_rwlock()
// Acquire a RW lock for reading.
void
-gtm_rwlock::read_lock (gtm_transaction *tx)
+gtm_rwlock::read_lock (gtm_thread *tx)
{
// Fast path: first announce our intent to read, then check for conflicting
// intents to write. The barrier makes sure that this happens in exactly
@@ -120,7 +120,7 @@ gtm_rwlock::read_lock (gtm_transaction *tx)
// this if this will actually happen often enough in real workloads.
bool
-gtm_rwlock::write_lock_generic (gtm_transaction *tx)
+gtm_rwlock::write_lock_generic (gtm_thread *tx)
{
pthread_mutex_lock (&this->mutex);
@@ -190,8 +190,8 @@ gtm_rwlock::write_lock_generic (gtm_transaction *tx)
// next retry instead? This might reduce the number of cache misses that
// we get when checking reader flags.
int readers = 0;
- for (gtm_transaction *it = gtm_transaction::list_of_tx; it != 0;
- it = it->next_tx)
+ for (gtm_thread *it = gtm_thread::list_of_threads; it != 0;
+ it = it->next_thread)
{
// Don't count ourself if this is an upgrade.
if (it->shared_state != ~(typeof it->shared_state)0)
@@ -225,7 +225,7 @@ gtm_rwlock::write_lock ()
// if this attempt fails (i.e. another thread also upgraded).
bool
-gtm_rwlock::write_upgrade (gtm_transaction *tx)
+gtm_rwlock::write_upgrade (gtm_thread *tx)
{
return write_lock_generic (tx);
}
@@ -234,7 +234,7 @@ gtm_rwlock::write_upgrade (gtm_transaction *tx)
// Release a RW lock from reading.
void
-gtm_rwlock::read_unlock (gtm_transaction *tx)
+gtm_rwlock::read_unlock (gtm_thread *tx)
{
tx->shared_state = ~(typeof tx->shared_state)0;
__sync_synchronize();
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2009, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Transactional Memory Library (libitm).
@@ -29,7 +29,7 @@
namespace GTM HIDDEN {
-struct gtm_transaction;
+struct gtm_thread;
// This datastructure is the blocking, mutex-based side of the Dekker-style
// reader-writer lock used to provide mutual exclusion between active and
@@ -64,16 +64,16 @@ class gtm_rwlock
gtm_rwlock();
~gtm_rwlock();
- void read_lock (gtm_transaction *tx);
- void read_unlock (gtm_transaction *tx);
+ void read_lock (gtm_thread *tx);
+ void read_unlock (gtm_thread *tx);
void write_lock ();
void write_unlock ();
- bool write_upgrade (gtm_transaction *tx);
+ bool write_upgrade (gtm_thread *tx);
protected:
- bool write_lock_generic (gtm_transaction *tx);
+ bool write_lock_generic (gtm_thread *tx);
};
} // namespace GTM
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Transactional Memory Library (libitm).
@@ -29,7 +29,6 @@
/* Use slots in the TCB head rather than __thread lookups.
GLIBC has reserved words 10 through 13 for TM. */
#define HAVE_ARCH_GTM_THREAD 1
-#define HAVE_ARCH_GTM_THREAD_TX 1
#define HAVE_ARCH_GTM_THREAD_DISP 1
#endif
@@ -65,40 +64,22 @@ static inline struct gtm_thread *gtm_thr(void)
return r;
}
-static inline struct gtm_thread *setup_gtm_thr(void)
+static inline void set_gtm_thr(struct gtm_thread *x)
{
- gtm_thread *thr = gtm_thr();
- if (thr == NULL)
- {
- thr = &_gtm_thr;
- asm volatile (SEG_WRITE(10) : : "r"(thr));
- }
- return thr;
-}
-
-static inline struct gtm_transaction * gtm_tx(void)
-{
- struct gtm_transaction *r;
- asm (SEG_READ(11) : "=r"(r));
- return r;
-}
-
-static inline void set_gtm_tx(struct gtm_transaction *x)
-{
- asm volatile (SEG_WRITE(11) : : "r"(x));
+ asm volatile (SEG_WRITE(10) : : "r"(x));
}
static inline struct abi_dispatch *abi_disp(void)
{
struct abi_dispatch *r;
- asm (SEG_DECODE_READ(12) : "=r"(r));
+ asm (SEG_DECODE_READ(11) : "=r"(r));
return r;
}
static inline void set_abi_disp(struct abi_dispatch *x)
{
void *scratch;
- asm volatile (SEG_ENCODE_WRITE(12) : "=r"(scratch) : "0"(x));
+ asm volatile (SEG_ENCODE_WRITE(11) : "=r"(scratch) : "0"(x));
}
#undef SEG_READ
@@ -46,33 +46,33 @@ void *
_ITM_cxa_allocate_exception (size_t size)
{
void *r = __cxa_allocate_exception (size);
- gtm_tx()->cxa_unthrown = r;
+ gtm_thr()->cxa_unthrown = r;
return r;
}
void
_ITM_cxa_throw (void *obj, void *tinfo, void *dest)
{
- gtm_tx()->cxa_unthrown = NULL;
+ gtm_thr()->cxa_unthrown = NULL;
__cxa_throw (obj, tinfo, dest);
}
void *
_ITM_cxa_begin_catch (void *exc_ptr)
{
- gtm_tx()->cxa_catch_count++;
+ gtm_thr()->cxa_catch_count++;
return __cxa_begin_catch (exc_ptr);
}
void
_ITM_cxa_end_catch (void)
{
- gtm_tx()->cxa_catch_count--;
+ gtm_thr()->cxa_catch_count--;
__cxa_end_catch ();
}
void
-GTM::gtm_transaction::revert_cpp_exceptions (gtm_transaction_cp *cp)
+GTM::gtm_thread::revert_cpp_exceptions (gtm_transaction_cp *cp)
{
if (cp)
{
@@ -325,6 +325,10 @@ the respective calls to @code{_ITM_addUserUndoAction} happened. The ordering of
undo actions w.r.t. the roll-back of other actions (e.g., data transfers or
memory allocations) is undefined.
+@code{_ITM_getThreadnum} is not supported currently because its only purpose
+is to provide a thread ID that matches some assumed performance tuning output,
+but this output is not part of the ABI nor further defined by it.
+
@code{_ITM_dropReferences} is not supported currently because its semantics and
the intention behind it is not entirely clear. The
specification suggests that this function is necessary because of certain
@@ -92,7 +92,7 @@ enum gtm_restart_reason
};
// This type is private to alloc.c, but needs to be defined so that
-// the template used inside gtm_transaction can instantiate.
+// the template used inside gtm_thread can instantiate.
struct gtm_alloc_action
{
void (*free_fn)(void *);
@@ -102,7 +102,7 @@ struct gtm_alloc_action
// This type is private to local.c.
struct gtm_local_undo;
-struct gtm_transaction;
+struct gtm_thread;
// A transaction checkpoint: data that has to saved and restored when doing
// closed nesting.
@@ -123,12 +123,22 @@ struct gtm_transaction_cp
// the outermost transaction).
uint32_t nesting;
- void save(gtm_transaction* tx);
- void commit(gtm_transaction* tx);
+ void save(gtm_thread* tx);
+ void commit(gtm_thread* tx);
};
-// All data relevant to a single transaction.
-struct gtm_transaction
+// Contains all thread-specific data required by the entire library.
+// This includes all data relevant to a single transaction. Because most
+// thread-specific data is about the current transaction, we also refer to
+// the transaction-specific parts of gtm_thread as "the transaction" (the
+// same applies to names of variables and arguments).
+// All but the shared part of this data structure are thread-local data.
+// gtm_thread could be split into transaction-specific structures and other
+// per-thread data (with those parts then nested in gtm_thread), but this
+// would make it harder to later rearrange individual members to optimize data
+// accesses. Thus, for now we keep one flat object, and will only split it if
+// the code gets too messy.
+struct gtm_thread
{
struct user_action
@@ -192,12 +202,12 @@ struct gtm_transaction
uint32_t restart_reason[NUM_RESTARTS];
uint32_t restart_total;
- // *** The shared part of gtm_transaction starts here. ***
+ // *** The shared part of gtm_thread starts here. ***
// Shared state is on separate cachelines to avoid false sharing with
- // thread-local parts of gtm_transaction.
+ // thread-local parts of gtm_thread.
- // Points to the next transaction in the list of all threads' transactions.
- gtm_transaction *next_tx __attribute__((__aligned__(HW_CACHELINE_SIZE)));
+ // Points to the next thread in the list of all threads.
+ gtm_thread *next_thread __attribute__((__aligned__(HW_CACHELINE_SIZE)));
// If this transaction is inactive, shared_state is ~0. Otherwise, this is
// an active or serial transaction.
@@ -209,10 +219,7 @@ struct gtm_transaction
static gtm_rwlock serial_lock;
// The head of the list of all threads' transactions.
- static gtm_transaction *list_of_tx;
-
- gtm_transaction() : shared_state(~(typeof shared_state)0)
- {}
+ static gtm_thread *list_of_threads;
// In alloc.cc
void commit_allocations (bool, aa_tree<uintptr_t, gtm_alloc_action>*);
@@ -228,6 +235,9 @@ struct gtm_transaction
bool trycommit ();
void restart (gtm_restart_reason) ITM_NORETURN;
+ gtm_thread();
+ ~gtm_thread();
+
static void *operator new(size_t);
static void operator delete(void *);
@@ -35,7 +35,7 @@ struct gtm_local_undo
void
-gtm_transaction::commit_local ()
+gtm_thread::commit_local ()
{
size_t i, n = local_undo.size();
@@ -48,7 +48,7 @@ gtm_transaction::commit_local ()
}
void
-gtm_transaction::rollback_local (size_t until_size)
+gtm_thread::rollback_local (size_t until_size)
{
size_t i, n = local_undo.size();
@@ -69,7 +69,7 @@ gtm_transaction::rollback_local (size_t until_size)
/* Forget any references to PTR in the local log. */
void
-gtm_transaction::drop_references_local (const void *ptr, size_t len)
+gtm_thread::drop_references_local (const void *ptr, size_t len)
{
size_t i, n = local_undo.size();
@@ -93,7 +93,7 @@ gtm_transaction::drop_references_local (const void *ptr, size_t len)
void ITM_REGPARM
GTM_LB (const void *ptr, size_t len)
{
- gtm_transaction *tx = gtm_tx();
+ gtm_thread *tx = gtm_thr();
gtm_local_undo *undo;
undo = (gtm_local_undo *) xmalloc (sizeof (struct gtm_local_undo) + len);
@@ -156,9 +156,9 @@ class serialirr_onwrite_dispatch : public serialirr_dispatch
protected:
static void pre_write()
{
- gtm_transaction *tx = gtm_tx();
- if (!(tx->state & (gtm_transaction::STATE_SERIAL
- | gtm_transaction::STATE_IRREVOCABLE)))
+ gtm_thread *tx = gtm_thr();
+ if (!(tx->state & (gtm_thread::STATE_SERIAL
+ | gtm_thread::STATE_IRREVOCABLE)))
tx->serialirr_mode();
}
@@ -191,8 +191,8 @@ class serialirr_onwrite_dispatch : public serialirr_dispatch
virtual void rollback(gtm_transaction_cp *cp)
{
- gtm_transaction *tx = gtm_tx();
- if (tx->state & gtm_transaction::STATE_IRREVOCABLE)
+ gtm_thread *tx = gtm_thr();
+ if (tx->state & gtm_thread::STATE_IRREVOCABLE)
abort();
}
};
@@ -225,7 +225,7 @@ GTM::dispatch_serialirr_onwrite ()
// Put the transaction into serial-irrevocable mode.
void
-GTM::gtm_transaction::serialirr_mode ()
+GTM::gtm_thread::serialirr_mode ()
{
struct abi_dispatch *disp = abi_disp ();
bool need_restart = true;
@@ -264,5 +264,5 @@ void ITM_REGPARM
_ITM_changeTransactionMode (_ITM_transactionState state)
{
assert (state == modeSerialIrrevocable);
- gtm_tx()->serialirr_mode ();
+ gtm_thr()->serialirr_mode ();
}
@@ -43,10 +43,10 @@ _ITM_libraryVersion (void)
_ITM_howExecuting ITM_REGPARM
_ITM_inTransaction (void)
{
- struct gtm_transaction *tx = gtm_tx();
+ struct gtm_thread *tx = gtm_thr();
if (tx && (tx->nesting > 0))
{
- if (tx->state & gtm_transaction::STATE_IRREVOCABLE)
+ if (tx->state & gtm_thread::STATE_IRREVOCABLE)
return inIrrevocableTransaction;
else
return inRetryableTransaction;
@@ -58,28 +58,11 @@ _ITM_inTransaction (void)
_ITM_transactionId_t ITM_REGPARM
_ITM_getTransactionId (void)
{
- struct gtm_transaction *tx = gtm_tx();
+ struct gtm_thread *tx = gtm_thr();
return (tx && (tx->nesting > 0)) ? tx->id : _ITM_noTransactionId;
}
-int ITM_REGPARM
-_ITM_getThreadnum (void)
-{
- static int global_num;
- struct gtm_thread *thr = setup_gtm_thr();
- int num = thr->thread_num;
-
- if (num == 0)
- {
- num = __sync_add_and_fetch (&global_num, 1);
- thr->thread_num = num;
- }
-
- return num;
-}
-
-
void ITM_REGPARM ITM_NORETURN
_ITM_error (const _ITM_srcLocation * loc UNUSED, int errorCode UNUSED)
{
@@ -25,7 +25,7 @@
#include "libitm_i.h"
void
-GTM::gtm_transaction::decide_retry_strategy (gtm_restart_reason r)
+GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r)
{
struct abi_dispatch *disp = abi_disp ();
@@ -83,7 +83,7 @@ GTM::gtm_transaction::decide_retry_strategy (gtm_restart_reason r)
// transaction. If the state is set to STATE_SERIAL, the caller will set the
// dispatch.
GTM::abi_dispatch*
-GTM::gtm_transaction::decide_begin_dispatch (uint32_t prop)
+GTM::gtm_thread::decide_begin_dispatch (uint32_t prop)
{
// ??? Probably want some environment variable to choose the default
// STM implementation once we have more than one implemented.
@@ -27,7 +27,7 @@
namespace GTM HIDDEN {
void
-gtm_transaction::rollback_user_actions(size_t until_size)
+gtm_thread::rollback_user_actions(size_t until_size)
{
for (size_t s = user_actions.size(); s > until_size; s--)
{
@@ -39,7 +39,7 @@ gtm_transaction::rollback_user_actions(size_t until_size)
void
-gtm_transaction::commit_user_actions()
+gtm_thread::commit_user_actions()
{
for (vector<user_action>::iterator i = user_actions.begin(),
ie = user_actions.end(); i != ie; i++)
@@ -58,11 +58,11 @@ void ITM_REGPARM
_ITM_addUserCommitAction(_ITM_userCommitFunction fn,
_ITM_transactionId_t tid, void *arg)
{
- gtm_transaction *tx = gtm_tx();
+ gtm_thread *tx = gtm_thr();
if (tid != _ITM_noTransactionId)
GTM_fatal("resumingTransactionId in _ITM_addUserCommitAction must be "
"_ITM_noTransactionId");
- gtm_transaction::user_action *a = tx->user_actions.push();
+ gtm_thread::user_action *a = tx->user_actions.push();
a->fn = fn;
a->arg = arg;
a->on_commit = true;
@@ -73,8 +73,8 @@ _ITM_addUserCommitAction(_ITM_userCommitFunction fn,
void ITM_REGPARM
_ITM_addUserUndoAction(_ITM_userUndoFunction fn, void * arg)
{
- gtm_transaction *tx = gtm_tx();
- gtm_transaction::user_action *a = tx->user_actions.push();
+ gtm_thread *tx = gtm_thr();
+ gtm_thread::user_action *a = tx->user_actions.push();
a->fn = fn;
a->arg = arg;
a->on_commit = false;