linux系统在完成中断/异常事件的处理之后,决定是否应该执行schedule函数。
如果是非抢占,那么策略如下:
如果是被抢占的进程被强占的时候处于内核态(内核线程或者用户态进程通过系统调用进入内核态),那么中断/异常处理程序返回后,linux系统必须回到该进程继续执行。
如果一个进程在用户空间被中断/异常打断,那么linux系统可以根据进程的优先级选择合适的进程获得CPU资源。
对于抢占式内核:
无论进程在用户空间,或者内核空间被打断,中断/异常返回后,linux系统都将根据进程的优先级选择合适的进程获得CPU资源。
ret_from_intr:
check_userspace://检查被中断打断进程的CS,查看是用户态还是内核态,如果是内核态则进入内核态流程resume_kernel ;否则进入用户态流程resume_userspace
movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS
movb PT_CS(%esp), %al
andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
cmpl $USER_RPL, %eax
jb resume_kernel//对于非抢占内核,resume_kernel被重定义为restore_all
ENTRY(resume_userspace)
movl TI_flags(%ebp), %ecx
andl $_TIF_WORK_MASK, %ecx # is there any work to be done on
# int/exception return?
jne work_pending
jmp restore_all
END(ret_from_exception)
/*对于抢占内核,内核态选择一个合适的线程调度*/
#ifdef CONFIG_PREEMPT
ENTRY(resume_kernel)
DISABLE_INTERRUPTS(CLBR_ANY)
cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ?
jnz restore_all
need_resched:
movl TI_flags(%ebp), %ecx # need_resched set ?
testb $_TIF_NEED_RESCHED, %cl
jz restore_all
testl $X86_EFLAGS_IF,PT_EFLAGS(%esp) # interrupts off (exception path) ?
jz restore_all
call preempt_schedule_irq
jmp need_resched
END(resume_kernel)
#endif
restore_all:
TRACE_IRQS_IRET
restore_all_notrace:
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
# are returning to the kernel.
# See comments in process.c:copy_thread() for details.
movb PT_OLDSS(%esp), %ah
movb PT_CS(%esp), %al
andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
CFI_REMEMBER_STATE
je ldt_ss # returning to user-space with LDT SS
restore_nocheck:
RESTORE_REGS 4 # skip orig_eax/error_code
CFI_ADJUST_CFA_OFFSET -4
irq_return:
INTERRUPT_RETURN
选自王齐的《linux powerpc详解》
另外
http://blog.csdn.net/yyd19921214/article/details/36482331
http://blog.csdn.net/ruanjianruanjianruan/article/details/49082191
写得也不错
内核抢占实现(preempt) 好文
http://blog.chinaunix.net/uid-12461657-id-3353217.html