Search code examples
linux-kernelspinlock

How Linux implement the 'queue spin lock'?


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/


Solution

  • 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 ifdefs. The exact path taken will depend on your architecture and any custom selections you've made in your .config.