]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libitm/method-gl.cc
Add -fmin-function-alignmnet
[thirdparty/gcc.git] / libitm / method-gl.cc
index 5bae22b90c161adcec077efa7c2ecf3c4e95f1e2..d6c054dc64b5e8afbc187da838093561120d5078 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2024 Free Software Foundation, Inc.
    Contributed by Torvald Riegel <triegel@redhat.com>.
 
    This file is part of the GNU Transactional Memory Library (libitm).
@@ -41,7 +41,8 @@ struct gl_mg : public method_group
   static gtm_word clear_locked(gtm_word l) { return l & ~LOCK_BIT; }
 
   // The global ownership record.
-  atomic<gtm_word> orec;
+  // No tail-padding necessary (the virtual functions aren't used frequently).
+  atomic<gtm_word> orec __attribute__((aligned(HW_CACHELINE_SIZE)));
 
   virtual void init()
   {
@@ -52,7 +53,6 @@ struct gl_mg : public method_group
   virtual void fini() { }
 };
 
-// TODO cacheline padding
 static gl_mg o_gl_mg;
 
 
@@ -291,12 +291,18 @@ public:
         // See begin_or_restart() for why we need release memory order here.
        v = gl_mg::clear_locked(v) + 1;
        o_gl_mg.orec.store(v, memory_order_release);
-
-       // Need to ensure privatization safety. Every other transaction must
-       // have a snapshot time that is at least as high as our commit time
-       // (i.e., our commit must be visible to them).
-       priv_time = v;
       }
+
+    // Need to ensure privatization safety. Every other transaction must have
+    // a snapshot time that is at least as high as our commit time (i.e., our
+    // commit must be visible to them).  Because of proxy privatization, we
+    // must ensure that even if we are a read-only transaction.  See
+    // ml_wt_dispatch::trycommit() for details: We can't get quite the same
+    // set of problems because we just use one orec and thus, for example,
+    // there cannot be concurrent writers -- but we can still get pending
+    // loads to privatized data when not ensuring privatization safety, which
+    // is problematic if the program unmaps the privatized memory.
+    priv_time = v;
     return true;
   }
 
@@ -314,30 +320,43 @@ public:
     // value that is correct wrt. privatization safety.
     if (gl_mg::is_locked(v))
       {
-       // Release the global orec, increasing its version number / timestamp.
-        // See begin_or_restart() for why we need release memory order here.
+       // With our rollback, global time increases.
        v = gl_mg::clear_locked(v) + 1;
-       o_gl_mg.orec.store(v, memory_order_release);
 
-       // Also reset the timestamp published via shared_state.
+       // First reset the timestamp published via shared_state.  Release
+       // memory order will make this happen after undoing prior data writes.
+       // This must also happen before we actually release the global orec
+       // next, so that future update transactions in other threads observe
+       // a meaningful snapshot time for our transaction; otherwise, they
+       // could read a shared_store value with the LOCK_BIT set, which can
+       // break privatization safety because it's larger than the actual
+       // snapshot time.  Note that we only need to consider other update
+       // transactions because only those will potentially privatize data.
        tx->shared_state.store(v, memory_order_release);
 
-       // We need a store-load barrier after this store to prevent it
-       // from becoming visible after later data loads because the
-       // previous value of shared_state has been higher than the actual
-       // snapshot time (the lock bit had been set), which could break
-       // privatization safety. We do not need a barrier before this
-       // store (see pre_write() for an explanation).
-       // ??? What is the precise reasoning in the C++11 model?
-       atomic_thread_fence(memory_order_seq_cst);
+       // Release the global orec, increasing its version number / timestamp.
+       // See begin_or_restart() for why we need release memory order here,
+       // and we also need it to make future update transactions read the
+       // prior update to shared_state too (update transactions acquire the
+       // global orec with acquire memory order).
+       o_gl_mg.orec.store(v, memory_order_release);
       }
 
   }
 
+  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()
 
-  gl_wt_dispatch() : abi_dispatch(false, true, false, false, &o_gl_mg)
+  gl_wt_dispatch() : abi_dispatch(false, true, false, false, 0, &o_gl_mg)
   { }
 };