- 论坛徽章:
- 1
|
刚看了一下,简单理清了思路,希望对LZ有用
让我们先来看一下clock_getres的实现
- 2.6.31/kernel/posix-timers.c
- 这里有两种方式,一直是common_clock_getres,直接访问posix_clocks[which_clock].res;另一种是使用
- 939行定义的函数,其间接调用了posix_clocks[clock].clock_getres
- ……
- 134static struct k_clock posix_clocks[MAX_CLOCKS];
- ……
- 158#define CLOCK_DISPATCH(clock, call, arglist) \
- 159 ((clock) < 0 ? posix_cpu_##call arglist : \
- 160 (posix_clocks[clock].call != NULL \
- 161 ? (*posix_clocks[clock].call) arglist : common_##call arglist))
- ……
- 171static inline int common_clock_getres(const clockid_t which_clock,
- 172 struct timespec *tp)
- 173{
- 174 tp->tv_sec = 0;
- 175 tp->tv_nsec = posix_clocks[which_clock].res;
- 176 return 0;
- 177}
- ……
- 939SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
- 940 struct timespec __user *, tp)
- 941{
- 942 struct timespec rtn_tp;
- 943 int error;
- 944
- 945 if (invalid_clockid(which_clock))
- 946 return -EINVAL;
- 947
- 948 error = CLOCK_DISPATCH(which_clock, clock_getres,
- 949 (which_clock, &rtn_tp));
- 950
- 951 if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) {
- 952 error = -EFAULT;
- 953 }
- 954
- 955 return error;
- 956}
复制代码
走到这里,目标都集中到posix_clocks上。来看一下posix_clocks的定义
- 2.6.31/kernel/posix-timers.c
- 134static struct k_clock posix_clocks[MAX_CLOCKS];
-
- 2.6.31/include/linux/posix-timers.h
- 69struct k_clock {
- 70 int res; /* in nanoseconds */
- 71 int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
- 72 int (*clock_set) (const clockid_t which_clock, struct timespec * tp);
- 73 int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
- 74 int (*timer_create) (struct k_itimer *timer);
- 75 int (*nsleep) (const clockid_t which_clock, int flags,
- 76 struct timespec *, struct timespec __user *);
- 77 long (*nsleep_restart) (struct restart_block *restart_block);
- 78 int (*timer_set) (struct k_itimer * timr, int flags,
- 79 struct itimerspec * new_setting,
- 80 struct itimerspec * old_setting);
- 81 int (*timer_del) (struct k_itimer * timr);
- 82#define TIMER_RETRY 1
- 83 void (*timer_get) (struct k_itimer * timr,
- 84 struct itimerspec * cur_setting);
- 85};
复制代码
接下来我们看一下posix_clocks的初始化
- 2.6.31/kernel/posix-timers.c
- 245/*
- 246 * Initialize everything, well, just everything in Posix clocks/timers ;)
- 247 */
- 248static __init int init_posix_timers(void)
- 249{
- 250 struct k_clock clock_realtime = {
- 251 .clock_getres = hrtimer_get_res,
- 252 };
- 253 struct k_clock clock_monotonic = {
- 254 .clock_getres = hrtimer_get_res,
- 255 .clock_get = posix_ktime_get_ts,
- 256 .clock_set = do_posix_clock_nosettime,
- 257 };
- 258 struct k_clock clock_monotonic_raw = {
- 259 .clock_getres = hrtimer_get_res,
- 260 .clock_get = posix_get_monotonic_raw,
- 261 .clock_set = do_posix_clock_nosettime,
- 262 .timer_create = no_timer_create,
- 263 .nsleep = no_nsleep,
- 264 };
- 265
- 266 register_posix_clock(CLOCK_REALTIME, &clock_realtime);
- 267 register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
- 268 register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
- 269
- 270 posix_timers_cache = kmem_cache_create("posix_timers_cache",
- 271 sizeof (struct k_itimer), 0, SLAB_PANIC,
- 272 NULL);
- 273 idr_init(&posix_timers_id);
- 274 return 0;
- 275}
- 276
- 277__initcall(init_posix_timers);
复制代码
看到CLOCK_REALTIME和CLOCK_MONOTONIC了没,是不是感觉很熟悉。可以看到,要获取精度,都会调用hrtimer_get_res,这 就可以解释为什么CLOCK_REALTIME和CLOCK_MONOTONIC的输出相同了
我们跟踪一下hrtimer_get_res的实现
- 2.6.31/kernel/hrtimer.c
- 1189int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
- 1190{
- 1191 struct hrtimer_cpu_base *cpu_base;
- 1192
- 1193 cpu_base = &__raw_get_cpu_var(hrtimer_bases);
- 1194 *tp = ktime_to_timespec(cpu_base->clock_base[which_clock].resolution);
- 1195
- 1196 return 0;
- 1197}
- 1198EXPORT_SYMBOL_GPL(hrtimer_get_res);
复制代码
目标成了hrtimer_bases和hrtimer_cpu_base了,这里可以猜出hrtimer_bases是一个Per CPU变量,用于记录每个CPU的
hrtimer_cpu_base,这里先关注hrtimer_cpu_base
- 2.6.31/include/linux/hrtimer.h
- 172struct hrtimer_cpu_base {
- 173 spinlock_t lock;
- 174 struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];
- 175#ifdef CONFIG_HIGH_RES_TIMERS
- 176 ktime_t expires_next;
- 177 int hres_active;
- 178 unsigned long nr_events;
- 179#endif
- 180};
复制代码
目标转为hrtimer_cpu_base,看看它如何设置clock_base。先看一下struct hrtimer_clock_base的定义
- 2.6.31/include/linux/hrtimer.h
- 131/**
- 132 * struct hrtimer_clock_base - the timer base for a specific clock
- 133 * @cpu_base: per cpu clock base
- 134 * @index: clock type index for per_cpu support when moving a
- 135 * timer to a base on another cpu.
- 136 * @active: red black tree root node for the active timers
- 137 * @first: pointer to the timer node which expires first
- 138 * @resolution: the resolution of the clock, in nanoseconds
- 139 * @get_time: function to retrieve the current time of the clock
- 140 * @softirq_time: the time when running the hrtimer queue in the softirq
- 141 * @offset: offset of this clock to the monotonic base
- 142 */
- 143struct hrtimer_clock_base {
- 144 struct hrtimer_cpu_base *cpu_base;
- 145 clockid_t index;
- 146 struct rb_root active;
- 147 struct rb_node *first;
- 148 ktime_t resolution;
- 149 ktime_t (*get_time)(void);
- 150 ktime_t softirq_time;
- 151#ifdef CONFIG_HIGH_RES_TIMERS
- 152 ktime_t offset;
- 153#endif
- 154};
复制代码
看来最后的目标是查看hrtimer_clock_base的设置和初始化化了
- 91DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
- 92{
- 93
- 94 .clock_base =
- 95 {
- 96 {
- 97 .index = CLOCK_REALTIME,
- 98 .get_time = &ktime_get_real,
- 99 .resolution = KTIME_LOW_RES,
- 100 },
- 101 {
- 102 .index = CLOCK_MONOTONIC,
- 103 .get_time = &ktime_get,
- 104 .resolution = KTIME_LOW_RES,
- 105 },
- 106 }
- 107};
复制代码
跟踪一下KTIME_LOW_RES的定义
- 2.6.31/include/linux/ktime.h
- 321#define LOW_RES_NSEC TICK_NSEC
- 322#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC }
- 2.6.31/include/linux/jiffies.h
- 42/* LATCH is used in the interval timer and ftape setup. */
- 43#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
- 44
- 45/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, then we can
- 46 * improve accuracy by shifting LSH bits, hence calculating:
- 47 * (NOM << LSH) / DEN
- 48 * This however means trouble for large NOM, because (NOM << LSH) may no
- 49 * longer fit in 32 bits. The following way of calculating this gives us
- 50 * some slack, under the following conditions:
- 51 * - (NOM / DEN) fits in (32 - LSH) bits.
- 52 * - (NOM % DEN) fits in (32 - LSH) bits.
- 53 */
- 54#define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \
- 55 + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
- 56
- 57/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
- 58#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
- 59
- 60/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
- 61#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
复制代码
看看HZ的值是多少
- 2.6.31/arch/x86/include/asm/param.h
- 10#ifndef HZ
- 11#define HZ 100
- 12#endif
- 2.6.31/arch/ia64/include/asm/param.h
- 30# define HZ 1024
- 2.6.31/arch/arm/include/asm/param.h
- 13#ifdef __KERNEL__
- 14# define HZ CONFIG_HZ /* Internal kernel timer frequency */
- 15# define USER_HZ 100 /* User interfaces are in "ticks" */
- 16# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
- 17#else
- 18# define HZ 100
- 19#endif
- 20
复制代码
====================================================================
整理的有些乱,自己对这块也不熟悉。给LZ提供一个思路吧
一路看多来,感觉还是跟系统硬件有关系的,终归编译内核时候的配置选项会根据硬件来做,HZ就会有变化了
另外 KTIME_LOW_RES仅仅是初始化值,具体在后面运行中是否会发生变化也不一定,这样可能通过系统调用得到的
值与单纯自己根据这个流程得到的值会不一样
还有一点,配置不同也会影响初始化时调用的函数,我这里没有细看,LZ可以自己看看不同配置会有什么影响
LZ可以自己看看/kernel/hrtimer.c文件
[ 本帖最后由 openspace 于 2009-11-6 16:22 编辑 ] |
|