無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

マルチ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下て起動されるのが確認できます。
[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:1
forkから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);
}


最終更新 2016/08/23 18:08:49 - north
(2016/08/23 15:38:01 作成)