全部博文(14)
2012年(14)
分类: LINUX
2012-12-06 17:06:04
在分析之前,我先要说说几个概念。
内核抢占:在2.6内核加入了抢占的能力,就是说调度程序有办法在一个内核级的任务正在执行的时候从新调度。但是必须要保证重新调度要安全,这样就要靠一把锁来保证了。
计数器(thread_info.[reempt_count):其实也可以把他叫成锁的,它的初值定义为0,每当使用锁的时候加1.
好了,我们现在来看看lock_kernel()的具体代码啦(2.6.10版本的)
#ifndef __LINUX_SMPLOCK_H
#define __LINUX_SMPLOCK_H
#include
#include
#include
#ifdef CONFIG_LOCK_KERNEL
#define kernel_locked() (current->lock_depth >= 0)
extern int __lockfunc get_kernel_lock(void);
extern void __lockfunc put_kernel_lock(void);
/*
* Release/re-acquire global kernel lock for the scheduler
*/
#define release_kernel_lock(tsk) do { /
if (unlikely((tsk)->lock_depth >= 0)) /
put_kernel_lock(); /
} while (0)
/*
* Non-SMP kernels will never block on the kernel lock,
* so we are better off returning a constant zero from
* reacquire_kernel_lock() so that the compiler can see
* it at compile-time.
*/
#ifdef CONFIG_SMP
#define return_value_on_smp return
#else
#define return_value_on_smp
#endif
static inline int reacquire_kernel_lock(struct task_struct *task)
{
if (unlikely(task->lock_depth >= 0))
return_value_on_smp get_kernel_lock();
return 0;
}
extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
extern void __lockfunc unlock_kernel(void) __releases(kernel_lock);
#else
#define lock_kernel() do { } while(0)
#define unlock_kernel() do { } while(0)
#define release_kernel_lock(task) do { } while(0)
#define reacquire_kernel_lock(task) 0
#define kernel_locked() 1
#endif /* CONFIG_LOCK_KERNEL */
#endif /* __LINUX_SMPLOCK_H */
这个是对lock_kernel()函数的宏定义,#ifdef CONFIG_LOCK_KERNEL这里判断是否支持内核锁,如果不支持的话,lock_kernel就不做任何事情,我们来具体分析一下当配置了CONFIG_LOCK_KERNEL时lock_kernel()做些什么!我们直接看看这行代码extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
void __lockfunc lock_kernel(void)
{
int depth = current->lock_depth+1;
if (likely(!depth))
__lock_kernel();
current->lock_depth = depth;
}
这里可以看到有个标志lock_depth存在,对于这个标志,它的初始值为-1,如果自加后发现其实为0时,说明kernel_flag这个内核全局锁成功被这个进程所占有(current->lock_depth+1这个意味着0号进程的init_task.lock_depth加1)。接着就来到了__lock_kernel();这里的调用。我们来展开看看它的代码吧!
#ifdef CONFIG_PREEMPT
static inline void __lock_kernel(void)
{
preempt_disable();
if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
/*
* If preemption was disabled even before this
* was called, there's nothing we can be polite
* about - just spin.
*/
if (preempt_count() > 1) {
_raw_spin_lock(&kernel_flag);
return;
}
/*
* Otherwise, let's wait for the kernel lock
* with preemption enabled..
*/
do {
preempt_enable();
while (spin_is_locked(&kernel_flag))
cpu_relax();
preempt_disable();
} while (!_raw_spin_trylock(&kernel_flag));
}
}
#else
/*
* Non-preemption case - just get the spinlock
*/
static inline void __lock_kernel(void)
{
_raw_spin_lock(&kernel_flag);
}
#endif
看到一上来就对CONFIG_PREEMPT进行判断,这个是判断内核是否支持抢占。如果是抢占大的话,就执行上面的__lock_kernel(),我们来看看第一行语句, preempt_disable();
#define preempt_disable() /
do { /
inc_preempt_count(); /
barrier(); /
} while (0)
我们来看看inc_preempt_count();这个函数是什么内容。
#define inc_preempt_count() /
do { /
preempt_count()++; /
} while (0)
我再进一步再往里看看。
#define preempt_count() (current_thread_info()->preempt_count)
终于看到了是对current_thread_info()->preempt_count自增。(在start_kernel来说就是init_thread_info.preempt_count加1)这样我们又回到了__lock_kernel函数了,对于下面代码的分析不太清楚,这里就不进行讲解了。接着我们来到了没有进行宏定义的else部分。
#else
/*
* Non-preemption case - just get the spinlock
*/
static inline void __lock_kernel(void)
{
_raw_spin_lock(&kernel_flag);
}
#endif
这里就是简单的对kernel_flag这个全局变量加锁。好了,到这里我们算是把lock_kernel()分析了一遍了。其实总的来说,对于有抢占的,我们就不用用kernel_flag这个全局变量。这个全局变量其实是在2.4内核没有抢占功能内核的代码使用的。对于lock_kernel的分析就只是理解这么多,以后了解了跟多再来完善!
*/
static inline void __lock_kernel(void)
{
_raw_spin_lock(&kernel_flag);
}
#endif
这里就是简单的对kernel_flag这个全局变量加锁。好了,到这里我们算是把lock_kernel()分析了一遍了。其实总的来说,对于有抢占的,我们就不用用kernel_flag这个全局变量。这个全局变量其实是在2.4内核没有抢占功能内核的代码使用的。对于lock_kernel的分析就只是理解这么多,以后了解了跟多再来完善!