changes
authorPeizhao Ou <peizhaoo@uci.edu>
Thu, 12 Feb 2015 06:34:47 +0000 (22:34 -0800)
committerPeizhao Ou <peizhaoo@uci.edu>
Thu, 12 Feb 2015 06:34:47 +0000 (22:34 -0800)
mcs-lock/Makefile
mcs-lock/mcs-lock-wildcard.h [new file with mode: 0644]
mcs-lock/testcase1.cc [new file with mode: 0644]

index 5a311b36643f081deecb5cd4b2006aed3f9c614a..51f98910ab5ec15467bbf0e2264138e3fd35c8a1 100644 (file)
@@ -2,10 +2,16 @@ include ../benchmarks.mk
 
 TESTNAME = mcs-lock
 
-all: $(TESTNAME)
+WILDCARD_TESTS = testcase1
+
+all: $(TESTNAME) $(WILDCARD_TESTS)
+       echo $^
 
 $(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/mcs-lock/mcs-lock-wildcard.h b/mcs-lock/mcs-lock-wildcard.h
new file mode 100644 (file)
index 0000000..b8d92b2
--- /dev/null
@@ -0,0 +1,103 @@
+// mcs on stack
+
+#include <stdatomic.h>
+#include <unrelacy.h>
+#include "wildcard.h" 
+
+
+struct mcs_node {
+       std::atomic<mcs_node *> next;
+       std::atomic<int> gate;
+
+       mcs_node() {
+               next.store(0);
+               gate.store(0);
+       }
+};
+
+struct mcs_mutex {
+public:
+       // tail is null when lock is not held
+       std::atomic<mcs_node *> m_tail;
+
+       mcs_mutex() {
+               m_tail.store( NULL);
+       }
+       ~mcs_mutex() {
+               //ASSERT( m_tail.load() == NULL );
+       }
+
+       // Each thread will have their own guard.
+       class guard {
+       public:
+               mcs_mutex * m_t;
+               mcs_node    m_node; // node held on the stack
+
+               guard(mcs_mutex * t) : m_t(t) { t->lock(this); }
+               ~guard() { m_t->unlock(this); }
+       };
+
+       void lock(guard * I) {
+               mcs_node * me = &(I->m_node);
+
+               // set up my node :
+               // not published yet so relaxed :
+               me->next.store(NULL, wildcard(1) ); // relaxed
+               me->gate.store(1, wildcard(2) ); // relaxed
+
+               // publish my node as the new tail :
+               mcs_node * pred = m_tail.exchange(me, wildcard(3)); // acq_rel
+               if ( pred != NULL ) {
+                       // (*1) race here
+                       // unlock of pred can see me in the tail before I fill next
+
+                       // publish me to previous lock-holder :
+                       pred->next.store(me, wildcard(4) ); // release
+
+                       // (*2) pred not touched any more       
+
+                       // now this is the spin -
+                       // wait on predecessor setting my flag -
+                       rl::linear_backoff bo;
+                       int my_gate = 1;
+                       while ( (my_gate = me->gate.load(wildcard(5))) ) { // acquire
+                               thrd_yield();
+                       }
+               }
+       }
+
+       void unlock(guard * I) {
+               mcs_node * me = &(I->m_node);
+
+               mcs_node * next = me->next.load(wildcard(6)); // acquire
+               if ( next == NULL )
+               {
+                       mcs_node * tail_was_me = me;
+                       bool success;
+                       // FIXME: SCFence infers acq_rel / release
+                       // Could be release if wildcard(8) is acquire
+                       if ( (success = m_tail.compare_exchange_strong(
+                               tail_was_me,NULL,wildcard(7))) ) { // acq_rel
+                               // got null in tail, mutex is unlocked
+                               return;
+                       }
+
+                       // (*1) catch the race :
+                       rl::linear_backoff bo;
+                       for(;;) {
+                               // FIXME: SCFence infers relaxed / acquire
+                               // Could be relaxed if wildcard(7) is acq_rel
+                               next = me->next.load(wildcard(8)); // acquire
+                               if ( next != NULL )
+                                       break;
+                               thrd_yield();
+                       }
+               }
+
+               // (*2) - store to next must be done,
+               //  so no locker can be viewing my node any more        
+
+               // let next guy in :
+               next->gate.store( 0, wildcard(9) ); // release
+       }
+};
diff --git a/mcs-lock/testcase1.cc b/mcs-lock/testcase1.cc
new file mode 100644 (file)
index 0000000..971bf1d
--- /dev/null
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <threads.h>
+
+#include "mcs-lock-wildcard.h"
+
+/* For data race instrumentation */
+#include "librace.h"
+
+struct mcs_mutex *mutex;
+static uint32_t shared;
+
+void threadA(void *arg)
+{
+       mcs_mutex::guard g(mutex);
+       printf("store: %d\n", 17);
+       store_32(&shared, 17);
+       mutex->unlock(&g);
+       mutex->lock(&g);
+       printf("load: %u\n", load_32(&shared));
+}
+
+void threadB(void *arg)
+{
+       mcs_mutex::guard g(mutex);
+       printf("load: %u\n", load_32(&shared));
+       mutex->unlock(&g);
+       mutex->lock(&g);
+       printf("store: %d\n", 17);
+       store_32(&shared, 17);
+}
+
+int user_main(int argc, char **argv)
+{
+       thrd_t A, B;
+
+       mutex = new mcs_mutex();
+
+       thrd_create(&A, &threadA, NULL);
+       thrd_create(&B, &threadB, NULL);
+       thrd_join(A);
+       thrd_join(B);
+       return 0;
+}