Chinaunix首页 | 论坛 | 博客
  • 博客访问: 106052
  • 博文数量: 17
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 184
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-20 11:19
个人简介

学习内核中~

文章分类

全部博文(17)

文章存档

2013年(17)

我的朋友

分类: LINUX

2013-05-23 23:36:08

自从以前写了一个测试程序,去获得一个初始化为锁着的自旋锁,导致整个系统被锁住之后,我对自旋锁的认识也就是,它能“禁止抢占”。那个时候我还以为自旋锁之所以能够禁止抢占,是因为它禁止了中断(因为中断能够引发抢占),后来对抢占和时钟中断的认识比较清楚以及看了下面的帖子之后,才知道禁止抢占并不等同于禁止中断(当然,自旋锁API也提供了相应的版本来禁止中断),也明白阅读源码是多么重要。

当need_sched标志被设置时,schedule()函数就会被调用,实际上在内核态的抢占中,并没有那么简单,因为还为每个进程的thread_info引入了preempt_count,当preempt_count为1时,说明该进程正拥有着锁,因此不能被抢占。

点击(此处)折叠或打开

  1. // 在linux/spinlock_api_up.h

  2. #define __LOCK(lock)
  3.   do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

  4. #define _raw_spin_lock(lock)            __LOCK(lock)

  5. // 在linux/spinlock.h

  6. #define raw_spin_lock(lock)    _raw_spin_lock(lock)

  7. static inline void spin_lock(spinlock_t *lock)
  8. {
  9.     raw_spin_lock(&lock->rlock);
  10. }
可以看出自旋锁先是禁止抢占(preempt_disable()),再请求锁__acquire(lock)。
再看下preempt_disable()

点击(此处)折叠或打开

  1. // 在linux/preempt.h

  2. #ifdef CONFIG_PREEMPT_COUNT

  3. #define preempt_disable()
  4. do {
  5.     inc_preempt_count();
  6.     barrier();
  7. } while (0)

  8. #else /* !CONFIG_PREEMPT_COUNT */

  9. #define preempt_disable()        do { } while (0)
可以看出在抢占式内核的情况下,preempt_disable做的就是给preempt_count加1,而在非抢占内核的情况下什么也不做(本身都是非抢占的了,禁止抢占也没什么意义)。
在单处理机的情况下,自旋锁的意义就只是禁止抢占,因为只要自旋锁初始化为1并且加锁和解锁操作总是成对出现,那么一个进程要是想获得自旋锁,它总是能够立即获得(也就是从不自旋),因此自旋锁就只是禁止抢占了。
自旋锁一般在不可休眠的环境中用于同步对临界资源的访问,也用在等待锁比切换进程开销小的情况(后者要求自旋锁的粒度足够小,也就是获得自旋锁后执行的代码足够短)。

已知spin_lock_irq()能够禁止本地中断,因此我们写个程序,先打印当前的jiffies,再用这个函数禁止本地中断,延迟一段时间后再打印jiffies的值,看下是否和原来的相同,注意延迟操作不能使用和jiffies有关的API,因为jiffies已经不增长了。

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/proc_fs.h>
  4. #include <linux/sched.h>
  5. #include <linux/jiffies.h>
  6. #include <linux/spinlock.h>
  7. #include <linux/delay.h>

  8. spinlock_t my_lock;

  9. int delay_jiffies(char *buf,char **start,off_t offset,int count,int *eof,void *data)
  10. {
  11.     int len = 0;
  12.     unsigned long delay_time = 3000;
  13.     
  14.     spin_lock_irq(&my_lock);
  15.     len += sprintf(buf + len,"Now jiffies is %un",jiffies);
  16.     udelay(delay_time);
  17.     len += sprintf(buf + len,"After delay,jiffies is %un",jiffies);
  18.     spin_unlock_irq(&my_lock);
  19.     
  20.     return len;
  21. }

  22. static int main_init(void)
  23. {
  24.     spin_lock_init(&my_lock);
  25.     create_proc_read_entry("delay_jiffies",0,NULL,delay_jiffies,NULL);
  26.     return 0;
  27. }

  28. static void main_exit(void)
  29. {
  30.     remove_proc_entry("delay_jiffies",NULL);
  31. }

  32. module_init(main_init);
  33. module_exit(main_exit);
cat /proc/delay_jiffies,发现有时候两次获得的jiffies相同,有时则相差3,结果和想象中的不一样,原因还未探明。
阅读(2124) | 评论(0) | 转发(0) |
0

上一篇:对抢占的理解

下一篇:内核数据结构

给主人留下些什么吧!~~