时钟中断处理程序可以划分为两个部分:体系结构相关部分和体系结构无关部分。
与体系结构相关的例程作为系统定时器的中断处理程序而注册到内核中,以便在产生时钟中断时,它都能够相应地运行。这部分处理程序主要完成:
获得xtime_lock锁,以便对访问jiffies_64和墙上时间xtime进行保护
需要时应答或重新设置系统时钟
周期性地使用墙上时间更新实时时钟
调用体系结构无关的时钟例程:do_timer()
- 在<Time.h(incluce/linux)>中
- extern struct timespec xtime;
- #ifndef _STRUCT_TIMESPEC
- #define _STRUCT_TIMESPEC
- struct timespec {
- time_t tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds 十亿分之一秒*/
- };
- #endif
中断服务程序主要通过调用与体系结构无关的例程do_timer()执行下面的工作:
给jiffies_64变量增加1
更新资源消耗的统计值,比如当前进程所消耗的系统时间和用户时间
执行已经到期的动态定时器
执行scheduler_tick()函数
更新墙上时间,该时间存放在xtime变量中
计算平均负载
- 在<Time.c(kernel)>中
- /*
- * Called by the timer interrupt. xtime_lock must already be taken
- * by the timer IRQ!
- */
- static inline void update_times(unsigned long ticks)
- {
- update_wall_time(); /* 更新墙上时间 */
- calc_load(ticks); /* 计算平均负载值*/
- }
- /*
- * The 64-bit jiffies value is not atomic - you MUST NOT read it
- * without sampling the sequence number in xtime_lock.
- * jiffies is defined in the linker script...
- */
- void do_timer(unsigned long ticks)
- {
- jiffies_64 += ticks;/* 给jiffies_64变量加1: */
- update_times(ticks);
- }
- /**
- * update_wall_time - Uses the current clocksource to increment the wall time
- *
- * Called from the timer interrupt, must hold a write on xtime_lock.
- */
- static void update_wall_time(void)
- {
- cycle_t offset;
- /* Make sure we're fully resumed: */
- if (unlikely(timekeeping_suspended))
- return;
- #ifdef CONFIG_GENERIC_TIME
- offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
- #else
- offset = clock->cycle_interval;
- #endif
- clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
- /* normally this loop will run just once, however in the
- * case of lost or late ticks, it will accumulate correctly.
- */
- while (offset >= clock->cycle_interval) {
- /* accumulate one interval */
- clock->xtime_nsec += clock->xtime_interval;
- clock->cycle_last += clock->cycle_interval;
- offset -= clock->cycle_interval;
- if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
- clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
- xtime.tv_sec++;
- second_overflow();
- }
- /* interpolator bits */
- time_interpolator_update(clock->xtime_interval
- >> clock->shift);
- /* accumulate error between NTP and clock interval */
- clock->error += current_tick_length();
- clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
- }
- /* correct the clock when NTP error is too big */
- clocksource_adjust(clock, offset);
- /* store full nanoseconds into xtime */
- xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
- clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
- /* check to see if there is a new clocksource to use */
- change_clocksource();
- update_vsyscall(&xtime, clock);
- }
- /*
- * calc_load - given tick count, update the avenrun load estimates.
- * This is called while holding a write_lock on xtime_lock.
- */
- static inline void calc_load(unsigned long ticks)
- {
- unsigned long active_tasks; /* fixed-point */
- static int count = LOAD_FREQ;
- count -= ticks;
- if (unlikely(count < 0)) {
- active_tasks = count_active_tasks();
- do {
- CALC_LOAD(avenrun[0], EXP_1, active_tasks);
- CALC_LOAD(avenrun[1], EXP_5, active_tasks);
- CALC_LOAD(avenrun[2], EXP_15, active_tasks);
- count += LOAD_FREQ;
- } while (count < 0);
- }
- }
do_timer()执行完毕后返回与体系结构相关的中断处理程序,继续执行后面的工作,释放xtime_lock锁,然后退出。
以上全部工作每1/Hz秒都要发生一次。
相关数据类型如下:
- 在<Clocksource.h(include/linux)>中
- /* clocksource cycle base type */
- typedef u64 cycle_t;
- struct clocksource;
- /**
- * struct clocksource - hardware abstraction for a free running counter
- * Provides mostly state-free accessors to the underlying hardware.
- *
- * @name: ptr to clocksource name
- * @list: list head for registration
- * @rating: rating value for selection (higher is better)
- * To avoid rating inflation the following
- * list should give you a guide as to how
- * to assign your clocksource a rating
- * 1-99: Unfit for real use
- * Only available for bootup and testing purposes.
- * 100-199: Base level usability.
- * Functional for real use, but not desired.
- * 200-299: Good.
- * A correct and usable clocksource.
- * 300-399: Desired.
- * A reasonably fast and accurate clocksource.
- * 400-499: Perfect
- * The ideal clocksource. A must-use where
- * available.
- * @read: returns a cycle value
- * @mask: bitmask for two's complement
- * subtraction of non 64 bit counters
- * @mult: cycle to nanosecond multiplier
- * @shift: cycle to nanosecond divisor (power of two)
- * @flags: flags describing special properties
- * @vread: vsyscall based read
- * @cycle_interval: Used internally by timekeeping core, please ignore.
- * @xtime_interval: Used internally by timekeeping core, please ignore.
- */
- struct clocksource {
- char *name;
- struct list_head list;
- int rating;
- cycle_t (*read)(void);
- cycle_t mask;
- u32 mult;
- u32 shift;
- unsigned long flags;
- cycle_t (*vread)(void);
- /* timekeeping specific data, ignore */
- cycle_t cycle_last, cycle_interval;
- u64 xtime_nsec, xtime_interval;
- s64 error;
- #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
- /* Watchdog related data, used by the framework */
- struct list_head wd_list;
- cycle_t wd_last;
- #endif
呵呵