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; } } }
|