linux 锁 源码,linux 2.6 互斥锁的实现-源码分析

Linux 2.6 kernel的源码,下面结合代码来分析一下在X86体系结构下,互斥锁的实现原理。

代码分析:

1. 首先介绍一下互斥锁所使用的数据结构:

struct mutex {

atomic_t count; //引用计数器,1: 所可以利用,小于等于0:该锁已被获取,需要等待

spinlock_t wait_lock;//自旋锁类型,保证多cpu下,对等待队列访问是安全的。

spinlock_t wait_lock; //等待队列,如果该锁被获取,任务将挂在此队列上,等待调度。

struct list_head wait_list;

};

2. 互斥锁加锁函数

void inline __sched mutex_lock(struct mutex *lock)

调用了宏:

__mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);

宏的定义:将mutex数据结构中,引用计数器减1,如果不为负数就返回,如果为负数,需要调用函数:__mutex_lock_slowpath,接下来我们再来分析这个函数,我们先来分析一下这个宏。

#define __mutex_fastpath_lock(count, fail_fn) /

do { /

unsigned int dummy; /

//检查参数类型的有效性

typecheck(atomic_t *, count); /

typecheck_fn(void (*)(atomic_t *), fail_fn); /

//输入,输出寄存器为eax,输入为count,输出为dummy,仅将eax的值减1

asm volatile(LOCK_PREFIX " decl (%%eax)/n" /

" jns 1f /n" /

//如果减后为负数,调用回调函数,尝试阻塞该进程

" call " #fail_fn "/n" /

"1:/n" /

: "=a" (dummy) /

: "a" (count) /

: "memory", "ecx", "edx"); /

} while (0)

3. 回调函数

static noinline int __sched __mutex_lock_killable_slowpath(atomic_t *lock_count)

{

//通过结构的成员地址,获取该结构地址

struct mutex *lock = container_of(lock_count, struct mutex, count);

//该函数在后面做详细介绍

return __mutex_lock_common(lock, TASK_KILLABLE, 0, _RET_IP_);

}

4. 阻塞进程真正获取锁的地方

static inline int __sched

__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,unsigned long ip)

{

//获取当前进程的task_struct的地址

struct task_struct *task = current;

struct mutex_waiter waiter;

unsigned int old_val;

unsigned long flags;

//对该锁上的等待队列加自旋锁,防止多个CPU的情况。

spin_lock_mutex(&lock->wait_lock, flags);

//将该任务添加到该锁的等待队列上

list_add_tail(&waiter.list, &lock->wait_list);

waiter.task = task;

//用一条汇编指令对count进行付值,lock->count=-1,保证该操作在一个cpu上是原子的

old_val = atomic_xchg(&lock->count, -1);

//如果lock->count之前的值为1,说明是可以获取锁的

if (old_val == 1)

goto done;

lock_contended(&lock->dep_map, ip);

for (;;) {

//在这个地方,又尝试去获取锁,处理方式如上。

old_val = atomic_xchg(&lock->count, -1);

if (old_val == 1)

break;

//如果该进程是可中断的,或者该进程是可kiilable的,如果有信号被递送到该任务,那么该进程将从等待队列中移除

if (unlikely((state == TASK_INTERRUPTIBLE &&signal_pending(task)) ||(state == TASK_KILLABLE &&fatal_signal_pending(task)))) {

mutex_remove_waiter(lock, &waiter,task_thread_info(task));

mutex_release(&lock->dep_map, 1, ip);

spin_unlock_mutex(&lock->wait_lock, flags);

debug_mutex_free_waiter(&waiter);

//返回被信号中断

return -EINTR;

}

__set_task_state(task, state);

//如果还不能获取所,则将自旋锁解除,当从schedule返回时再次获取自旋锁,重复如上操作。

spin_unlock_mutex(&lock->wait_lock, flags);

schedule();

spin_lock_mutex(&lock->wait_lock, flags);

}

//表示已经获取了锁

done:

lock_acquired(&lock->dep_map);

//将该任务从等待队列中删除

mutex_remove_waiter(lock, &waiter, task_thread_info(task));

debug_mutex_set_owner(lock, task_thread_info(task));

//如果等待队列为空将lock->count置为0

if (likely(list_empty(&lock->wait_list)))

atomic_set(&lock->count, 0);

spin_unlock_mutex(&lock->wait_lock, flags);

debug_mutex_free_waiter(&waiter);

return 0;

}

5. 解锁过程

void __sched mutex_unlock(struct mutex *lock)

{

//解锁后lock->count将从0变为1

__mutex_fastpath_unlock(&lock->count,__mutex_unlock_slowpath);

}

//该宏是对引用计数器实行加1操作,如果加后小于等于0,说明该等待队列上还有任务需要获取锁。调用__mutex_unlock_slowpath函数。

#define __mutex_fastpath_unlock(count, fail_fn) /

do { /

unsigned int dummy; /

/

typecheck(atomic_t *, count); /

typecheck_fn(void (*)(atomic_t *), fail_fn); /

/

asm volatile(LOCK_PREFIX " incl (%%eax)/n" /

" jg 1f/n" /

" call " #fail_fn "/n" /

"1:/n" /

: "=a" (dummy) /

: "a" (count) /

: "memory", "ecx", "edx"); /

} while (0)

//该函数调用了__mutex_unlock_slowpath函数。

static noinline void

__mutex_unlock_slowpath(atomic_t *lock_count)

{

__mutex_unlock_common_slowpath(lock_count, 1);

}

static inline void

__mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)

{

//通过结构的成员地址,获取该结构地址

struct mutex *lock = container_of(lock_count, struct mutex, count);

unsigned long flags;

//为等待队列加自旋锁

spin_lock_mutex(&lock->wait_lock, flags);

mutex_release(&lock->dep_map, nested, _RET_IP_);

debug_mutex_unlock(lock);

if (__mutex_slowpath_needs_to_unlock())

atomic_set(&lock->count, 1);

//先看看等待队列是不是为空了,如果已经为空,不需要做任何处理,否则将该等待队列上面的队首进程唤醒

if (!list_empty(&lock->wait_list)) {

struct mutex_waiter *waiter =list_entry(lock->wait_list.next,struct mutex_waiter, list);

debug_mutex_wake_waiter(lock, waiter);

wake_up_process(waiter->task);

}

debug_mutex_clear_owner(lock);

spin_unlock_mutex(&lock->wait_lock, flags);

}

总结:

互斥锁的实现,实际上就是一把锁维护了一个等待队列和一个引用计数器,当获取锁之前,先对引用计数器减1操作,如果为非负,则可以获取锁进入临界区。否则需要将该任务挂在该等待对列上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值