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;
}
进程调度API之set_cpus_allowed_ptr
最新推荐文章于 2022-03-29 13:58:17 发布