2015년 6월 13일 토요일

[Linux Kernel] 105주차(2015.06.13)

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

105 주차 진도

  • 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 1219 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
      • enqueue_hrtimer 1154 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
        • timerqueue_add 1001 ~/kernel/iamroot/linux-stable/kernel/hrtimer.c
          • rb_link_node 73 rb_link_node(&node->node, parent, p);

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

// 2015/05/30 종료

    // 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()

sched_clock.c::sched_clock_register()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
// 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()

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;

    base = lock_hrtimer_base(timer, &flags);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()

hrtimer.c::lock_hrtimer_base()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
static
struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
                         unsigned long *flags)
{
    struct hrtimer_clock_base *base;

    for (;;) {
        base = timer->base;
        if (likely(base != NULL)) {
            raw_spin_lock_irqsave(&base->cpu_base->lock, *flags);
            if (likely(base == timer->base))
                return base;
            /* The timer has migrated to another CPU: */
            raw_spin_unlock_irqrestore(&base->cpu_base->lock, *flags);
        }
        cpu_relax();
    }
}
  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
// 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;

    base = lock_hrtimer_base(timer, &flags);

    /* Remove an active timer from the queue: */
    ret = remove_hrtimer(timer, base);
  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
    • ->remove_hrtimer()
      • return: &hrtimer_base->clock_base[0], flags
    • remove_hrtimer()

hrtimer.c::remove_hrtimer()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
static inline int
remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
{
    if (hrtimer_is_queued(timer)) {
        unsigned long state;
        int reprogram;

        /*
         * Remove the timer and force reprogramming when high
         * resolution mode is active and the timer is on the current
         * CPU. If we remove a timer on another CPU, reprogramming is
         * skipped. The interrupt event on this CPU is fired and
         * reprogramming happens in the interrupt handler. This is a
         * rare case and less expensive than a smp call.
         */
        debug_deactivate(timer);
        timer_stats_hrtimer_clear_start_info(timer);
        reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
        /*
         * We must preserve the CALLBACK state flag here,
         * otherwise we could move the timer base in
         * switch_hrtimer_base.
         */
        state = timer->state & HRTIMER_STATE_CALLBACK;
        __remove_hrtimer(timer, base, state, reprogram);
        return 1;
    }
    return 0;
}
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0

hrtimer.c::__hrtimer_start_range_ns()

  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
// 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;

    base = lock_hrtimer_base(timer, &flags);

    /* Remove an active timer from the queue: */
    ret = remove_hrtimer(timer, base);

    /* Switch the timer base, if necessary: */
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()

hrtimer.c::switch_hrtimer_base()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
            int pinned)
{
    struct hrtimer_clock_base *new_base;
    struct hrtimer_cpu_base *new_cpu_base;
    int this_cpu = smp_processor_id();
    int cpu = hrtimer_get_target(this_cpu, pinned);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()

hrtimer.c::hrtimer_get_target()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned); -> hrtimer_get_target()
static int hrtimer_get_target(int this_cpu, int pinned)
{
#ifdef CONFIG_NO_HZ_COMMON
    if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
        return get_nohz_timer_target();
#endif
    return this_cpu;
}
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
core.c::idle_cpu()
  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
int idle_cpu(int cpu)
{
    struct rq *rq = cpu_rq(cpu);

    if (rq->curr != rq->idle)
        return 0;

    if (rq->nr_running)
        return 0;

#ifdef CONFIG_SMP
    if (!llist_empty(&rq->wake_list))
        return 0;
#endif

    return 1;
}
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
        • return 1

hrtimer.c::hrtimer_get_target()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
        • return 1
static int hrtimer_get_target(int this_cpu, int pinned)
{
#ifdef CONFIG_NO_HZ_COMMON
    // pinned:
    // get_sysctl_timer_migration(): 
    // idle_cpu(this_cpu: 0): 1
    if (!pinned && get_sysctl_timer_migration() && idle_cpu(this_cpu))
        return get_nohz_timer_target();
#endif
    return this_cpu;
}
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
core.c::get_nohz_timer_target()
  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
int get_nohz_timer_target(void)
{
    int cpu = smp_processor_id();
    int i;
    struct sched_domain *sd;

    rcu_read_lock();
    for_each_domain(cpu, sd) {
        // 
        for_each_cpu(i, sched_domain_span(sd)) {
        // 
            if (!idle_cpu(i)) {
                cpu = i;
                goto unlock;
            }
        }
    }
unlock:
    rcu_read_unlock();
    return cpu;
}
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();

hrtimer.c::switch_hrtimer_base()

  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
            int pinned)
{
    struct hrtimer_clock_base *new_base;
    struct hrtimer_cpu_base *new_cpu_base;
    int this_cpu = smp_processor_id();
    int cpu = hrtimer_get_target(this_cpu, pinned);
    int basenum = base->index;

again:
    new_cpu_base = &per_cpu(hrtimer_bases, cpu);
    new_base = &new_cpu_base->clock_base[basenum];

    if (base != new_base) {
        /*
         * We are trying to move timer to new_base.
         * However we can't change timer's base while it is running,
         * so we keep it on the same CPU. No hassle vs. reprogramming
         * the event source in the high resolution case. The softirq
         * code will take care of this when the timer function has
         * completed. There is no conflict as we hold the lock until
         * the timer is enqueued.
         */
        if (unlikely(hrtimer_callback_running(timer)))
            return base;

        /* See the comment in lock_timer_base() */
        timer->base = NULL;
        raw_spin_unlock(&base->cpu_base->lock);
        raw_spin_lock(&new_base->cpu_base->lock);

        if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
            cpu = this_cpu;
            raw_spin_unlock(&new_base->cpu_base->lock);
            raw_spin_lock(&base->cpu_base->lock);
            timer->base = base;
            goto again;
        }
        timer->base = new_base;
    }
    return new_base;
}
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();

hrtimer.c::__hrtimer_start_range_ns()

  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
// 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;

    base = lock_hrtimer_base(timer, &flags);

    /* Remove an active timer from the queue: */
    ret = remove_hrtimer(timer, base);

    /* Switch the timer base, if necessary: */
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);

    if (mode & HRTIMER_MODE_REL) {
        tim = ktime_add_safe(tim, new_base->get_time());

#ifdef CONFIG_TIME_LOW_RES
        tim = ktime_add_safe(tim, base->resolution);
#endif
    }
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()

hrtimer.c::ktime_add_safe()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs)
{
    ktime_t res = ktime_add(lhs, rhs);

    /*
     * We use KTIME_SEC_MAX here, the maximum timeout which we can
     * return to user space in a timespec:
     */
    if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64)
        res = ktime_set(KTIME_SEC_MAX, 0);

    return res;
}

EXPORT_SYMBOL_GPL(ktime_add_safe);
  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()

hrtimer.c::__hrtimer_start_range_ns()

  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
// 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;

    base = lock_hrtimer_base(timer, &flags);

    /* Remove an active timer from the queue: */
    ret = remove_hrtimer(timer, base);

    /* Switch the timer base, if necessary: */
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);

    if (mode & HRTIMER_MODE_REL) {
        tim = ktime_add_safe(tim, new_base->get_time());

#ifdef CONFIG_TIME_LOW_RES
        tim = ktime_add_safe(tim, base->resolution);
#endif
    }

    hrtimer_set_expires_range_ns(timer, tim, delta_ns);

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • hrtimer_set_expires_range_ns()

hrtimer.h::hrtimer_set_expires_range_ns()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • hrtimer_set_expires_range_ns()
static inline void hrtimer_set_expires_range_ns(struct hrtimer *timer, ktime_t time, unsigned long delta)
{
    timer->_softexpires = time;
    timer->node.expires = ktime_add_safe(time, ns_to_ktime(delta));
}
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • hrtimer_set_expires_range_ns()
      • ktime_add_safe()

hrtimer.c::__hrtimer_start_range_ns()

  • return: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
// 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;

    base = lock_hrtimer_base(timer, &flags);

    /* Remove an active timer from the queue: */
    ret = remove_hrtimer(timer, base);

    /* Switch the timer base, if necessary: */
    new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);

    if (mode & HRTIMER_MODE_REL) {
        tim = ktime_add_safe(tim, new_base->get_time());

#ifdef CONFIG_TIME_LOW_RES
        tim = ktime_add_safe(tim, base->resolution);
#endif
    }

    hrtimer_set_expires_range_ns(timer, tim, delta_ns);

    timer_stats_hrtimer_set_start_info(timer);

    leftmost = enqueue_hrtimer(timer, new_base);
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • enqueue_hrtimer()

hrtimer.c::enqueue_hrtimer()

  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • enqueue_hrtimer()
static int enqueue_hrtimer(struct hrtimer *timer,
               struct hrtimer_clock_base *base)
{
    debug_activate(timer);

    timerqueue_add(&base->active, &timer->node);
    base->cpu_base->active_bases |= 1 << base->index;

    /*
     * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the
     * state of a possibly running callback.
     */
    timer->state |= HRTIMER_STATE_ENQUEUED;

    return (&timer->node == base->active.next);
}
  • call: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • enqueue_hrtimer()
      • timerqueue_add()

timerqueue.c::timerqueue_add()

  • called: start_kernel()->sched_clock_postinit()->hrtimer_start()
    • ->__hrtimer_start_range_ns()
    • ->lock_hrtimer_base()
      • return: &hrtimer_base->clock_base[0], flags
    • ->remove_hrtimer()
      • ret: 0
    • ->switch_hrtimer_base()
      • cpu = hrtimer_get_target(this_cpu, pinned);
      • -> hrtimer_get_target()
        • idle_cpu()
          • return 1
        • get_nohz_timer_target();
    • ktime_add_safe()
    • enqueue_hrtimer()
      • timerqueue_add()
void timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)
{
    struct rb_node **p = &head->head.rb_node;
    struct rb_node *parent = NULL;
    struct timerqueue_node  *ptr;

    /* Make sure we don't add nodes that are already added */
    WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node));

    while (*p) {
        parent = *p;
        ptr = rb_entry(parent, struct timerqueue_node, node);
        if (node->expires.tv64 < ptr->expires.tv64)
            p = &(*p)->rb_left;
        else
            p = &(*p)->rb_right;
    }
    rb_link_node(&node->node, parent, p);
    rb_insert_color(&node->node, &head->head);

    if (!head->next || node->expires.tv64 < head->next->expires.tv64)
        head->next = node;
}
EXPORT_SYMBOL_GPL(timerqueue_add);

log

  • 1st log
   07692bc..b67cef4  master     -> origin/master
Updating 07692bc..b67cef4
Fast-forward
README.md                      |   2 +
arch/arm/include/asm/barrier.h |   1 +
include/asm-generic/current.h  |   1 +
include/asm-generic/percpu.h   |   1 +
include/linux/compiler.h       |   2 +
include/linux/hrtimer.h        |  20 +++++++
include/linux/irqflags.h       |   1 +
include/linux/ktime.h          |   9 ++++
include/linux/llist.h          |   5 ++
include/linux/lockdep.h        |   2 +
include/linux/rbtree.h         |   6 +++
include/linux/rcupdate.h       |  32 +++++++++++
include/linux/sched.h          |   2 +
include/linux/sched/sysctl.h   |   5 +-
include/linux/smp.h            |   1 +
include/linux/spinlock.h       |   2 +
include/linux/timerqueue.h     |   1 +
include/trace/events/timer.h   |   2 +
kernel/hrtimer.c               | 118 ++++++++++++++++++++++++++++++++++++++---
kernel/locking/lockdep.c       |  34 +++++++++++-
kernel/rcu/update.c            |   4 ++
kernel/sched/core.c            |  38 +++++++++++--
kernel/sched/sched.h           |  14 ++++-
kernel/time/sched_clock.c      |   1 +
kernel/time/timekeeping.c      |   1 +
lib/timerqueue.c               |  16 ++++++
26 files changed, 308 insertions(+), 13 deletions(-)
b67cef4..1829c7c  master     -> origin/master
Merge made by the 'recursive' strategy.
include/asm-generic/percpu.h |  1 +
include/linux/hrtimer.h      |  7 ++++++
include/linux/ktime.h        |  2 ++
include/linux/rbtree.h       |  8 +++++++
include/linux/timerqueue.h   |  1 +
kernel/hrtimer.c             | 54 +++++++++++++++++++++++++++++++++++++++++++-
lib/rbtree.c                 |  3 +++
lib/timerqueue.c             | 20 ++++++++++++++++
8 files changed, 95 insertions(+), 1 deletion(-)

댓글 없음:

댓글 쓰기