本篇文章基于Linux-6.5源码
建议:搭配Linux源码观看更佳
- struct mutex {
- atomic_long_t owner;
- spinlock_t wait_lock; //自旋锁,该自旋锁的作用是保护后面的等待队列的原子性
- struct list_head wait_list; //等待队列
- };
互斥锁初始化比较简单,就是把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
- 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
- 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变量中(相当于下一个任务获得了互斥锁),唤醒下一个任务继续执行。