Skip to main content

Command Palette

Search for a command to run...

Linux Kernel Synchronization: ISA, Critical Sections, Spinlocks and Atomic Operations

Updated
5 min read
Linux Kernel Synchronization: ISA, Critical Sections, Spinlocks and Atomic Operations

Introduction

Writing Linux kernel code is very different from writing user-space applications. The kernel runs with direct access to hardware, supports multiple CPUs, handles interrupts, and manages shared resources that may be accessed concurrently.

Because of this, synchronization becomes a fundamental requirement. Without proper synchronization, race conditions, data corruption, and system instability can occur.

In this article, I explore several important Linux kernel concepts through a simple kernel module:

  • ISA (Instruction Set Architecture) detection

  • Critical sections

  • Exclusive execution

  • Interrupt-safe locking

  • Atomic counters

  • Global shared variables

  • Spinlocks


What This Kernel Module Demonstrates

Concept Mechanism
ISA Detection CONFIG_X86 / CONFIG_ARM64
Critical Section Protected code block
Exclusive Execution Spinlock
Interrupt Safety spin_lock_irqsave()
Atomic Operations atomic_t
Shared Resource Global Counter
Logging printk()
Module Lifecycle module_init() / module_exit()

ISA (Instruction Set Architecture)

An Instruction Set Architecture (ISA) defines the machine instructions that a processor understands.

Common examples include:

  • x86_64

  • ARM64

  • RISC-V

  • MIPS

The Linux kernel is compiled for a specific architecture. Sometimes kernel code must behave differently depending on the target processor.

A simple ISA detection example:

#if defined(CONFIG_X86)
    printk(KERN_INFO "ISA = x86\n");
#elif defined(CONFIG_ARM64)
    printk(KERN_INFO "ISA = ARM64\n");
#endif

This allows architecture-specific behavior inside kernel modules and drivers.


Critical Sections

A critical section is a region of code that accesses shared data.

Example:

global_counter++;

Although this looks like a single operation, it actually involves multiple CPU instructions:

  1. Read memory

  2. Increment value

  3. Write result back

If two CPUs execute this sequence simultaneously, updates can be lost.

This problem is known as a race condition.

Critical sections must therefore be protected to ensure correctness.


Exclusive Execution

Exclusive execution means only one execution context may enter a critical section at a time.

In Linux kernel development, this is commonly achieved using synchronization primitives such as:

  • Spinlocks

  • Mutexes

  • Semaphores

  • RW Locks

In this example, a spinlock is used.

spin_lock_irqsave(&counter_lock, flags);

/* critical section */

spin_unlock_irqrestore(&counter_lock, flags);

This guarantees exclusive access to shared resources.


Global Counter

The module contains a shared global variable:

static int global_counter;

Because global variables can be accessed by multiple CPUs or kernel threads, they must be protected when modified.

Example:

global_counter++;

Without synchronization:

  • Lost updates

  • Race conditions

  • Data corruption

With synchronization:

  • Predictable behavior

  • Correct results

  • Safe concurrent access

Global variables are often the first place where synchronization bugs appear.


Spinlocks

A spinlock is a lightweight synchronization mechanism used inside the kernel.

Initialization:

spin_lock_init(&counter_lock);

Lock acquisition:

spin_lock_irqsave(&counter_lock, flags);

Lock release:

spin_unlock_irqrestore(&counter_lock, flags);

Unlike mutexes, a spinlock does not put the thread to sleep. Instead, the CPU continuously checks until the lock becomes available.

Spinlocks are therefore suitable for:

  • Short critical sections

  • Interrupt contexts

  • Performance-sensitive kernel code

They are not suitable for long operations.


Interrupt Safety

Kernel code may be interrupted at almost any time.

Sources of interrupts include:

  • Keyboard

  • Mouse

  • Network devices

  • Storage devices

  • System timers

If both an interrupt handler and normal kernel code access the same data, race conditions may occur.

To prevent this, the module uses:

spin_lock_irqsave(&counter_lock, flags);

This operation:

  1. Saves interrupt state

  2. Disables local interrupts

  3. Acquires the lock

After the critical section:

spin_unlock_irqrestore(&counter_lock, flags);

This restores the original interrupt state.

The result is safe access even when interrupts are involved.


Atomic Operations

Linux provides atomic data types for operations that must occur as indivisible actions.

Example:

static atomic_t atomic_counter =
        ATOMIC_INIT(0);

Increment:

atomic_inc(&atomic_counter);

Read:

atomic_read(&atomic_counter);

Atomic operations eliminate race conditions for simple counter updates.

Benefits include:

  • No lost updates

  • No partial modifications

  • CPU-level atomic guarantees

They are commonly used for:

  • Reference counters

  • Statistics

  • Resource tracking

  • State flags


Atomic Counter vs Global Counter

Feature Global Counter Atomic Counter
Shared Resource Yes Yes
Requires Protection Yes Often No
Race Condition Risk High Low
Lock Required Usually Usually Not
Performance Lower Higher

Atomic counters are ideal for simple increment/decrement operations.

More complex operations may still require locks.


Kernel Logging with printk()

The kernel equivalent of printf() is printk().

Example:

printk(KERN_INFO
       "critical section entered\n");

Messages can be viewed using:

dmesg

This is one of the most important debugging techniques in kernel development.


Module Lifecycle

Every Linux kernel module typically contains two entry points.

Initialization:

module_init(demo_init);

Cleanup:

module_exit(demo_exit);

Initialization runs when:

sudo insmod big_kernel_demo.ko

Cleanup runs when:

sudo rmmod big_kernel_demo

This lifecycle allows modules to allocate and release resources safely.


Key Takeaways

This small kernel module demonstrates several core synchronization concepts used throughout Linux kernel development.

I learned about:

  • ISA detection

  • Critical sections

  • Exclusive execution

  • Global shared variables

  • Spinlocks

  • Interrupt-safe locking

  • Atomic counters

  • Kernel logging

  • Module lifecycle management

These concepts form the foundation of:

  • Device driver development

  • Embedded Linux

  • Operating systems

  • Multicore programming

  • Linux security engineering

  • Low-level cybersecurity research

Mastering these fundamentals makes it easier to understand advanced topics such as semaphores, mutexes, RCU, memory barriers, lock-free programming, and kernel concurrency design.


Source Code

GitHub Repository:

https://github.com/aj333git/linux_kernel_sync6