Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1216550
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2008-09-27 18:00:12

Spin_lock()

//

Spin_unlock()

自旋锁的作用就是对于一个临界资源将其进行锁定,使得同时不能有两个及以上的进程对该临界资源进行访问。

smp上面,调用了spin_lock()之后,如果该锁现在没有被锁定,则锁定该锁并进入临界区,此时如果另一个CPU也要用到当前锁,则会自旋,但是在自旋的时候,它会调用preemp_enable(),使得其进程是可抢占的,因此可以被更高优先权的进程所抢占。

如果是在单CPU上面,则只是执行禁止与开户抢占这个功能。对于这个情况:

Spin_lock()

//

Spin_unlock()

假如运行在其中的时候该进程的时间片用完了的话,是该如何来处理呢?

在单处理机上,spin_lock()就退化成了。Preemp_disable(),它就是禁止抢占,即虽然时间片用完了,但是仍然是不能切换到其它进程去的。因此每个进程有一个preemp_count这个变量,如果这个变量为0的话表示其可以被其它进程所抢占,如果大于0则不能够被抢占,而在调用preemp_disable()的时候就会将该进程的preemp_count值加1。使得其不能够被抢占。而继续运行该进程,直到调用preemp_enable()将其设为可抢占,由于时间一般不长,因此不会有影响。

但是spin_lock()虽然不会进行进程切换,但它可能会被中断给打断,执行中断处理程序,此时在中断处理程序中就不能再调用spin_lock()去锁定刚刚被锁定的内容。否则会引起死锁。因此在内核中就会使用另外两个函数。

Spin_lock_irqsave()

Spin_unlock_irqstore()

 

 

QUOTE:原帖由 bobpipi 于 2007-10-22 10:57 发表
刚开始学习内核。有个疑问
内核进程是可以被抢占的,但如果这个进程运行时被中断打断,这算不算内核抢占。如果说preemp_count的值大于0的话,进程不能被抢占,那么中断来时,进程是不是还是会被打断。
还有 ...
中断不算内核抢占。举个例子解释抢占:
进程A正在运行,这时有一个进程B,优先级比进程A更高,那么在可抢占的内核里,进程B就可能在进程A运行结束之前被调度执行,迫使进程A进入等待队列。
linux中通常会在中断和异常的handler执行结束后检查抢占,如果这个时候有一个等待的进程比当前运行的进程优先级更高,并且当前进程是可抢占的,那么抢占就会发生,优先级高的进程得以运行。
要把中断和抢占区分开,两者没有直接联系。

 
在2.6内核中,内核进程是可以被抢占的,但是如果preemp_count的值大于0的话,则当前进程是不能够被抢占的.我在看schedule()函数的时候,看到在里面有一个in_atomic()的函数.请教一下这个函数是不是就是判断preemp_count是不是为0的吗? 那么仿佛没有看到它的返回是如何实现的啊.
谢谢.
 
在entry_armv.S中:(我的是ARM平台)
代码:
irq_handler #ifdef CONFIG_PREEMPT ldr r0, [tsk, #TI_FLAGS] @ get flags tst r0, #_TIF_NEED_RESCHED ◎检查TIF_NEED_RESCHED标志位 blne svc_preempt . . . svc_preempt: teq r8, #0 @ was preempt count = 0 ldreq r6, .LCirq_stat movne pc, lr @ no ldr r0, [r6, #4] @ local_irq_count ldr r1, [r6, #8] @ local_bh_count adds r0, r0, r1 movne pc, lr mov r7, #0 @ preempt_schedule_irq str r7, [tsk, #TI_PREEMPT] @ 保存preemnt_count值,但愿它是0,哦,expects preempt_count == 0 1: bl preempt_schedule_irq
 
而在preempt_schedule_irq()函数中有:
代码:
struct thread_info *ti = current_thread_info(); #ifdef CONFIG_PREEMPT_BKL struct task_struct *task = current; int saved_lock_depth; #endif /* Catch callers which need to be fixed*/ BUG_ON(ti->preempt_count || !irqs_disabled()); //不为0就BUG了 . . . local_irq_enable(); schedule(); //就可以调用schedule()了 local_irq_disable();
而在我的pxa_timer_init()函数中注册的pxa_timer_irq.handler=pxa_timer_interrupt() -> time_tick() -> update_process_times() -> scheduler_tick() 中设置NEED_RESCHED标志:
代码:
if (!--p->time_slice) { dequeue_task(p, rq->active); set_tsk_need_resched(p);//时间片用完了,晕了吧,该设置TIF_NEED_RESCHED标志了 p->prio = effective_prio(p); p->time_slice = task_timeslice(p); p->first_time_slice = 0; if (!rq->expired_timestamp) rq->expired_timestamp = jiffies; if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) { enqueue_task(p, rq->expired); if (p->static_prio < rq->best_expired_prio) rq->best_expired_prio = p->static_prio; } else enqueue_task(p, rq->active); }
 
阅读(928) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~