4 #include "libinterface.h"
20 // tail is null when lock is not held
24 store_64(&m_tail, (uint64_t)NULL);
27 // ASSERT( m_tail.load() == NULL );
33 mcs_node m_node; // node held on the stack
35 guard(mcs_mutex * t) : m_t(t) { t->lock(this); }
36 ~guard() { m_t->unlock(this); }
39 void lock(guard * I) {
40 mcs_node * me = &(I->m_node);
43 // not published yet so relaxed :
44 store_64(&me->next, (uint64_t)NULL);
45 store_32(&me->gate, 1);
47 // publish my node as the new tail :
48 // mcs_node * pred = m_tail.exchange(me, std::mo_acq_rel);
49 mcs_node * pred = (mcs_node *)rmw_64(EXC, &m_tail, (uint64_t) me, (uint64_t) NULL);
52 // unlock of pred can see me in the tail before I fill next
54 // publish me to previous lock-holder :
55 store_64(&pred->next, (uint64_t)me);
57 // (*2) pred not touched any more
59 // now this is the spin -
60 // wait on predecessor setting my flag -
62 if (!load_32(&me->gate)) {
72 void unlock(guard * I) {
73 mcs_node * me = &(I->m_node);
75 mcs_node * next = (mcs_node *)load_64(&me->next);
78 mcs_node * tail_was_me = me;
79 //if ( m_tail.compare_exchange_strong( tail_was_me,NULL,std::mo_acq_rel) ) {
80 if (rmw_64(CAS, &m_tail, (uint64_t)tail_was_me, (uint64_t)NULL)) {
81 // got null in tail, mutex is unlocked
85 // (*1) catch the race :
87 next = (mcs_node *)load_64(&me->next);
97 // (*2) - store to next must be done,
98 // so no locker can be viewing my node any more
101 store_32(&next->gate, 0);
105 struct mcs_mutex *mutex;
106 static uint32_t shared;
108 void threadA(void *arg)
110 mcs_mutex::guard g(mutex);
111 printf("store: %d\n", 17);
112 store_32(&shared, 17);
115 printf("load: %u\n", load_32(&shared));
118 void threadB(void *arg)
120 mcs_mutex::guard g(mutex);
121 printf("load: %u\n", load_32(&shared));
124 printf("store: %d\n", 17);
125 store_32(&shared, 17);
128 int user_main(int argc, char **argv)
132 mutex = new mcs_mutex();
134 thrd_create(&A, &threadA, NULL);
135 thrd_create(&B, &threadB, NULL);