可搶佔
可搶佔是從2.5.4開始支持的。 grep一下代碼,大致有這些文件添加了CONFIG_PREEMPT的代碼
$ grep -R CONFIG_PREEMPT *
arch/i386/kernel/entry.S:#ifdef CONFIG_PREEMPT
arch/i386/kernel/entry.S:#ifdef CONFIG_PREEMPT
include/linux/smp_lock.h:#if !defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT)
include/linux/smp.h:#ifndef CONFIG_PREEMPT
include/linux/spinlock.h:#ifndef CONFIG_PREEMPT
include/linux/spinlock.h:#ifdef CONFIG_PREEMPT
include/asm/hw_irq.h:#ifdef CONFIG_PREEMPT
include/asm/smplock.h:#ifdef CONFIG_PREEMPT
include/asm/smplock.h:#ifdef CONFIG_PREEMPT
include/asm-i386/hw_irq.h:#ifdef CONFIG_PREEMPT
include/asm-i386/smplock.h:#ifdef CONFIG_PREEMPT
include/asm-i386/smplock.h:#ifdef CONFIG_PREEMPT
kernel/ksyms.c:#ifdef CONFIG_PREEMPT
kernel/sched.c:#ifdef CONFIG_PREEMPT
kernel/sched.c:#if CONFIG_SMP || CONFIG_PREEMPT
kernel/sched.c:#ifdef CONFIG_PREEMPT
kernel/sched.c:#endif /* CONFIG_PREEMPT */
kernel/fork.c:#ifdef CONFIG_PREEMPT
net/socket.c:#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
看一下PREEMPT在make config裡的註釋,大概知道可搶佔的作用。
CONFIG_PREEMPT
This option reduces the latency of the kernel when reacting to
real-time or interactive events by allowing a low priority process to
be preempted even if it is in kernel mode executing a system call.
即使在內核空間,在運行系統調用,也是可以切換上下文。
分析arch/i386/kernel/entry.S文件
ENTRY(ret_from_intr)
GET_THREAD_INFO(%ebx)
init_ret_intr
ret_from_exception:
movl EFLAGS(%esp),%eax # mix EFLAGS and CS
movb CS(%esp),%al
testl $(VM_MASK | 3),%eax
jz resume_kernel # returning to kernel or vm86-space
ENTRY(resume_userspace)
cli # make sure we don't miss an interrupt setting need_resched
從中斷返回或從異常返回
IOPL為0且非Virtual 8086 Mode,返回kernel空間
IOPL非0或在Virtual 8086 Mode,返回用戶空間
PREEMPT發生在內核空間,也就是resume_kernel
[SCHEDULE]每次中斷返回都會調度?還有沒其它產生調度的路徑?
[SIGNAL]發現應用程序信號處理的路徑:
resume_userspace -> work_pending -> work_notifysig -> do_notify_resume -> do_signal
#ifdef CONFIG_PREEMPT
ENTRY(resume_kernel)
cmpl $0,TI_PRE_COUNT(%ebx)
jnz restore_all
movl TI_FLAGS(%ebx),%ecx
testb $_TIF_NEED_RESCHED,%cl
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 TI_PRE_COUNT(%ebx)
sti
call SYMBOL_NAME(preempt_schedule)
jmp ret_from_intr
#endif
thread_info的preempt_count等於0,flags中設置了TIF_NEED_RESCHED,local irq為0,才會開中斷並調度,用preempt_schedule切換上下文
#define spin_lock(lock) \
do { \
preempt_disable(); \
_raw_spin_lock(lock); \
} while(0)
從include/linux/spinlock.h我們可以知道,在spin_lock之前,可搶佔被禁止了。
preemp需要思考跟schedule的關係