Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149031
  • 博文数量: 17
  • 博客积分: 359
  • 博客等级: 一等列兵
  • 技术积分: 382
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-08 19:51
文章分类

全部博文(17)

文章存档

2012年(17)

我的朋友

分类: LINUX

2012-04-16 15:24:29

谈到lock_kernel,首先应该参看源码(此处所讲的是2.6.11版本的内核)中的include/linux/smp_lock.h文件。具体请参见该文件,在此处就不列出源码了
下面就开始分析了
  1. #ifdef CONFIG_LOCK_KERNEL
首先就是判断我们是否配置内核支持内核锁。当然分两种情况了,要么配置了,要么就没有要这种功能
先来看配置了内核锁之后的代码部分
  1. #define kernel_locked() (current->lock_depth >= 0)

上面的宏是判断内核是否已经被锁,通过什么判断呢?通过当前的进程的lock_depth这个变量的值来判断,提示:current就是当前正在执行的进程的tast_struct类型的指针变量。具体可参见include/linux/sched.h文件关于task_struct结构体的定义。如果这个变量的值大于0,那么内核就被锁住了,否则就没有锁。在初始化中lock_depth的值=-1.

现在就看看lock_kernel函数的实现部分吧

  1. void __lockfunc lock_kernel(void)
  2. {
  3. struct task_struct *task = current;
  4. int depth = task->lock_depth + 1;

  5. if (likely(!depth))
  6. /*
  7. * No recursion worries - we set up lock_depth _after_
  8. */
  9. down(&kernel_sem);

  10. task->lock_depth = depth;
  11. }

从上面的代码中,首先将当前进程的lock_depth变量+1,然后判断depth变量的值是否为0,为什么是0?其实前面已经提到了,lock_depth的值初始化是-1,在此加上了1,当然是0了,那么if这个判断语句就成立了。

在分析down函数之前我们需要注意下kernel_sem变量是什么?

  1. DECLARE_MUTEX(kernel_sem);

又出来一个DECLARE_MUTEX宏,我们追踪一下子

  1. if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
  2. #define DECLARE_MUTEX(name) struct semaphore name=MUTEX

显然这个不是,因为我当前的版本内核是2.6.11,而不是低于2.4的。

  1. #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
  2. define __DECLARE_SEMAPHORE_GENERIC(name,count) \
  3. struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
  4. #define __SEMAPHORE_INITIALIZER(name, n) \
  5. { \
  6. .count = ATOMIC_INIT(n), \
  7. .sleepers = 0, \
  8. .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
  9. }

从上面的代码就可以看出这个宏的作用了,就是对semaphore这个结构体进行初始化。

  1. struct semaphore {
  2. atomic_t count;
  3. int sleepers;
  4. wait_queue_head_t wait;
  5. };
  1. typedef struct { volatile int counter; } atomic_t;
  2. /*此处通过typedef来重新定义一个标示符,其实就是一个整形的变量,但是为了用在多进程中,采用了volatile来修饰,至于为什么要定义成结构体,当然是为了提高类型检查了*/

通过上面的一些基本信息,我们就来深入看一下怎样初始化了这个结构体变量。首先就是将count变量的值初始化为1,sleepers为0,wait变量通过宏来初始化了,主要说明了这个进程没有自旋,而且将等待队列初始化了空循环队列。具体可以查看内核源码。

有了对kernel_sem变量的了解,接着就是执行down函数。我们来看看down函数:

  1. static inline void down(struct semaphore * sem)
  2. {
  3. might_sleep();
  4. __asm__ __volatile__(
  5. "# atomic down operation\n\t"
  6. LOCK "decl %0\n\t" /* --sem->count */
  7. "js 2f\n"
  8. "1:\n"
  9. LOCK_SECTION_START("")
  10. "2:\tlea %0,%%eax\n\t"
  11. "call __down_failed\n\t"
  12. "jmp 1b\n"
  13. LOCK_SECTION_END
  14. :"=m" (sem->count)
  15. :
  16. :"memory","ax");
  17. }

哇,是内嵌汇编语言。先来看看might_sleep宏

  1. #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
  2. #define might_sleep() __might_sleep(__FILE__, __LINE__)
  3. #else
  4. #define might_sleep() do {} while(0)
  5. #endif

此处仅仅提供了might_sleep宏的实现代码而没有进行深入的探究。有兴趣的可以深入探究,__might_sleep函数定义在kernel/sched.c源文件中

上面的down函数主要功能就是对semaphore结构体中的count变量变量进行减1操作。

截至此处我们才弄清楚了lock_kernel这个函数到底做了什么工作,现在总结一下:

首先让lock_depth变量自增,然后判断结果是否为0,如果是,则进行对信号量的自减操作,类似于PV操作。

以上部分转载自:http://blog.chinaunix.net/uid-25588566-id-2231120.html

lock_kernel 的真实身份还需要内核编译的 CONFIG_LOCK_KERNEL 确定.

内核使用了arch/arm/configs/s3c2410_defconfig作为默认的配置文件,Code maturity level options 选项下没有设置

CONFIG_LOCK_KERNEL 项.所以在这里lock_kernel应该就是 #define lock_kernel() do { } while (0)的空操作。

 

阅读(3233) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~