I’m using 2 locks: TAS & TCLock, I want to maintain a counter of how many times the locks are called, and switch lock when it hits some threshold.
Basic structure:
1 2 3 4 5 6 7 8
   | struct slock_struct { 	   atomic_t tas; 	struct orig_qspinlock komb; 	 	enum LockType type; 	atomic_t count; };
  | 
 
1st try
Initially I tried using a counter:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | void slock_lock(struct slock_struct *lock) {     while (1) {         int count = atomic_read(&lock->count);       	         if (count < SWITCH_THRESHOLD) {             if (atomic_cmpxchg_acquire(&lock->count, count, count + 1) == count) {                                  slock_lock_chosen(lock);                 return;             }         }     } }
  void slock_unlock(struct slock_struct *lock) {     slock_unlock_chosen(lock);     if(atomic_read(&lock->count) == SWITCH_THRESHOLD){ 				 				if(lock->type == TAS){ 					lock->type = KOMB; 				}else{ 					lock->type = TAS; 				}
        int count = atomic_cmpxchg_release(&lock->count, SWITCH_THRESHOLD, 0);       if (count != SWITCH_THRESHOLD){         print_debug("!!!!!!!!!!!!!RESET COUNT ERROR, current_count=%d", count);       }     } }
   | 
 
When running rcuhashtable test, I sometimes get error with current_count==1 (or 2, 8…)
and something like:
 BUG: soft Lockup CPU#0 stuck for 26s
Bug example
The above code crashes in this example (say threshold is 100):
1 2 3 4 5 6 7 8 9 10 11 12 13
   | T1                T2 ---               --- get count 99                   get count 100 lock TAS CS unlock TAS 									lock TAS read count 100 change lock reset count --- 									unlock TCLock [BOOM!]
   | 
 
2nd try
I changed to 2 counters, one for threads entering, one for leaving
Now it’s passing the test (for a few times, no bug yet)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
   | void slock_lock(struct slock_struct *lock) {     while (1) { 		int count = atomic_read(&lock->count_in);         if(count < SWITCH_THRESHOLD) {             if(atomic_cmpxchg_acquire(&lock->count_in, count, count+1) == count) {                                  slock_lock_chosen(lock);                 return;             }         }     } }
  void slock_unlock(struct slock_struct *lock) {     slock_unlock_chosen(lock);          while(1){         int count = atomic_read(&lock->count_out);         if(atomic_cmpxchg_acquire(&lock->count_out, count, count+1) == count){           	             if(count == SWITCH_THRESHOLD-1) {                                  if(lock->type == TAS){                     lock->type = KOMB;                 }else{                     lock->type = TAS;                 }
                                   int count_out = atomic_cmpxchg_release(&lock->count_out, SWITCH_THRESHOLD, 0);                 if (count_out != SWITCH_THRESHOLD){                   	print_debug("!!!!!!!!!!!!!RESET COUNT ERROR, count_in=%d", count_out);                 }                 int count_in = atomic_cmpxchg_release(&lock->count_in, SWITCH_THRESHOLD, 0);                 if (count_in != SWITCH_THRESHOLD){                   	print_debug("!!!!!!!!!!!!!RESET COUNT ERROR, count_in=%d", count_in);                 }             }             return;         }     } }
   |