linux 进程调度切换过程分析

本文主要探讨了在Linux内核4.10版本中,当系统调用或异常中断返回用户空间时,如何触发进程调度的过程。涉及到的关键代码位于entry.S和signal.c文件中,以及sched核心函数的实现。在切换完成后,通过finish_task_switch()函数进行后续清理工作。
摘要由CSDN通过智能技术生成

从系统调用或者异常中断返回用户空间时,thread_flags 被设置成TIF_NEED_RESCHED 会发生调度,当然还有其他几个时机也会发生调度,这里主要介绍中断返回用户空间时的情况。

linux-4.10/arch/arm64/kernel/entry.S

744  ret_fast_syscall:
745  	disable_irq				// disable interrupts
746  	str	x0, [sp, #S_X0]			// returned x0
747  	ldr	x1, [tsk, #TSK_TI_FLAGS]	// re-check for syscall tracing
748  	and	x2, x1, #_TIF_SYSCALL_WORK
749  	cbnz	x2, ret_fast_syscall_trace
750  	and	x2, x1, #_TIF_WORK_MASK
751  	cbnz	x2, work_pending   //跳到work_pending
752  	enable_step_tsk x1, x2
753  	kernel_exit 0

761  work_pending:
762  	mov	x0, sp				// 'regs'
763  	bl	do_notify_resume     //跳到do_notify_resume
764  #ifdef CONFIG_TRACE_IRQFLAGS
765  	bl	trace_hardirqs_on		// enabled while in userspace
766  #endif
767  	ldr	x1, [tsk, #TSK_TI_FLAGS]	// re-check for single-step
768  	b	finish_ret_to_user

这个流程在前面的博客中有贴出来过,在应用发生crash 异常的时候,会走到这里。

linux-4.10/arch/arm64/kernel/signal.c

402  asmlinkage void do_notify_resume(struct pt_regs *regs,
403  				 unsigned int thread_flags)
404  {
405  	/*
406  	 * The assembly code enters us with IRQs off, but it hasn't
407  	 * informed the tracing code of that for efficiency reasons.
408  	 * Update the trace code with the current status.
409  	 */
410  	trace_hardirqs_off();
411  	do {
412  		if (thread_flags & _TIF_NEED_RESCHED) {
413  			schedule();  //如果调度的标识位被设置,则进行调度
414  		} else {
...
430  		}
431  
432  		local_irq_disable();
433  		thread_flags = READ_ONCE(current_thread_info()->flags);
434  	} while (thread_flags & _TIF_WORK_MASK);
435  }
thread_flags 被设置成(或者添加)_TIF_NEED_RESCHED是,这时候会调用schedule()进行调度

linux-4.10/kernel/sched/core.c

3451  asmlinkage __visible void __sched schedule(void)
3452  {
3453  	struct task_struct *tsk = current;
3454  
3455  	sched_submit_work(tsk);
3456  	do {
3457  		preempt_disable();  //禁止抢占
3458  		__schedule(false);  
3459  		sched_preempt_enable_no_resched(); //开启抢占
3460  	} while (need_resched());
3461  }
3462  EXPORT_SYMBOL(schedule);
接着跑到__schedule() 参数preempt 表示是否运行抢占,这里参数的参数是false,也就是不允许抢占。

3334  static void __sched notrace __schedule(bool preempt)
3335  {
3336  	struct task_struct *prev, *next;
3337  	unsigned long *switch_count;
3338  	struct pin_cookie cookie;
3339  	struct rq *rq;
3340  	int cpu;
3341  
/*
  * linux-4.10/include/linux/smp.h
  *  # define smp_processor_id() raw_smp_processor_id()
  *   
  *   linux-4.10/arch/arm64/include/asm/smp.h
  *   #define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))  //虽然写法比较奇怪,认为就是当前运行的cpu id就可以了,如果是下面的写就很直观
  *   linux-4.10/arch/arm/include/asm/smp.h
  *   #define raw_smp_processor_id() (current_thread_info()->cpu)
*/
3342  	cpu = smp_processor_id();
3343  	rq = cpu_rq(cpu);  //获取运行队列
3344  	prev = rq->curr;   //当前运行的task_struct
3345  
3346  	schedule_debug(prev);
3347  
3348  	if (sched_feat(HRTICK))  //是否开启了HRTICK
3349  		hrtick_clear(rq); //
3350  
3351  	local_irq_disable();  //关闭中断
3352  	rcu_note_context_switch(); //RCU(Read-Copy Update),对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它
3353  
3354  	/*
3355  	 * Make sure that si
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值