Skip to content

Commit 61511e2

Browse files
author
Andy Ross
committed
kernel/spinlock: Add a depth count to spinlock validation
Right now the validation layer catches mismatched locking, but another common gotcha is failing to release an outer nested lock before entering a blocking primitive. In these cases, the OS would swap away, and the next thread (if any) to try to take the outer lock would hit a "not my spinlock" error, which while correct isn't very informative. By keeping a single per-cpu nesting count we can check this at the point of the swap, which is more helpful. Signed-off-by: Andy Ross <[email protected]>
1 parent f6d5de3 commit 61511e2

File tree

3 files changed

+15
-0
lines changed

3 files changed

+15
-0
lines changed

kernel/include/kernel_structs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <misc/rb.h>
1616
#include <misc/util.h>
1717
#include <string.h>
18+
#include <spinlock.h>
1819
#endif
1920

2021
#define K_NUM_PRIORITIES \
@@ -107,6 +108,10 @@ struct _cpu {
107108
/* True when _current is allowed to context switch */
108109
u8_t swap_ok;
109110
#endif
111+
112+
#ifdef SPIN_VALIDATE
113+
u8_t spin_depth;
114+
#endif
110115
};
111116

112117
typedef struct _cpu _cpu_t;

kernel/include/kswap.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ static ALWAYS_INLINE unsigned int do_swap(unsigned int key,
5959

6060
if (is_spinlock) {
6161
k_spin_release(lock);
62+
#ifdef SPIN_VALIDATE
63+
__ASSERT(_current_cpu->spin_depth == 0,
64+
"Swapping with spinlock held!");
65+
#endif
6266
}
6367

6468
new_thread = z_get_next_ready_thread();
@@ -142,6 +146,10 @@ static inline int z_swap_irqlock(unsigned int key)
142146
static ALWAYS_INLINE int z_swap(struct k_spinlock *lock, k_spinlock_key_t key)
143147
{
144148
k_spin_release(lock);
149+
#ifdef SPIN_VALIDATE
150+
__ASSERT(_current_cpu->spin_depth == 0,
151+
"Swapping with spinlock held!");
152+
#endif
145153
return z_swap_irqlock(key.key);
146154
}
147155

kernel/thread.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ int z_spin_lock_valid(struct k_spinlock *l)
720720
}
721721
}
722722
l->thread_cpu = _current_cpu->id | (u32_t)_current;
723+
_current_cpu->spin_depth++;
723724
return 1;
724725
}
725726

@@ -729,6 +730,7 @@ int z_spin_unlock_valid(struct k_spinlock *l)
729730
return 0;
730731
}
731732
l->thread_cpu = 0;
733+
_current_cpu->spin_depth--;
732734
return 1;
733735
}
734736
#endif

0 commit comments

Comments
 (0)