- 論壇徽章:
- 0
|
錯~
如果是從異常返回的話。Cli禁止中斷。(中斷返回時,本地中斷是禁止的)
1. 確定要返回到內(nèi)核態(tài)還是用戶態(tài)。
2. 如果是返回到內(nèi)核態(tài)的話:
resume_kernel:
cli
cmpl $0, 0x14(%ebp) //檢查是否可以搶占thread_info->preempt_count
jz need_resched
restore_all:
popl %ebx
popl %ecx
popl %edx
popl %esi
popl %edi
popl %ebp
popl %eax
popl %ds
popl %es
addl $4, %esp
iret //中斷和異常退出的硬件處理過程
need_resched:
movl 0x8(%ebp), %ecx
testb $(1<<TIF_NEED_RESCHED), %cl
jz restore_all //如果falgs沒有設(shè)置TIF_NEED_RESCHED,不需要搶占
testl $0x00000200,0x30(%esp)
jz restore_all //如果正在禁用本地CPU,不需要搶占
call preempt_schedule_irq //打開本地中斷,調(diào)用preempt_schedule,進(jìn)行搶占
jmp need_resched
3. 如果是返回到用戶態(tài)的話:
resume_userspace:
cli
movl 0x8(%ebp), %ecx
andl $0x0000ff6e, %ecx //檢查flags是否只設(shè)置了某些標(biāo)志
je restore_all
jmp work_pending
work_pending:
testb $(1<<TIF_NEED_RESCHED), %cl
jz work_notifysig //如果falgs沒有設(shè)置TIF_NEED_RESCHED,不需要調(diào)度
work_resched:
call schedule //進(jìn)程調(diào)度
cli
jmp resume_userspace
work_notifysig: //處理掛起的信號,虛擬8086和單步執(zhí)行
movl %esp, %eax
testl $0x00020000, 0x30(%esp)
je 1f
work_notifysig_v86:
pushl %ecx
call save_v86_state
popl %ecx
movl %eax, %esp
1:
xorl %edx, %edx
call do_notify_resume
jmp restore_all
restore_all:
popl %ebx
popl %ecx
popl %edx
popl %esi
popl %edi
popl %ebp
popl %eax
popl %ds
popl %es
addl $4, %esp
iret //中斷和異常退出的硬件處理過程
注意:不管返回到內(nèi)核態(tài)還是返回到用戶態(tài),都會試圖進(jìn)行進(jìn)程調(diào)度。在返回內(nèi)核態(tài)進(jìn)行進(jìn)程調(diào)度就叫做內(nèi)核搶占。在返回用戶態(tài)進(jìn)行進(jìn)程調(diào)度屬于普通進(jìn)程調(diào)度。它們都會檢查current->thread_info->flags 的TIF_NEED_RESCHED標(biāo)志是否需要進(jìn)行進(jìn)程調(diào)度。但是返回內(nèi)核態(tài)的時候,額外的需要檢查current->thread_info->preempt_count的內(nèi)核搶占位確定是否可以進(jìn)行內(nèi)核搶占。
|
|