|
CPU在内核中运行时并不是处处不可抢占的,内核中存在一些空隙,在这时进行抢占是安全的,内核抢占补丁的基本原理就是将SMP可并行的代码段看成是可以进行内核抢占的区域。
2.4内核正好细化了多CPU下的内核线程同步机构,对不可并行的指令块用spinlock和rwlock作了细致的表示,该补丁的实现可谓水到渠成。具体的方法就是在进程的任务结构上增加一个preempt_count变量作为内核抢占锁,它随着spinlock和rwlock一起加锁和解锁。当preempt_count为0时表示可以进行内核调度。内核调度器的入口为preempt_schedule(),它将当前进程标记为TASK_PREEMPTED状态再调用schedule(),在TASK_PREEMPTED状态,schedule()不会将进程从运行队列中删除。
下面是内核抢占补丁的主要代码示意:
arch/i386/kernel/entry.S: preempt_count = 4 # 将task_struct中的flags用作preempt_count,flags被移到了别 的位置 ret_from_exception: # 从异常返回 #ifdef CONFIG_SMP GET_CURRENT(%ebx) movl processor(%ebx),%eax shll $CONFIG_X86_L1_CACHE_SHIFT,%eax movl SYMBOL_NAME(irq_stat)(,%eax),%ecx # softirq_active testl SYMBOL_NAME(irq_stat)+4(,%eax),%ecx # softirq_mask #else movl SYMBOL_NAME(irq_stat),%ecx # softirq_active testl SYMBOL_NAME(irq_stat)+4,%ecx # softirq_mask #endif jne handle_softirq #ifdef CONFIG_PREEMPT cli incl preempt_count(%ebx) # 异常的入口没有禁止内核调度的指令,与ret_from_intr 匹配一下 #endif ENTRY(ret_from_intr) # 硬件中断的返回 GET_CURRENT(%ebx) #ifdef CONFIG_PREEMPT cli decl preempt_count(%ebx) # 恢复内核抢占标志 #endif movl EFLAGS(%esp),%eax # mix EFLAGS and CS movb CS(%esp),%al testl $(VM_MASK | 3),%eax # return to VM86 mode or non-supervisor? jne ret_with_reschedule #ifdef CONFIG_PREEMPT cmpl $0,preempt_count(%ebx) jnz restore_all # 如果preempt_count非零则表示禁止内核抢占 cmpl $0,need_resched(%ebx) jz restore_all # movl SYMBOL_NAME(irq_stat)+irq_stat_local_bh_count CPU_INDX,%ecx addl SYMBOL_NAME(irq_stat)+irq_stat_local_irq_count CPU_INDX,%ecx jnz restore_all incl preempt_count(%ebx) sti call SYMBOL_NAME(preempt_schedule) jmp ret_from_intr # 新进程返回,返回ret_from_intr恢复抢占标志后再返回
[1] [2] [3] [4] [5] [6] 下一页 |