From patchwork Fri Aug 5 23:24:15 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Torvald Riegel X-Patchwork-Id: 108748 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 544D7B6F7B for ; Sat, 6 Aug 2011 09:24:50 +1000 (EST) Received: (qmail 23005 invoked by alias); 5 Aug 2011 23:24:47 -0000 Received: (qmail 22997 invoked by uid 22791); 5 Aug 2011 23:24:42 -0000 X-SWARE-Spam-Status: No, hits=-4.2 required=5.0 tests=AWL, BAYES_00, KAM_STOCKTIP, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_CX, TW_GJ, TW_RW, TW_TN X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 05 Aug 2011 23:24:18 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p75NOId5027506 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 5 Aug 2011 19:24:18 -0400 Received: from [10.36.7.146] (vpn1-7-146.ams2.redhat.com [10.36.7.146]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p75NOFB2017122; Fri, 5 Aug 2011 19:24:16 -0400 Subject: [trans-mem] Removed gtm_thread and threadnum. Renamed gtm_transaction to gtm_thread. From: Torvald Riegel To: GCC Patches Cc: Aldy Hernandez , Richard Henderson Date: Sat, 06 Aug 2011 01:24:15 +0200 Message-ID: <1312586655.3533.353.camel@triegel.csb> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Here is one try at cleaning up the gtm_transaction vs. gtm_thread confusion. As suggested off-list, gtm_transaction is renamed to gtm_thread. This makes up the largest part of the patch. _ITM_getThreadnum is not supported anymore. According to the ABI spec, its only purpose was to provide an ID that would match hypothetical statistics output generated by the library, but this output isn't part of the ABI nor further explained by it. _ITM_getThreadnum is the only ABI function for which we'd need thread-local storage even when no transaction is ever used by the thread, so it's seems worthwhile to remove support for it until there is a well-defined reason to provide it. Removing _ITM_getThreadnum then allows us to not keep the single-TLS-slot helper structure around (formerly gtm_thread), provided that the target offers efficient access to TLS. Otherwise, we still keep it, but it doesn't have to accessed outside of the TLS accessors for abi_disp and the new gtm_thread anymore. Note that I did have code ready to have a single statically allocated __thread gtm_thread object. However, I then saw that unlike discussed off-list, the compiler does indeed complain about using non-trivial objects with __thread (which makes sense). Is there a way to avoid this and use the explicit dtors calls and ctor calls via placement new? Assuming that this is not possible, I'd rather want objects to have constructors (e.g., for the vectors, aa_tree, etc.) than to avoid the __thread helper object (gtm_thread_tls in config/generic/tls.h, only for targets without fast access to two TLS slots) by having statically allocated __thread gtm_thread objects. Comments? commit de85227d4531eca090a19d1ec54aa91036189f5f Author: Torvald Riegel Date: Sat Aug 6 01:06:34 2011 +0200 Removed gtm_thread and threadnum. Renamed gtm_transaction to gtm_thread. * config/x86/tls.h (gtm_tx, set_gtm_tx, setup_gtm_thr): Removed. (abi_disp, set_abi_disp): Move to tx's TLS slot. (set_gtm_thr): New. * config/generic/tls.h (gtm_tx, set_gtm_tx, setup_gtm_thr): Removed. (set_gtm_thr): New. (GTM::gtm_thread::thread_num): Removed. (GTM::gtm_thread): Renamed to GTM::gtm_thread_tls. * libitm_i.h (GTM::gtm_transaction): Renamed to GTM::gtm_thread. More tx-to-thread renaming. * beginend.cc: Adapted to tx-to-thread renaming. (GTM::gtm_thread::~gtm_thread): Extracted from thread_exit_handler(). (GTM::gtm_thread::gtm_thread): Extracted from begin_transaction(). * query.cc (_ITM_getTransactionId, _ITM_inTransaction): Renamed gtm_transaction to gtm_thread. (_ITM_getThreadnum): Removed. Not supported anymore. * libitm.texi: Documented that _ITM_getThreadnum is not supported. * useraction.cc: Renamed gtm_transaction to gtm_thread. Adapted to gtm_tx-to-gtm_thr renaming if necessary. * eh_cpp.cc: Same. * local.cc: Same. * retry.cc: Same. * clone.cc: Same. * alloc.cc: Same. * alloc_c.cc: Same. * alloc_cpp.cc: Same. * method-serial.cc: Same. * config/generic/tls.cc: Same. * config/posix/rwlock.h (gtm_rwlock): Same. * config/posix/rwlock.cc: Same. Adapted to more tx-to-thread renaming. 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* 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 = >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; 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 . 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 . 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 . 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 . 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*); @@ -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::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;