谈到lock_kernel,首先应该参看源码(此处所讲的是2.6.11版本的内核)中的include/linux/smp_lock.h文件。具体请参见该文件,在此处就不列出源码了
下面就开始分析了
#ifdef CONFIG_LOCK_KERNEL
首先就是判断我们是否配置内核支持内核锁。当然分两种情况了,要么配置了,要么就没有要这种功能
先来看配置了内核锁之后的代码部分
#define kernel_locked() (current->lock_depth >= 0)
上面的宏是判断内核是否已经被锁,通过什么判断呢?通过当前的进程的lock_depth这个变量的值来判断,提示:current就是当前正在执行的进程的tast_struct类型的指针变量。具体可参见include/linux/sched.h文件关于task_struct结构体的定义。如果这个变量的值大于0,那么内核就被锁住了,否则就没有锁。在初始化中lock_depth的值=-1.
现在就看看lock_kernel函数的实现部分吧
void __lockfunc lock_kernel(void)
{
struct task_struct *task = current;
int depth = task->lock_depth + 1;
if (likely(!depth))
/*
* No recursion worries - we set up lock_depth _after_
*/
down(&kernel_sem);
task->lock_depth = depth;
}
从上面的代码中,首先将当前进程的lock_depth变量+1,然后判断depth变量的值是否为0,为什么是0?其实前面已经提到了,lock_depth的值初始化是-1,在此加上了1,当然是0了,那么if这个判断语句就成立了。
在分析down函数之前我们需要注意下kernel_sem变量是什么?
DECLARE_MUTEX(kernel_sem);
又出来一个DECLARE_MUTEX宏,我们追踪一下子
if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
显然这个不是,因为我当前的版本内核是2.6.11,而不是低于2.4的。
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
define __DECLARE_SEMAPHORE_GENERIC(name,count) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
#define __SEMAPHORE_INITIALIZER(name, n) \
{ \
.count = ATOMIC_INIT(n), \
.sleepers = 0, \
.wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
}
从上面的代码就可以看出这个宏的作用了,就是对semaphore这个结构体进行初始化。
struct semaphore {
atomic_t count;
int sleepers;
wait_queue_head_t wait;
};
typedef struct { volatile int counter; } atomic_t;
/*此处通过typedef来重新定义一个标示符,其实就是一个整形的变量,但是为了用在多进程中,采用了volatile来修饰,至于为什么要定义成结构体,当然是为了提高类型检查了*/
通过上面的一些基本信息,我们就来深入看一下怎样初始化了这个结构体变量。首先就是将count变量的值初始化为1,sleepers为0,wait变量通过宏来初始化了,主要说明了这个进程没有自旋,而且将等待队列初始化了空循环队列。具体可以查看内核源码。
有了对kernel_sem变量的了解,接着就是执行down函数。我们来看看down函数:
static inline void down(struct semaphore * sem)
{
might_sleep();
__asm__ __volatile__(
"# atomic down operation\n\t"
LOCK "decl %0\n\t" /* --sem->count */
"js 2f\n"
"1:\n"
LOCK_SECTION_START("")
"2:\tlea %0,%%eax\n\t"
"call __down_failed\n\t"
"jmp 1b\n"
LOCK_SECTION_END
:"=m" (sem->count)
:
:"memory","ax");
}
哇,是内嵌汇编语言。先来看看might_sleep宏
#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
#define might_sleep() __might_sleep(__FILE__, __LINE__)
#else
#define might_sleep() do {} while(0)
#endif
此处仅仅提供了might_sleep宏的实现代码而没有进行深入的探究。有兴趣的可以深入探究,__might_sleep函数定义在kernel/sched.c源文件中
上面的down函数主要功能就是对semaphore结构体中的count变量变量进行减1操作。
截至此处我们才弄清楚了lock_kernel这个函数到底做了什么工作,现在总结一下:
首先让lock_depth变量自增,然后判断结果是否为0,如果是,则进行对信号量的自减操作,类似于PV操作(如果学习了操作系统的同学了).
以上就是我对lock_kernel函数的一些理解了,分析不正确的地方还望有人能够指出,我一定感激不尽。
至于其他的函数我会陆续进行分析并贴出来,望大家能够互相学习,指正错误。