setitimer 手続きの実装を掘削してみる (4)
我慢できず臨時朝練。run_timer_sftirq という手続きについて。
timer.c の init_timers 手続きにてソフト割り込み登録されてます。
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
ざっくり探したところでは raise してるのは以下らしい。
./kernel/timer.c: raise_softirq(TIMER_SOFTIRQ); ./kernel/time/tick-sched.c: raise_softirq_irqoff(TIMER_SOFTIRQ);
timer.c では run_local_timers 手続き。コールグラフてきに以下なカンジ?
update_process_times -> run_local_timers
update_process_times のコメントが以下。
* Called from the timer interrupt handler to charge one tick to the current * process. user_tick is 1 if the tick is user time, 0 for system.
タイマ割り込みから云々、なのかな。ただ今 grep 中。なんとなくアタリなのが以下ら辺なのかどうなのか。
./kernel/time/tick-sched.c: * time we slept as update_process_times does only a 1 tick ./kernel/time/tick-sched.c: update_process_times(user_mode(regs)); ./kernel/time/tick-sched.c: update_process_times(user_mode(regs)); ./kernel/time/tick-common.c: update_process_times(user_mode(get_irq_regs()));
それぞれ
- tick-sched.c の tick_nohz_handler 手続き
- tick-sched.c の tick_sched_timer 手続き
- tick-common.c の tick_periodic 手続き
というカンジ。なんとなく tick_periodic 手続きが本流な感触です。
話を元に戻します
run_timer_softirq 手続きです。__run_timers 手続きを呼び出してるんですが、そこから割り込みなナニを呼び出している模様。てか、ここでようやく tv2 とか tv3 とかってソレが出てきました。
static inline void __run_timers(struct tvec_base *base) { struct timer_list *timer; spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->timer_jiffies)) { struct list_head work_list; struct list_head *head = &work_list; int index = base->timer_jiffies & TVR_MASK; /* * Cascade timers: */ if (!index && (!cascade(base, &base->tv2, INDEX(0))) && (!cascade(base, &base->tv3, INDEX(1))) && !cascade(base, &base->tv4, INDEX(2))) cascade(base, &base->tv5, INDEX(3));
ええと、struct tvec_base 型ッスか。定義は kernel/timer.c ってことはこの中に閉じちゃってるんですね。
struct tvec_base { spinlock_t lock; struct timer_list *running_timer; unsigned long timer_jiffies; unsigned long next_timer; unsigned long active_timers; struct tvec_root tv1; struct tvec tv2; struct tvec tv3; struct tvec tv4; struct tvec tv5; } ____cacheline_aligned;
struct tvec 型も直上で定義されてます。
struct tvec { struct list_head vec[TVN_SIZE]; };
うーん、参考書持ってくるの忘れた。
もう少し
setitimer 手続きの実装を掘削してみる (3) でタイマ割り込みの根拠の部分までは行きついてますね
ただ、global_clock_event な抽象化で足が止まっているのか。で、結局ここが分からないので、TIMER_SOFTIRQ を raise しているはずの update_process_times がどこから呼ばれてるかが分からない??
とゆーことで再度 grep 祭りがアレ。
global_clock_event な出力が以下 (一部のみ)。
./System.map:ffffffff81ddb448 B global_clock_event ./arch/x86/include/asm/time.h:extern struct clock_event_device *global_clock_event; ./arch/x86/kernel/hpet.c: global_clock_event = &hpet_clockevent; ./arch/x86/kernel/apb_timer.c: global_clock_event = &adev->timer->ced; ./arch/x86/kernel/apb_timer.c: global_clock_event->name); ./arch/x86/kernel/i8253.c:struct clock_event_device *global_clock_event; ./arch/x86/kernel/i8253.c: global_clock_event = &i8253_clockevent; ./arch/x86/kernel/apic/apic.c: real_handler = global_clock_event->event_handler; ./arch/x86/kernel/apic/apic.c: global_clock_event->event_handler = lapic_cal_handler; ./arch/x86/kernel/apic/apic.c: global_clock_event->event_handler = real_handler; ./arch/x86/kernel/time.c: global_clock_event->event_handler(global_clock_event);
当り前ですが gtags で見える以上のものは無い。そして update_process_times な出力が以下 (これもバイナリは除去)。
./include/linux/sched.h:extern void update_process_times(int user); ./.tmp_System.map:ffffffff81067f70 T update_process_times ./System.map:ffffffff81067f70 T update_process_times ./kernel/timer.c:void update_process_times(int user_tick) ./kernel/time/tick-sched.c: * time we slept as update_process_times does only a 1 tick ./kernel/time/tick-sched.c: update_process_times(user_mode(regs)); ./kernel/time/tick-sched.c: update_process_times(user_mode(regs)); ./kernel/time/tick-common.c: update_process_times(user_mode(get_irq_regs())); ./arch/cris/arch-v10/kernel/time.c: update_process_times(user_mode(regs)); ./arch/cris/arch-v32/kernel/time.c: update_process_times(user_mode(regs)); ./arch/alpha/kernel/smp.c: update_process_times(user); ./arch/alpha/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/frv/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/ia64/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/parisc/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/blackfin/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/m68k/sun3/sun3ints.c: update_process_times(user_mode(get_irq_regs())); ./arch/m68k/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/xtensa/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/openrisc/kernel/time.c: * update_process_times() expects us to have called irq_enter(). ./arch/h8300/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/mn10300/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/x86/kernel/apic/apic.c: * update_process_times() expects us to have done irq_enter(). ./arch/arm/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./arch/m32r/kernel/smp.c: update_process_times(user); ./arch/m32r/kernel/time.c: update_process_times(user_mode(get_irq_regs())); ./Documentation/timers/highres.txt: - cpu local update_process_times ./Documentation/timers/highres.txt:and calls update_process_times and profiling. The implementation of the hrtimer
とりあえず update_process_times 手続きはタイマ割り込みから呼び出される、ってことにしときます。あ、あと上の grep 出力に出てきている Documentation/timers/highres.txt も確認の方向です。