Linux Device Driver Tutorial Part 23 – Spinlock in Linux Kernel Part 1

This is the Series on Linux Device Driver. The aim of this series is to provide easy and practical examples that anyone can understand. This is the Linux Device Driver Tutorial Part 23 – Spinlock in Linux Kernel Part 1.


In the example section, I had used Kthread to explain Mutex. If you don’t know what is Kthread and How to use it, then I would recommend you to explore that by using below link.

  1. Kthread Tutorial in Linux Kernel
  2. Mutex Tutorial in Linux Kernel


In our previous tutorial, we have understood the use of Mutex and its Implementation. If you have understood Mutex then Spinlock is also similar. Both are used to protect a shared resource from being modified by two or more processes simultaneously.


In the Mutex concept, when the thread is trying to lock or acquire the Mutex which is not available then that thread will go to sleep until that Mutex is available. Whereas in Spinlock it is different. The spinlock is a very simple single-holder lock. If a process attempts to acquire a spinlock and it is unavailable, the process will keep trying (spinning) until it can acquire the lock. This simplicity creates a small and fast lock.

Like Mutex, there are two possible states in Spinlock: Locked or Unlocked.

SpinLock in Linux Kernel Device Driver

If the kernel is running on a uniprocessor and CONFIG_SMPCONFIG_PREEMPT aren’t enabled while compiling the kernel then spinlock will not be available. Because there is no reason to have a lock when no one else can run at the same time.

But if you have disabled CONFIG_SMP and enabled  CONFIG_PREEMPT then spinlock will simply disable preemption, which is sufficient to prevent any races.


We can initialize Spinlock in Linux kernel in two ways.

  1. Static Method
  2. Dynamic Method

Static Method

You can statically initialize a Spinlock using the macro given below.

The macro given above will create a spinlock_t variable in the name of etx_spinlock and initialize to UNLOCKED STATE. Take a look at the expansion of DEFINE_SPINLOCK below.

Dynamic Method

If you want to initialize dynamically you can use the method as given below.

You can use any one of the methods.

After initializing the spinlock, there are several ways to use spinlock to lock or unlock, based on where the spinlock is used; either in user context or interrupt context. Let’s look at the approaches with these situations.

Approach 1 (Locking between User context)

If you share data with user context (between Kernel Threads), then you can use this approach.


spin_lock(spinlock_t *lock)

This will take the lock if it is free, otherwise, it’ll spin until that lock is free (Keep trying).

Try Lock:

spin_trylock(spinlock_t *lock)

Locks the spinlock if it is not already locked. If unable to obtain the lock it exits with an error and do not spin. It returns non-zero if it obtains the lock otherwise returns zero.


spin_unlock(spinlock_t *lock)

It does the reverse of the lock. It will unlock which is locked by the above call.

Checking Lock:

spin_is_locked(spinlock_t *lock)

This is used to check whether the lock is available or not. It returns non-zero if the lock is currently acquired. otherwise returns zero.


Approach 2 (Locking between Bottom Halves)

If you want to share data between two different Bottom halves or the same bottom halves, then you can use the Approach 1.

Approach 3 (Locking between User context and Bottom Halves)

If you share data with a bottom half and user context (like Kernel Thread), then this approach will be useful.


spin_lock_bh(spinlock_t *lock)

It disables soft interrupts on that CPU, then grabs the lock. This has the effect of preventing softirqs, tasklets, and bottom halves from running on the local CPU. Here the suffix ‘_bh‘ refers to “Bottom Halves“.


spin_unlock_bh(spinlock_t *lock)

It will release the lock and re-enables the soft interrupts which are disabled by the above call.


Approach 4 (Locking between Hard IRQ and Bottom Halves)

If you share data between Hardware ISR and Bottom halves then you have to disable the IRQ before lock. Because the bottom halves processing can be interrupted by a hardware interrupt. So this will be used in that scenario.


spin_lock_irq(spinlock_t *lock)

This will disable interrupts on that cpu, then grab the lock.


spin_unlock_irq(spinlock_t *lock)

It will release the lock and re-enables the interrupts which are disabled by the above call.


Approach 5 (Alternative way of Approach 4)

If you want to use a different variant rather than using spin_lock_irq() and spin_unlock_irq() then you can use this approach.


spin_lock_irqsave( spinlock_t *lock, unsigned long flags );

This will save whether interrupts were on or off in a flags word and grab the lock.


spin_unlock_irqrestore( spinlock_t *lock, unsigned long flags );

This will release the spinlock and restores the interrupts using the flags argument.

Approach 6 (Locking between Hard IRQs)

If you want to share data between two different IRQs, then you should use Approach 5.

Spinlock in Linux kernel example programming

This code snippet explains how to create two threads that access a global variable (etx_gloabl_variable). So before accessing the variable, it should lock the spinlock. After that, it will release the spinlock. This example is using Approach 1.

Driver Source Code

[Get the source from the GitHub]


In our next part of the tutorial, we will see another variant of the spinlock (Reader/writer spinlocks).

5 1 vote
Article Rating
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Newest Most Voted
Inline Feedbacks
View all comments
May 23, 2019 6:31 AM

Why you need to disable IRQ while sharing data between ISR, hard IRQ (Apporch 6) ?
Spin lock is enough…..

riddhi patel
riddhi patel
May 23, 2019 6:50 AM

Why you need to disable IRQ while sharing data between ISR (hard IRQ , …. Apporch 6) ?
During ISR execution interrupts on particular core are already disabled… So Spin lock is enough…..
Isn’t it ?

Would love your thoughts, please comment.x
%d bloggers like this: