进程调度API之set_cpus_allowed_ptr

int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
此函数的作用是改变进程struct task_struct *p 执行时所占的cpu资源
其使用的例程如下:
在kernel中的main函数中
	/*
	 * init can run on any cpu.
	 */
	set_cpus_allowed_ptr(current, cpu_all_mask);
通过此函数可以染init 运行在所有cpu上
其源码分析如下:
int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
{
	return __set_cpus_allowed_ptr(p, new_mask, false);
}
这里的第三个形参check为false
static int __set_cpus_allowed_ptr(struct task_struct *p,
				  const struct cpumask *new_mask, bool check)
{
	const struct cpumask *cpu_valid_mask = cpu_active_mask;
	unsigned int dest_cpu;
	struct rq_flags rf;
	struct rq *rq;
	int ret = 0;
#得到task 运行的队列rq,running queue
	rq = task_rq_lock(p, &rf);
	update_rq_clock(rq);
#根据flag PF_KTHREAD 可以判断当前task是在kernel space 创建的还是在user space创建的
#kernel thread 默认是可以运行在所有online cpu上的
	if (p->flags & PF_KTHREAD) {
		/*
		 * Kernel threads are allowed on online && !active CPUs
		 */
		cpu_valid_mask = cpu_online_mask;
	}

	/*
	 * Must re-check here, to close a race against __kthread_bind(),
	 * sched_setaffinity() is not guaranteed to observe the flag.
	 */
#如果thread不允许改变所占的cpu资源,则直接退出
	if (check && (p->flags & PF_NO_SETAFFINITY)) {
		ret = -EINVAL;
		goto out;
	}
#如果当前thread 可以运行的cpu已经和要设置运行的cpu相等,则就没有必要再次设置了,直接退出.
	if (cpumask_equal(&p->cpus_allowed, new_mask))
		goto out;

	if (!cpumask_intersects(new_mask, cpu_valid_mask)) {
		ret = -EINVAL;
		goto out;
	}
#将new_mask 设置到task cpus_allowed 中
	do_set_cpus_allowed(p, new_mask);

	if (p->flags & PF_KTHREAD) {
		/*
		 * For kernel threads that do indeed end up on online &&
		 * !active we want to ensure they are strict per-CPU threads.
		 */
		WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) &&
			!cpumask_intersects(new_mask, cpu_active_mask) &&
			p->nr_cpus_allowed != 1);
	}

	/* Can the task run on the task's current CPU? If so, we're done */
#如果task 能运行在task 本来运行的cpu上,则直接就退出了
	if (cpumask_test_cpu(task_cpu(p), new_mask))
		goto out;
#否则,task 不能运行在task 本来运行的cpu上,也就是new_mask 中不包含task 本来可以运行的cpu
#则根据task是wakeup还是sleep 两种情况,将task 迁移到new_mask 中规定的可以运行cpu上
	dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask);
	if (task_running(rq, p) || p->state == TASK_WAKING) {
		struct migration_arg arg = { p, dest_cpu };
		/* Need help from migration thread: drop lock and wait. */
#否则的case中,如果当前cpu 正在运行,则通过stop_one_cpu 停止并迁移到允许运行的cpu上
		task_rq_unlock(rq, p, &rf);
		stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
		tlb_migrate_finish(p->mm);
		return 0;
	} else if (task_on_rq_queued(p)) {
		/*
		 * OK, since we're going to drop the lock immediately
		 * afterwards anyway.
		 */
#否则的case中,如果task 处于sleep状态吗,则直接迁移,和前一种case相比少了停止task 运行这一步.
		rq = move_queued_task(rq, &rf, p, dest_cpu);
	}
out:
	task_rq_unlock(rq, p, &rf);

	return ret;
}

你可能感兴趣的:(Linux,源码分析,kernel常用API源码分析)