| 6.2 The Linux Timekeeping Architecture | |||||||||
| · The kernel uses two basic timekeeping functions: | |||||||||
| one to keep the current time up-to-date and | |||||||||
| another to count the number of nanoseconds that have elapsed within the current second | |||||||||
| Data Structures of the Timekeeping Architecture | |||||||||
| · include/asm-i386/timer.h | |||||||||
| struct timer_opts { | |||||||||
| char* name; | |||||||||
| void (*mark_offset)(void); | |||||||||
| unsigned long (*get_offset)(void); | |||||||||
| unsigned long long (*monotonic_clock)(void); | |||||||||
| void (*delay)(unsigned long); | |||||||||
| }; | |||||||||
| struct init_timer_opts { | |||||||||
| int (*init)(char *override); | |||||||||
| struct timer_opts *opts; | |||||||||
| }; | |||||||||
| /* list of timers, ordered by preference, NULL terminated */ | |||||||||
| static struct init_timer_opts* __initdata timers[] = { | |||||||||
| #ifdef CONFIG_X86_CYCLONE_TIMER | |||||||||
| &timer_cyclone_init, | |||||||||
| #endif | |||||||||
| #ifdef CONFIG_HPET_TIMER | |||||||||
| &timer_hpet_init, | |||||||||
| #endif | |||||||||
| #ifdef CONFIG_X86_PM_TIMER | |||||||||
| &timer_pmtmr_init, | |||||||||
| #endif | |||||||||
| &timer_tsc_init, | |||||||||
| &timer_pit_init, | |||||||||
| NULL, | |||||||||
| }; | |||||||||
| /* iterates through the list of timers, returning the first | |||||||||
| * one that initializes successfully. | |||||||||
| */ | |||||||||
| struct timer_opts* __init select_timer(void) | |||||||||
| { | |||||||||
| int i = 0; | |||||||||
| /* find most preferred working timer */ | |||||||||
| while (timers[i]) { | |||||||||
| if (timers[i]->init) | |||||||||
| if (timers[i]->init(clock_override) == 0) | |||||||||
| return timers[i]->opts; | |||||||||
| ++i; | |||||||||
| } | |||||||||
| panic("select_timer: Cannot find a suitable timer/n"); | |||||||||
| return NULL; | |||||||||
| } | |||||||||
| u64 get_jiffies_64(void) | |||||||||
| { | |||||||||
| unsigned long seq; | |||||||||
| u64 ret; | |||||||||
| do { | |||||||||
| seq = read_seqbegin(&xtime_lock); | |||||||||
| ret = jiffies_64; | |||||||||
| } while (read_seqretry(&xtime_lock, seq)); | |||||||||
| return ret; | |||||||||
| } | |||||||||
| struct timespec { | |||||||||
| time_t | tv_sec; | /* seconds */ | |||||||
| long | tv_nsec; | /* nanoseconds */ | |||||||
| }; | |||||||||
| · Timekeeping Architecture in Uniprocessor Systems | |||||||||
| · Initialization phase | |||||||||
| void __init time_init(void) | |||||||||
| { | |||||||||
| #ifdef CONFIG_HPET_TIMER | |||||||||
| if (is_hpet_capable()) { | |||||||||
| /* | |||||||||
| * HPET initialization needs to do memory-mapped io. So, let | |||||||||
| * us do a late initialization after mem_init(). | |||||||||
| */ | |||||||||
| late_time_init = hpet_time_init; | |||||||||
| return; | |||||||||
| } | |||||||||
| #endif | |||||||||
| xtime.tv_sec = get_cmos_time(); | |||||||||
| xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | |||||||||
| set_normalized_timespec(&wall_to_monotonic, | |||||||||
| -xtime.tv_sec, -xtime.tv_nsec); | |||||||||
| cur_timer = select_timer(); | |||||||||
| printk(KERN_INFO "Using %s for high-res timesource/n",cur_timer->name); | |||||||||
| time_init_hook(); | |||||||||
| } | |||||||||
| 1. Initializes the xtime variable | |||||||||
| 2. Initializes the wall_to_monotonic variable | |||||||||
| 3. If the kernel supports HPET, it invokes the hpet_enable( ) function to determine | |||||||||
| whether the ACPI firmware has probed the chip and mapped | |||||||||
| its registers in the memory address space | |||||||||
| ※hpet_enable( ) programs the first timer of the HPET chip so that it raises the | |||||||||
| IRQ 0 interrupt 1000 times per second. Otherwise, if the HPET chip is not available, | |||||||||
| the kernel will use the PIT: the chip has already been programmed by the init_IRQ( ) | |||||||||
| function to raise 1000 timer interrupts per second | |||||||||
| 4. Invokes select_timer( ) to select the best timer source available in the system, | |||||||||
| and sets the cur_timer variable to the address of the corresponding timer object | |||||||||
| 5. Invokes setup_irq( 0,&irq0) to set up the interrupt gate corresponding to IRQ0 | |||||||||
| the line associated with the system timer interrupt source (PIT or HPET) | |||||||||
| static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL}; | |||||||||
| · The timer interrupt handler | |||||||||
| The timer_interrupt( ) function is the interrupt service routine (ISR) | |||||||||
| of the PIT or of the HPET; it performs the following steps: | |||||||||
| 1. Protects the time-related kernel variables | |||||||||
| by issuing a write_seqlock() on the xtime_lock seqlock | |||||||||
| 2. Executes the mark_offset method of the cur_timer timer object | |||||||||
| 3. Invokes the do_timer_interrupt( ) function | |||||||||
| which in turn performs the following actions: | |||||||||
| a. Increases by one the value of jiffies_64 | |||||||||
| b. Invokes the update_times( ) function to update | |||||||||
| the system date and time and to compute the current system load | |||||||||
| c. Invokes the update_process_times( ) function to perform several | |||||||||
| time-related accounting operations for the local CPU | |||||||||
| d. Invokes the profile_tick( ) function | |||||||||
| e. If the system clock is synchronized with an external clock | |||||||||
| invokes the set_rtc_mmss( ) function once every 660 seconds | |||||||||
| 4. Releases the xtime_lock seqlock by invoking write_sequnlock(). | |||||||||
| 5. Returns the value 1 to notify that the interrupt has been effectively handled | |||||||||
| Timekeeping Architecture in Multiprocessor Systems | |||||||||
| Passed | |||||||||
Understanding the linux kernel-ch6-Timing Measurements
最新推荐文章于 2025-12-03 11:14:46 发布
本文介绍了Linux内核的时间管理架构,包括单处理器系统中的时间初始化过程、选择最佳定时器源的方法及中断处理程序的工作流程等关键内容。
2884

被折叠的 条评论
为什么被折叠?



