mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 13:54:19 +08:00
libitm: Fix privatization safety interaction with serial mode.
From-SVN: r232322
This commit is contained in:
parent
8bc47ae2a7
commit
629e47295b
@ -1,3 +1,15 @@
|
||||
2016-01-13 Torvald Riegel <triegel@redhat.com>
|
||||
|
||||
* beginend.cc (gtm_thread::trycommit): Fix privatization safety.
|
||||
* config/linux/rwlock.cc (gtm_rwlock::write_lock_generic): Likewise.
|
||||
* config/posix/rwlock.cc (gtm_rwlock::write_lock_generic): Likewise.
|
||||
* dispatch.h (abi_dispatch::snapshot_most_recent): New.
|
||||
* method-gl.cc (gl_wt_dispatch::snapshot_most_recent): New.
|
||||
* method-ml.cc (ml_wt_dispatch::snapshot_most_recent): New.
|
||||
* method-serial.cc (serial_dispatch::snapshot_most_recent): New.
|
||||
(serialirr_dispatch::snapshot_most_recent): New.
|
||||
(serialirr_onwrite_dispatch::snapshot_most_recent): New.
|
||||
|
||||
2016-01-12 Torvald Riegel <triegel@redhat.com>
|
||||
|
||||
* libitm_i.h (gtm_mask_stack): Remove.
|
||||
|
@ -568,8 +568,9 @@ GTM::gtm_thread::trycommit ()
|
||||
gtm_word priv_time = 0;
|
||||
if (abi_disp()->trycommit (priv_time))
|
||||
{
|
||||
// The transaction is now inactive. Everything that we still have to do
|
||||
// will not synchronize with other transactions anymore.
|
||||
// The transaction is now finished but we will still access some shared
|
||||
// data if we have to ensure privatization safety.
|
||||
bool do_read_unlock = false;
|
||||
if (state & gtm_thread::STATE_SERIAL)
|
||||
{
|
||||
gtm_thread::serial_lock.write_unlock ();
|
||||
@ -578,7 +579,27 @@ GTM::gtm_thread::trycommit ()
|
||||
priv_time = 0;
|
||||
}
|
||||
else
|
||||
gtm_thread::serial_lock.read_unlock (this);
|
||||
{
|
||||
// If we have to ensure privatization safety, we must not yet
|
||||
// release the read lock and become inactive because (1) we still
|
||||
// have to go through the list of all transactions, which can be
|
||||
// modified by serial mode threads, and (2) we interpret each
|
||||
// transactions' shared_state in the context of what we believe to
|
||||
// be the current method group (and serial mode transactions can
|
||||
// change the method group). Therefore, if we have to ensure
|
||||
// privatization safety, delay becoming inactive but set a maximum
|
||||
// snapshot time (we have committed and thus have an empty snapshot,
|
||||
// so it will always be most recent). Use release MO so that this
|
||||
// synchronizes with other threads observing our snapshot time.
|
||||
if (priv_time)
|
||||
{
|
||||
do_read_unlock = true;
|
||||
shared_state.store((~(typeof gtm_thread::shared_state)0) - 1,
|
||||
memory_order_release);
|
||||
}
|
||||
else
|
||||
gtm_thread::serial_lock.read_unlock (this);
|
||||
}
|
||||
state = 0;
|
||||
|
||||
// We can commit the undo log after dispatch-specific commit and after
|
||||
@ -618,8 +639,11 @@ GTM::gtm_thread::trycommit ()
|
||||
}
|
||||
}
|
||||
|
||||
// After ensuring privatization safety, we execute potentially
|
||||
// privatizing actions (e.g., calling free()). User actions are first.
|
||||
// After ensuring privatization safety, we are now truly inactive and
|
||||
// thus can release the read lock. We will also execute potentially
|
||||
// privatizing actions (e.g., calling free()). User actions are first.
|
||||
if (do_read_unlock)
|
||||
gtm_thread::serial_lock.read_unlock (this);
|
||||
commit_user_actions ();
|
||||
commit_allocations (false, 0);
|
||||
|
||||
|
@ -158,6 +158,19 @@ gtm_rwlock::write_lock_generic (gtm_thread *tx)
|
||||
while (it->shared_state.load (memory_order_relaxed)
|
||||
!= ~(typeof it->shared_state)0)
|
||||
{
|
||||
// If this is an upgrade, we have to break deadlocks with
|
||||
// privatization safety. This may fail on our side, in which
|
||||
// case we need to cancel our attempt to upgrade. Also, we do not
|
||||
// block but just spin so that we never have to be woken.
|
||||
if (tx != 0)
|
||||
{
|
||||
if (!abi_disp()->snapshot_most_recent ())
|
||||
{
|
||||
write_unlock ();
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// An active reader. Wait until it has finished. To avoid lost
|
||||
// wake-ups, we need to use Dekker-like synchronization.
|
||||
// Note that we can reset writer_readers to zero when we see after
|
||||
|
@ -200,6 +200,26 @@ gtm_rwlock::write_lock_generic (gtm_thread *tx)
|
||||
if (readers == 0)
|
||||
break;
|
||||
|
||||
// If this is an upgrade, we have to break deadlocks with
|
||||
// privatization safety. This may fail on our side, in which
|
||||
// case we need to cancel our attempt to upgrade. Also, we do not
|
||||
// block using the convdar but just spin so that we never have to be
|
||||
// woken.
|
||||
// FIXME This is horribly inefficient -- but so is not being able
|
||||
// to use futexes in this case.
|
||||
if (tx != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&this->mutex);
|
||||
if (!abi_disp ()->snapshot_most_recent ())
|
||||
{
|
||||
write_unlock ();
|
||||
return false;
|
||||
}
|
||||
pthread_mutex_lock (&this->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// We've seen a number of readers, so we publish this number and wait.
|
||||
this->a_readers = readers;
|
||||
pthread_cond_wait (&this->c_confirmed_writers, &this->mutex);
|
||||
|
@ -291,6 +291,10 @@ public:
|
||||
// Rolls back a transaction. Called on abort or after trycommit() returned
|
||||
// false.
|
||||
virtual void rollback(gtm_transaction_cp *cp = 0) = 0;
|
||||
// Returns true iff the snapshot is most recent, which will be the case if
|
||||
// this transaction cannot be the reason why other transactions cannot
|
||||
// ensure privatization safety.
|
||||
virtual bool snapshot_most_recent() = 0;
|
||||
|
||||
// Return an alternative method that is compatible with the current
|
||||
// method but supports closed nesting. Return zero if there is none.
|
||||
|
@ -338,6 +338,15 @@ public:
|
||||
|
||||
}
|
||||
|
||||
virtual bool snapshot_most_recent()
|
||||
{
|
||||
// This is the same check as in validate() except that we do not restart
|
||||
// on failure but simply return the result.
|
||||
return o_gl_mg.orec.load(memory_order_relaxed)
|
||||
== gtm_thr()->shared_state.load(memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
||||
CREATE_DISPATCH_METHODS(virtual, )
|
||||
CREATE_DISPATCH_METHODS_MEM()
|
||||
|
||||
|
@ -604,6 +604,24 @@ public:
|
||||
tx->readlog.clear();
|
||||
}
|
||||
|
||||
virtual bool snapshot_most_recent()
|
||||
{
|
||||
// This is the same code as in extend() except that we do not restart
|
||||
// on failure but simply return the result, and that we don't validate
|
||||
// if our snapshot is already most recent.
|
||||
gtm_thread* tx = gtm_thr();
|
||||
gtm_word snapshot = o_ml_mg.time.load(memory_order_acquire);
|
||||
if (snapshot == tx->shared_state.load(memory_order_relaxed))
|
||||
return true;
|
||||
if (!validate(tx))
|
||||
return false;
|
||||
|
||||
// Update our public snapshot time. Necessary so that we do not prevent
|
||||
// other transactions from ensuring privatization safety.
|
||||
tx->shared_state.store(snapshot, memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool supports(unsigned number_of_threads)
|
||||
{
|
||||
// Each txn can commit and fail and rollback once before checking for
|
||||
|
@ -95,6 +95,7 @@ class serialirr_dispatch : public abi_dispatch
|
||||
virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; }
|
||||
virtual bool trycommit(gtm_word& priv_time) { return true; }
|
||||
virtual void rollback(gtm_transaction_cp *cp) { abort(); }
|
||||
virtual bool snapshot_most_recent() { return true; }
|
||||
|
||||
virtual abi_dispatch* closed_nesting_alternative()
|
||||
{
|
||||
@ -149,6 +150,7 @@ public:
|
||||
// Local undo will handle this.
|
||||
// trydropreference() need not be changed either.
|
||||
virtual void rollback(gtm_transaction_cp *cp) { }
|
||||
virtual bool snapshot_most_recent() { return true; }
|
||||
|
||||
CREATE_DISPATCH_METHODS(virtual, )
|
||||
CREATE_DISPATCH_METHODS_MEM()
|
||||
@ -210,6 +212,8 @@ class serialirr_onwrite_dispatch : public serialirr_dispatch
|
||||
if (tx->state & gtm_thread::STATE_IRREVOCABLE)
|
||||
abort();
|
||||
}
|
||||
|
||||
virtual bool snapshot_most_recent() { return true; }
|
||||
};
|
||||
|
||||
// This group is pure HTM with serial mode as a fallback. There is no
|
||||
|
Loading…
Reference in New Issue
Block a user