Blame SOURCES/gcc48-rh1491395.patch

5ed81e
2016-01-16  Torvald Riegel  <triegel@redhat.com>
5ed81e
5ed81e
	* method-gl.cc (gl_wt_dispatch::trycommit): Ensure proxy privatization
5ed81e
	safety.
5ed81e
	* method-ml.cc (ml_wt_dispatch::trycommit): Likewise.
5ed81e
	* libitm/testsuite/libitm.c/priv-1.c: New.
5ed81e
5ed81e
--- libitm/method-gl.cc
5ed81e
+++ libitm/method-gl.cc
5ed81e
@@ -291,12 +291,18 @@ public:
5ed81e
         // See begin_or_restart() for why we need release memory order here.
5ed81e
 	v = gl_mg::clear_locked(v) + 1;
5ed81e
 	o_gl_mg.orec.store(v, memory_order_release);
5ed81e
-
5ed81e
-	// Need to ensure privatization safety. Every other transaction must
5ed81e
-	// have a snapshot time that is at least as high as our commit time
5ed81e
-	// (i.e., our commit must be visible to them).
5ed81e
-	priv_time = v;
5ed81e
       }
5ed81e
+
5ed81e
+    // Need to ensure privatization safety. Every other transaction must have
5ed81e
+    // a snapshot time that is at least as high as our commit time (i.e., our
5ed81e
+    // commit must be visible to them).  Because of proxy privatization, we
5ed81e
+    // must ensure that even if we are a read-only transaction.  See
5ed81e
+    // ml_wt_dispatch::trycommit() for details: We can't get quite the same
5ed81e
+    // set of problems because we just use one orec and thus, for example,
5ed81e
+    // there cannot be concurrent writers -- but we can still get pending
5ed81e
+    // loads to privatized data when not ensuring privatization safety, which
5ed81e
+    // is problematic if the program unmaps the privatized memory.
5ed81e
+    priv_time = v;
5ed81e
     return true;
5ed81e
   }
5ed81e
 
5ed81e
--- libitm/method-ml.cc
5ed81e
+++ libitm/method-ml.cc
5ed81e
@@ -513,6 +513,21 @@ public:
5ed81e
     if (!tx->writelog.size())
5ed81e
       {
5ed81e
         tx->readlog.clear();
5ed81e
+        // We still need to ensure privatization safety, unfortunately.  While
5ed81e
+        // we cannot have privatized anything by ourselves (because we are not
5ed81e
+        // an update transaction), we can have observed the commits of
5ed81e
+        // another update transaction that privatized something.  Because any
5ed81e
+        // commit happens before ensuring privatization, our snapshot and
5ed81e
+        // commit can thus have happened before ensuring privatization safety
5ed81e
+        // for this commit/snapshot time.  Therefore, before we can return to
5ed81e
+        // nontransactional code that might use the privatized data, we must
5ed81e
+        // ensure privatization safety for our snapshot time.
5ed81e
+        // This still seems to be better than not allowing use of the
5ed81e
+        // snapshot time before privatization safety has been ensured because
5ed81e
+        // we at least can run transactions such as this one, and in the
5ed81e
+        // meantime the transaction producing this commit time might have
5ed81e
+        // finished ensuring privatization safety for it.
5ed81e
+        priv_time = tx->shared_state.load(memory_order_relaxed);
5ed81e
         return true;
5ed81e
       }
5ed81e
 
5ed81e
--- /dev/null
5ed81e
+++ libitm/testsuite/libitm.c/priv-1.c
5ed81e
@@ -0,0 +1,117 @@
5ed81e
+/* Quick stress test for proxy privatization.  */
5ed81e
+
5ed81e
+/* We need to use a TM method that has to enforce privatization safety
5ed81e
+   explicitly.  */
5ed81e
+/* { dg-set-target-env-var ITM_DEFAULT_METHOD "ml_wt" } */
5ed81e
+/* { dg-options "-std=gnu11" } */
5ed81e
+
5ed81e
+#include <stdlib.h>
5ed81e
+#include <stdio.h>
5ed81e
+#include <pthread.h>
5ed81e
+
5ed81e
+/* Make them likely to be mapped to different orecs.  */
5ed81e
+#define ALIGN __attribute__((aligned (256)))
5ed81e
+/* Don't make these static to work around PR 68591.  */
5ed81e
+int x ALIGN;
5ed81e
+int *ptr ALIGN;
5ed81e
+int *priv_ptr ALIGN;
5ed81e
+int priv_value ALIGN;
5ed81e
+int barrier ALIGN = 0;
5ed81e
+const int iters = 100;
5ed81e
+
5ed81e
+static void arrive_and_wait (int expected_value)
5ed81e
+{
5ed81e
+  int now = __atomic_add_fetch (&barrier, 1, __ATOMIC_ACQ_REL);
5ed81e
+  while (now < expected_value)
5ed81e
+    __atomic_load (&barrier, &now, __ATOMIC_ACQUIRE);
5ed81e
+}
5ed81e
+
5ed81e
+static void __attribute__((transaction_pure,noinline)) delay (int i)
5ed81e
+{
5ed81e
+  for (volatile int v = 0; v < i; v++);
5ed81e
+}
5ed81e
+
5ed81e
+/* This tries to catch a case in which proxy privatization safety is not
5ed81e
+   ensured by privatization_user.  Specifically, it's access to the value
5ed81e
+   of it's transactional snapshot of ptr must read from an uncommitted write
5ed81e
+   by writer; thus, writer must still be active but must have read ptr before
5ed81e
+   proxy can privatize *ptr by assigning to ptr.
5ed81e
+   We try to make this interleaving more likely by delaying the commit of
5ed81e
+   writer and the start of proxy.  */
5ed81e
+static void *writer (void *dummy __attribute__((unused)))
5ed81e
+{
5ed81e
+  for (int i = 0; i < iters; i++)
5ed81e
+    {
5ed81e
+      /* Initialize state in each round.  */
5ed81e
+      x = 0;
5ed81e
+      ptr = &x;
5ed81e
+      priv_ptr = NULL;
5ed81e
+      int wrote = 1;
5ed81e
+      arrive_and_wait (i * 6 + 3);
5ed81e
+      /* Interference by another writer.  Has a conflict with the proxy
5ed81e
+	 privatizer.  */
5ed81e
+      __transaction_atomic
5ed81e
+	{
5ed81e
+	  if (ptr != NULL)
5ed81e
+	    *ptr = 1;
5ed81e
+	  else
5ed81e
+	    wrote = 0;
5ed81e
+	  delay (2000000);
5ed81e
+	}
5ed81e
+      arrive_and_wait (i * 6 + 6);
5ed81e
+      /* If the previous transaction committed first, wrote == 1 and x == 1;
5ed81e
+	 otherwise, if the proxy came first, wrote == 0 and priv_value == 0.
5ed81e
+       */
5ed81e
+      if (wrote != priv_value)
5ed81e
+	abort ();
5ed81e
+    }
5ed81e
+  return NULL;
5ed81e
+}
5ed81e
+
5ed81e
+static void *proxy (void *dummy __attribute__((unused)))
5ed81e
+{
5ed81e
+  for (int i = 0; i < iters; i++)
5ed81e
+    {
5ed81e
+      arrive_and_wait (i * 6 + 3);
5ed81e
+      delay(1000000);
5ed81e
+      __transaction_atomic
5ed81e
+	{
5ed81e
+	  /* Hand-off to privatization-user and its read-only transaction and
5ed81e
+	     subsequent use of privatization.  */
5ed81e
+	  priv_ptr = ptr;
5ed81e
+	  ptr = NULL;
5ed81e
+	}
5ed81e
+      arrive_and_wait (i * 6 + 6);
5ed81e
+    }
5ed81e
+  return NULL;
5ed81e
+}
5ed81e
+
5ed81e
+static void *privatization_user (void *dummy __attribute__((unused)))
5ed81e
+{
5ed81e
+  for (int i = 0; i < iters; i++)
5ed81e
+    {
5ed81e
+      arrive_and_wait (i * 6 + 3);
5ed81e
+      /* Spin until we have gotten a pointer from the proxy.  Then access
5ed81e
+	 the value pointed to nontransactionally.  */
5ed81e
+      int *p = NULL;
5ed81e
+      while (p == NULL)
5ed81e
+	__transaction_atomic { p = priv_ptr; }
5ed81e
+      priv_value = *p;
5ed81e
+      arrive_and_wait (i * 6 + 6);
5ed81e
+    }
5ed81e
+  return NULL;
5ed81e
+}
5ed81e
+
5ed81e
+int main()
5ed81e
+{
5ed81e
+  pthread_t p[3];
5ed81e
+
5ed81e
+  pthread_create (p+0, NULL, writer, NULL);
5ed81e
+  pthread_create (p+1, NULL, proxy, NULL);
5ed81e
+  pthread_create (p+2, NULL, privatization_user, NULL);
5ed81e
+
5ed81e
+  for (int i = 0; i < 3; ++i)
5ed81e
+    pthread_join  (p[i], NULL);
5ed81e
+
5ed81e
+  return 0;
5ed81e
+}