2014년 9월 27일 토요일

[Linux Kernel] 71주차(2014.09.27)

ARM10C 71주차 후기

일시 : 2014.09.27 (71주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

스터디 진도 :

  • rcu_init()

main.c::start_kernel()

  • rcu_init()을 분석합니다.
  • start_kernel()부터 rcu_init() 전에 어떤 일을 했는지 간추려서 보겠습니다.
asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];

...

    local_irq_disable();
    // IRQ를 disable한다.
    early_boot_irqs_disabled = true;

    boot_cpu_init()
    // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.

    page_address_init();
    // 128개의 page_address_htable 배열을 초기화

    pr_notice("%s", linux_banner);
    // 배너:
    //  Linux version 2.6.37_DM385_IPNC_3.50.00
    //  (a0875405@bangvideoapps01) (gcc version 4.5.3 20110311 
    //  (prerelease) (GCC) ) #1 Fri Dec 21 17:27:08 IST 2012

    setup_arch(&command_line);
    // ARM 아키텍쳐에 맞게 초기화한다.

    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    // pcpu 구조체를 만들어 줌 (mm/percpu.c)

    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
    // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌

...
    pidhash_init();
    // pidhash의 크기를 16kB만큼 할당 받고 4096개의 hash list를 만듬

    vfs_caches_init_early();
    // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
    // 131072, 65536개 만큼 hash table을 각각 만듬

...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관

    sched_init();
    // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅

    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable();
    // preempt count를 증가시켜 preemption 못하도록 막음

    // irqs_disabled(): 1
    if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
        local_irq_disable();

    idr_init_cache();
    // integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당

    rcu_init(); 
  • mm_init()에서 buddy와 slab을 활성화하고 sched_init()을 실행한다.
  • sched_init()에서 rq를 초기화하고 // scheduler_running: 1
  • integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당 *

tree.c::rcu_init()

  • rcu_bootup_announce();
    • "Preemptible hierarchical RCU implementation." 출력
  • rcu_init_geometry();
    • // jiffies_till_first_fqs: 1
    • // jiffies_till_next_fqs: 1
  • rcu_init_one(&rcu_bh_state, &rcu_bh_data);
    • // (&rcu_bh_state)->levelcnt[0]: 1
    • // (&rcu_bh_state)->levelspread[0]: 4
    • // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_bh_state)->level[0])->qsmask: 0
    • // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_bh_state)->level[0])->grplo: 0
    • // ((&rcu_bh_state)->level[0])->grphi: 3
    • // ((&rcu_bh_state)->level[0])->gpnum: 0
    • // ((&rcu_bh_state)->level[0])->grpmask: 0
    • // ((&rcu_bh_state)->level[0])->parent: NULL
    • // ((&rcu_bh_state)->level[0])->level: 0
    • // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • // (&rcu_bh_state)->rda: &rcu_bh_data
    • // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    • // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_bh_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_bh_state)->level[0]
    • // pcp1->mynode: (&rcu_bh_state)->level[0]
    • // pcp2->mynode: (&rcu_bh_state)->level[0]
    • // pcp3->mynode: (&rcu_bh_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_bh_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_bh_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_bh_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_bh_state
    • //
    • // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
  • rcu_init_one(&rcu_sched_state, &rcu_sched_data);
    • // (&rcu_sched_state)->levelcnt[0]: 1
    • // (&rcu_sched_state)->levelspread[0]: 4
    • // &((&rcu_sched_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_sched_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_sched_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_sched_state)->level[0])->qsmask: 0
    • // ((&rcu_sched_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_sched_state)->level[0])->grplo: 0
    • // ((&rcu_sched_state)->level[0])->grphi: 3
    • // ((&rcu_sched_state)->level[0])->gpnum: 0
    • // ((&rcu_sched_state)->level[0])->grpmask: 0
    • // ((&rcu_sched_state)->level[0])->parent: NULL
    • // ((&rcu_sched_state)->level[0])->level: 0
    • // &((&rcu_sched_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • //
    • // (&rcu_sched_state)->rda: &rcu_sched_data
    • // &(&(&rcu_sched_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_sched_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_sched_state)->wakeup_work)->flags: 0
    • // (&(&rcu_sched_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_sched_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_sched_state)->level[0]
    • // pcp1->mynode: (&rcu_sched_state)->level[0]
    • // pcp2->mynode: (&rcu_sched_state)->level[0]
    • // pcp3->mynode: (&rcu_sched_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_sched_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_sched_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_sched_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_sched_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_sched_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_sched_state
    • //
    • // rcu_struct_flavors에 (&rcu_sched_state)->flavors를 list 추가
  • open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
    • // softirq_vec[9].action: rcu_process_callbacks
  • cpu_notifier(rcu_cpu_notify, 0);
    • // (&cpu_chain)->head: rcu_cpu_notify_nb 포인터 대입
    • // (&rcu_cpu_notify_nb)->next은 (&sched_ilb_notifier_nb)->next로 대입
  • pm_notifier(rcu_pm_notify, 0);
    • // (&pm_chain_head)->head: rcu_pm_notify_nb 포인터 대입
    • // n->next: (&rcu_pm_notify_nb)->next: NULL
  • for_each_online_cpu(cpu)
// ARM10C 20140920
void __init rcu_init(void)
{
    int cpu;

    rcu_bootup_announce();
    rcu_init_geometry();
    // jiffies_till_first_fqs: 1
    // jiffies_till_next_fqs: 1

// 2014/09/20 종료
// 2014/09/27 시작

    rcu_init_one(&rcu_bh_state, &rcu_bh_data);
    // (&rcu_bh_state)->levelcnt[0]: 1
    // (&rcu_bh_state)->levelspread[0]: 4
    // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_bh_state)->level[0])->qsmask: 0
    // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    // ((&rcu_bh_state)->level[0])->grplo: 0
    // ((&rcu_bh_state)->level[0])->grphi: 3
    // ((&rcu_bh_state)->level[0])->gpnum: 0
    // ((&rcu_bh_state)->level[0])->grpmask: 0
    // ((&rcu_bh_state)->level[0])->parent: NULL
    // ((&rcu_bh_state)->level[0])->level: 0
    // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_bh_state)->rda: &rcu_bh_data
    // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_bh_state)->level[0]
    //
    // [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp1] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp2] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    // [pcp3] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    //
    // [pcp0] (&rcu_bh_data)->grpmask: 1
    // [pcp0] (&rcu_bh_data)->nxtlist: NULL
    // [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    // [pcp0] (&rcu_bh_data)->qlen_lazy: 0
    // [pcp0] (&rcu_bh_data)->qlen: 0
    // [pcp0] (&rcu_bh_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_bh_data)->cpu: 0
    // [pcp0] (&rcu_bh_data)->rsp: &rcu_bh_state
    //
    // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가

    rcu_init_one(&rcu_sched_state, &rcu_sched_data);
    // (&rcu_sched_state)->levelcnt[0]: 1
    // (&rcu_sched_state)->levelspread[0]: 4
    // &((&rcu_sched_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_sched_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_sched_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_sched_state)->level[0])->qsmask: 0
    // ((&rcu_sched_state)->level[0])->qsmaskinit: 0
    // ((&rcu_sched_state)->level[0])->grplo: 0
    // ((&rcu_sched_state)->level[0])->grphi: 3
    // ((&rcu_sched_state)->level[0])->gpnum: 0
    // ((&rcu_sched_state)->level[0])->grpmask: 0
    // ((&rcu_sched_state)->level[0])->parent: NULL
    // ((&rcu_sched_state)->level[0])->level: 0
    // &((&rcu_sched_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_sched_state)->rda: &rcu_sched_data
    // &(&(&rcu_sched_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_sched_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_sched_state)->wakeup_work)->flags: 0
    // (&(&rcu_sched_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_sched_state)->level[0]
    //
    // [pcp0] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp1] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp2] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    // [pcp3] (&rcu_sched_data)->mynode: (&rcu_sched_state)->level[0]
    //
    // [pcp0] (&rcu_sched_data)->grpmask: 1
    // [pcp0] (&rcu_sched_data)->nxtlist: NULL
    // [pcp0] (&rcu_sched_data)->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    // [pcp0] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp0] (&rcu_sched_data)->qlen: 0
    // [pcp0] (&rcu_sched_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_sched_data)->cpu: 0
    // [pcp0] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp1] (&rcu_sched_data)->grpmask: 2
    // [pcp1] (&rcu_sched_data)->nxtlist: NULL
    // [pcp1] (&rcu_sched_data)->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist
    // [pcp1] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp1] (&rcu_sched_data)->qlen: 0
    // [pcp1] (&rcu_sched_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_sched_data)->cpu: 1
    // [pcp1] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp2] (&rcu_sched_data)->grpmask: 4
    // [pcp2] (&rcu_sched_data)->nxtlist: NULL
    // [pcp2] (&rcu_sched_data)->nxttail[0...3]: [pcp2] &(&rcu_sched_data)->nxtlist
    // [pcp2] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp2] (&rcu_sched_data)->qlen: 0
    // [pcp2] (&rcu_sched_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_sched_data)->cpu: 2
    // [pcp2] (&rcu_sched_data)->rsp: &rcu_sched_state
    // [pcp3] (&rcu_sched_data)->grpmask: 8
    // [pcp3] (&rcu_sched_data)->nxtlist: NULL
    // [pcp3] (&rcu_sched_data)->nxttail[0...3]: [pcp3] &(&rcu_sched_data)->nxtlist
    // [pcp3] (&rcu_sched_data)->qlen_lazy: 0
    // [pcp3] (&rcu_sched_data)->qlen: 0
    // [pcp3] (&rcu_sched_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_sched_data)->cpu: 3
    // [pcp3] (&rcu_sched_data)->rsp: &rcu_sched_state
    //
    // rcu_struct_flavors에 (&rcu_sched_state)->flavors를 list 추가

    __rcu_init_preempt();
    // __rcu_init_preempt 한일:
    // (&rcu_preempt_state)->levelcnt[0]: 1
    // (&rcu_preempt_state)->levelspread[0]: 4
    // &((&rcu_preempt_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_preempt_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_preempt_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_preempt_state)->level[0])->qsmask: 0
    // ((&rcu_preempt_state)->level[0])->qsmaskinit: 0
    // ((&rcu_preempt_state)->level[0])->grplo: 0
    // ((&rcu_preempt_state)->level[0])->grphi: 3
    // ((&rcu_preempt_state)->level[0])->gpnum: 0
    // ((&rcu_preempt_state)->level[0])->grpmask: 0
    // ((&rcu_preempt_state)->level[0])->parent: NULL
    // ((&rcu_preempt_state)->level[0])->level: 0
    // &((&rcu_preempt_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_preempt_state)->rda: &rcu_preempt_data
    // &(&(&rcu_preempt_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_preempt_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_preempt_state)->wakeup_work)->flags: 0
    // (&(&rcu_preempt_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp1] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp2] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp3] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->grpmask: 1
    // [pcp0] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp0] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp0] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp0] (&rcu_preempt_data)->qlen: 0
    // [pcp0] (&rcu_preempt_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_preempt_data)->cpu: 0
    // [pcp0] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp1] (&rcu_preempt_data)->grpmask: 2
    // [pcp1] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp1] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp1] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp1] (&rcu_preempt_data)->qlen: 0
    // [pcp1] (&rcu_preempt_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_preempt_data)->cpu: 1
    // [pcp1] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp2] (&rcu_preempt_data)->grpmask: 4
    // [pcp2] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp2] (&rcu_preempt_data)->nxttail[0...3]: [pcp2] &(&rcu_preempt_data)->nxtlist
    // [pcp2] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp2] (&rcu_preempt_data)->qlen: 0
    // [pcp2] (&rcu_preempt_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_preempt_data)->cpu: 2
    // [pcp2] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp3] (&rcu_preempt_data)->grpmask: 8
    // [pcp3] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp3] (&rcu_preempt_data)->nxttail[0...3]: [pcp3] &(&rcu_preempt_data)->nxtlist
    // [pcp3] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp3] (&rcu_preempt_data)->qlen: 0
    // [pcp3] (&rcu_preempt_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_preempt_data)->cpu: 3
    // [pcp3] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    //
    // rcu_struct_flavors에 (&rcu_preempt_state)->flavors를 list 추가

    // RCU_SOFTIRQ: 9,
    open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
    // open_softirq에서 한일:
    // softirq_vec[9].action: rcu_process_callbacks

    /*
     * We don't need protection against CPU-hotplug here because
     * this is called early in boot, before either interrupts
     * or the scheduler are operational.
     */
    cpu_notifier(rcu_cpu_notify, 0);
    // cpu_notifier에서 한일:
    // (&cpu_chain)->head: rcu_cpu_notify_nb 포인터 대입
    // (&rcu_cpu_notify_nb)->next은 (&sched_ilb_notifier_nb)->next로 대입

    pm_notifier(rcu_pm_notify, 0);
    // pm_notifier에서 한일:
    // (&pm_chain_head)->head: rcu_pm_notify_nb 포인터 대입
    // n->next: (&rcu_pm_notify_nb)->next: NULL

    for_each_online_cpu(cpu)
    // for ((cpu) = -1; (cpu) = cpumask_next((cpu), (cpu_online_mask)), (cpu) < nr_cpu_ids; )

        // CPU_UP_PREPARE: 0x0003, cpu: 0
        // rcu_cpu_notify(NULL, 0x0003, 0): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 1
        // rcu_cpu_notify(NULL, 0x0003, 1): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 2
        // rcu_cpu_notify(NULL, 0x0003, 2): NOTIFY_OK: 0x0001
        // CPU_UP_PREPARE: 0x0003, cpu: 3
        // rcu_cpu_notify(NULL, 0x0003, 3): NOTIFY_OK: 0x0001
        rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
        // rcu_cpu_notify에서 한일:
        // [pcp0...3] (&rcu_bh_data)->beenonline: 1
        // [pcp0...3] (&rcu_bh_data)->preemptible: 0
        // [pcp0...3] (&rcu_bh_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_bh_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_bh_data)->blimit: 10
        // [pcp0...3] (&rcu_bh_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_bh_data)->nxttail[0...3]: [pcp0...3] &(&rcu_bh_data)->nxtlist
        // [pcp0...3] (&rcu_bh_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_bh_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_bh_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_bh_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_bh_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_bh_data)->qs_pending: 0
        //
        // [pcp0...3] (&rcu_sched_data)->beenonline: 1
        // [pcp0...3] (&rcu_sched_data)->preemptible: 0
        // [pcp0...3] (&rcu_sched_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_sched_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_sched_data)->blimit: 10
        // [pcp0...3] (&rcu_sched_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_sched_data)->nxttail[0...3]: [pcp0...3] &(&rcu_sched_data)->nxtlist
        // [pcp0...3] (&rcu_sched_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_sched_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_sched_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_sched_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_sched_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_sched_data)->qs_pending: 0
        //
        // [pcp0...3] (&rcu_preempt_data)->beenonline: 1
        // [pcp0...3] (&rcu_preempt_data)->preemptible: 1
        // [pcp0...3] (&rcu_preempt_data)->len_last_fqs_check: 0
        // [pcp0...3] (&rcu_preempt_data)->n_force_qs_snap: 0
        // [pcp0...3] (&rcu_preempt_data)->blimit: 10
        // [pcp0...3] (&rcu_preempt_data)->nxtlist: NULL
        // [pcp0...3] (&rcu_preempt_data)->nxttail[0...3]: [pcp0...3] &(&rcu_preempt_data)->nxtlist
        // [pcp0...3] (&rcu_preempt_data)->dynticks->dynticks_nesting: 0x140000000000000
        // [pcp0...3] (&rcu_preempt_data)->dynticks->dynticks: 1
        // [pcp0...3] ((&rcu_preempt_state)->level[0])->qsmaskinit: [pcp0] 1, [pcp1] 2, [pcp2] 4, [pcp3] 8
        // [pcp0...3] (&rcu_preempt_data)->gpnum: 0xfffffed4
        // [pcp0...3] (&rcu_preempt_data)->passed_quiesce: 0
        // [pcp0...3] (&rcu_preempt_data)->qs_pending: 0

// 2014/09/27 종료
}

tree_plugin.h::rcu_bootup_announce();

// ARM10C 20140920
static void __init rcu_bootup_announce(void)
{
    pr_info("Preemptible hierarchical RCU implementation.\n");
    rcu_bootup_announce_oddness();
}

tree_plugin.h::rcu_bootup_annouce_oddness()

// ARM10C 20140920
static void __init rcu_bootup_announce_oddness(void)
{
#ifdef CONFIG_RCU_TRACE // CONFIG_RCU_TRACE=n
    pr_info("\tRCU debugfs-based tracing is enabled.\n");
#endif

// CONFIG_64BIT=n, CONFIG_RCU_FANOUT=32
#if (defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 64) || (!defined(CONFIG_64BIT) && CONFIG_RCU_FANOUT != 32)
    pr_info("\tCONFIG_RCU_FANOUT set to non-default value of %d\n",
           CONFIG_RCU_FANOUT);
#endif
#ifdef CONFIG_RCU_FANOUT_EXACT // CONFIG_RCU_FANOUT_EXACT=n
    pr_info("\tHierarchical RCU autobalancing is disabled.\n");
#endif

#ifdef CONFIG_RCU_FAST_NO_HZ // CONFIG_RCU_FAST_NO_HZ=n
    pr_info("\tRCU dyntick-idle grace-period acceleration is enabled.\n");
#endif

#ifdef CONFIG_PROVE_RCU // CONFIG_PROVE_RCU=n
    pr_info("\tRCU lockdep checking is enabled.\n");
#endif

#ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE // CONFIG_RCU_TORTURE_TEST_RUNNABLE=n
    pr_info("\tRCU torture testing starts during boot.\n");
#endif

// CONFIG_TREE_PREEMPT_RCU=y, CONFIG_RCU_CPU_STALL_VERBOSE=y
#if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
    pr_info("\tDump stacks of tasks blocking RCU-preempt GP.\n");
#endif

#if defined(CONFIG_RCU_CPU_STALL_INFO) // CONFIG_RCU_CPU_STALL_INFO=n
    pr_info("\tAdditional per-CPU info printed with stalls.\n");
#endif

#if NUM_RCU_LVL_4 != 0 // NUM_RCU_LVL_4: 0
    pr_info("\tFour-level hierarchy is enabled.\n");
#endif
    // rcu_fanout_leaf: 16, CONFIG_RCU_FANOUT_LEAF: 16
    if (rcu_fanout_leaf != CONFIG_RCU_FANOUT_LEAF)
        pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);

    // nr_cpu_ids: 4, NR_CPUS: 4
    if (nr_cpu_ids != NR_CPUS)
        pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);

#ifdef CONFIG_RCU_NOCB_CPU // CONFIG_RCU_NOCB_CPU=n
#ifndef CONFIG_RCU_NOCB_CPU_NONE // CONFIG_RCU_NOCB_CPU_NONE=n
    if (!have_rcu_nocb_mask) {
        zalloc_cpumask_var(&rcu_nocb_mask, GFP_KERNEL);
        have_rcu_nocb_mask = true;
    }
#ifdef CONFIG_RCU_NOCB_CPU_ZERO // CONFIG_RCU_NOCB_CPU_ZERO=n
    pr_info("\tOffload RCU callbacks from CPU 0\n");
    cpumask_set_cpu(0, rcu_nocb_mask);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
#ifdef CONFIG_RCU_NOCB_CPU_ALL // CONFIG_RCU_NOCB_CPU_ALL=n
    pr_info("\tOffload RCU callbacks from all CPUs\n");
    cpumask_copy(rcu_nocb_mask, cpu_possible_mask);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
    if (have_rcu_nocb_mask) {
        if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
            pr_info("\tNote: kernel parameter 'rcu_nocbs=' contains nonexistent CPUs.\n");
            cpumask_and(rcu_nocb_mask, cpu_possible_mask,
                    rcu_nocb_mask);
        }
        cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
        pr_info("\tOffload RCU callbacks from CPUs: %s.\n", nocb_buf);
        if (rcu_nocb_poll)
            pr_info("\tPoll for callbacks from no-CBs CPUs.\n");
    }
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
}

rcu_init_geometry();

  • rcu_init_geometry에서 한일:
    • // jiffies_till_first_fqs: 1
    • // jiffies_till_next_fqs: 1
// ARM10C 20140920
static void __init rcu_init_geometry(void)
{
    ulong d;
    int i;
    int j;

    // nr_cpu_ids: 4
    int n = nr_cpu_ids;
    // n: 4

    // MAX_RCU_LVLS: 4
    int rcu_capacity[MAX_RCU_LVLS + 1];

    /*
     * Initialize any unspecified boot parameters.
     * The default values of jiffies_till_first_fqs and
     * jiffies_till_next_fqs are set to the RCU_JIFFIES_TILL_FORCE_QS
     * value, which is a function of HZ, then adding one for each
     * RCU_JIFFIES_FQS_DIV CPUs that might be on the system.
     */
    // RCU_JIFFIES_TILL_FORCE_QS: 1, nr_cpu_ids: 4, RCU_JIFFIES_FQS_DIV: 256
    d = RCU_JIFFIES_TILL_FORCE_QS + nr_cpu_ids / RCU_JIFFIES_FQS_DIV;
    // d: 1

    // jiffies_till_first_fqs: 0xFFFFFFFF, ULONG_MAX: 0xFFFFFFFF
    if (jiffies_till_first_fqs == ULONG_MAX)
        // d: 1
        jiffies_till_first_fqs = d;
        // jiffies_till_first_fqs: 1

    // jiffies_till_next_fqs: 0xFFFFFFFF, ULONG_MAX: 0xFFFFFFFF
    if (jiffies_till_next_fqs == ULONG_MAX)
        // d: 1
        jiffies_till_next_fqs = d;
        // jiffies_till_next_fqs: 1

    /* If the compile-time values are accurate, just leave. */
    // rcu_fanout_leaf: 16, CONFIG_RCU_FANOUT_LEAF: 16, nr_cpu_ids: 4, NR_CPUS: 4
    if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF &&
        nr_cpu_ids == NR_CPUS)
        return;
        // return 수행

    /*
     * Compute number of nodes that can be handled an rcu_node tree
     * with the given number of levels.  Setting rcu_capacity[0] makes
     * some of the arithmetic easier.
     */
    rcu_capacity[0] = 1;
    rcu_capacity[1] = rcu_fanout_leaf;
    for (i = 2; i <= MAX_RCU_LVLS; i++)
        rcu_capacity[i] = rcu_capacity[i - 1] * CONFIG_RCU_FANOUT;

    /*
     * The boot-time rcu_fanout_leaf parameter is only permitted
     * to increase the leaf-level fanout, not decrease it.  Of course,
     * the leaf-level fanout cannot exceed the number of bits in
     * the rcu_node masks.  Finally, the tree must be able to accommodate
     * the configured number of CPUs.  Complain and fall back to the
     * compile-time values if these limits are exceeded.
     */
    if (rcu_fanout_leaf < CONFIG_RCU_FANOUT_LEAF ||
        rcu_fanout_leaf > sizeof(unsigned long) * 8 ||
        n > rcu_capacity[MAX_RCU_LVLS]) {
        WARN_ON(1);
        return;
    }

    /* Calculate the number of rcu_nodes at each level of the tree. */
    for (i = 1; i <= MAX_RCU_LVLS; i++)
        if (n <= rcu_capacity[i]) {
            for (j = 0; j <= i; j++)
                num_rcu_lvl[j] =
                    DIV_ROUND_UP(n, rcu_capacity[i - j]);
            rcu_num_lvls = i;
            for (j = i + 1; j <= MAX_RCU_LVLS; j++)
                num_rcu_lvl[j] = 0;
            break;
        }

    /* Calculate the total number of rcu_node structures. */
    rcu_num_nodes = 0;
    for (i = 0; i <= MAX_RCU_LVLS; i++)
        rcu_num_nodes += num_rcu_lvl[i];
    rcu_num_nodes -= n;
}
  • rcu_init_one(&rcu_bh_state)한일:
    • // (&rcu_bh_state)->levelcnt[0]: 1
    • // (&rcu_bh_state)->levelspread[0]: 4
    • // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화
    • // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화
    • // ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
    • // ((&rcu_bh_state)->level[0])->qsmask: 0
    • // ((&rcu_bh_state)->level[0])->qsmaskinit: 0
    • // ((&rcu_bh_state)->level[0])->grplo: 0
    • // ((&rcu_bh_state)->level[0])->grphi: 3
    • // ((&rcu_bh_state)->level[0])->gpnum: 0
    • // ((&rcu_bh_state)->level[0])->grpmask: 0
    • // ((&rcu_bh_state)->level[0])->parent: NULL
    • // ((&rcu_bh_state)->level[0])->level: 0
    • // &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    • //
    • // (&rcu_bh_state)->rda: &rcu_bh_data
    • // &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    • // &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화
    • // (&(&rcu_bh_state)->wakeup_work)->flags: 0
    • // (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup
    • //
    • // (&rcu_bh_state)->level[0]
    • //
    • // pcp0->mynode: (&rcu_bh_state)->level[0]
    • // pcp1->mynode: (&rcu_bh_state)->level[0]
    • // pcp2->mynode: (&rcu_bh_state)->level[0]
    • // pcp3->mynode: (&rcu_bh_state)->level[0]
    • //
    • // pcp0->grpmask: 1
    • // pcp0->nxtlist: NULL
    • // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp0->qlen_lazy: 0
    • // pcp0->qlen: 0
    • // pcp0->dynticks: [pcp0] &rcu_dynticks
    • // pcp0->cpu: 0
    • // pcp0->rsp: &rcu_bh_state
    • // pcp1->grpmask: 2
    • // pcp1->nxtlist: NULL
    • // pcp1->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
    • // pcp1->qlen_lazy: 0
    • // pcp1->qlen: 0
    • // pcp1->dynticks: [pcp1] &rcu_dynticks
    • // pcp1->cpu: 1
    • // pcp1->rsp: &rcu_bh_state
    • // pcp2->grpmask: 4
    • // pcp2->nxtlist: NULL
    • // pcp2->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
    • // pcp2->qlen_lazy: 0
    • // pcp2->qlen: 0
    • // pcp2->dynticks: [pcp2] &rcu_dynticks
    • // pcp2->cpu: 2
    • // pcp2->rsp: &rcu_bh_state
    • // pcp3->grpmask: 8
    • // pcp3->nxtlist: NULL
    • // pcp3->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
    • // pcp3->qlen_lazy: 0
    • // pcp3->qlen: 0
    • // pcp3->dynticks: [pcp3] &rcu_dynticks
    • // pcp3->cpu: 3
    • // pcp3->rsp: &rcu_bh_state
    • //
    • // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
// ARM10C 20140927
// &rcu_bh_state, &rcu_bh_data
static void __init rcu_init_one(struct rcu_state *rsp,
        struct rcu_data __percpu *rda)
{
    static char *buf[] = { "rcu_node_0",
                   "rcu_node_1",
                   "rcu_node_2",
                   "rcu_node_3" };  /* Match MAX_RCU_LVLS */
    static char *fqs[] = { "rcu_node_fqs_0",
                   "rcu_node_fqs_1",
                   "rcu_node_fqs_2",
                   "rcu_node_fqs_3" };  /* Match MAX_RCU_LVLS */
    int cpustride = 1;
    // cpustride: 1
    int i;
    int j;
    struct rcu_node *rnp;

    // MAX_RCU_LVLS: 4, ARRAY_SIZE(buf): 4
    BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf));  /* Fix buf[] init! */

    /* Silence gcc 4.8 warning about array index out of range. */
    // rcu_num_lvls: 1, RCU_NUM_LVLS: 1
    if (rcu_num_lvls > RCU_NUM_LVLS)
        panic("rcu_init_one: rcu_num_lvls overflow");

    /* Initialize the level-tracking arrays. */

    // rcu_num_lvls: 1
    for (i = 0; i < rcu_num_lvls; i++)
        // i:0, rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0], num_rcu_lvl[0]: 1
        rsp->levelcnt[i] = num_rcu_lvl[i];
        // rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0]: 1

    // rcu_num_lvls: 1
    for (i = 1; i < rcu_num_lvls; i++)
        rsp->level[i] = rsp->level[i - 1] + rsp->levelcnt[i - 1];

    // rsp: &rcu_bh_state
    rcu_init_levelspread(rsp);
    // rcu_init_levelspread에서 한일:
    // rsp->levelspread[0]: (&rcu_bh_state)->levelspread[0]: 4

    /* Initialize the elements themselves, starting from the leaves. */

    // rcu_num_lvls: 1
    for (i = rcu_num_lvls - 1; i >= 0; i--) {
        // i: 0, cpustride: 1, rsp->levelspread[0]: (&rcu_bh_state)->levelspread[0]: 4
        cpustride *= rsp->levelspread[i];
        // cpustride: 4

        // i: 0, rsp->level[0]: (&rcu_bh_state)->level[0]
        rnp = rsp->level[i];
        // rnp: (&rcu_bh_state)->level[0]: &rcu_bh_state.node[0]

        // i: 0, rsp->levelcnt[0]: (&rcu_bh_state)->levelcnt[0]: 1
        for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
            // &rnp->lock: &((&rcu_bh_state)->level[0])->lock
            raw_spin_lock_init(&rnp->lock);
            // &((&rcu_bh_state)->level[0])->lock 사용한 spinlock 초기화

            // &rnp->lock: &((&rcu_bh_state)->level[0])->lock,
            // i: 0, rcu_node_class[0], buf[0]: "rcu_node_0"
            lockdep_set_class_and_name(&rnp->lock,
                           &rcu_node_class[i], buf[i]); // null function

            // &rnp->fqslock: &((&rcu_bh_state)->level[0])->fqslock
            raw_spin_lock_init(&rnp->fqslock);
            // &((&rcu_bh_state)->level[0])->fqslock 사용한 spinlock 초기화

            // &rnp->fqslock: &((&rcu_bh_state)->level[0])->fqslock,
            // i: 0, rcu_fqs_class[0], fqs[0]: "rcu_node_fqs_0"
            lockdep_set_class_and_name(&rnp->fqslock,
                           &rcu_fqs_class[i], fqs[i]); // null function

            // rnp: ((&rcu_bh_state)->level[0])->gpnum,
            // rsp->gpnum: (&rcu_bh_state)->gpnum: 0xfffffed4
            rnp->gpnum = rsp->gpnum;
            // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0xfffffed4

            // rnp->completed: ((&rcu_bh_state)->level[0])->completed,
            // rsp->completed: (&rcu_bh_state)->completed: 0xfffffed4
            rnp->completed = rsp->completed;
            // rnp->completed: ((&rcu_bh_state)->level[0])->completed: 0xfffffed4

            // rnp->qsmask: ((&rcu_bh_state)->level[0])->qsmask
            rnp->qsmask = 0;
            // rnp->qsmask: ((&rcu_bh_state)->level[0])->qsmask: 0

            // rnp->qsmaskinit: ((&rcu_bh_state)->level[0])->qsmaskinit
            rnp->qsmaskinit = 0;
            // rnp->qsmaskinit: ((&rcu_bh_state)->level[0])->qsmaskinit: 0

            // rnp->grplo: ((&rcu_bh_state)->level[0])->grplo, j: 0, cpustride: 4
            rnp->grplo = j * cpustride;
            // rnp->grplo: ((&rcu_bh_state)->level[0])->grplo: 0

            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi, j: 0, cpustride: 4
            rnp->grphi = (j + 1) * cpustride - 1;
            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3

            // rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3, NR_CPUS: 4
            if (rnp->grphi >= NR_CPUS)
                rnp->grphi = NR_CPUS - 1;

            // i: 0
            if (i == 0) {
                // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0xfffffed4
                rnp->grpnum = 0;
                // rnp->gpnum: ((&rcu_bh_state)->level[0])->gpnum: 0

                // rnp->grpmask: ((&rcu_bh_state)->level[0])->grpmask
                rnp->grpmask = 0;
                // rnp->grpmask: ((&rcu_bh_state)->level[0])->grpmask: 0

                // rnp->parent: ((&rcu_bh_state)->level[0])->parent
                rnp->parent = NULL;
                // rnp->parent: ((&rcu_bh_state)->level[0])->parent: NULL
            } else {
                rnp->grpnum = j % rsp->levelspread[i - 1];
                rnp->grpmask = 1UL << rnp->grpnum;
                rnp->parent = rsp->level[i - 1] +
                          j / rsp->levelspread[i - 1];
            }
            // rnp->level: ((&rcu_bh_state)->level[0])->level, i: 0
            rnp->level = i;
            // rnp->level: ((&rcu_bh_state)->level[0])->level: 0

            // &rnp->blkd_tasks: &((&rcu_bh_state)->level[0])->blkd_tasks
            INIT_LIST_HEAD(&rnp->blkd_tasks);
            // &rnp->blkd_tasks: &((&rcu_bh_state)->level[0])->blkd_tasks 을 사용한 list 초기화

            // rnp: (&rcu_bh_state)->level[0]
            rcu_init_one_nocb(rnp); // null function
        }
    }

    // rsp->rda: (&rcu_bh_state)->rda, rda: &rcu_bh_data
    rsp->rda = rda;
    // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data

    // &rsp->gp_wq: &(&rcu_bh_state)->gp_wq
    init_waitqueue_head(&rsp->gp_wq);
    // init_waitqueue_head에서 한일:
    // &q->lock: &(&(&rcu_bh_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &q->task_list: &(&(&rcu_bh_state)->gp_wq)->task_list를 사용한 list 초기화

    // &rsp->wakeup_work: &(&rcu_bh_state)->wakeup_work
    init_irq_work(&rsp->wakeup_work, rsp_wakeup);
    // init_irq_work에서 한일:
    // work->flags: (&(&rcu_bh_state)->wakeup_work)->flags: 0
    // work->func: (&(&rcu_bh_state)->wakeup_work)->func: rsp_wakeup

    // rcu_num_lvls: 1, rsp->level[0]: (&rcu_bh_state)->level[0]
    rnp = rsp->level[rcu_num_lvls - 1];
    // rnp: (&rcu_bh_state)->level[0]

    for_each_possible_cpu(i) {
    // for ((i) = -1; (i) = cpumask_next((i), (cpu_possible_mask)), (i) < nr_cpu_ids; )

        // i: 0, rnp->grphi: ((&rcu_bh_state)->level[0])->grphi: 3
        while (i > rnp->grphi)
            rnp++;

        // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data, i: 0
        // per_cpu_ptr(&rcu_bh_data, 0)->mynode: [pcp0] (&rcu_bh_data)->mynode,
        // rnp: (&rcu_bh_state)->level[0]
        per_cpu_ptr(rsp->rda, i)->mynode = rnp;
        // per_cpu_ptr(&rcu_bh_data, 0)->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]

        // i: 0, rsp: &rcu_bh_state
        rcu_boot_init_percpu_data(i, rsp);
        // rcu_boot_init_percpu_data(0) 에서 한일:
        // rdp->grpmask: [pcp0] (&rcu_bh_data)->grpmask: 1
        // rdp->nxtlist: [pcp0] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp0] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp0] (&rcu_bh_data)->dynticks: [pcp0] &rcu_dynticks
        // rdp->cpu: [pcp0] (&rcu_bh_data)->cpu: 0
        // rdp->rsp: [pcp0] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(1) 에서 한일:
        // rdp->grpmask: [pcp1] (&rcu_bh_data)->grpmask: 2
        // rdp->nxtlist: [pcp1] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp1] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp1] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp1] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp1] (&rcu_bh_data)->dynticks: [pcp1] &rcu_dynticks
        // rdp->cpu: [pcp1] (&rcu_bh_data)->cpu: 1
        // rdp->rsp: [pcp1] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(2) 에서 한일:
        // rdp->grpmask: [pcp2] (&rcu_bh_data)->grpmask: 4
        // rdp->nxtlist: [pcp2] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp2] (&rcu_bh_data)->nxttail[0...3]: [pcp2] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp2] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp2] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp2] (&rcu_bh_data)->dynticks: [pcp2] &rcu_dynticks
        // rdp->cpu: [pcp2] (&rcu_bh_data)->cpu: 2
        // rdp->rsp: [pcp2] (&rcu_bh_data)->rsp: &rcu_bh_state
        //
        // rcu_boot_init_percpu_data(3) 에서 한일:
        // rdp->grpmask: [pcp3] (&rcu_bh_data)->grpmask: 8
        // rdp->nxtlist: [pcp3] (&rcu_bh_data)->nxtlist: NULL
        // rdp->nxttail[0...3]: [pcp3] (&rcu_bh_data)->nxttail[0...3]: [pcp3] &(&rcu_bh_data)->nxtlist
        // rdp->qlen_lazy: [pcp3] (&rcu_bh_data)->qlen_lazy: 0
        // rdp->qlen: [pcp3] (&rcu_bh_data)->qlen: 0
        // rdp->dynticks: [pcp3] (&rcu_bh_data)->dynticks: [pcp3] &rcu_dynticks
        // rdp->cpu: [pcp3] (&rcu_bh_data)->cpu: 3
        // rdp->rsp: [pcp3] (&rcu_bh_data)->rsp: &rcu_bh_state
    }

    // rsp->flavors: (&rcu_bh_state)->flavors
    list_add(&rsp->flavors, &rcu_struct_flavors);
    // rcu_struct_flavors에 (&rcu_bh_state)->flavors를 list 추가
}

tree_plugin.h::__rcu_init_preempt()

static void __init __rcu_init_preempt(void)
{
    rcu_init_one(&rcu_preempt_state, &rcu_preempt_data);
    // rcu_init_one(&rcu_preempt_state)한일:
    // (&rcu_preempt_state)->levelcnt[0]: 1
    // (&rcu_preempt_state)->levelspread[0]: 4
    // &((&rcu_preempt_state)->level[0])->lock 사용한 spinlock 초기화
    // &((&rcu_preempt_state)->level[0])->fqslock 사용한 spinlock 초기화
    // ((&rcu_preempt_state)->level[0])->completed: 0xfffffed4
    // ((&rcu_preempt_state)->level[0])->qsmask: 0
    // ((&rcu_preempt_state)->level[0])->qsmaskinit: 0
    // ((&rcu_preempt_state)->level[0])->grplo: 0
    // ((&rcu_preempt_state)->level[0])->grphi: 3
    // ((&rcu_preempt_state)->level[0])->gpnum: 0
    // ((&rcu_preempt_state)->level[0])->grpmask: 0
    // ((&rcu_preempt_state)->level[0])->parent: NULL
    // ((&rcu_preempt_state)->level[0])->level: 0
    // &((&rcu_preempt_state)->level[0])->blkd_tasks 을 사용한 list 초기화
    //
    // (&rcu_preempt_state)->rda: &rcu_preempt_data
    // &(&(&rcu_preempt_state)->gp_wq)->lock을 사용한 spinlock 초기화
    // &(&(&rcu_preempt_state)->gp_wq)->task_list를 사용한 list 초기화
    // (&(&rcu_preempt_state)->wakeup_work)->flags: 0
    // (&(&rcu_preempt_state)->wakeup_work)->func: rsp_wakeup
    //
    // (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp1] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp2] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    // [pcp3] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]
    //
    // [pcp0] (&rcu_preempt_data)->grpmask: 1
    // [pcp0] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp0] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp0] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp0] (&rcu_preempt_data)->qlen: 0
    // [pcp0] (&rcu_preempt_data)->dynticks: [pcp0] &rcu_dynticks
    // [pcp0] (&rcu_preempt_data)->cpu: 0
    // [pcp0] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp1] (&rcu_preempt_data)->grpmask: 2
    // [pcp1] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp1] (&rcu_preempt_data)->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist
    // [pcp1] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp1] (&rcu_preempt_data)->qlen: 0
    // [pcp1] (&rcu_preempt_data)->dynticks: [pcp1] &rcu_dynticks
    // [pcp1] (&rcu_preempt_data)->cpu: 1
    // [pcp1] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp2] (&rcu_preempt_data)->grpmask: 4
    // [pcp2] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp2] (&rcu_preempt_data)->nxttail[0...3]: [pcp2] &(&rcu_preempt_data)->nxtlist
    // [pcp2] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp2] (&rcu_preempt_data)->qlen: 0
    // [pcp2] (&rcu_preempt_data)->dynticks: [pcp2] &rcu_dynticks
    // [pcp2] (&rcu_preempt_data)->cpu: 2
    // [pcp2] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    // [pcp3] (&rcu_preempt_data)->grpmask: 8
    // [pcp3] (&rcu_preempt_data)->nxtlist: NULL
    // [pcp3] (&rcu_preempt_data)->nxttail[0...3]: [pcp3] &(&rcu_preempt_data)->nxtlist
    // [pcp3] (&rcu_preempt_data)->qlen_lazy: 0
    // [pcp3] (&rcu_preempt_data)->qlen: 0
    // [pcp3] (&rcu_preempt_data)->dynticks: [pcp3] &rcu_dynticks
    // [pcp3] (&rcu_preempt_data)->cpu: 3
    // [pcp3] (&rcu_preempt_data)->rsp: &rcu_preempt_state
    //
    // rcu_struct_flavors에 (&rcu_preempt_state)->flavors를 list 추가
}

tree.c:: RCU_STATE_INITIALIZER(sname, sabbr, cr)

#define RCU_STATE_INITIALIZER(sname, sabbr, cr) \
static char sname##_varname[] = #sname; \
static const char *tp_##sname##_varname __used __tracepoint_string = sname##_varname; \
struct rcu_state sname##_state = { \
    .level = { &sname##_state.node[0] }, \
    .call = cr, \
    .fqs_state = RCU_GP_IDLE, \
    .gpnum = 0UL - 300UL, \
    .completed = 0UL - 300UL, \
    .orphan_lock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.orphan_lock), \
    .orphan_nxttail = &sname##_state.orphan_nxtlist, \
    .orphan_donetail = &sname##_state.orphan_donelist, \
    .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
    .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
    .name = sname##_varname, \
    .abbr = sabbr, \
}; \
DEFINE_PER_CPU(struct rcu_data, sname##_data)

RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);

softirq.c::open_softirq()

// ARM10C 20140927
// RCU_SOFTIRQ: 9, rcu_process_callbacks
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
    // nr: 7, action: run_rebalance_domains
    // nr: 9, action: rcu_process_callbacks
    softirq_vec[nr].action = action;
    // softirq_vec[7].action: run_rebalance_domains
    // softirq_vec[9].action: rcu_process_callbacks
}

cpu.h::cpu_notifier()

// ARM10C 20140927
// cpu_notifier(rcu_cpu_notify, 0):
// {
//  static struct notifier_block rcu_cpu_notify_nb =
//      { .notifier_call = rcu_cpu_notify, .priority = 0 };
//  register_cpu_notifier(&rcu_cpu_notify_nb);
// }
#define cpu_notifier(fn, pri) {                 \
    static struct notifier_block fn##_nb =          \
        { .notifier_call = fn, .priority = pri };   \
    register_cpu_notifier(&fn##_nb);            \
}

suspend.h::pm_notifier()

// ARM10C 20140927
// #define pm_notifier(rcu_pm_notify, 0):
// {
//  static struct notifier_block rcu_pm_notify_nb =
//      { .notifier_call = rcu_pm_notify, .priority = 0 };
//  register_pm_notifier(&rcu_pm_notify_nb);
// }
#define pm_notifier(fn, pri) {              \
    static struct notifier_block fn##_nb =          \
        { .notifier_call = fn, .priority = pri };   \
    register_pm_notifier(&fn##_nb);         \
}

wait.c::init_waitqueue_head()

#define init_waitqueue_head(q)              \
    do {                        \
        static struct lock_class_key __key; \
                            \
        __init_waitqueue_head((q), #q, &__key); \
    } while (0)

irq_work.h::init_irq_work()

  • &work
static inline
void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
{
    work->flags = 0;
    work->func = func;
}

tree.c::rcu_boot_init_percpu_data()

static void __init
rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
{
    unsigned long flags;
    struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);

    struct rcu_node *rnp = rcu_get_root(rsp);
    // rn

    /* Set up local state, ensuring consistent view of global state. */
    raw_spin_lock_irqsave(&rnp->lock, flags);

    rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
    // rdp->grpmask: [pcp0] &rcu_bh_data->grpmask

    // rdp: [pcp0] &rcu_bh_data
    init_callback_list(rdp);

    // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy
    rdp->qlen_lazy = 0;
    // rdp->qlen_lazy: [pcp0] (&rcu_bh_data)->qlen_lazy:0

    ACCESS_ONCE(rdp->qlen) = 0;

    // cpu:0 [pcp0] &per_cpu((&rcu_bh_data)->dynticks, 0 )
    rdp->dynticks = &per_cpu(rcu_dynticks, cpu);


    WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
    WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);

    rdp->cpu = cpu;
    // [pcp0] (&rcu_bh_data)->cpu: cpu: 0

    rdp->rsp = rsp;
    // [pcp0] (&rcu_bh_data)->rsp: rsp: &rcu_bh_state

    rcu_boot_init_nocb_percpu_data(rdp);
    // null function

    raw_spin_unlock_irqrestore(&rnp->lock, flags);
}

notifier.c::blocking_notifier_chain_register()

int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
        struct notifier_block *n)
{
    int ret;

    /*
     * This code gets used during boot-up, when task switching is
     * not yet working and interrupts must remain disabled.  At
     * such times we must not call down_write().
     */
    if (unlikely(system_state == SYSTEM_BOOTING))
        return notifier_chain_register(&nh->head, n);

    down_write(&nh->rwsem);
    ret = notifier_chain_register(&nh->head, n);
    up_write(&nh->rwsem);
    return ret;
}
EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);

cpumask.h::for_each_online_cpu()

  • for_each_online_cpu(cpu) rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
#define for_each_online_cpu(cpu)   for_each_cpu((cpu), cpu_online_mask)
// #define for_each_cpu(i, cpu_online_mask)
//  for ((i) = -1; (i) = cpumask_next((i), (cpu_online_mask)), (i) < nr_cpu_ids; )

tree.c::rcu_cpu_notify()

static int rcu_cpu_notify(struct notifier_block *self,
                    unsigned long action, void *hcpu)
{
    // hcpu: 0
    long cpu = (long)hcpu;
    // cpu: 0

    // rcu_state->rda: (&rcu_preempt_state)->rda: &rcu_preempt_data, cpu: 0
    // per_cpu_ptr(&rcu_preempt_data, 0): [pcp0] &rcu_preempt_data
    struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
    // rdp: [pcp0] &rcu_preempt_data

    // rdp->mynode: [pcp0] (&rcu_preempt_data)->mynode: (&rcu_preempt_state)->level[0]: &rcu_preempt_state.node[0]
    struct rcu_node *rnp = rdp->mynode;
    // rnp: (&rcu_preempt_state)->level[0]

    struct rcu_state *rsp;

    trace_rcu_utilization(TPS("Start CPU hotplug"));

    // action: CPU_UP_PREPARE: 0x0003
    switch (action) {
    case CPU_UP_PREPARE:
    case CPU_UP_PREPARE_FROZEN:
        // cpu: 0
        rcu_prepare_cpu(cpu);

        // cpu: 0
        rcu_prepare_kthreads(cpu); // null function

        break;
    case CPU_ONLINE:
    case CPU_DOWN_FAILED:
        rcu_boost_kthread_setaffinity(rnp, -1);
        break;
    case CPU_DOWN_PREPARE:
        rcu_boost_kthread_setaffinity(rnp, cpu);
        break;
    case CPU_DYING:
    case CPU_DYING_FROZEN:
        for_each_rcu_flavor(rsp)
            rcu_cleanup_dying_cpu(rsp);
        break;
    case CPU_DEAD:
    case CPU_DEAD_FROZEN:
    case CPU_UP_CANCELED:
    case CPU_UP_CANCELED_FROZEN:
        for_each_rcu_flavor(rsp)
            rcu_cleanup_dead_cpu(cpu, rsp);
        break;
    default:
        break;
    }
    trace_rcu_utilization(TPS("End CPU hotplug"));
    return NOTIFY_OK;
}

tree.c::rcu_prepare_cpu()

  • rcu_prepare_cpu에서 한일: // pcp0->beenonline: 1 // pcp0->preemptible: 0 // pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 // pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 // pcp0->qs_pending: 0 // // pcp0->beenonline: 1 // pcp0->preemptible: 0 // pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_sched_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 // pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 // pcp0->qs_pending: 0 // // pcp0->beenonline: 1 // pcp0->preemptible: 1 //pcp0->len_last_fqs_check: 0 // pcp0->n_force_qs_snap: 0 // pcp0->blimit: 10 // pcp0->nxtlist: NULL // pcp0->nxttail[0...3]: [pcp0] &(&rcu_preempt_data)->nxtlist // pcp0->dynticks->dynticks_nesting: 0x140000000000000 //pcp0->dynticks->dynticks: 1 // pcp0->qsmaskinit: 1 // pcp0->gpnum: 0xfffffed4 // pcp0->passed_quiesce: 0 //pcp0->qs_pending: 0
// ARM10C 20140927
// cpu: 0
static void rcu_prepare_cpu(int cpu)
{
    struct rcu_state *rsp;

    for_each_rcu_flavor(rsp)
    // for (rsp = list_first_entry(&rcu_struct_flavors, typeof(*rsp), flavors);
    //     &rsp->flavors != (&rcu_struct_flavors); rsp = list_next_entry(rsp, flavors))

        // cpu: 0, rsp: &rcu_bh_state, rsp->name: (&rcu_bh_state)->name: "rcu_bh", strcmp("rcu_bh", "rcu_preempt"): -1
        // cpu: 0, rsp: &rcu_sched_data, rsp->name: (&rcu_bh_state)->name: "rcu_sched", strcmp("rcu_sched", "rcu_preempt"): -1
        // cpu: 0, rsp: &rcu_preempt_data, rsp->name: (&rcu_preempt_state)->name: "rcu_preempt", strcmp("rcu_preempt", "rcu_preempt"): 0
        rcu_init_percpu_data(cpu, rsp,
                     strcmp(rsp->name, "rcu_preempt") == 0);
}

tree.c::rcu_init_percpu_data()

// ARM10C 20140927
// cpu: 0, rsp: &rcu_bh_state, 0
static void
rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
{
    unsigned long flags;
    unsigned long mask;

    // rsp->rda: (&rcu_bh_state)->rda: &rcu_bh_data, cpu: 0
    // per_cpu_ptr(&rcu_bh_data, 0): [pcp0] &rcu_bh_data
    struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
    // rdp: [pcp0] &rcu_bh_data

    // rsp: &rcu_bh_state, rcu_get_root(&rcu_bh_state): &(&rcu_bh_state)->node[0]
    struct rcu_node *rnp = rcu_get_root(rsp);
    // rnp: &(&rcu_bh_state)->node[0]

    /* Exclude new grace periods. */
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex
    mutex_lock(&rsp->onoff_mutex);
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex을 사용한 mutex lock 수행

    /* Set up local state, ensuring consistent view of global state. */
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock
    raw_spin_lock_irqsave(&rnp->lock, flags);
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock을 사용한 spinlock을 걸고 cpsr을 flags에 저장

    // rdp->beenonline: [pcp0] (&rcu_bh_data)->beenonline
    rdp->beenonline = 1;     /* We have now been online. */
    // rdp->beenonline: [pcp0] (&rcu_bh_data)->beenonline: 1

    // rdp->preemptible: [pcp0] (&rcu_bh_data)->preemptible, preemptible: 0
    rdp->preemptible = preemptible;
    // rdp->preemptible: [pcp0] (&rcu_bh_data)->preemptible: 0

    // rdp->len_last_fqs_check: [pcp0] (&rcu_bh_data)->len_last_fqs_check
    rdp->qlen_last_fqs_check = 0;
    // rdp->len_last_fqs_check: [pcp0] (&rcu_bh_data)->len_last_fqs_check: 0

    // rdp->n_force_qs_snap: [pcp0] (&rcu_bh_data)->n_force_qs_snap
    // rsp->n_force_qs: (&rcu_bh_state)->n_force_qs: 0
    rdp->n_force_qs_snap = rsp->n_force_qs;
    // rdp->n_force_qs_snap: [pcp0] (&rcu_bh_data)->n_force_qs_snap: 0

    // rdp->blimit: [pcp0] (&rcu_bh_data)->blimit, blimit: 10
    rdp->blimit = blimit;
    // rdp->blimit: [pcp0] (&rcu_bh_data)->blimit: 10

    // rdp: [pcp0] &rcu_bh_data
    init_callback_list(rdp);  /* Re-enable callbacks on this CPU. */
    // init_callback_list에서 한일:
    // [pcp0] (&rcu_bh_data)->nxtlist: NULL
    // [pcp0] (&rcu_bh_data)->nxttail[0...3]: [pcp0] &(&rcu_bh_data)->nxtlist

    // rdp->dynticks->dynticks_nesting: [pcp0] (&rcu_bh_data)->dynticks->dynticks_nesting,
    // DYNTICK_TASK_EXIT_IDLE: 0x140000000000000
    rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
    // rdp->dynticks->dynticks_nesting: [pcp0] (&rcu_bh_data)->dynticks->dynticks_nesting: 0x140000000000000

    // rdp->dynticks: [pcp0] (&rcu_bh_data)->dynticks
    rcu_sysidle_init_percpu_data(rdp->dynticks); // null function

    // &rdp->dynticks->dynticks: [pcp0] (&rcu_bh_data)->dynticks->dynticks: 1,
    // atomic_read((&rcu_bh_data)->dynticks->dynticks): 1
    atomic_set(&rdp->dynticks->dynticks,
           (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
    // &rdp->dynticks->dynticks: [pcp0] (&rcu_bh_data)->dynticks->dynticks: 1

    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock
    raw_spin_unlock(&rnp->lock);        /* irqs remain disabled. */
    // &rnp->lock: &(&(&rcu_bh_state)->node[0])->lock을 사용한 spinlock을 풀고 flags에 저장된 cpsr을 복원

    /* Add CPU to rcu_node bitmasks. */
    // rdp->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
    rnp = rdp->mynode;
    // rnp: [pcp0] (&rcu_bh_state)->level[0]

    // rdp->grpmask: [pcp0] (&rcu_bh_data)->grpmask: 1
    mask = rdp->grpmask;
    // mask: 1

    do {
        /* Exclude any attempts to start a new GP on small systems. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock
        raw_spin_lock(&rnp->lock);  /* irqs already disabled. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock을 사용한 spinlock 수행

        // rnp->qsmaskinit: [pcp0] ((&rcu_bh_state)->level[0])->qsmaskinit: 0, mask: 1
        rnp->qsmaskinit |= mask;
        // rnp->qsmaskinit: [pcp0] ((&rcu_bh_state)->level[0])->qsmaskinit: 1

        // rnp->grpmask: [pcp0] ((&rcu_bh_state)->level[0])->grpmask: 0, mask: 1
        mask = rnp->grpmask;
        // mask: 0

        // rnp: [pcp0] (&rcu_bh_state)->level[0],
        // rdp->mynode: [pcp0] (&rcu_bh_data)->mynode: (&rcu_bh_state)->level[0]
        if (rnp == rdp->mynode) {
            /*
             * If there is a grace period in progress, we will
             * set up to wait for it next time we run the
             * RCU core code.
             */
            // rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum,
            // rnp->completed: [pcp0] ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
            rdp->gpnum = rnp->completed;
            // rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum: 0xfffffed4

            // rdp->completed: [pcp0] (&rcu_bh_data)->completed,
            // rnp->completed: [pcp0] ((&rcu_bh_state)->level[0])->completed: 0xfffffed4
            rdp->completed = rnp->completed;
            // rdp->completed: [pcp0] (&rcu_bh_data)->completed: 0xfffffed4

            // rdp->passed_quiesce: [pcp0] (&rcu_bh_data)->passed_quiesce
            rdp->passed_quiesce = 0;
            // rdp->passed_quiesce: [pcp0] (&rcu_bh_data)->passed_quiesce: 0

            // rdp->qs_pending: [pcp0] (&rcu_bh_data)->qs_pending
            rdp->qs_pending = 0;
            // rdp->qs_pending: [pcp0] (&rcu_bh_data)->qs_pending: 0

            // rsp->name: (&rcu_bh_state)->name: "rcu_bh", rdp->gpnum: [pcp0] (&rcu_bh_data)->gpnum: 0xfffffed4
            trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl")); // null function
        }
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock
        raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
        // &rnp->lock: [pcp0] &((&rcu_bh_state)->level[0])->lock을 사용한 spin unlock 수행

        // rnp->parent: (&(&rcu_bh_state)->node[0])->parent: NULL
        rnp = rnp->parent;
        // rnp: NULL

        // rnp: NULL, rnp->qsmaskinit: (&(&rcu_bh_state)->node[0])->qsmaskinit: 1, mask: 0
    } while (rnp != NULL && !(rnp->qsmaskinit & mask));

    local_irq_restore(flags);
    // flags에 저장된 cpsr을 복원

    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex
    mutex_unlock(&rsp->onoff_mutex);
    // &rsp->onoff_mutex: &(&rcu_bh_state)->onoff_mutex을 사용한 mutex unlock 수행
}

2014년 9월 26일 금요일

ARM Cortex A15/A17 SoCs Comparison

ModelExynos 5422Tegra K1A80RK3288
MakerSamsung Nvidia AllWinner Rockchip
CPU4x ARM Cortex-A15 @ 2.1 GHz +
4x ARM Cortex-A7 @ 1.5 GHz
big.LITTLE Processing
Quad Core ARM Cortex-A15 r3 @ 2.3GHz + Cortex A15 r3 companion core4x ARM Cortex-A15 r4 @ 2.0?? GHz +
4x ARM Cortex-A7 @ ?? GHz
big.LITTLE Processing
4x ARM Cortex-A17 @ 1.8 GHZ
L1 Icache/Dcache32KB/32KB32KB/32KB32KB/32KB32KB/32KB
L2 Cache2MB + 512 KB2MB + 512 KB2MB + 512KB1MB
GPUARM Mali-T628 MP6Kepler GK20a (192-cores)PowerVR G6230 (64-cores)ARM Mali-T764
GPU APIOpenGL ES 1.1/2.0/3.0, OpenCL 1.1,OpenVG 1.0.1, DirectX 11, and Google RenderscriptOpenGL ES 2.0/3.0/3.1, OpenGL 4.4, OpenCL 1.2, CUDA 6.0, Directx 12OpenGL ES 2.0/3.0, OpenCL 1.x, Directx 9.3OpenGL ES 1.1/2.0/3.0, OpenVG 1.1, OpenCL 1.1 and Renderscript, Directx11
Video Decoder1920×1080@120fps – MPEG-4/MPEG-2/H.263/H.264/VP8//VC1
8192×8192 – H.264 and VP8
1440p – H.264 BP/MP/HP/MVC, VC-1, VP8, MPEG-2 and MPEG-44K2K@30fps: H.264 and VP8
1080p60: MPEG 1/2/4. H.263, H.264, WMV9/VC1, etc…
1080p30: H.265/VP9
3D decoding @ 3840×1080@30fps
4K2K@60fps: HEVC
4K2K@24fps: H.264, MPEG-2, VP6/VP8, MVC
1080p: MPEG-4, Sorenson Spark, VC-1, RV8/RV9/RV10, and AVS
720×576:H.263
Video Encoder1920×1080@120fps – MPEG-4//H.263/H.264/VP8
8192×8192 – H.264 and VP8
H.264
BP/MP/HP/MVC and VP8
4K2K@30fps: H.264 and VP81080p30: H.264, MVC, and VP8
Memory (On-chip)No data64KB Boot ROM (IROM)No data20KB BootRom, 100KB internal SRAM
Memory InterfacesLPDDR3/DDR3 – 2-ports 32-bit up to 933 MHz
LPDDR2 – 2-ports 32-bit up to 533 MHz
2x eMMC 5.0, 1x eMMC 4.5
8-bit SDIO 3.0,
4-bit SD 3.0
DDR3L, and LPDDR3, up to 8GB
LPDDR2 might work but not tested by Nvidia
eMMC version 4.5
SDIO
DDR3/DDR3L/LPDDR3/LPDDR2, Up to 8GB
Raw NAND with 72-bit ECC
eMMC v4.5
4x SD/MMC
DDR3-1333/DDR3L-1333, LPDDR2-1066, LPDDR3-1066, up to 4GB
Dual channel async NAND flash, 8-bit, 60-bit ECC
Single channel async NAND flash, 16-bit, 60-bit ECC
eMMC v4.5
SD/MMC Interface (SD 3.0, MMC ver 4.5)
Display Interfaces4-lane MIPI DSI up to WUXGA (1920×1200) @ 60 fps
1-port (4 lanes) eDisplayPort (eDP) up to WQXGA (2560×1600) @ 60 fps
HDMI 1.4a interfaces with on-chip PHY
LVDS up to 1920×1200@60fps
2x 4-lane MIPI DSI (Dual link: up to 3840×1920@60fps, single link: 2560×1440@60fps)
4-lane eDP up to 3840×2160@60fps
HDMI 1.4b up to 4096×2160@30fps
Dual channel LVDS up to 1920×1080@60fps
RGB LCD up to 2048×1536@60fps
4-lane MIPI DSI up to 1920×1200@60fps
4-lane eDP up to 2560×1600@60fps
HDMI 1.4
Dual channel LVDS
2x Parallel and serial RGB interfaces: Up to 3840×2160 or 2560×1600
MCU LCD interface (optional)
4-lane MIPI up to 1080p60
4-lane eDP up to 4K2K@30fps
HDMI 1.4 and 2.0
Camera Interfaces2-ports (4/4 lanes) MIPI CSI2 interfaces
Up to 16MP @ 30fps
14-bit Bayer sensor
1x MIPI CSI
Up to 16MP @ 37 fps
2x 4x YUV / RAW / CSI
Parallel and MIPI I/F sensor
5M/8M/12M/16M CMOS sensor
8/10/12-bit YUV/Bayer sensor
12-bit CCIR/Camera I/F up to 5MP
MIPI CSI2 I/F up to 14MP
8/10/12-bit raw data interface
USB2x USB 3.0
1x USB 2.0
1x HSIC
2x USB 3.0
3x USB 2.0
HSIC
2x USB host
1x USB3.0/2.0 host / device
HSIC
2x USB 2.0 Host
1x USB 2.0 OTG
HSIC
EthernetN/AN/A1x Ethernet MAC1x GMAC (RMII/RGMII)
TS Interface1x TSI1x TSNo data2x IN, 1x IN
SATAN/ASATA 3.1N/AN/A
PCIeN/A5-lane PCIe with Gen1 (2.5GT/s) and Gen 2 (5.0 GT/s) speedsN/AN/A
Audio I/F1x PCM, 2x I2S, 1x S/PDIFPCM/I2S, S/PDIFPCM/I2SPCM/I2S, SPDIF
Other I/Os4x I2C, 7x HS-I2C, 3x SPI, 5x UART, GPIOs, 24-channel DMA controller3x I2C, 2x SPI, UART, Up to 64 MPIO (Multi Purpose IO)4x SPI, 7x TWI, 7x UART3x SPI, 6x I2C, 5x UART, 4x PWM, 2x DMAC, 160 GPIO
Antutu 4.x38580
Hardware: Samsung Galaxy S5 (SMG900H)
43851
Hardware: Tegra K1 Reference Tablet?
41556
Hardware: AllWinner OptimusBoard?
35225
Hardware: Pipo P8 (res: 2048×1536)
Low Cost Development BoardNone with Exynos 5422, but two with the similar Exynos 5420:
Arndale Octa for $179
Announced: ODROID XU-2 (Price not available)
Nvidia Jetson TK1 for $192Announced: OptimusBoard, PcDuino8, Cubieboard A80. No price available.Currently not available, none officially announced.