-#include <stdio.h>
-#include <threads.h>
-
#include "mcs-lock.h"
-/* For data race instrumentation */
-#include "librace.h"
+void mcs_mutex::lock(guard * I) {
+ mcs_node * me = &(I->m_node);
+
+ // set up my node :
+ // not published yet so relaxed :
+ me->next.store(NULL, std::mo_relaxed );
+ me->gate.store(1, std::mo_relaxed );
+
+ /********** Detected Correctness **********/
+ /** Run this in the -Y mode to expose the HB bug */
+ // publish my node as the new tail :
+ mcs_node * pred = m_tail.exchange(me, std::mo_acq_rel);
+ /** @OPDefine: pred == NULL */
+ if ( pred != NULL ) {
+ // (*1) race here
+ // unlock of pred can see me in the tail before I fill next
-struct mcs_mutex *mutex;
-static uint32_t shared;
+ // FIXME: detection miss, execution never ends
+ // If this is relaxed, the store 0 to gate will be read before and
+ // that lock will never ends.
+ // publish me to previous lock-holder :
+ pred->next.store(me, std::mo_release );
-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));
+ // (*2) pred not touched any more
+
+ // now this is the spin -
+ // wait on predecessor setting my flag -
+ rl::linear_backoff bo;
+ /********** Detected Correctness *********/
+ /** Run this in the -Y mode to expose the HB bug */
+ while ( me->gate.load(std::mo_acquire) ) {
+ thrd_yield();
+ }
+ /** @OPDefine: true */
+ }
}
-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);
+void mcs_mutex::unlock(guard * I) {
+ mcs_node * me = &(I->m_node);
+
+ // FIXME: detection miss, execution never ends
+ mcs_node * next = me->next.load(std::mo_acquire);
+ if ( next == NULL )
+ {
+ mcs_node * tail_was_me = me;
+ /********** Detected Correctness **********/
+ /** Run this in the -Y mode to expose the HB bug */
+ if ( m_tail.compare_exchange_strong(
+ tail_was_me,NULL,std::mo_acq_rel) ) {
+ // got null in tail, mutex is unlocked
+ /** @OPDefine: true */
+ return;
+ }
+
+ // (*1) catch the race :
+ rl::linear_backoff bo;
+ for(;;) {
+ // FIXME: detection miss, execution never ends
+ next = me->next.load(std::mo_acquire);
+ if ( next != NULL )
+ break;
+ thrd_yield();
+ }
+ }
+
+ // (*2) - store to next must be done,
+ // so no locker can be viewing my node any more
+
+ /********** Detected Correctness **********/
+ /** Run this in the -Y mode to expose the HB bug */
+ // let next guy in :
+ next->gate.store( 0, std::mo_release);
+ /** @OPDefine: true */
}
-int user_main(int argc, char **argv)
-{
- thrd_t A, B;
+// C-callable interface
+
+/** @DeclareState: bool lock;
+ @Initial: lock = false; */
- mutex = new mcs_mutex();
- thrd_create(&A, &threadA, NULL);
- thrd_create(&B, &threadB, NULL);
- thrd_join(A);
- thrd_join(B);
- return 0;
+/** @PreCondition: return STATE(lock) == false;
+@Transition: STATE(lock) = true; */
+void mcs_lock(mcs_mutex *mutex, CGuard guard) {
+ mcs_mutex::guard *myGuard = (mcs_mutex::guard*) guard;
+ mutex->lock(myGuard);
+}
+
+/** @PreCondition: return STATE(lock) == true;
+@Transition: STATE(lock) = false; */
+void mcs_unlock(mcs_mutex *mutex, CGuard guard) {
+ mcs_mutex::guard *myGuard = (mcs_mutex::guard*) guard;
+ mutex->unlock(myGuard);
}