According to the article http://www.phoronix.com/scan.php?page=news_item&px=queue-spinlocks-linux-4.2, since version 4.2, Linux kernel would have queue spin locks. But in version 4.4, I went through the implementation of spin_lock
and found that they implement the spin-lock like this in kernel/locking/spinlock.c
:
void __lockfunc __raw_##op##_lock(locktype##_t *lock) \
{ \
for (;;) { \
preempt_disable(); \
if (likely(do_raw_##op##_trylock(lock))) \
break; \
preempt_enable(); \
\
if (!(lock)->break_lock) \
(lock)->break_lock = 1; \
while (!raw_##op##_can_lock(lock) && (lock)->break_lock)\
arch_##op##_relax(&lock->raw_lock); \
} \
(lock)->break_lock = 0; \
} \
And there is a cmpxchg
in do_raw_spin_trylock
, so basically it just a TATAS spin-lock.
However, when I digging deeper, I find do_raw_spin_lock
will goes into a function queued_spin_trylock
and the type of lock
variable become qspinlock
. So where is the queue spin? Is it hiding in somewhere or just waiting for the future implementation?
For searching the identifiers in the source code, here is the tool: http://lxr.free-electrons.com/
The code you're looking at is in the #else case of this:
#if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC)
/*
* The __lock_function inlines are taken from
* include/linux/spinlock_api_smp.h
*/
#else
...
By default, on x86, CONFIG_GENERIC_LOCKBREAK is not defined, so the compiler won't compile that code (i.e. in the #else
clause). There are lots of potential paths through the maze of locking ifdef
s. The exact path taken will depend on your architecture and any custom selections you've made in your .config
.