Chinaunix首页 | 论坛 | 博客
  • 博客访问: 954826
  • 博文数量: 109
  • 博客积分: 1751
  • 博客等级: 上尉
  • 技术积分: 1817
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-31 22:37
文章分类

全部博文(109)

文章存档

2014年(9)

2013年(21)

2012年(48)

2011年(31)

分类: LINUX

2012-08-29 21:11:47

最近看了看preempt-rt的一些材料,总结了几个preempt-rt的关键点:

1 preemptible critical sections

1.1 用支持PIrt_mutex代替传统的禁用抢占的spin_lock,定义了新的数据类型:spin_lock_t。凡是使用spin_lock_t做参数的spin_lock函数行为有可能引起调度,不会禁用抢占。如果,希望使用传统的spin_lock,则需要使用raw_spin_lock_t类型作为参数。

1.2 同时,要注意per CPU变量的问题,以前用spin_lock保护的per CPU变量,现在会出现问题,即在现在的spin_lock中进程照样会睡眠,然后调度到别的CPU上。因此,引入了一个新的宏来定义一种可以锁住的per CPU变量。DEFINE_PER_CPU_LOCKED,就是这样的宏,通过get_cpu_var_locked来操作per CPU变量。不过,以前使用get_cpu/put_cpu保护的per CPU变量不受影响。

1.3 还有一种情况,就是在显示的改变的进程状态之后,调用spin_lock,参考下面的代码序列:

spin_lock(&mylock1); 
       current->state = TASK_UNINTERRUPTIBLE; 
                spin_lock(&mylock2); // [*] 
                     blah(); 
                spin_unlock(&mylock2); 
spin_unlock(&mylock1);

在锁住mylock2之前,进程被设置为TASK_UNINTERRUPTIBLE状态,但是现在spin_lock的行为与mutex一样,所以当获得mylock2的时候,进程有可能被设置为TASK_RUNNING状态,则与前面的逻辑相矛盾。所以,引入了TASK_MUTEX_RUNNING状态。这样,代码会选择将进程状态设置为以前的状态还是TASK_RUNNING

2 preemptible interrupt handlers

preempt-rt环境下,中断处理程序是运行在进程上下文中的,这与传统情况大相径庭,所以处理上有很多需要注意的地方。大概的过程是,redirect_hardirq唤醒某个中断处理程序(实际上是一个进程),然后交由do_irqd在进程上下文中执行。

如果,希望某个中断处理程序继续运行在中断上下文中,需要将该中断处理程序设置为SA_NODELAY。在这种情况下,任何于进程上下文的互斥都要使用raw_spin_lock_t来处理。

3 preemptible “interrupt disable” code sequence

preempt-rt环境下,spin_lock_irqsave并不会禁用中断和抢占,而且local_irq_save也不会禁用中断,只会禁用抢占。必须与SA_NODELAY类型中断打交道的代码不能使用local_irq_save,因为它不会真正禁用中断,此时,必须使用raw_local_irq_save

4 priority inheritance for in-kernel spinlocks and semaphore

对于preempt-rt中的spinlock来说,实现都是支持PIrt_mutex,即能够解决优先级翻转问题。优先级翻转是实时系统中比较严重的问题,具体成因是:

进程ABC,其中优先级A>B>CC持有锁SA需要S,则A睡眠在S上,但是B抢占C,则A只有等到B运行结束,C释放S后才能继续运行。这样就造成了优先级翻转问题。

解决办法是,在A尝试获得S的时候,判断持有S的进程与A的优先级,如果A的优先级更高,则提升C的优先级与A一样高。如果,C还依赖于某一个锁,这样循环下去,则需要循环提升持有锁的进程的优先级。当C释放S时,恢复C的优先级。

一旦,C释放S,则A尝试获得S,这时Spending状态,这时,更高优先级的进程可以尝试抢占A,否则A将彻底获得S。这种优化通过在spin_lock_t中加入task_struct指针实现,指针的低两位作为锁的状态位。在pendingheld状态转化过程中,是更高优先级进程“steal”锁的时机。在这个例子里面,A就是Stop waiter

针对于读写锁,由于依赖情况比较负责,preempt-rt做了简化,即只容许一个进程在一个时间持有一个读锁。

但是,这里面也有例外,某些用于同步的semaphore,不能执行PI,因为,不知道哪个进程持有这个semaphore,所以无法比较优先级。这种情况需要使用compat_semaphore或者compat_rw_semaphore代替。

5 deferred operations

由于spin_lock可以睡眠,因此在禁用抢占期间代用spin_lock是非法的。在这种情况下preempt-rt提供了一些解决办法:

put_task_struct_delayed排队put_task_struct稍后执行

mmdrop_delayed排队mm_drop稍后执行

TIF_NEED_RESCHED_DELAYED执行重调度,在进程准备返回到用户空间时,或者直到下一个preempt_check_resched_delayed

6 latency-reduction measures

preempt-rt中还有一些改变的主要目的是减少调度或中断延迟。

第一个例子是x86MMX/SSE硬件。这些硬件在内核中处理时禁用抢占,需要等待前面的指令完成,但是一些指令执行时间很长,preempt-rt做了改变。

第二个例子是使用slab分配器分配per CPU变量。

阅读(9742) | 评论(0) | 转发(0) |
0

上一篇:内核抢占

下一篇:PCI总线驱动概要

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