LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2191|回复: 7

关于内核抢占的一点疑问

[复制链接]
发表于 2007-4-12 19:31:25 | 显示全部楼层 |阅读模式
在2.6内核中,内核进程是可以被抢占的,但是如果preemp_count的值大于0的话,则当前进程是不能够被抢占的.我在看schedule()函数的时候,看到在里面有一个in_atomic()的函数.请教一下这个函数是不是就是判断preemp_count是不是为0的吗? 那么仿佛没有看到它的返回是如何实现的啊.
谢谢.
发表于 2007-4-14 10:38:19 | 显示全部楼层

  1. #if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)
  2. # define in_atomic()        ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
  3. #else
  4. # define in_atomic()        ((preempt_count() & ~PREEMPT_ACTIVE) != 0)
  5. #endif
复制代码

只有preempt_count()为0,in_atomic()才会返回0,其他都是返回1
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-4-14 10:40:41 | 显示全部楼层
Post by augustusqing
schedule()函数开头有这么一段:
代码:

  1. /*
  2.          * Test if we are atomic.  Since do_exit() needs to call into
  3.          * schedule() atomically, we ignore that path for now.
  4.          * Otherwise, whine if we are scheduling when we should not be.
  5.          */
  6.         if (likely(!current->exit_state)) {
  7.                 if (unlikely(in_atomic())) {
  8.                         printk(KERN_ERR "scheduling while atomic: "
  9.                                 "%s/0x%08x/%d\n",
  10.                                 current->comm, preempt_count(), current->pid);
  11.                         dump_stack();
  12.                 }
  13.         }
复制代码

所以我的理解是in_atomic()函数仅仅是判断是否在原子动作中,对于是从do_exit()调过来的就不用判断了,否则,printk(KERN_ERR "scheduling while atomic: "
我也看到了这一个,它仅仅只是说判断是否在原子动作中,那么每次在schedule()的时候都会判断当前进程的preemp_count值是否为0,为0的时候才可以进行抢占,那么这个判断又是在哪儿进行的呢?谢谢.
回复 支持 反对

使用道具 举报

发表于 2007-4-14 10:52:37 | 显示全部楼层
呵呵,我开始没有细想,再翻翻源码中。。。。。。
回复 支持 反对

使用道具 举报

发表于 2007-4-14 11:13:57 | 显示全部楼层
Hi,你知道传说中的预定义的中断处理入口在哪里吗?就是发生某个中断后CPU会跳入到的那个地方,那个处理入口会调用do_IRQ()的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-4-14 11:19:54 | 显示全部楼层
Post by augustusqing
Hi,你知道传说中的预定义的中断处理入口在哪里吗?就是发生某个中断后CPU会跳入到的那个地方,那个处理入口会调用do_IRQ()的
好像是在entry.S中吧!
回复 支持 反对

使用道具 举报

发表于 2007-4-14 12:25:13 | 显示全部楼层
在entry_armv.S中:(我的是ARM平台)

  1.         irq_handler
  2. #ifdef CONFIG_PREEMPT
  3.         ldr        r0, [tsk, #TI_FLAGS]                @ get flags
  4.         tst        r0, #_TIF_NEED_RESCHED       ◎检查TIF_NEED_RESCHED标志位
  5.         blne        svc_preempt
  6.                 .
  7.                 .
  8.                 .
  9. svc_preempt:
  10.         teq        r8, #0                                @ was preempt count = 0
  11.         ldreq        r6, .LCirq_stat
  12.         movne        pc, lr                                @ no
  13.         ldr        r0, [r6, #4]                        @ local_irq_count
  14.         ldr        r1, [r6, #8]                        @ local_bh_count
  15.         adds        r0, r0, r1
  16.         movne        pc, lr
  17.         mov        r7, #0                                @ preempt_schedule_irq
  18.         str        r7, [tsk, #TI_PREEMPT]                @ 保存preemnt_count值,但愿它是0,哦,expects preempt_count == 0
  19. 1:        bl        preempt_schedule_irq       
复制代码

而在preempt_schedule_irq()函数中有:

  1. struct thread_info *ti = current_thread_info();
  2. #ifdef CONFIG_PREEMPT_BKL
  3.         struct task_struct *task = current;
  4.         int saved_lock_depth;
  5. #endif
  6.         /* Catch callers which need to be fixed*/
  7.         BUG_ON(ti->preempt_count || !irqs_disabled());  //不为0就BUG了
  8.                 .
  9.                 .
  10.                 .
  11.                 local_irq_enable();
  12.         schedule();                  //就可以调用schedule()了
  13.         local_irq_disable();
复制代码

而在我的pxa_timer_init()函数中注册的pxa_timer_irq.handler=pxa_timer_interrupt() -> time_tick() -> update_process_times() -> scheduler_tick() 中设置NEED_RESCHED标志:

  1. if (!--p->time_slice) {
  2.                 dequeue_task(p, rq->active);
  3.                 set_tsk_need_resched(p);//时间片用完了,晕了吧,该设置TIF_NEED_RESCHED标志了
  4.                 p->prio = effective_prio(p);
  5.                 p->time_slice = task_timeslice(p);
  6.                 p->first_time_slice = 0;

  7.                 if (!rq->expired_timestamp)
  8.                         rq->expired_timestamp = jiffies;
  9.                 if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
  10.                         enqueue_task(p, rq->expired);
  11.                         if (p->static_prio < rq->best_expired_prio)
  12.                                 rq->best_expired_prio = p->static_prio;
  13.                 } else
  14.                         enqueue_task(p, rq->active);
  15.         }
复制代码


一起学习......
回复 支持 反对

使用道具 举报

发表于 2007-4-15 12:10:53 | 显示全部楼层
the kernel can be preempted only when it is executing an exception handler (in particular a system call) and the kernel preemption has not been explicitly disabled.
   典型情景:
      用户进程调用系统调用(sys_..之类),进入内核,这时cpu收到中断信号转去执行
中断处理 中断处理完返回前会检测preempt_count(),若为0且需要调度则执行schedule
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表