谈到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函数的一些理解了,分析不正确的地方还望有人能够指出,我一定感激不尽。
至于其他的函数我会陆续进行分析并贴出来,望大家能够互相学习,指正错误。
阅读(3637) | 评论(0) | 转发(0) |