I'd like to ask for permission to backport the following two LIBITM bug
fixes to the FSF 4.8 branch.  Although these are not technically fixing
regressions, they do fix the libitm.c/reentrant.c testsuite failure on
s390 and powerpc (or at least it will when we finally get our power8
code backported to FSF 4.8).  It also fixes a real bug on x86 that is
latent because we don't currently have a test case that warms up the
x86's RTM hardware enough such that its xbegin succeeds exposing the
bug.  I'd like this backport so that the 4.8 based distros won't need
to carry this as an add-on patch.

It should also be fairly safe as well, since the fixed code is limited
to the arches (x86, s390 and powerpc) that define USE_HTM_FASTPATH,
so all others definitely won't see a difference.

I'll note I CC'd some of the usual suspects interested in TM as well
as the normal RMs, because LIBITM doesn't seem to have a maintainer
or reviewer listed in the MAINTAINERS file.  Is that an oversight or???

Peter

        Backport from mainline
        2013-06-20  Torvald Riegel  <trie...@redhat.com>

        * query.cc (_ITM_inTransaction): Abort when using the HTM fastpath.
        (_ITM_getTransactionId): Same.
        * config/x86/target.h (htm_transaction_active): New.

        2013-06-20  Torvald Riegel  <trie...@redhat.com>

        PR libitm/57643
        * beginend.cc (gtm_thread::begin_transaction): Handle reentrancy in
        the HTM fastpath.

Index: libitm/beginend.cc
===================================================================
--- libitm/beginend.cc  (revision 208151)
+++ libitm/beginend.cc  (working copy)
@@ -197,6 +197,8 @@
              // We are executing a transaction now.
              // Monitor the writer flag in the serial-mode lock, and abort
              // if there is an active or waiting serial-mode transaction.
+             // Note that this can also happen due to an enclosing
+             // serial-mode transaction; we handle this case below.
              if (unlikely(serial_lock.is_write_locked()))
                htm_abort();
              else
@@ -219,6 +221,14 @@
                  tx = new gtm_thread();
                  set_gtm_thr(tx);
                }
+             // Check whether there is an enclosing serial-mode transaction;
+             // if so, we just continue as a nested transaction and don't
+             // try to use the HTM fastpath.  This case can happen when an
+             // outermost relaxed transaction calls unsafe code that starts
+             // a transaction.
+             if (tx->nesting > 0)
+               break;
+             // Another thread is running a serial-mode transaction.  Wait.
              serial_lock.read_lock(tx);
              serial_lock.read_unlock(tx);
              // TODO We should probably reset the retry count t here, unless
Index: libitm/config/x86/target.h
===================================================================
--- libitm/config/x86/target.h  (revision 208151)
+++ libitm/config/x86/target.h  (working copy)
@@ -125,6 +125,13 @@
 {
   return begin_ret & _XABORT_RETRY;
 }
+
+/* Returns true iff a hardware transaction is currently being executed.  */
+static inline bool
+htm_transaction_active ()
+{
+  return _xtest() != 0;
+}
 #endif


Index: libitm/query.cc
===================================================================
--- libitm/query.cc     (revision 208151)
+++ libitm/query.cc     (working copy)
@@ -43,6 +43,15 @@
 _ITM_howExecuting ITM_REGPARM
 _ITM_inTransaction (void)
 {
+#if defined(USE_HTM_FASTPATH)
+  // If we use the HTM fastpath, we cannot reliably detect whether we are
+  // in a transaction because this function can be called outside of
+  // a transaction and thus we can't deduce this by looking at just the serial
+  // lock.  This function isn't used in practice currently, so the easiest
+  // way to handle it is to just abort.
+  if (htm_fastpath && htm_transaction_active())
+    htm_abort();
+#endif
   struct gtm_thread *tx = gtm_thr();
   if (tx && (tx->nesting > 0))
     {
@@ -58,6 +67,11 @@
 _ITM_transactionId_t ITM_REGPARM
 _ITM_getTransactionId (void)
 {
+#if defined(USE_HTM_FASTPATH)
+  // See ITM_inTransaction.
+  if (htm_fastpath && htm_transaction_active())
+    htm_abort();
+#endif
   struct gtm_thread *tx = gtm_thr();
   return (tx && (tx->nesting > 0)) ? tx->id : _ITM_noTransactionId;
 }


Reply via email to