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 | | | | | | | |