X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libitm%2Fconfig%2Fposix%2Frwlock.cc;h=7ef39982ccf064b0fb0a785490d8fe3cf3789294;hp=f3793830e1203814b4f21105a6f1647541dc9ea9;hb=813b307549daffa9a654d62e98a71ea8a11f932d;hpb=4c0315d05fa0f707875686abc4f91f7a979a7c7b diff --git a/libitm/config/posix/rwlock.cc b/libitm/config/posix/rwlock.cc index f3793830e12..7ef39982ccf 100644 --- a/libitm/config/posix/rwlock.cc +++ b/libitm/config/posix/rwlock.cc @@ -53,11 +53,11 @@ void 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 - // this order. - tx->shared_state = 0; - __sync_synchronize(); - unsigned int sum = this->summary; + // intents to write. The fence ensure that this happens in exactly this + // order. + tx->shared_state.store (0, memory_order_relaxed); + atomic_thread_fence (memory_order_seq_cst); + unsigned int sum = this->summary.load (memory_order_relaxed); if (likely(!(sum & (a_writer | w_writer)))) return; @@ -69,13 +69,13 @@ gtm_rwlock::read_lock (gtm_thread *tx) // to happen before we leave the slow path and before we wait for any // writer). // ??? Add a barrier to enforce early visibility of this? - tx->shared_state = ~(typeof tx->shared_state)0; + tx->shared_state.store(-1, memory_order_relaxed); pthread_mutex_lock (&this->mutex); // Read summary again after acquiring the mutex because it might have // changed during waiting for the mutex to become free. - sum = this->summary; + sum = this->summary.load (memory_order_relaxed); // If there is a writer waiting for readers, wake it up. Only do that if we // might be the last reader that could do the wake-up, otherwise skip the @@ -92,16 +92,16 @@ gtm_rwlock::read_lock (gtm_thread *tx) // If there is an active or waiting writer, we must wait. while (sum & (a_writer | w_writer)) { - this->summary = sum | w_reader; + this->summary.store (sum | w_reader, memory_order_relaxed); this->w_readers++; pthread_cond_wait (&this->c_readers, &this->mutex); - sum = this->summary; + sum = this->summary.load (memory_order_relaxed); if (--this->w_readers == 0) sum &= ~w_reader; } // Otherwise we can acquire the lock for read. - tx->shared_state = 0; + tx->shared_state.store(0, memory_order_relaxed); pthread_mutex_unlock(&this->mutex); } @@ -124,7 +124,7 @@ gtm_rwlock::write_lock_generic (gtm_thread *tx) { pthread_mutex_lock (&this->mutex); - unsigned int sum = this->summary; + unsigned int sum = this->summary.load (memory_order_relaxed); // If there is an active writer, wait. while (sum & a_writer) @@ -137,27 +137,27 @@ gtm_rwlock::write_lock_generic (gtm_thread *tx) return false; } - this->summary = sum | w_writer; + this->summary.store (sum | w_writer, memory_order_relaxed); this->w_writers++; pthread_cond_wait (&this->c_writers, &this->mutex); - sum = this->summary; + sum = this->summary.load (memory_order_relaxed); if (--this->w_writers == 0) sum &= ~w_writer; } // Otherwise we can acquire the lock for write. As a writer, we have // priority, so we don't need to take this back. - this->summary = sum | a_writer; + this->summary.store (sum | a_writer, memory_order_relaxed); // We still need to wait for active readers to finish. The barrier makes // sure that we first set our write intent and check for active readers // after that, in strictly this order (similar to the barrier in the fast // path of read_lock()). - __sync_synchronize(); + atomic_thread_fence(memory_order_seq_cst); // If this is an upgrade, we are not a reader anymore. if (tx != 0) - tx->shared_state = ~(typeof tx->shared_state)0; + tx->shared_state.store(-1, memory_order_relaxed); // Count the number of active readers to be able to decrease the number of // wake-ups and wait calls that are necessary. @@ -194,7 +194,7 @@ gtm_rwlock::write_lock_generic (gtm_thread *tx) it = it->next_thread) { // Don't count ourself if this is an upgrade. - if (it->shared_state != ~(typeof it->shared_state)0) + if (it->shared_state.load(memory_order_relaxed) != (gtm_word)-1) readers++; } @@ -236,9 +236,18 @@ gtm_rwlock::write_upgrade (gtm_thread *tx) void gtm_rwlock::read_unlock (gtm_thread *tx) { - tx->shared_state = ~(typeof tx->shared_state)0; - __sync_synchronize(); - unsigned int sum = this->summary; + // We only need release memory order here because of privatization safety + // (this ensures that marking the transaction as inactive happens after + // any prior data accesses by this transaction, and that neither the + // compiler nor the hardware order this store earlier). + // ??? We might be able to avoid this release here if the compiler can't + // merge the release fence with the subsequent seq_cst fence. + tx->shared_state.store (-1, memory_order_release); + // We need this seq_cst fence here to avoid lost wake-ups. Furthermore, + // the privatization safety implementation in gtm_thread::try_commit() + // relies on the existence of this seq_cst fence. + atomic_thread_fence (memory_order_seq_cst); + unsigned int sum = this->summary.load (memory_order_relaxed); if (likely(!(sum & (a_writer | w_writer)))) return; @@ -271,8 +280,8 @@ gtm_rwlock::write_unlock () { pthread_mutex_lock (&this->mutex); - unsigned int sum = this->summary; - this->summary = sum & ~a_writer; + unsigned int sum = this->summary.load (memory_order_relaxed); + this->summary.store (sum & ~a_writer, memory_order_relaxed); // If there is a waiting writer, wake it. if (unlikely (sum & w_writer))