wordpress网站如何引流,江苏有什么网站找工程建设人员,中文logo设计网站,百度商城网站建设目录
抢占流程
抢占时机
用户态抢占时机
1、 从系统调用返回用户空间
2、 从中断返回用户空间
内核态抢占时机
1、中断处理程序返回内核空间
可以看到最终是到了 preempt_schedule_irq
2、当内核从non-preemptible#xff08;禁止抢占#xff09;状态变成pr…目录
抢占流程
抢占时机
用户态抢占时机
1、 从系统调用返回用户空间
2、 从中断返回用户空间
内核态抢占时机
1、中断处理程序返回内核空间
可以看到最终是到了 preempt_schedule_irq
2、当内核从non-preemptible禁止抢占状态变成preemptible允许抢占的时候
3、内核主动进行任务切换
备注 https://blog.csdn.net/heyangge/article/details/134666931
https://zhuanlan.zhihu.com/p/519030765
17 | 调度下抢占式调度是如何发生的-CSDN博客 抢占式调度和非抢占式调度是操作系统中两种不同的进程调度方式。 在抢占式调度中操作系统可以在任何时候中断正在运行的进程并将 CPU分配给另一个处于就绪状态的进程。这意味着一个高优先级的进程可以随时抢占正在运行的低优先级进程的 CPU时间片。这种方式可以保证高优先级进程得到更快的响应时间但可能会导致低优先级进程的运行时间不确定。 相反在非抢占式调度中一个进程只有在自愿放弃CPU或者因为等待某个事件而被阻塞时操作系统才会将 CPU分配给另一个进程。这种方式可以保证低优先级进程得到更稳定的运行时间但可能会导致高优先级进程得不到及时响应。总的来说抢占式调度适用于实时系统或需要快速响应的场景而非抢占式调度适用于一些需要稳定运行的应用如批处理系统 抢占式内核当一个进程在内核模式下运行时如果有一个更高优先级的任务出现内核可以强制将当前任务挂起执行更高优先级的任务。这种内核总是执行准备运行的最高优先级任务除非函数是互斥的否则不能使用非可重入函数。非抢占式内核也称为合作式内核进程必须显式地放弃CPU才能让另一个进程运行。这种内核不会中断正在运行的进程直到它自愿释放CPU。 对于非抢占内核就是内核线程能一直运行下去除非自己主动调用schedule或者进行了会休眠的动作才会让出cpu 。即使当前执行流被中断/软中断打断当其执行完成后也必须回到打断的线程继续执行。这种内核解决异常问题稍微简单点但是如果代码里面有啥死循环或者死锁之类的那这个核就废了。
对于抢占式内核感觉可能在中断触发后可能就会切换到其他进程了回不来了。这点用户态和内核态应该都是一样的。没有用过。。
抢占流程 Linux抢占(PREEMPTION)_linux preempt-CSDN博客 抢占的过程分两步第一步触发抢占第二步执行抢占这两步中间不一定是连续的有些特殊情况下甚至会间隔相当长的时间 1、触发抢占给正在CPU上运行的当前进程设置一个请求重新调度的标志(TIF_NEED_RESCHED)仅此而已此时进程并没有切换。 2、执行抢占在随后的某个时刻内核会检查TIF_NEED_RESCHED标志并调用schedule()执行抢占。 抢占时机
如果是抢占式的它应该在何时进行抢占呢
用户态抢占时机 有两种情况分别是从系统调用返回用户空间和从中断处理程序返回用户空间
1、 从系统调用返回用户空间
https://zhuanlan.zhihu.com/p/363148708 //这个是用户态抢占调度的地方 1、内核态抢占是可以关闭的用户态抢占是无法关闭的。 2、如果内核编译配置是“CONFIG_PREEMPT_NONEy”。这就意味着一个正处于内核态的进程是不能被抢占的无论它运行的时间有多长也无论其他进程的优先级比它高多少都只能等它回到用户态才能抢占。这个意思就是非抢占内核的情况下即使是一个用户态进程如果其进行了系统调用陷入内核在内核里面执行的这段时间也是无法被抢占的。如果是内核线程那就永远无法被抢占 Linux抢占(PREEMPTION)_linux preempt-CSDN博客 //这个文章写了用户态的抢占是无法关闭的 用户态进行系统调用的时候会进入到vector_swi在该函数里面会跳转到内核系统调用接口里面去并且设置返回值为ret_fast_syscall 其实现如下其实它有两种实现参考文章arm系统调用过程_arm系统调用号-CSDN博客
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \_TIF_NOTIFY_RESUME | _TIF_UPROBE)ret_fast_syscall:UNWIND(.fnstart )UNWIND(.cantunwind )str r0, [sp, #S_R0 S_OFF]! save returned r0disable_irq_notrace disable interruptsldr r2, [tsk, #TI_ADDR_LIMIT]cmp r2, #TASK_SIZEblne addr_limit_check_failedldr r1, [tsk, #TI_FLAGS] re-check for syscall tracingtst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASKbeq no_work_pending //如果没有设置need sch或者是有信号待处理则跳转到no_work_pending返回用户空间如果相等我感觉应该是继续往下执行UNWIND(.fnend )
ENDPROC(ret_fast_syscall)/* Slower path - fall through to work_pending */
#endiftst r1, #_TIF_SYSCALL_WORKbne __sys_trace_return_nosave
slow_work_pending:mov r0, sp regsmov r2, why syscallbl do_work_pendingcmp r0, #0beq no_work_pendingmovlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia sp, {r0 - r6} have to reload r0 - r6b local_restart ... and off we go
ENDPROC(ret_fast_syscall) tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK //如果不为0则跳转到slow_work_pending去进行抢占或者下信号处理(上面提到根据定义的宏的不同ret_fast_syscall有两种实现但是最终都会走到slow_work_pending)
slow_work_pending:mov r0, sp regsmov r2, why syscallbl do_work_pendingcmp r0, #0beq no_work_pendingmovlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia sp, {r0 - r6} have to reload r0 - r6b local_restart ... and off we go
ENDPROC(ret_fast_syscall)
slow_work_pending--do_work_pending:可以看到这就是为什么用户态无法禁止抢占了。只要你设置了_TIF_NEED_RESCHED标记走到这里就会无条件进行任务切换了
asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
...............................trace_hardirqs_off();do {/* 如果设置可以抢占的标记,就会直接进行调度了 */if (likely(thread_flags _TIF_NEED_RESCHED)) {schedule();} else {...............................}local_irq_disable();thread_flags current_thread_info()-flags;} while (thread_flags _TIF_WORK_MASK);return 0;
}
2、 从中断返回用户空间 vector_irq--__irq_usr(被打断的是用户态)
__irq_usr:usr_entrykuser_cmpxchg_checkirq_handlerget_thread_info tskmov why, #0b ret_to_user_from_irqUNWIND(.fnend )
ENDPROC(__irq_usr)
可以看到在中断处理完以后会走到ret_to_user_from_irq在该函数里面也是调用的slow_work_pending。所以用户态无论是通过系统调用还是中断陷入内核抢占都是在这里发生的。主要的一个中断就是时钟中断
ENTRY(ret_to_user_from_irq)ldr r2, [tsk, #TI_ADDR_LIMIT]cmp r2, #TASK_SIZEblne addr_limit_check_failedldr r1, [tsk, #TI_FLAGS]tst r1, #_TIF_WORK_MASKbne slow_work_pending
no_work_pending:asm_trace_hardirqs_on save 0/* perform architecture specific actions before user return */arch_ret_to_user r1, lrct_user_enter save 0restore_user_regs fast 0, offset 0
ENDPROC(ret_to_user_from_irq)
内核态抢占时机
内核为了支持抢占为每个进程的thread info引入了preempt_count计数器。该计数初始为0每当加锁还得看代码具体代码实现或者是显示禁止抢占preempt_disable等操作会加1反之释放锁或者是开启抢占则减1。当计数器为0的时候表示内核允许抢占
可以通过CONFIG_PREEMPT_COUNTy开启抢占计数器。这样内核就能在切换时检查preempt_count计数是否为0是否运行进行抢占切换 1、中断处理程序返回内核空间
中断处理程序返回内核空间之前会检查TIF_NEED_RESCHED标志如果置位则调用preempt_schedule_irq()执行抢占。preempt_schedule_irq()是对schedule()的包装 中断发生在内核__irq_svcCONFIG_PREEMPT开启了表示内核运行抢占。中断返回时会去检查TIF_NEED_RESCHED如果设置表示可以抢占
__irq_svc:将中断现场保存到内核栈中svc_entry中断处理过程irq_handler如果开启了抢占功能,则中断返回时会检查是否可以抢占发生中断时的进程
检查thread_info-preempt_count是否为0
#ifdef CONFIG_PREEMPTget_thread_info tskldr r8, [tsk, #TI_PREEMPT] get preempt countldr r0, [tsk, #TI_FLAGS] get flagsteq r8, #0 if preempt count ! 0movne r0, #0 force flags to 0tst r0, #_TIF_NEED_RESCHEDblne svc_preempt
#endifsvc_exit r5, irq 1 return from exceptionUNWIND(.fnend )
ENDPROC(__irq_svc)
#ifdef CONFIG_PREEMPT
svc_preempt:mov r8, lr
1: bl preempt_schedule_irq irq en/disable is done insideldr r0, [tsk, #TI_FLAGS] get new tasks TI_FLAGStst r0, #_TIF_NEED_RESCHEDreteq r8 go againb 1b
#endif
可以看到最终是到了 preempt_schedule_irq
schedule前调用preempt_disable禁止抢占原因因为调度前开启了中断如果不禁止抢占那么可能被中断打断这样在中断退出时preemp_cout又是0并且TIF_NEED_RESCHED未清除又能够走到这里 来回套娃
asmlinkage __visible void __sched preempt_schedule_irq(void)
{enum ctx_state prev_state;/* Catch callers which need to be fixed */BUG_ON(preempt_count() || !irqs_disabled());prev_state exception_enter();do {/*不明白在切换之前为什么还需要将抢占计数加1,这样不是不能抢占了吗?看了网上说调用__schedule都会显示禁用抢占然后schedule_debug就判断是preempt_count是不是1,不是1就打印原子上下文调度告警*/preempt_disable();local_irq_enable();__schedule(true);local_irq_disable();sched_preempt_enable_no_resched();} while (need_resched());exception_exit(prev_state);
}
2、当内核从non-preemptible禁止抢占状态变成preemptible允许抢占的时候
在preempt_enable()中会最终调用 preempt_schedule 来执行抢占。preempt_schedule()是对schedule()的包装。 asmlinkage __visible void __sched notrace preempt_schedule(void)
{if (likely(!preemptible()))return;preempt_schedule_common();
}
static void __sched notrace preempt_schedule_common(void)
{do {preempt_disable_notrace();preempt_latency_start(1);__schedule(true);preempt_latency_stop(1);preempt_enable_no_resched_notrace();/** Check again in case we missed a preemption opportunity* between schedule and now.*/} while (need_resched());
}
3、内核主动进行任务切换
其实这个感觉不算抢占了
备注
1、开启了CONFIG_PREEMPT_COUNT抢占计数器才会生效即preempt_disable/preempt_enablec才会修改preempt_count否则这些操作只是等价于barrier()
2、CONFIG_PREEMPT配置了内核才开启抢占否则就算是计数器生效了内核也无法进行抢占只是会任务切换的时候打告警告诉切换时preempt_count不为1可能有风险