为了弄清楚在多cpu系统中是如何实现实时调度的,先引入以下几个概念:

cpu的状态:

    我们知道,在linux系统中,任务的优先级为0~140。

INVALID:(-1)该cpu不可用

IDLE(0):140

NORMAL(1):100~139对应于普通任务的优先级

RT0~RT99(2~102):对应于实时任务的优先级

进程优先级:

    在linux内核中,每个进程都有一个task_struct,其中与优先级相关的属性包括

     1、prio:对于非实时进程而言prio==normal_prio=99-rt_priority(prio的值越大,则进程的优先级越小)

     2、normal_prio:99-rt_priority

     3、static_prio:=100+nice

     4、rt_priority:0:非实时任务;[1,99]实时任务,值越大,优先级越高。

        在调度时使用了prio,其数值0对应最高优先级,99为最低实时优先级。Prionormal_prio 数值越大优先级越小,而rt_priority的数值越大优先级越大。

task balance:

    在多cpu系统中,为了保证各个cpu上实时任务的负载均衡,引入了push和pull操作:

1、push操作:

    当当前cpu上有多于一个的实时任务,那么需要使用pull操作看看是否可以将还未运行的实时任务移动到其他的cpu上,主要操作由push_rt_task函数完成。

static int push_rt_task(struct rq *rq)
{
	struct task_struct *next_task;
	struct rq *lowest_rq;
	int ret = 0;
///如果当前队列不是超载状态,则直接返回
	if (!rq->rt.overloaded)
		return 0;
///选择rq中下一个进程
	next_task = pick_next_pushable_task(rq);
	if (!next_task)
		return 0;
retry:
        ......
	 ///如果下一个进程的优先级比当前进程的优先级高,那么需要执行的不是push操作而是重新调度
	if (unlikely(next_task->prio < rq->curr->prio)) {
		resched_task(rq->curr);
		return 0;
	}
 ......
	 ///寻找那个cpu的rq符合条件,将其rq上锁
	lowest_rq = find_lock_lowest_rq(next_task, rq);
	///如果没有找到合适的rq,我们则需要判断:到底还要不要再找,因为在find_lock_lowest_rq函数中释放了当前rq上的锁,因此可能会导致当前rq上没有需要push的任务,在这种情况下我们就不用再试,如果需要push的任务还在,那么则进入retry继续尝试。
	if (!lowest_rq) {
		struct task_struct *task;
		task = pick_next_pushable_task(rq);
		if (task_cpu(next_task) == rq->cpu && task == next_task) {	 
			goto out;
		}
		if (!task)			 
			goto out;
		put_task_struct(next_task);
		next_task = task;
		goto retry;
	}
	///执行任务迁移相关的工作。
	deactivate_task(rq, next_task, 0);
	set_task_cpu(next_task, lowest_rq->cpu);
	activate_task(lowest_rq, next_task, 0);
	ret = 1;

	resched_task(lowest_rq->curr);

	double_unlock_balance(rq, lowest_rq);

out:
	put_task_struct(next_task);

	return ret;
}

2、pull操作

    与push操作相反,pull操作用于当前cpu的rq比较空闲,想要主动调入实时任务,该操作主要由

pull_rt_task完成。

static int pull_rt_task(struct rq *this_rq)
{
	int this_cpu = this_rq->cpu, ret = 0, cpu;
	struct task_struct *p;
	struct rq *src_rq;

	if (likely(!rt_overloaded(this_rq)))
		return 0;
///查找每一个超载的cpu
	for_each_cpu(cpu, this_rq->rd->rto_mask) {
		 ......
///src_rq:需要pull的cpu。
		src_rq = cpu_rq(cpu);
///如果src_rq的下一个任务的优先级高于当前cpu的优先级,则什么都不用做,因为src_cpu会主动执行pull操作。		 
		if (src_rq->rt.highest_prio.next >=
		    this_rq->rt.highest_prio.curr)
			continue;	 
		double_lock_balance(this_rq, src_rq);
 ///判断是否有需要被pull的任务,没有则退出
		if (src_rq->rt.rt_nr_running <= 1)
			goto skip;
///找到src_rq上最高优先级的任务
		p = pick_next_highest_task_rt(src_rq, this_cpu);
		 
		if (p && (p->prio < this_rq->rt.highest_prio.curr)) {
			WARN_ON(p == src_rq->curr);
			WARN_ON(!p->on_rq);
			 
			if (p->prio < src_rq->curr->prio)
				goto skip;
			ret = 1;

			deactivate_task(src_rq, p, 0);
			set_task_cpu(p, this_cpu);
			activate_task(this_rq, p, 0);
			 
		}
skip:
		double_unlock_balance(this_rq, src_rq);
	}

	return ret;
}