- 论坛徽章:
- 0
|
本帖最后由 tgvlcw 于 2011-03-04 15:50 编辑
最近在研究互斥锁与信号量,信号量还好理解,但是互斥锁的逻辑却有些乱,求人帮忙理一下。太乱了!!!
获得与释放互斥锁最重要的几段代码如下:
- //这是提供给驱动的接口
- void __sched mutex_lock(struct mutex *lock)
- {
- might_sleep();
- /*
- * The locking fastpath is the 1->0 transition from
- * 'unlocked' into 'locked' state.
- */
- __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
- mutex_set_owner(lock);
- }
- //这个函数会根据CPU所支持的ARM指令版本而选择不同的版本,以下为V5以下
- //arm指令通用的函数,V5以上的在arch/arm目录下
- static inline void
- __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
- {
- if (unlikely(atomic_xchg(count, 0) != 1))
- fail_fn(count);
- }
- static __used noinline void __sched
- __mutex_lock_slowpath(atomic_t *lock_count)
- {
- struct mutex *lock = container_of(lock_count, struct mutex, count);
- __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
- }
- //以下为没有获得锁而处理的最核心的函数,看着多,其实不难
- static inline int __sched
- __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
- unsigned long ip)
- {
- struct task_struct *task = current;
- struct mutex_waiter waiter;
- unsigned long flags;
- preempt_disable();
- mutex_acquire(&lock->dep_map, subclass, 0, ip);
- spin_lock_mutex(&lock->wait_lock, flags);
- debug_mutex_lock_common(lock, &waiter);
- debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
- /* add waiting tasks to the end of the waitqueue (FIFO): */
- list_add_tail(&waiter.list, &lock->wait_list);
- waiter.task = task;
- if (atomic_xchg(&lock->count, -1) == 1)
- goto done;
- lock_contended(&lock->dep_map, ip);
- for (;;) {
- if (atomic_xchg(&lock->count, -1) == 1)
- break;
- if (unlikely(signal_pending_state(state, 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);
- preempt_enable();
- return -EINTR;
- }
- __set_task_state(task, state);
- //printk(KERN_DEBUG "%s: before, lock_count: 0x%x, pid: %d\n", __func__, \
- //(int)lock->count.counter, task_tgid_vnr(current));
- /* didnt get the lock, go to sleep: */
- spin_unlock_mutex(&lock->wait_lock, flags);
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- printk(KERN_DEBUG "%s: after, lock_count: 0x%x, pid: %d\n", __func__, \
- (int)lock->count.counter, task_tgid_vnr(current));
- spin_lock_mutex(&lock->wait_lock, flags);
- }
- done:
- //printk(KERN_DEBUG "%s: lock_count: 0x%x, pid: %d\n", __func__, \
- //(int)lock->count.counter, task_tgid_vnr(current));
- lock_acquired(&lock->dep_map, ip);
- /* got the lock - rejoice! */
- mutex_remove_waiter(lock, &waiter, current_thread_info());
- mutex_set_owner(lock);
- /* set it to 0 if there are no waiters left: */
- if (likely(list_empty(&lock->wait_list)))
- atomic_set(&lock->count, 0);
- spin_unlock_mutex(&lock->wait_lock, flags);
- debug_mutex_free_waiter(&waiter);
- preempt_enable();
- return 0;
- }
- //以下为释放锁的
- void __sched mutex_unlock(struct mutex *lock)
- {
- __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
- }
- static inline void
- __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
- {
- if (unlikely(atomic_xchg(count, 1) != 0))
- fail_fn(count);
- }
- static __used 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)) {
- /* get the first entry from the 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);
- printk(KERN_DEBUG "%s: lock_count: 0x%x, pid: %d\n", __func__, \
- (int)lock->count.counter, task_tgid_vnr(current));
- }
- spin_unlock_mutex(&lock->wait_lock, flags);
- }
复制代码
互斥锁的实现原理和信号量是一样的,最根本的区别是互斥锁的计数变量是volitale的,而信号量却不是。双方都有一个等待队列。
若此时有a和 b两个进程,a先获得锁,然后b也要获得锁,而因为a已经占有锁了,所以b会进入休眠。 当a释放锁后,会去唤醒在等待队列上的进程,按正常逻辑此时应该是b被唤醒而获得锁。但是现在却是,a在释放锁之后,又重新获得锁,a会在调度b之前先将计数值减1,然后才调度进程b,b会因为判断计数值不成功而重新进入休眠。为什么呢?为什么a会在调度b之前而先将计数值减1了呢?
而信号量却不是这样的,信号量是在a释放这个信号之后,唤醒等待队列上的进程,此时会马上调度b,使b获得信号量,若a又要重新获得信号量,会因为信号量的计数值小于等于0而进入休眠。
谁能帮我解释一下。
以下是我打印的log
- /这是互斥锁的log
- <7>[ 83.890838] i2c_transfer: get i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- <7>[ 83.890930] i2c_transfer: get i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 1
- <7>[ 83.890960] __mutex_lock_common: before, lock_count: 0xffffffff, pid: 1041
- <7>[ 83.891143] __mutex_unlock_common_slowpath: lock_count: 0x1, pid: 206
- <7>[ 83.891174] i2c_transfer: release i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- <7>[ 83.891174]
- <7>[ 83.891204] i2c_transfer: get i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- <7>[ 83.891235] __mutex_lock_common: after, lock_count: 0x0, pid: 1041
- <7>[ 83.891235] __mutex_lock_common: before, lock_count: 0xffffffff, pid: 1041
- <7>[ 83.891510] __mutex_unlock_common_slowpath: lock_count: 0x1, pid: 206
- <7>[ 83.891510] i2c_transfer: release i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- <7>[ 83.891876]
- <7>[ 83.891876] i2c_transfer: get i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- <7>[ 83.891906] __mutex_lock_common: after, lock_count: 0x0, pid: 1041
- <7>[ 83.891937] __mutex_lock_common: before, lock_count: 0xffffffff, pid: 1041
- <7>[ 83.895751] __mutex_unlock_common_slowpath: lock_count: 0x1, pid: 206
- <7>[ 83.895751] i2c_transfer: release i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 1
- .........
- <7>[ 83.904693] i2c_transfer: get i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 2
- <7>[ 83.904693] __mutex_lock_common: after, lock_count: 0x0, pid: 1041
- <7>[ 83.904724] __mutex_lock_common: before, lock_count: 0xffffffff, pid: 1041
- <7>[ 83.904876] __mutex_unlock_common_slowpath: lock_count: 0x1, pid: 206
- <7>[ 83.904876] i2c_transfer: release i2c lock, slave->addr: 0x34, cur_pid: 206, flags: 0x0, len: 2
- <7>[ 83.904907]
- <7>[ 83.904937] __mutex_lock_common: after, lock_count: 0x1, pid: 1041
- <7>[ 83.904937] __mutex_lock_common: lock_count: 0xffffffff, pid: 1041
- <7>[ 83.905090] i2c_transfer: release i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 1
- //以下是信号量的log
- <7>[ 53.400207] i2c_transfer: get i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 1
- <7>[ 53.400329] i2c_transfer: get i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
- <7>[ 53.400360] __down_common: before count: 0x0, pid: 5, up: 0
- <7>[ 53.400390] __up: count: 0x0, pid: 1041, up: 1
- <7>[ 53.400390] i2c_transfer: release i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 1
- <7>[ 53.400421]
- <7>[ 53.400421] i2c_transfer: get i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x1, len: 32
- <7>[ 53.400451] __down_common: before count: 0x0, pid: 1041, up: 0
- <7>[ 53.400451] __down_common: after count: 0x0, pid: 5, up: 1
- <7>[ 53.400695] __up: count: 0x0, pid: 5, up: 1
- <7>[ 53.400726] i2c_transfer: release i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
- <7>[ 53.400726]
- <7>[ 53.400726] i2c_transfer: get i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
- <7>[ 53.400756] __down_common: before count: 0x0, pid: 5, up: 0
- <7>[ 53.400756] __down_common: after count: 0x0, pid: 1041, up: 1
- <7>[ 53.402404] __up: count: 0x0, pid: 1041, up: 1
- <7>[ 53.402435] i2c_transfer: release i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x1, len: 32
- <7>[ 53.402435]
- <7>[ 53.402465] i2c_transfer: get i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 2
- <7>[ 53.402496] __down_common: before count: 0x0, pid: 1041, up: 0
- <7>[ 53.402557] __down_common: after count: 0x0, pid: 5, up: 1
- <7>[ 53.402832] __up: count: 0x0, pid: 5, up: 1
- <7>[ 53.402862] i2c_transfer: release i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
- <7>[ 53.402862]
- <7>[ 53.402862] i2c_transfer: get i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
- <7>[ 53.402893] __down_common: before count: 0x0, pid: 5, up: 0
- <7>[ 53.402923] __down_common: after count: 0x0, pid: 1041, up: 1
- <7>[ 53.403106] __up: count: 0x0, pid: 1041, up: 1
- <7>[ 53.403106] i2c_transfer: release i2c lock, slave->addr: 0x67, cur_pid: 1041, flags: 0x0, len: 2
- <7>[ 53.403137]
- <7>[ 53.404083] __down_common: after count: 0x0, pid: 5, up: 1
- <7>[ 53.404479] i2c_transfer: release i2c lock, slave->addr: 0x44, cur_pid: 5, flags: 0x0, len: 1
复制代码 |
|