2015년 6월 20일 토요일

[Linux Kernel] 106주차(2015.06.20)

ARM10C : 106 주차
일시 : 2015.06.20 (106 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 2명

106 주차 진도

  • start_kernel 1 ~/kernel/iamroot/linux-stable/init/main.c
    • sched_clock_postinit 750 ~/kernel/iamroot/linux-stable/init/main.c
      • hrtimer_start 364 ~/kernel/iamroot/linux-stable/kernel/time/sched_clock.c
        • __hrtimer_start_range_ns 1279 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
          • lock_hrtimer_base 1137 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
            • hrtimer_enqueue_reprogram 1223 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
              • hrtimer_reprogram 789 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
                • tick_program_event 753 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c

main.c::main.c()

  • called: start_kernel()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
  • call: start_kernel()->sched_clock_postinit()

sched_clock.c::sched_clockinit()

  • called: start_kernel()->sched_clock_postinit()
// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

        // sched_clock_register에서 한일:
        // read_sched_clock: jiffy_sched_clock_read
        // sched_clock_mask: 0xFFFFFFFF
        // cd.rate: 100
        // cd.epoch_ns: 0
        // cd.epoch_cyc: 0
        // cd.wrap_kt: 0x42C1D83B9ACA00
        // (&cd)->mult: 0x98968000
        // (&cd)->shift: 8
        // (&cd.seq)->sequence: 2

    update_sched_clock();

    // update_sched_clock에서 한일:
    // cd.epoch_ns: 0
    // cd.epoch_cyc: 0
    // (&cd.seq)->sequence: 4

    /*
     * Start the timer to keep sched_clock() properly updated and
     * sets the initial epoch.
     */
    // CLOCK_MONOTONIC: 1, HRTIMER_MODE_REL: 1
    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

    // hrtimer_init에서 한일:
    // sched_clock_timer의 값을 0으로 초기화
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 &(&sched_clock_timer)->node 를 초기화

    sched_clock_timer.function = sched_clock_poll;
    // sched_clock_timer.function: sched_clock_poll

    // cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
    hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);

sched_clock.c::sched_clock_register()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
// ARM10C 20150530
// &sched_clock_timer, cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
int
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, mode: 1
    return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
}
EXPORT_SYMBOL_GPL(hrtimer_start);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()->__hrtimer_start_range_ns()
    • return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);

hrtimer.c::__hrtimer_start_range_ns()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()->__hrtimer_start_range_ns()
// ARM10C 20150530
// timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, 0, mode: 1, 1
int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
        unsigned long delta_ns, const enum hrtimer_mode mode,
        int wakeup)
{
    struct hrtimer_clock_base *base, *new_base;
    unsigned long flags;
    int ret, leftmost;

    // timer: &sched_clock_timer
    // lock_hrtimer_base(&sched_clock_timer, &flags): &hrtimer_bases->clock_base[0]
    base = lock_hrtimer_base(timer, &flags);
    // base: &hrtimer_bases->clock_base[0]

    // lock_hrtimer_base에서 한일:
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0] 을 리턴
    // flags에 cpsr값을 가져옴

    /* Remove an active timer from the queue: */
    // timer: &sched_clock_timer, base: &hrtimer_bases->clock_base[0]
    // remove_hrtimer(&sched_clock_timer, &hrtimer_bases->clock_base[0]): 0
    ret = remove_hrtimer(timer, base);
    // ret: 0

    /* Switch the timer base, if necessary: */
    // timer: &sched_clock_timer, base: &hrtimer_bases->clock_base[0], mode: 1,
    // HRTIMER_MODE_PINNED: 0x02
    // switch_hrtimer_base(&sched_clock_timer, &hrtimer_bases->clock_base[0], 0):
    // [pcp0] &(&hrtimer_bases)->clock_base[0]
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
    // new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]

    // mode: 1, HRTIMER_MODE_REL: 1
    if (mode & HRTIMER_MODE_REL) {
        // tim.tv64: 0x42C1D83B9ACA00,
        // new_base->get_time: [pcp0] (&(&hrtimer_bases)->clock_base[0])->get_time: &ktime_get,
        // ktime_get(): (ktime_t) { .tv64 = 0}
        // ktime_add_safe(0x42C1D83B9ACA00, (ktime_t) { .tv64 = 0}): (ktime_t) { .tv64 = 0x42C1D83B9ACA00}
        tim = ktime_add_safe(tim, new_base->get_time());
        // tim.tv64: 0x42C1D83B9ACA00

        /*
         * CONFIG_TIME_LOW_RES is a temporary way for architectures
         * to signal that they simply return xtime in
         * do_gettimeoffset(). In this case we want to round up by
         * resolution when starting a relative timer, to avoid short
         * timeouts. This will go away with the GTOD framework.
         */
#ifdef CONFIG_TIME_LOW_RES // CONFIG_TIME_LOW_RES=n
        tim = ktime_add_safe(tim, base->resolution);
#endif
    }

    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, delta_ns: 0
    hrtimer_set_expires_range_ns(timer, tim, delta_ns);

    // hrtimer_set_expires_range_ns에서 한일:
    // timer->_softexpires: (&sched_clock_timer)->_softexpires: 0x42C1D83B9ACA00
    // timer->node.expires: (&sched_clock_timer)->node.expires: 0x42C1D83B9ACA00

    // timer: &sched_clock_timer
    timer_stats_hrtimer_set_start_info(timer); // null function

    // timer: &sched_clock_timer, new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]
    // enqueue_hrtimer(&sched_clock_timer, [pcp0] &(&hrtimer_bases)->clock_base[0]): 1
    leftmost = enqueue_hrtimer(timer, new_base);
    // leftmost: 1

    // enqueue_hrtimer에서 한일:
    // (&(&(&sched_clock_timer)->node)->node)->__rb_parent_color: NULL
    // (&(&(&sched_clock_timer)->node)->node)->rb_left: NULL
    // (&(&(&sched_clock_timer)->node)->node)->rb_right: NULL
    // [pcp0] (&(&(&hrtimer_bases)->clock_base[0])->active)->head.rb_node: &(&(&sched_clock_timer)->node)->node
    //
    // [pcp0] &(&(&(&hrtimer_bases)->clock_base[0])->active)->head 에 RB Tree 형태로
    // &(&(&sched_clock_timer)->node)->node 를 추가함
    //
    // [pcp0] &(&(&(&hrtimer_bases)->clock_base[0])->active)->next: &(&sched_clock_timer)->node
    // [pcp0] (&(&hrtimer_bases)->clock_base[0])->cpu_base->active_bases: 1
    //
    // (&sched_clock_timer)->state: 0x01

    // leftmost: 1, new_base->cpu_base: [pcp0] (&(&hrtimer_bases)->clock_base[0])->cpu_base: [pcp0] &hrtimer_bases,
    // &__get_cpu_var(hrtimer_bases): [pcp0] &hrtimer_bases
    // timer: &sched_clock_timer, new_base: [pcp0] &(&hrtimer_bases)->clock_base[0]
    if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)
        && hrtimer_enqueue_reprogram(timer, new_base)) {
        if (wakeup) {
            /*
             * We need to drop cpu_base->lock to avoid a
             * lock ordering issue vs. rq->lock.
             */
            raw_spin_unlock(&new_base->cpu_base->lock);
            raise_softirq_irqoff(HRTIMER_SOFTIRQ);
            local_irq_restore(flags);
            return ret;
        } else {
            __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
        }
    }


    unlock_hrtimer_base(timer, &flags);

    // ret: 0
    return ret;
    // return 0
}
  • return: start_kernel()->sched_clock_postinit()
    • hrtimer_start()
    • __hrtimer_start_range_ns()
    • return 0

hrtimer.c::hrtimer_start()

  • return: start_kernel()->sched_clock_postinit()
    • hrtimer_start()
    • __hrtimer_start_range_ns()
    • return 0
// ARM10C 20150530
// &sched_clock_timer, cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
int
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
    // timer: &sched_clock_timer, tim: 0x42C1D83B9ACA00, mode: 1
    return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
}
EXPORT_SYMBOL_GPL(hrtimer_start);

sched_clock.c::sched_clock_postinit()

// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

        // sched_clock_register에서 한일:
        // read_sched_clock: jiffy_sched_clock_read
        // sched_clock_mask: 0xFFFFFFFF
        // cd.rate: 100
        // cd.epoch_ns: 0
        // cd.epoch_cyc: 0
        // cd.wrap_kt: 0x42C1D83B9ACA00
        // (&cd)->mult: 0x98968000
        // (&cd)->shift: 8
        // (&cd.seq)->sequence: 2

    update_sched_clock();

    // update_sched_clock에서 한일:
    // cd.epoch_ns: 0
    // cd.epoch_cyc: 0
    // (&cd.seq)->sequence: 4

    /*
     * Start the timer to keep sched_clock() properly updated and
     * sets the initial epoch.
     */
    // CLOCK_MONOTONIC: 1, HRTIMER_MODE_REL: 1
    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

    // hrtimer_init에서 한일:
    // sched_clock_timer의 값을 0으로 초기화
    // (&sched_clock_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 &(&sched_clock_timer)->node 를 초기화

    sched_clock_timer.function = sched_clock_poll;
    // sched_clock_timer.function: sched_clock_poll

    // cd.wrap_kt: 0x42C1D83B9ACA00, HRTIMER_MODE_REL: 1
    hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
}
  • sched_clock_postinit(); 에서 한일
    • sched_clock_timer을 초기화 수행

main.c::main.c()

  • return: start_kernel()->sched_clock_postinit()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
    // sched_clock_timer을 초기화 수행    

    perf_event_init();
    // null function.
    profile_init();
    // null function.

    call_function_init();
  • call: start_kernel()->call_function_init()

smp.c::call_function_init()

  • called: start_kernel()->call_function_init()
void __init call_function_init(void)
{
    void *cpu = (void *)(long)smp_processor_id();
    // cpu: NULL

    int i;

    for_each_possible_cpu(i) {
        struct call_single_queue *q = &per_cpu(call_single_queue, i);

        raw_spin_lock_init(&q->lock);
        INIT_LIST_HEAD(&q->list);
    }

    // &hotplug_cfd_notifier, CPU_UP_PREPARE: 0x0003, cpu
    hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
  • call: start_kernel()->call_function_init()->hotplug_cfd()

smp.c::hotplug_cfd()

  • called: start_kernel()->call_function_init()->hotplug_cfd()
  • ipi: interl processor interupt
  • csd call single data
static int
hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
    long cpu = (long)hcpu;
    struct call_function_data *cfd = &per_cpu(cfd_data, cpu);

    switch (action) {
    case CPU_UP_PREPARE:
    case CPU_UP_PREPARE_FROZEN:
        if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                cpu_to_node(cpu)))
            return notifier_from_errno(-ENOMEM);
        if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
                cpu_to_node(cpu))) {
            free_cpumask_var(cfd->cpumask);
            return notifier_from_errno(-ENOMEM);
        }

        cfd->csd = alloc_percpu(struct call_single_data);
        if (!cfd->csd) {
            free_cpumask_var(cfd->cpumask_ipi);
            free_cpumask_var(cfd->cpumask);
            return notifier_from_errno(-ENOMEM);
        }
        break;

#ifdef CONFIG_HOTPLUG_CPU
    case CPU_UP_CANCELED:
    case CPU_UP_CANCELED_FROZEN:

    case CPU_DEAD:
    case CPU_DEAD_FROZEN:
        free_cpumask_var(cfd->cpumask);
        free_cpumask_var(cfd->cpumask_ipi);
        free_percpu(cfd->csd);
        break;
#endif
    };

    return NOTIFY_OK;
}
  • return: start_kernel()->call_function_init()->hotplug_cfd()

smp.c::call_function_init()

  • return: start_kernel()->call_function_init()->hotplug_cfd()
void __init call_function_init(void)
{
    void *cpu = (void *)(long)smp_processor_id();
    // cpu: NULL

    int i;

    for_each_possible_cpu(i) {
        struct call_single_queue *q = &per_cpu(call_single_queue, i);

        raw_spin_lock_init(&q->lock);
        INIT_LIST_HEAD(&q->list);
    }

    // &hotplug_cfd_notifier, CPU_UP_PREPARE: 0x0003, cpu
    hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
    register_cpu_notifier(&hotplug_cfd_notifier);
  • return: start_kernel()->call_function_init()

main.c::main.c()

  • called: start_kernel()->call_function_init()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
sched_clock_postinit();
// sched_clock_timer을 초기화 수행

perf_event_init();
profile_init();
call_function_init();

// irqs_disabled()
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;

local_irq_enable();

* call: start_kernel()->local_irq_enable()

## irqflags.h::local_irq_enable()
* called: start_kernel()->local_irq_enable()

```irqflags.h
#define local_irq_enable() \
    do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
# define trace_hardirqs_on()        do { } while (0)    // ARM10C this
#define raw_local_irq_enable()      arch_local_irq_enable()
  • call: start_kernel()->local_irq_enable()->arch_local_irq_enable()

irqflags.h::arch_local_irq_enable()

  • call: start_kernel()->local_irq_enable()->arch_local_irq_enable()
static inline void arch_local_irq_enable(void)
{
    asm volatile(
        "   cpsie i         @ arch_local_irq_enable"
        :
        :
        : "memory", "cc");
}
  • return: start_kernel()->local_irq_enable()->arch_local_irq_enable()

main.c::main.c()

  • called: start_kernel()->call_function_init()
asmlinkage void __init start_kernel(void)
{
...
    time_init();
    // timer 를 사용하기 위한 clk source, clk_table 메모리 할당 및 초기화,
    // timer event를 위한 timer irq (MCT) 초기화 수행

    sched_clock_postinit();
    // sched_clock_timer을 초기화 수행

    perf_event_init();
    // null funciton
    profile_init();
    // null funciton
    call_function_init();

        irqs_disabled()
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");
    early_boot_irqs_disabled = false;

    local_irq_enable();

    kmem_cache_init_late();
    // null funciton

log

  • 1st log
1829c7c..d1c31fb  master     -> origin/master
Merge made by the 'recursive' strategy.
include/linux/clockchips.h       |   4 ++
include/linux/err.h              |   1 +
include/linux/hrtimer.h          |  10 ++++
include/linux/ktime.h            |   6 ++
include/linux/percpu.h           |   1 +
include/linux/spinlock.h         |   1 +
include/linux/time.h             |   1 +
include/uapi/asm-generic/errno.h |   2 +
init/main.c                      |   2 +
kernel/hrtimer.c                 | 123 +++++++++++++++++++++++++++------------
kernel/sched/core.c              |  17 +++++-
kernel/sched/rt.c                |   3 +-
kernel/time/clockevents.c        |  15 +++++
kernel/time/sched_clock.c        |  19 +++++-
kernel/time/tick-internal.h      |   2 +
kernel/time/tick-oneshot.c       |   7 +++
kernel/time/timekeeping.c        |   1 +
17 files changed, 173 insertions(+), 42 deletions(-)
  • 2nd log
d1c31fb..4f4095e  master     -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/irqflags.h       |   1 +
arch/arm/include/asm/spinlock_types.h |   3 +
include/asm-generic/topology.h        |   1 +
include/linux/bitmap.h                |   4 ++
include/linux/cpu.h                   |  22 ++++++++
include/linux/cpumask.h               |  21 +++++++
include/linux/gfp.h                   |   1 +
include/linux/irqflags.h              |   3 +
include/linux/list.h                  |   2 +
include/linux/notifier.h              |   2 +
include/linux/percpu-defs.h           |  12 ++++
include/linux/percpu.h                |   3 +
include/linux/perf_event.h            |   3 +-
include/linux/profile.h               |   3 +-
include/linux/smp.h                   |   8 ++-
include/linux/spinlock.h              |   5 +-
include/linux/spinlock_types.h        |   3 +
init/main.c                           |  23 ++++++--
kernel/cpu.c                          |  13 +++++
kernel/locking/spinlock_debug.c       |  23 ++++++--
kernel/notifier.c                     |  11 ++++
kernel/smp.c                          | 102 +++++++++++++++++++++++++++++++---
mm/percpu.c                           |   2 +
mm/slub.c                             |   1 +
24 files changed, 251 insertions(+), 21 deletions(-)

댓글 없음:

댓글 쓰기