本篇文章基于Linux-6.5源码
建议:搭配Linux源码观看更佳
struct mutex {
atomic_long_t owner;
spinlock_t wait_lock; //自旋锁,该自旋锁的作用是保护后面的等待队列的原子性
struct list_head wait_list; //等待队列
};
API接口
mutex_init
互斥锁初始化比较简单,就是把owner,wait_lock,wait_list这几个成员初始化一下
#define mutex_init(mutex) \
do { \
static struct lock_class_key __key; \
\
__mutex_init((mutex), #mutex, &__key); \
} while (0)
void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
atomic_long_set(&lock->owner, 0);//初始化锁的所有者
spin_lock_init(&lock->wait_lock);//初始化自旋锁
INIT_LIST_HEAD(&lock->wait_list);//初始化等待队列
}
mutex_lock
加锁:mutex_lock
void __sched mutex_lock(struct mutex *lock)
{
might_sleep();
//尝试直接加锁,如果不成功,则进入slowpath,
if (!__mutex_trylock_fast(lock))
__mutex_lock_slowpath(lock);
}
EXPORT_SYMBOL(mutex_lock);
static __always_inline bool __mutex_trylock_fast(struct mutex *lock)
{
unsigned long curr = (unsigned long)current;//sp_el0,指向当前进程的task_struct
unsigned long zero = 0UL;
//判断owner是否为0,如果为0表示当前锁没有被占用,则把current写入owner返回true表示加锁成功
if (atomic_long_try_cmpxchg_acquire(&lock->owner, &zero, curr))
return true;
//owner不为0,表示锁被占用了,返回false
return false;
}
__mutex_lock_slowpath(慢加锁)中执行的过程大概是:
mutex_unlock
解锁:mutex_unlock
void __sched mutex_unlock(struct mutex *lock)
{
#ifndef CONFIG_DEBUG_LOCK_ALLOC
if (__mutex_unlock_fast(lock))
return;
#endif
__mutex_unlock_slowpath(lock, _RET_IP_);
}
EXPORT_SYMBOL(mutex_unlock);
__mutex_unlock_fast(快解锁):比较lock->owner和curr是否一致,一致则直接把0写到lock->owner中,表示解锁。
__mutex_unlock_slowpath:等待队列的第一个对象出列,表示下一个将要获得锁的任务。把下一个任务的task_struct地址写入到mutex lock的owner变量中(相当于下一个任务获得了互斥锁),唤醒下一个任务继续执行。