4 #include "libinterface.h"
9 MCID _mnext; mcs_node * next;
13 MC2_nextOpStore(MCID_NODEP, MCID_NODEP);
15 MC2_nextOpStore(MCID_NODEP, MCID_NODEP);
22 // tail is null when lock is not held
26 MC2_nextOpStore(MCID_NODEP, MCID_NODEP);
27 store_64(&m_tail, (uint64_t)NULL);
30 // ASSERT( m_tail.load() == NULL );
36 mcs_node m_node; // node held on the stack
38 guard(MCID _mt, mcs_mutex * t) : m_t(t) { t->lock(MCID_NODEP, this); }
39 ~guard() { m_t->unlock(MCID_NODEP, this); }
42 void lock(MCID _mI, guard * I) {
43 MCID _mme; mcs_node * me = &(I->m_node);
46 // not published yet so relaxed :
48 void * _p0 = &me->next;
49 MCID _fn0 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p0, (uint64_t)_mme); MC2_nextOpStore(_fn0, MCID_NODEP);
50 store_64(_p0, (uint64_t)NULL);
52 void * _p1 = &me->gate;
53 MCID _fn1 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p1, (uint64_t)_mme); MC2_nextOpStore(_fn1, MCID_NODEP);
56 // publish my node as the new tail :
57 // mcs_node * pred = m_tail.exchange(me, std::mo_acq_rel);
58 MCID _rmw0 = MC2_nextRMW(MCID_NODEP, _mme, MCID_NODEP);
59 MCID _mpred; mcs_node * pred = (mcs_node *)rmw_64(EXC, &m_tail, (uint64_t) me, (uint64_t) NULL);
63 // unlock of pred can see me in the tail before I fill next
65 // publish me to previous lock-holder :
66 _br0 = MC2_branchUsesID(_rmw0, 1, 2, true);
68 void * _p2 = &pred->next;
69 MCID _fn2 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p2, (uint64_t)_mpred); MC2_nextOpStore(_fn2, _mme);
70 store_64(_p2, (uint64_t)me);
72 // (*2) pred not touched any more
74 // now this is the spin -
75 // wait on predecessor setting my flag -
79 void * _p99 = &me->gate;
80 MCID _fn99 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p99, (uint64_t)_mme); MC2_nextOpLoad(_fn99);
81 int c88 = !load_32(_p99);
82 MCID _fn88 = MC2_function(1, MC2_PTR_LENGTH, c88, _p99);
84 _br1 = MC2_branchUsesID(_fn88, 1, 2, true);
87 _br1 = MC2_branchUsesID(_fn88, 0, 2, true);
96 } else { _br0 = MC2_branchUsesID(_rmw0, 0, 2, true); MC2_merge(_br0);
100 void unlock(MCID _mI, guard * I) {
101 MCID _mme; mcs_node * me;
105 void * _p3 = &me->next;
106 MCID _mnext; MCID _fn3 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p3, _mme); _mnext=MC2_nextOpLoad(_fn3); mcs_node * next = (mcs_node *)load_64(_p3);
110 _br2 = MC2_branchUsesID(_mnext, 1, 2, true);
111 mcs_node * tail_was_me = me;
112 //if ( m_tail.compare_exchange_strong( tail_was_me,NULL,std::mo_acq_rel) ) {
114 MCID _rmw77 = MC2_nextRMW(MCID_NODEP, MCID_NODEP, MCID_NODEP);
115 if (rmw_64(CAS, &m_tail, (uint64_t)tail_was_me, (uint64_t)NULL)) {
116 // got null in tail, mutex is unlocked
117 _br3 = MC2_branchUsesID(_rmw77, 1, 2, true);
119 } else { _br3 = MC2_branchUsesID(_rmw77, 0, 2, true); MC2_merge(_br3);
122 // (*1) catch the race :
126 void * _p4 = &me->next;
127 MCID _fn4 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p4, _mme); _fn6=MC2_nextOpLoad(_fn4), next = (mcs_node *)load_64(_p4);
128 _fn6 = MC2_function(1, sizeof (next), (uint64_t)next, (uint64_t)_fn6);
130 if ( next != NULL ) {
131 _br4 = MC2_branchUsesID(_fn6, 1, 2, true);
134 _br4 = MC2_branchUsesID(_fn6, 0, 2, true);
143 } else { _br2 = MC2_branchUsesID(_mnext, 0, 2, true); MC2_merge(_br2);
146 // (*2) - store to next must be done,
147 // so no locker can be viewing my node any more
151 void * _p5 = &next->gate;
152 MCID _fn5 = MC2_function(1, MC2_PTR_LENGTH, (uint64_t)_p5, _fn6); MC2_nextOpStore(_fn5, MCID_NODEP);
157 struct mcs_mutex *mutex;
158 static uint32_t shared;
160 void threadA(void *arg)
162 mcs_mutex::guard g(MCID_NODEP, mutex);
163 printf("store: %d\n", 17);
164 MC2_nextOpStore(MCID_NODEP, MCID_NODEP);
165 store_32(&shared, 17);
166 mutex->unlock(MCID_NODEP, &g);
167 mutex->lock(MCID_NODEP, &g);
168 printf("load: %u\n", load_32(&shared));
171 void threadB(void *arg)
173 mcs_mutex::guard g(MCID_NODEP, mutex);
174 printf("load: %u\n", load_32(&shared));
175 mutex->unlock(MCID_NODEP, &g);
176 mutex->lock(MCID_NODEP, &g);
177 printf("store: %d\n", 17);
178 MC2_nextOpStore(MCID_NODEP, MCID_NODEP);
179 store_32(&shared, 17);
182 int user_main(int argc, char **argv)
186 mutex = new mcs_mutex();
188 thrd_create(&A, &threadA, NULL);
189 thrd_create(&B, &threadB, NULL);