hrtimer

本文详细介绍了Linux内核中的hrtimer数据结构和API,包括hrtimer_init、hrtimer_set_expires等初始化及设置方法。同时,解析了nanosleep的调用过程,并详细阐述了hrtimer在低精度和高精度模式下的到期处理,展示了从低精度到高精度模式的转换过程。
摘要由CSDN通过智能技术生成

相关数据结构

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 + 
hrtimer的延迟可以通过hrtimer_start函数设置。该函数接受一个时间参数来指定延迟的时长,以及一个枚举类型的参数来指定定时器的模式。具体来说,hrtimer_start函数会在指定的时间后触发定时器,并根据模式的设置来确定触发的方式(绝对时间或相对时间)。 在原子上下文中,任务无法进入睡眠状态,也不能进行调度。因此,延迟必须在繁忙等待循环中使用。内核提供了一系列的Xdelay函数,可以在繁忙循环中消耗足够长的时间来实现所需的延迟。其中包括ndelay函数(用于纳秒延迟)、udelay函数(用于微秒延迟)和mdelay函数(用于毫秒延迟)。通过调用这些函数,可以在原子上下文中实现所需的延迟。 总结起来,可以通过hrtimer_start函数设置hrtimer的延迟,并在原子上下文中使用Xdelay函数实现所需的延迟。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [延迟和定时器管理](https://blog.csdn.net/qq_41683305/article/details/124765359)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [RK3588平台开发系列讲解(基础篇)延迟和定时器管理](https://blog.csdn.net/qq_33487044/article/details/130071687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值