barrier with weaker inferences & notes in comment
authorPeizhao Ou <peizhaoo@uci.edu>
Fri, 13 Feb 2015 01:02:50 +0000 (17:02 -0800)
committerPeizhao Ou <peizhaoo@uci.edu>
Fri, 13 Feb 2015 01:02:50 +0000 (17:02 -0800)
barrier/Makefile
barrier/barrier-wildcard.h [new file with mode: 0644]
barrier/testcase.cc [new file with mode: 0644]

index 22df22369b2b102e4dfc22fb4825c7a7f6e01ed3..90389ba617f40eab315b7a06e3536b5537f3f3b9 100644 (file)
@@ -2,10 +2,15 @@ include ../benchmarks.mk
 
 TESTNAME = barrier
 
-all: $(TESTNAME)
+WILDCARD_TESTS = testcase
+
+all: $(TESTNAME) $(WILDCARD_TESTS)
 
 $(TESTNAME): $(TESTNAME).cc $(TESTNAME).h
        $(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS)
 
+$(WILDCARD_TESTS): % : %.cc $(TESTNAME)-wildcard.h
+       $(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS)
+
 clean:
-       rm -f $(TESTNAME) *.o
+       rm -f $(TESTNAME) *.o $(WILDCARD_TESTS)
diff --git a/barrier/barrier-wildcard.h b/barrier/barrier-wildcard.h
new file mode 100644 (file)
index 0000000..58d01c5
--- /dev/null
@@ -0,0 +1,53 @@
+#include <atomic>
+#include "wildcard.h"
+
+class spinning_barrier {
+ public:
+       spinning_barrier (unsigned int n) : n_ (n) {
+               nwait_ = 0;
+               step_ = 0;
+       }
+
+       // The purpose of wait() is that threads that enter it synchronize with
+       // threads when they get out of it.
+       /** wildcard(2) is acq_rel, ensuring that all threads hb before other
+        *  threads in the rmw chain order, then the wildcard (4) and (5) are
+        *  release/acquire to make sure the last thread synchronize with all other
+        *  earlier threads. Plus, the (4) and (5) synchronization can make sure the
+        *  reset of nwait_ in wildcard(3) happens-before any other threads in the
+        *  later usage of the barrier.
+       */
+
+       // All orderings are SC originally!!!
+       bool wait() {
+               // Infer relaxed
+               unsigned int step = step_.load (wildcard(1));
+               
+               // Infer acq_rel 
+               if (nwait_.fetch_add (1, wildcard(2)) == n_ - 1) {
+                       /* OK, last thread to come.  */
+                       // Infer relaxed 
+                       nwait_.store (0, wildcard(3)); // XXX: maybe can use relaxed ordering here ??
+                       // Infer release
+                       step_.fetch_add (1, wildcard(4));
+                       return true;
+               } else {
+                       /* Run in circles and scream like a little girl.  */
+                       // Infer acquire 
+                       while (step_.load (wildcard(5)) == step)
+                               thrd_yield();
+                       return false;
+               }
+       }
+
+ protected:
+       /* Number of synchronized threads. */
+       const unsigned int n_;
+
+       /* Number of threads currently spinning.  */
+       std::atomic<unsigned int> nwait_;
+
+       /* Number of barrier syncronizations completed so far, 
+        *      * it's OK to wrap.  */
+       std::atomic<unsigned int> step_;
+};
diff --git a/barrier/testcase.cc b/barrier/testcase.cc
new file mode 100644 (file)
index 0000000..2d0ba49
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <threads.h>
+
+#include "barrier-wildcard.h"
+
+#include "librace.h"
+#include <atomic> 
+
+spinning_barrier *barr;
+std::atomic_int var;
+
+void threadA(void *arg)
+{
+       //store_32(&var, 1);
+       var.store(1, std::memory_order_relaxed);
+       barr->wait();
+}
+
+void threadB(void *arg)
+{
+       barr->wait();
+       //printf("var = %d\n", load_32(&var));
+       var.load(std::memory_order_relaxed);
+}
+
+#define NUMREADERS 2
+int user_main(int argc, char **argv)
+{
+       thrd_t A, B[NUMREADERS];
+       int i;
+
+       barr = new spinning_barrier(NUMREADERS + 1);
+
+       thrd_create(&A, &threadA, NULL);
+       for (i = 0; i < NUMREADERS; i++)
+               thrd_create(&B[i], &threadB, NULL);
+
+       for (i = 0; i < NUMREADERS; i++)
+               thrd_join(B[i]);
+       thrd_join(A);
+
+       return 0;
+}