Linux进程调度——schedule()函数分析

刘森林 原创作品转载请注明出处 《Linux内核分析》MOOC课程
打开终端中输入qemu –kernel linux-3.18.6/arch/x86/boot/bzImage –initrd rootfs.img –S –s
然后打开另一个终端输入

gdb
(gdb)file linux-3.18.6/vmlinux
(gdb)target remote:1234
(gdb)b schedule
(gdb)c

进行调试跟踪schedule的执行过程。

这里写图片描述
进程调度时,首先进入schedule()函数,将一个task_struct结构体的指针tsk赋值为当前进程。
然后调用sched_submit_work(tsk)
我们进入这个函数,查看一下做了什么工作
我们在执行到sched_submit_work时,输入si进入函数。
这里写图片描述
可以看到这个函数时检测tsk->state是否为0 (runnable)若为运行态时则返回,
tsk_is_pi_blocked(tsk),检测tsk的死锁检测器是否为空,若非空的话就return。
这里写图片描述
然后检测是否需要刷新plug队列,用来避免死锁。
sched_submit_work主要是来避免死锁。
然后我们进入__schedule()函数。
这里写图片描述
__schedule()是切换进程的真正代码,我们来分析一下具体的关键代码

  • 1.创建一些局部变量
struct task_struct *prev, *next;//当前进程和一下个进程的进程结构体
unsigned long *switch_count;//进程切换次数
struct rq *rq;//就绪队列
int cpu;
  • 2.关闭内核抢占,初始化一部分变量
need_resched:
preempt_disable();//关闭内核抢占
cpu = smp_processor_id();
rq = cpu_rq(cpu);//与CPU相关的runqueue保存在rq中
rcu_note_context_switch(cpu);
prev = rq->curr;//将runqueue当前的值赋给prev
  • 3.选择next进程

                
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux进程调度有关的函数主要包括以下几个: 1. schedule():这个函数Linux内核中最重要的进程调度函数之一,它会根据进程的优先级和调度策略来选择下一个要执行的进程,并将当前进程切换出去。 ``` void __sched schedule(void) { struct task_struct *prev, *next; struct rq *rq; int cpu; cpu = smp_processor_id(); rq = cpu_rq(cpu); prev = rq->curr; schedule_debug(prev); if (unlikely(prev->state == TASK_RUNNING)) { /* * The previous task running on this CPU was not * properly scheduled-away. Set the timestamp for * its delay accounting here so that it is charged * for its full timeslice. */ rq->clock_task = prev; update_rq_clock(rq); } next = pick_next_task(rq); clear_tsk_need_resched(prev); rq->skip_clock_update = 0; if (likely(prev != next)) { rq->nr_switches++; rq->curr = next; ++*switch_count; /* * If switching to a new process, reset the * time slice counter */ if (unlikely(prev->policy != SCHED_BATCH)) { if (unlikely(!prev->array)) { prev->array = rq->active; prev->array->nr_active++; } if (prev->se.exec_start == 0) prev->se.exec_start = rq_clock_task(rq); else if (task_cpu(prev) != cpu) prev->se.exec_start = rq_clock_task(rq); if (unlikely(++prev->se.nr_cpus_pin > 1)) prev->se.nr_cpus_pin = 1; /* * The running process is the last * to have run on this cpu */ prev->cpu_timers.cpu = cpu; prev->cpu_timers.prev_count = 0; prev->cpu_timers.cur_clock = 0; prev->cpu_timers.start_time = rq_clock_task(rq); prev->state = TASK_RUNNING; /* * Use a barrier to ensure that the above * stores complete before the stores to * prev->on_cpu and rq->curr. */ smp_mb(); prev->on_cpu = cpu; context_switch(rq, prev, next); /* * If the task got requeued meanwhile (e.g. signals), * we don't want to lose track of it. */ if (prev->state == TASK_RUNNING) resched_curr(rq); } } task_rq_unlock(rq, &flags); } ``` 2. pick_next_task():这个函数会在可运行队列中选择下一个要执行的进程,并返回其指针。 ``` static inline struct task_struct * pick_next_task(struct rq *rq) { const struct sched_class *class; struct task_struct *p; class = rq->curr->sched_class; p = class->pick_next_task(rq, rq->curr, rq->nr_running); if (!p) p = idle_task(rq); return p; } ``` 3. enqueue_task():这个函数会将一个进程添加到可运行队列中。 ``` static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) { const struct sched_class *class; class = p->sched_class; class->enqueue_task(rq, p, flags); } ``` 4. dequeue_task():这个函数会将一个进程从可运行队列中移除。 ``` static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) { const struct sched_class *class; class = p->sched_class; class->dequeue_task(rq, p, flags); } ``` 5. yield():这个函数会让当前进程主动放弃CPU,让其他进程有机会执行。 ``` void __sched yield(void) { struct task_struct *p = current; struct rq *rq = task_rq_lock(p, NULL); /* * If we are the only task in the runqueue, we do not want * to yield the CPU, but instead want to continue executing. */ if (unlikely(rq->nr_running == 1)) goto out_unlock; p->state = TASK_RUNNING; resched_curr(rq); out_unlock: task_rq_unlock(rq, NULL); } ``` 以上是Linux进程调度相关函数的部分源代码,它们的具体实现可能因不同的版本和架构而有所差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值