相关数据结构
4.19内核
110 struct hrtimer {
111 struct timerqueue_node node;//一个timerqueue_node结构体变量。这个结构体中有两个成员,node是红黑树的节点,expires:表示该定时器的硬超时时间:
/*
9 struct timerqueue_node {
10 struct rb_node node;
11 ktime_t expires;
12 };
struct rb_node//红黑树原理见https://www.cnblogs.com/theseventhson/p/15798449.html
{
unsigned long rb_parent_color;rb_parent_color这个域其实同时包含了颜色信息以及父亲节点的指针,因为该域是一个long的类型,需要大小为sizeof(long)的对齐,那么在一般的32位机器上,其后两位的数值永远是0,于是可以拿其中的一位来表示颜色。事实上,这里就是使用了最低位来表示颜色信息。明白了这点,那么以下关于父亲指针和颜色信息的操作都比较容易理解了,其本质上都是对rb_parent_color的位进行操作。
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) //低两位清0
#define rb_color(r) ((r)->rb_parent_color & 1) //取最后一位
#define rb_is_red(r) (!rb_color(r)) //最后一位为0?
#define rb_is_black(r) rb_color(r) //最后一位为1?
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) //最后一位置0
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) //最后一位置1
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
*/
112 ktime_t _softexpires;//表示该定时器的软超时时间。高精度定时器一般都有一个到期的时间范围,而不像(低精度)定时器那样就是一个时间点。这个时间范围的前时间点就是软超时时间,而后一个时间点就是硬超时时间。达到软超时时间后,还可以再拖一会再调用超时回调函数,而到达硬超时时间后就不能再拖了。
113 enum hrtimer_restart (*function)(struct hrtimer *);//定时器到期后的回调函数。
114 struct hrtimer_clock_base *base;//指向包含该高分辨率定时器的的hrtimer_clock_base结构体
115 u8 state;//用来表示该高分辨率定时器当前所处的状态,目前共有两种状态:
/* 表示定时器还未激活 */
#define HRTIMER_STATE_INACTIVE 0x00
/* 表示定时器已激活(入列) */
#define HRTIMER_STATE_ENQUEUED 0x01
116 u8 is_rel;//表示该定时器的到期时间是否是相对时间
117 u8 is_soft;//表示该定时器是否是“软”定时器。
118 };
138 /**
139 * struct hrtimer_clock_base - the timer base for a specific clock
140 * @cpu_base: per cpu clock base
141 * @index: clock type index for per_cpu support when moving a
142 * timer to a base on another cpu.
143 * @clockid: clock id for per_cpu support
144 * @seq: seqcount around __run_hrtimer
145 * @running: pointer to the currently running hrtimer
146 * @active: red black tree root node for the active timers
147 * @get_time: function to retrieve the current time of the clock
148 * @offset: offset of this clock to the monotonic base
149 */
150 struct hrtimer_clock_base {
151 struct hrtimer_cpu_base *cpu_base;//指向所属CPU的hrtimer_cpu_base结构体
152 unsigned int index;//表示该结构体在当前CPU的hrtimer_cpu_base结构体中clock_base数组中所处的下标。
153 clockid_t clockid;//表示当前时钟类型的ID值
154 seqcount_t seq; //顺序锁,在处理到期定时器的函数__run_hrtimer中会用到。
155 struct hrtimer *running;//指向当前正在处理的那个定时器
156 struct timerqueue_head active;//红黑树,包含了所有使用该时间类型的定时器。
157 ktime_t (*get_time)(void);//是一个函数指针,指定了如何获取该时间类型的当前时间的函数。由于不同类型的时间在Linux中都是由时间维护层来统一管理的,因此这些函数都是在时间维护层里面定义好的。
158 ktime_t offset;//表示当前时间类型和monotonic时间之间的差值。
159 } __hrtimer_clock_base_align;
173 /**
174 * struct hrtimer_cpu_base - the per cpu clock bases
175 * @lock: lock protecting the base and associated clock bases
176 * and timers
177 * @cpu: cpu number
178 * @active_bases: Bitfield to mark bases with active timers
179 * @clock_was_set_seq: Sequence counter of clock was set events
180 * @hres_active: State of high resolution mode
181 * @in_hrtirq: hrtimer_interrupt() is currently executing
182 * @hang_detected: The last hrtimer interrupt detected a hang
183 * @softirq_activated: displays, if the softirq is raised - update of softirq
184 * related settings is not required then.
185 * @nr_events: Total number of hrtimer interrupt events
186 * @nr_retries: Total number of hrtimer interrupt retries
187 * @nr_hangs: Total number of hrtimer interrupt hangs
188 * @max_hang_time: Maximum time spent in hrtimer_interrupt
189 * @expires_next: absolute time of the next event, is required for remote
190 * hrtimer enqueue; it is the total first expiry time (hard
191 * and soft hrtimer are taken into account)
192 * @next_timer: Pointer to the first expiring timer
193 * @softirq_expires_next: Time to check, if soft queues needs also to be expired
194 * @softirq_next_timer: Pointer to the first expiring softirq based timer
195 * @clock_base: array of clock bases for this cpu
196 *
197 * Note: next_timer is just an optimization for __remove_hrtimer().
198 * Do not dereference the pointer because it is not reliable on
199 * cross cpu removals.
200 */
201 struct hrtimer_cpu_base {
202 raw_spinlock_t lock; //用来保护该结构体的自旋锁。
203 unsigned int cpu; //绑定到的CPU编号。
204 unsigned int active_bases; //表示clock_base数组中哪些元素下的红黑树中含有定时器。
205 unsigned int clock_was_set_seq;//表示时钟被设置的序数。
206 unsigned int hres_active : 1, //表示是否已经处在了高精度模式下
207 in_hrtirq : 1, //是否正在执行hrtimer_interrupt中断处理程序中
208 hang_detected : 1, //表明在前一次执行hrtimer_interrupt中断处理程序的时候发生了错误。
209 softirq_activated : 1;//是否正在执行hrtimer_run_softirq软中断处理程序。
210 #ifdef CONFIG_HIGH_RES_TIMERS
211 unsigned int nr_events; //表明一共执行了多少次hrtimer_interrupt中断处理程序。
212 unsigned short nr_retries; //表明在执行hrtimer_interrupt中断处理程序的时候对定时事件设备编程错误后重试的次数。
213 unsigned short nr_hangs; //表明在执行hrtimer_interrupt中断处理程序的时候发生错误的次数。
214 unsigned int max_hang_time;//表明在碰到错误后,在hrtimer_interrupt中断处理程序中停留的最长时间。
215 #endif
216 ktime_t expires_next;//该CPU上即将要到期定时器的到期时间。
217 struct hrtimer *next_timer;//该CPU上即将要到期的定时器。
218 ktime_t softirq_expires_next;//该CPU上即将要到期的“软”定时器的到期时间
219 struct hrtimer *softirq_next_timer;//该CPU上即将要到期的“软”定时器。
220 struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];//高分辨率定时器的到期时间可以基于以下几种时间类型,clock_base数组为每种时间基准系统都定义了一个hrtimer_clock_base结构体:
/*
161 enum hrtimer_base_type {
162 HRTIMER_BASE_MONOTONIC,
163 HRTIMER_BASE_REALTIME,
164 HRTIMER_BASE_BOOTTIME,
165 HRTIMER_BASE_TAI,
166 HRTIMER_BASE_MONOTONIC_SOFT,
167 HRTIMER_BASE_REALTIME_SOFT,
168 HRTIMER_BASE_BOOTTIME_SOFT,
169 HRTIMER_BASE_TAI_SOFT,
170 HRTIMER_MAX_CLOCK_BASES,
171 };
*/
221 } ____cacheline_aligned;
没有加 SOFT 后缀的,表示是“硬”定时器,将直接在中断处理程序中处理;而加了SOFT后缀的,表示是“软”定时器,将在软中断(HRTIMER_SOFTIRQ)中处理。而且前面的一半都定义成“硬”定时器类型,后面一半都定义成“软”定时器类型,硬的一半和软的一半申明的次序也是对应的。这样设计就方便根据“硬”“软”特性和时间类型很快查出对应 hrtimer_clock_base 结构体的下标。
所以,综上所述,高分辨率定时器层的组织相对来说还是比较简单的,甚至比(低分辨率)定时器层还要简单。每个CPU对应有一个 hrtimer_cpu_base 的 Per CPU 结构体变量,其定义如下:
2.6.32内核
80 /**
81 * struct hrtimer - the basic hrtimer structure
82 * @node: red black tree node for time ordered insertion
83 * @_expires: the absolute expiry time in the hrtimers internal
84 * representation. The time is related to the clock on
85 * which the timer is based. Is setup by adding
86 * slack to the _softexpires value. For non range timers
87 * identical to _softexpires.
//hrtimers内部表示形式中的绝对过期时间。时间与计时器所基于的时钟有关。通过向_softexpires值添加slack来设置。通过hrtimer_set_expires_range设置
//硬过期时间(hard)
88 * @_softexpires: the absolute earliest expiry time of the hrtimer.
89 * The time which was given as expiry time when the timer
90 * was armed.
91 * @function: timer expiry callback function
92 * @base: pointer to the timer base (per cpu and per clock)
93 * @state: state information (See bit values above)
100 *
101 * The hrtimer structure must be initialized by hrtimer_init()
102 */
103 struct hrtimer {
104 struct rb_node node;
105 ktime_t _expires;
106 ktime_t _softexpires;
107 enum hrtimer_restart (*function)(struct hrtimer *);
108 struct hrtimer_clock_base *base;
109 unsigned long state;
/*
* Values to track state of the timer
*
* Possible states:
*
* 0x00 inactive
* 0x01 enqueued into rbtree
* 0x02 callback function running
*
* Special cases:
* 0x03 callback function running and enqueued
* (was requeued on another CPU)
* 0x09 timer was migrated on CPU hotunplug
* The "callback function running and enqueued" status is only possible on
* SMP. It happens for example when a posix timer expired and the callback
* queued a signal. Between dropping the lock which protects the posix timer
* and reacquiring the base lock of the hrtimer, another CPU can deliver the
* signal and rearm the timer. We have to preserve the callback running state,
* as otherwise the timer could be removed before the softirq code finishes the
* the handling of the timer.
*
* The HRTIMER_STATE_ENQUEUED bit is always or'ed to the current state to
* preserve the HRTIMER_STATE_CALLBACK bit in the above scenario.
*
* All state transitions are protected by cpu_base->lock.
#define HRTIMER_STATE_INACTIVE 0x00
#define HRTIMER_STATE_ENQUEUED 0x01
#define HRTIMER_STATE_CALLBACK 0x02
#define HRTIMER_STATE_MIGRATE 0x04
*/
115 };
/**
* struct hrtimer_clock_base - the timer base for a specific clock
* @cpu_base: per cpu clock base
* @index: clock type index for per_cpu support when moving a
* timer to a base on another cpu.
* @active: red black tree root node for the active timers
* @first: pointer to the timer node which expires first
* @resolution: the resolution of the clock, in nanoseconds
* @get_time: function to retrieve the current time of the clock
* @softirq_time: the time when running the hrtimer queue in the softirq
* @offset: offset of this clock to the monotonic base
*/
struct hrtimer_clock_base {
struct hrtimer_cpu_base *cpu_base;
clockid_t index;
struct rb_root active;
struct rb_node *first;//最先到期的定时器node
ktime_t resolution;//精度单位 ns
ktime_t (*get_time)(void);
ktime_t softirq_time;//粗力度的软中断时间//不同的clock_base代表不同的意义
//monotonic启动 时间。不包含休眠的时间//real:墙上时间
ktime_t offset;
};
#define __get_cpu_var(var) \
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), my_cpu_offset)) ---》
#define per_cpu_var(var) per_cpu__##var
define SHIFT_PERCPU_PTR(__p, __offset) RELOC_HIDE((__p), (__offset))
#define my_cpu_offset __my_cpu_offset ---》 __per_cpu_offset[raw_smp_processor_id()]
#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id())
#define per_cpu_offset(x) (__per_cpu_offset[x])
unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
./mm/percpu.c: __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
/* 此宏用于直接将数值相加 */
https://www.cnblogs.com/zhangzhiwei122/p/16053900.html
#define RELOC_HIDE(ptr, off) \
({
unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
/*
* The timer bases:
*
* Note: If we want to add new timer bases, we have to skip the two
* clock ids captured by the cpu-timers. We do this by holding empty
* entries rather than doing math adjustment of the clock ids.
* This ensures that we capture erroneous accesses to these clock ids
* rather than moving them into the range of valid clock id's.
*/
#define DEFINE_PER_CPU(type, name) \
DEFINE_PER_CPU_SECTION(type, name, "")
#define DEFINE_PER_CPU_SECTION(type, name, sec) \
__PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES \
__typeof__(type) per_cpu__##name
#define __PCPU_ATTRS(sec) \
__attribute__((section(PER_CPU_BASE_SECTION sec))) \ //#define PER_CPU_BASE_SECTION ".data.percpu"
PER_CPU_ATTRIBUTES //#define PER_CPU_ATTRIBUTES
/*
attribute(section) 是一个 GCC 编译器的扩展,它允许开发人员把编译的代码放到指定的内存段中。这个特性常常用于在程序中定义常量数组,将它们放在 ROM 中,从而节省 RAM 空间。
使用方法是在变量或函数前面加上 attribute((section("section_name"))),section_name 是你希望把代码放到哪个内存段的名字。例如:
int foo __attribute__((section("foo_section"))) = 0;
1
2
这样,编译器会把 foo 变量放到名为 "foo_section" 的内存段中
*/
__attribute__((section(".data.percpu" ""))) __typeof__(struct hrtimer_cpu_base) per_cpu__hrtimer_bases =
{
.clock_base =
{
{
.index = 0,
.get_time = &ktime_get_real,
.resolution = (ktime_t){
.tv64 = (( (((1000000UL * 1000) / ((( (((1193182) / (((1193182 + 250/2) / 250))) << (8)) + ((((1193182) % (((1193182 + 250/2) / 250))) << (8)) + (((1193182 + 250/2) / 250)) / 2) / (((1193182 + 250/2) / 250)))))) << (8)) + ((((1000000UL * 1000) % ((( (((1193182) / (((1193182 + 250/2) / 250))) << (8)) + ((((1193182) % (((1193182 + 250/2) / 250))) << (8)) + (((1193182 + 250/2) / 250)) / 2) / (((1193182 + 250/2) / 250)))))) << (8)) + ((( (((1193182) / (((1193182 + 250/2) / 250))) << (8)) + ((((1193182) % (((1193182 + 250/2) / 250))) << (8)) + (((1193182 + 250/2) / 250)) / 2) / (((1193182 + 250/2) / 250))))) / 2) / ((( (((1193182) / (((1193182 +