Skip to content

Latest commit

 

History

History
582 lines (475 loc) · 16.9 KB

a10c_106.md

File metadata and controls

582 lines (475 loc) · 16.9 KB
ARM10C : 106 주차
일시 : 2015.06.20 (106 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_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(-)