[Linux Kernel] Mutex (3) - struct mutex
What is a Mutex?
A mutex (short for mutual exclusion) is a synchronization mechanism that ensures only one process can access a critical section at a time. It prevents multiple processes from modifying shared resources simultaneously, which helps maintain data integrity.
Although mutexes are widely used in the Linux kernel, they are not exclusive to it. The concept of mutexes exists in various operating systems, each with its own implementation. However, the core idea remains the same: preventing two processes from entering a critical section at the same time.
Example: Protecting a Critical Section Using a Mutex
Let’s analyze an example from the Linux kernel that demonstrates how a mutex protects a critical section. The following code is from the Linux kernel source for CPU frequency scaling (cpufreq_governor.c):
static void dbs_work_handler(struct work_struct *work)
{
struct policy_dbs_info *policy_dbs;
struct cpufreq_policy *policy;
struct dbs_governor *gov;
mutex_lock(&policy_dbs->update_mutex); // Acquire the mutex lock
gov_update_sample_delay(policy_dbs, gov->gov_dbs_update(policy)); // Critical section
mutex_unlock(&policy_dbs->update_mutex); // Release the mutex lock
}
Before executing this function, the process acquires the mutex lock using mutex_lock(). Once the function execution is complete, the process releases the mutex using mutex_unlock().
If one process has already locked the mutex and is executing the critical section, any other process attempting to enter it will be put to sleep inside mutex_lock() until the lock is released.
This ensures that only one process at a time can modify the shared resource, preventing race conditions.
Mutex Data Structure in Linux Kernel
The mutex is represented by the struct mutex data structure in the Linux kernel.
struct mutex {
atomic_long_t owner; // Stores the task descriptor of the process holding the mutex
spinlock_t wait_lock; // Protects the waiting list
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
struct optimistic_spin_queue osq; // Used for spin-waiting
#endif
struct list_head wait_list; // List of processes waiting for the mutex
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
In Raspbian, the kernel is compiled with CONFIG_DEBUG_MUTEXES and CONFIG_DEBUG_LOCK_ALLOC disabled, so the magic and dep_map fields are not included in the compiled binary. Key Fields in the mutex Structure
Recommended by LinkedIn
If the wait_list contains entries, it means some processes are waiting for the mutex.
Processes waiting for a mutex are represented by the struct mutex_waiter structure.
struct mutex_waiter {
struct list_head list; // Links waiting processes in a queue
struct task_struct *task; // Stores the task descriptor of the waiting process
struct ww_acquire_ctx *ww_ctx;
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
};
Key Fields in the mutex_waiter Structure
These fields are essential when analyzing which processes are blocked and why.
Mutex Lock and Unlock Functions
The kernel provides two key functions for mutex operations:
extern void mutex_lock(struct mutex *lock); // Acquire the mutex
extern void mutex_unlock(struct mutex *lock); // Release the mutex
Fastpath vs. Slowpath in Mutex Execution
When a process tries to acquire a mutex, the execution follows either the fastpath or slowpath, depending on whether the mutex is free.
Next post will cover the implementation of mutex_lock() in more detail. So please stay tuned.
Software Engineer at Wipro
2moUseful tips
Software Engineer at Goldman Sachs
2moThank you for the article! Looking for the implementation details!
Embedded software Engineer - SDE - Ex Amazon
2moExcelent article!