マルチCPU
ちゃんと理解しきれておらず、推測を交えての記載です。
マルチCPUはメモリを共有するCPU毎をバーチャルなコンピュータとし、ただしCPU単位で管理するrunキュー等は、CPU IDをインデックスとしてCPU毎に設定されます。forkで新しくタスクを作成し、それを条件に応じた該当CPUのrunキューに登録する事で実装されているようです。
カーネル起動時、CPU毎にCPU IDのidleタスクが起動され、このタスクによりかかるrunキューのタスクを起床させるようです。CPU IDはprocess->cpuに設定されます。
カレントプロセスのCPUIDを/proc/cpu-idで表示するサンプルです。私の環境は2CPUです。catコマンドでのforkによるプロセスが、CPU0/1下て起動されるのが確認できます。
runキューにプロセスを登録する時、プロセスのはenqueue_taskコールバックはp->sched_class下のコールバック関数がコールされ、リアルタイムタスク/フェアープロセスによる実装が行われます。
マルチCPUはメモリを共有するCPU毎をバーチャルなコンピュータとし、ただしCPU単位で管理するrunキュー等は、CPU IDをインデックスとしてCPU毎に設定されます。forkで新しくタスクを作成し、それを条件に応じた該当CPUのrunキューに登録する事で実装されているようです。
カーネル起動時、CPU毎にCPU IDのidleタスクが起動され、このタスクによりかかるrunキューのタスクを起床させるようです。CPU IDはprocess->cpuに設定されます。
カレントプロセスのCPUIDを/proc/cpu-idで表示するサンプルです。私の環境は2CPUです。catコマンドでのforkによるプロセスが、CPU0/1下て起動されるのが確認できます。
[root@localhost lkm]# cat proc_cpuid.c
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
static int cpuid_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%s cpuid:%d \n", rt_task(current)? "rt": "fair", get_cpu());
return 0;
}
static int cpuid_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, cpuid_proc_show, NULL);
}
static const struct file_operations cpuid_proc_fops = {
.open = cpuid_proc_open,
.read = seq_read,
};
static int __init cpuid_init(void)
{
proc_create("cpu-id", 0, NULL, &cpuid_proc_fops);
return 0;
}
static void __exit cpuid_exit( void )
{
remove_proc_entry("cpu-id", NULL);
}
module_init(cpuid_init);
module_exit(cpuid_exit);
検証[root@localhost lkm]# cat /sys/devices/system/cpu/online 0-1
[root@localhost lkm]# insmod proc_cpuid.ko [root@localhost lkm]# cat /proc/cpu-id fair cpuid:0 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:1 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:0 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:0 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:0 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:1 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:0 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:1 [root@localhost lkm]# cat /proc/cpu-id fair cpuid:1forkからp = copy_processで子プロセスを作成し、wake_up_new_task()で子プロセスを起床させます。set_task_cpu()でselect_task_rq()で条件に応じたCPU IDを取得し、子プロセスp->cpuに設定します。そして、__task_rq_lock()で子プロセスp->cpuのCPUのrunキューを取得し、activate_task()でそのrunキューにプロセスをリストします。
runキューにプロセスを登録する時、プロセスのはenqueue_taskコールバックはp->sched_class下のコールバック関数がコールされ、リアルタイムタスク/フェアープロセスによる実装が行われます。
void wake_up_new_task(struct task_struct *p)
{
unsigned long flags;
struct rq *rq;
raw_spin_lock_irqsave(&p->pi_lock, flags);
#ifdef CONFIG_SMP
set_task_cpu(p, select_task_rq(p, SD_BALANCE_FORK, 0));
#endif
rq = __task_rq_lock(p);
activate_task(rq, p, 0);
p->on_rq = 1;
trace_sched_wakeup_new(p, true);
check_preempt_curr(rq, p, WF_FORK);
#ifdef CONFIG_SMP
if (p->sched_class->task_woken)
p->sched_class->task_woken(rq, p);
#endif
task_rq_unlock(rq, p, &flags);
}
void activate_task(struct rq *rq, struct task_struct *p, int flags)
{
if (task_contributes_to_load(p))
rq->nr_uninterruptible--;
enqueue_task(rq, p, flags);
}
static void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
{
update_rq_clock(rq);
sched_info_queued(p);
p->sched_class->enqueue_task(rq, p, flags);
}






