进程管理基础学习笔记 - 3. schedule

本文详细介绍了Linux内核中的进程调度器__schedule函数,包括抢占时机、调度流程、上下文切换等关键步骤。重点讨论了__schedule函数内部如何选择下一个进程、上下文切换的实现以及deactivate_task的处理。通过对源码的分析,揭示了内核抢占和进程切换的机制。

1. 前言

本专题我们开始学习进程管理部分。本文主要参考了《奔跑吧, Linux内核》、ULA、ULK的相关内容。本文只是作为学习笔记以用于构建知识框架,可能存在一些理解不恰当或不到位的地方,后续会随着学习的深入,逐步进行迭代。
进程管理概述部分介绍过,进程的抢占分为触发抢占(设置TIF_NEED_RESCHED标记)和执行抢占,执行抢占的过程就是调用了schedule,其核心函数为__schedule。

kernel版本:5.10
平台:arm64

2. __schedule

在这里插入图片描述
这段注释翻译成中文如下:

__schedule()是调度器的主函数
让调度器执行调度,并进入到__schedule()函数的方法主要有:
1.调用block的函数,如: mutex, semaphore, waitqueue等等。
2.在中断时返回用户空间时会检查TIF_NEED_RESCHED标志。例如:可以参考arch/x86/entry_64.S:
为了触发抢占,在定时器中断处理函数scheduler_tick()中,调度器会设置TIF_NEED_RESCHED 抢占标志;
3.唤醒一个进程并不真正会引发执行schedule()。唤醒只是添加一个进程到run-queue,仅此而已;
假设,如果一个新的进程被添加到run-queue, 如果抢占当前运行的进程,唤醒操作会设置当前进程的TIF_NEED_RESCHED 标志,
在第一次发生如下情形时,schedule()会被调用:
(1)如果kernel允许抢占(CONFIG_PREEMPT=y)
- 在系统调用或异常上下文,preempt_enable()中会执行schedule()抢占调度(这种情形一般是在wake_up()后执行spin_unlock()时);
- 在中断上下文,从中断处理函数返回到被中断的上下文
(2)如果kernel抢占被禁用 (CONFIG_PREEMPT is not set),那么在下一次遇到如下情形时会执行schedule()抢占调度
- cond_resched()调用
- schedule()调用
- 从系统调用或异常返回到用户空间时
- 从中断处理函数返回到用户空间时

对如上注释进行简单总结为:

  1. 如果内核允许抢占,如下时机可以执行抢占:
    (1)preempt_enable
    (2)异常上下文返回到用户空间
    (3)异常上下文返回到内核空间
  2. 如果内核禁用抢占,如下时机可以执行抢占:
    (1)显式调用schedule()函数(mutex也属于此情况)
    (2)异常返回用户空间
asmlinkage __visible void __sched schedule(void)
    |--struct task_struct *tsk = current;
    |--sched_submit_work(tsk);//进程的plug队列泄洪操作
    |--do {
   
   
    |          preempt_disable();//关闭内核抢占
    |          __schedule(false); //调度核心实现
    |          sched_preempt_enable_no_resched();//打开内核抢占
    |  } while (need_resched());//判断当前进程的TIF_NEED_RESCHED是否置位
    \--sched_update_worker(tsk);
static void __sched notrace __schedule(bool preempt)
    |--cpu = smp_processor_id();
    |  rq = cpu_rq(cpu);
    |  prev = rq->curr;//prev指向当前进程
    |--schedule_debug(prev, preempt)//判断当前进程是否处于原子上下文
    |--if (!preempt && prev->state)//发生了非抢占调度,如主动调用schedule
    |      deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);//当前进程移出就绪队列
    |--next = pick_next_task(rq, prev, &rf);//选择下个合适的进程开始运行
    |--clear_tsk_need_resched(prev);//清除进程的TIF_NEED_RESCHED
    |  clear_preempt_need
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值