diff --git a/libitm/alloc.cc b/libitm/alloc.cc
index 9b60835..810d1d5 100644
--- a/libitm/alloc.cc
+++ b/libitm/alloc.cc
@@ -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)
diff --git a/libitm/alloc_c.cc b/libitm/alloc_c.cc
index b87b304..c0cf263 100644
--- a/libitm/alloc_c.cc
+++ b/libitm/alloc_c.cc
@@ -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.  */
diff --git a/libitm/alloc_cpp.cc b/libitm/alloc_cpp.cc
index 7036c2a..59d8b73 100644
--- a/libitm/alloc_cpp.cc
+++ b/libitm/alloc_cpp.cc
@@ -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"
diff --git a/libitm/beginend.cc b/libitm/beginend.cc
index 5c2aed5..7863042 100644
--- a/libitm/beginend.cc
+++ b/libitm/beginend.cc
@@ -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 = &gtm_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;
diff --git a/libitm/clone.cc b/libitm/clone.cc
index 4d0d53d..03865a1 100644
--- a/libitm/clone.cc
+++ b/libitm/clone.cc
@@ -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 ();
   }
 };
 
diff --git a/libitm/config/generic/tls.cc b/libitm/config/generic/tls.cc
index 204e84c..74830a3 100644
--- a/libitm/config/generic/tls.cc
+++ b/libitm/config/generic/tls.cc
@@ -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.
diff --git a/libitm/config/generic/tls.h b/libitm/config/generic/tls.h
index 3eea204..e282e54 100644
--- a/libitm/config/generic/tls.h
+++ b/libitm/config/generic/tls.h
@@ -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
diff --git a/libitm/config/posix/rwlock.cc b/libitm/config/posix/rwlock.cc
index e033567..a0da0a6 100644
--- a/libitm/config/posix/rwlock.cc
+++ b/libitm/config/posix/rwlock.cc
@@ -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();
diff --git a/libitm/config/posix/rwlock.h b/libitm/config/posix/rwlock.h
index b7a51ab..f538bd0 100644
--- a/libitm/config/posix/rwlock.h
+++ b/libitm/config/posix/rwlock.h
@@ -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
diff --git a/libitm/config/x86/tls.h b/libitm/config/x86/tls.h
index 712b1c2..03fdab2 100644
--- a/libitm/config/x86/tls.h
+++ b/libitm/config/x86/tls.h
@@ -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
diff --git a/libitm/eh_cpp.cc b/libitm/eh_cpp.cc
index 35c0b50..7f482de 100644
--- a/libitm/eh_cpp.cc
+++ b/libitm/eh_cpp.cc
@@ -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)
     {
diff --git a/libitm/libitm.texi b/libitm/libitm.texi
index 5a6582b..6e4f8a0 100644
--- a/libitm/libitm.texi
+++ b/libitm/libitm.texi
@@ -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
diff --git a/libitm/libitm_i.h b/libitm/libitm_i.h
index 7d5c345..befbe8c 100644
--- a/libitm/libitm_i.h
+++ b/libitm/libitm_i.h
@@ -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 *);
 
diff --git a/libitm/local.cc b/libitm/local.cc
index 3da67ab..735e5a7 100644
--- a/libitm/local.cc
+++ b/libitm/local.cc
@@ -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);
diff --git a/libitm/method-serial.cc b/libitm/method-serial.cc
index 8f29aba..6c803d3 100644
--- a/libitm/method-serial.cc
+++ b/libitm/method-serial.cc
@@ -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 ();
 }
diff --git a/libitm/query.cc b/libitm/query.cc
index 02f1813..ce72f70 100644
--- a/libitm/query.cc
+++ b/libitm/query.cc
@@ -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)
 {
diff --git a/libitm/retry.cc b/libitm/retry.cc
index 6c10d93..957da1e 100644
--- a/libitm/retry.cc
+++ b/libitm/retry.cc
@@ -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.
diff --git a/libitm/useraction.cc b/libitm/useraction.cc
index 4042366..198f175 100644
--- a/libitm/useraction.cc
+++ b/libitm/useraction.cc
@@ -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;
