8 #include <cdsannotate.h>
9 #include <specannotation.h>
10 #include <model_memory.h>
13 std::atomic<mcs_node *> next;
14 std::atomic<int> gate;
25 // tail is null when lock is not held
26 std::atomic<mcs_node *> m_tail;
37 ASSERT( m_tail.load() == NULL );
40 // Each thread will have their own guard.
44 mcs_node m_node; // node held on the stack
46 guard(mcs_mutex * t) : m_t(t) { t->lock(this); }
47 ~guard() { m_t->unlock(this); }
59 _lock_acquired = false;
68 @Commit_point_set: Lock_Enqueue_Point1 | Lock_Enqueue_Point2
70 _lock_acquired == false;
72 _lock_acquired = true;
75 void lock(guard * I) {
76 mcs_node * me = &(I->m_node);
79 // not published yet so relaxed :
80 me->next.store(NULL, std::mo_relaxed );
81 me->gate.store(1, std::mo_relaxed );
83 // publish my node as the new tail :
84 mcs_node * pred = m_tail.exchange(me, std::mo_acq_rel);
87 @Commit_point_define_check: pred == NULL
88 @Label: Lock_Enqueue_Point1
93 // unlock of pred can see me in the tail before I fill next
95 // publish me to previous lock-holder :
96 pred->next.store(me, std::mo_release );
98 // (*2) pred not touched any more
100 // now this is the spin -
101 // wait on predecessor setting my flag -
102 rl::linear_backoff bo;
105 my_gate = me->gate.load(std::mo_acquire);
108 @Commit_point_define_check: my_gate == 0
109 @Label: Lock_Enqueue_Point2
121 Unlock_Point_Success_1 | Unlock_Point_Success_2
123 _lock_acquired == true
125 _lock_acquired = false;
128 void unlock(guard * I) {
129 mcs_node * me = &(I->m_node);
131 mcs_node * next = me->next.load(std::mo_acquire);
134 mcs_node * tail_was_me = me;
136 success = m_tail.compare_exchange_strong(
137 tail_was_me,NULL,std::mo_acq_rel);
140 @Commit_point_define_check: success == true
141 @Label: Unlock_Point_Success_1
146 // got null in tail, mutex is unlocked
150 // (*1) catch the race :
151 rl::linear_backoff bo;
153 next = me->next.load(std::mo_acquire);
160 // (*2) - store to next must be done,
161 // so no locker can be viewing my node any more
164 next->gate.store( 0, std::mo_release );
167 @Commit_point_define_check: true
168 @Label: Unlock_Point_Success_2