might_sleep 分析

might_sleep()用于调试在不预期睡眠的地方是否会正的睡眠
#ifdef CONFIG_PREEMPT_VOLUNTARY
extern int _cond_resched(void);
# define might_resched() _cond_resched()
#else
# define might_resched() do { } while (0)
#endif

#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
  void ___might_sleep(const char *file, int line, int preempt_offset);
  void __might_sleep(const char *file, int line, int preempt_offset);
/**
 * might_sleep - annotation for functions that can sleep
 *
 * this macro will print a stack trace if it is executed in an atomic
 * context (spinlock, irq-handler, ...).
 *
 * This is a useful debugging help to be able to catch problems early and not
 * be bitten later when the calling function happens to sleep when it is not
 * supposed to.
 */
# define might_sleep() \
	do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
# define sched_annotate_sleep()	(current->task_state_change = 0)
#else
  static inline void ___might_sleep(const char *file, int line,
				   int preempt_offset) { }
  static inline void __might_sleep(const char *file, int line,
				   int preempt_offset) { }
# define might_sleep() do { might_resched(); } while (0)
# define sched_annotate_sleep() do { } while (0)
#endif
可以看到如果没有定义CONFIG_DEBUG_ATOMIC_SLEEP的话,might_sleep就是一个空函数,所以平常看code的时候可以忽略。
如果定义的CONFIG_DEBUG_ATOMIC_SLEEP的话,如果在包含might_sleep的函数中睡眠了,则会打印当前的callstack,具体分析如下:
void __might_sleep(const char *file, int line, int preempt_offset)
{
	/*
	 * Blocking primitives will set (and therefore destroy) current->state,
	 * since we will exit with TASK_RUNNING make sure we enter with it,
	 * otherwise we will destroy state.
	 */
//首先打印警告印象
	WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change,
			"do not call blocking ops when !TASK_RUNNING; "
			"state=%lx set at [<%p>] %pS\n",
			current->state,
			(void *)current->task_state_change,
			(void *)current->task_state_change);
//继续调用___might_sleep
	___might_sleep(file, line, preempt_offset);
}
void ___might_sleep(const char *file, int line, int preempt_offset)
{
	
//调用dump_stack 打印callstack
	dump_stack();
	add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
}


LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void) { TIMER_TRACE("begin"); /*Avoid concurrent running of the timer handler*/ static bool already_running = false; if(already_running) { TIMER_TRACE("already running, concurrent calls are not allow, returning"); return 1; } already_running = true; if(lv_timer_run == false) { already_running = false; /*Release mutex*/ return 1; } static uint32_t idle_period_start = 0; static uint32_t busy_time = 0; uint32_t handler_start = lv_tick_get(); if(handler_start == 0) { static uint32_t run_cnt = 0; run_cnt++; if(run_cnt > 100) { run_cnt = 0; LV_LOG_WARN("It seems lv_tick_inc() is not called."); } } /*Run all timer from the list*/ lv_timer_t * next; do { timer_deleted = false; timer_created = false; LV_GC_ROOT(_lv_timer_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); while(LV_GC_ROOT(_lv_timer_act)) { /*The timer might be deleted if it runs only once ('repeat_count = 1') *So get next element until the current is surely valid*/ next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), LV_GC_ROOT(_lv_timer_act)); if(lv_timer_exec(LV_GC_ROOT(_lv_timer_act))) { /*If a timer was created or deleted then this or the next item might be corrupted*/ if(timer_created || timer_deleted) { TIMER_TRACE("Start from the first timer again because a timer was created or deleted"); break; } } LV_GC_ROOT(_lv_timer_act) = next; /*Load the next timer*/ } } while(LV_GC_ROOT(_lv_timer_act)); uint32_t time_till_next = LV_NO_TIMER_READY; next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll)); while(next) { if(!next->paused) { uint32_t delay = lv_timer_time_remaining(next); if(delay < time_till_next) time_till_next = delay; } next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/ } busy_time += lv_tick_elaps(handler_start); uint32_t idle_period_time = lv_tick_elaps(idle_period_start); if(idle_period_time >= IDLE_MEAS_PERIOD) { idle_last = (busy_time * 100) / idle_period_time; /*Calculate the busy percentage*/ idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/ busy_time = 0; idle_period_start = lv_tick_get(); } already_running = false; /*Release the mutex*/ TIMER_TRACE("finished (%d ms until the next timer call)", time_till_next); return time_till_next; }
最新发布
03-25
<think>嗯,用户问的是关于LVGL中的lv_timer_handler函数,具体是uint32_t lv_timer_handler(void)这个函数的解析。首先,我需要回忆一下LVGL的定时器机制。LVGL使用定时器来处理周期性任务或者延时任务,比如动画、界面更新等。这个函数应该是负责执行所有注册的定时器任务,并返回下一个需要执行的时间间隔。 看代码结构,首先函数内部有一个静态变量already_running,用来防止重入,确保同一时间只有一个定时器处理程序在运行。如果已经在运行,就直接返回1。然后检查lv_timer_run是否为false,如果是的话也释放互斥锁并返回。这可能是一个全局控制变量,用来暂停所有定时器的执行。 接下来是idle_period_start和busy_time这两个静态变量,看起来是用来统计处理器的忙碌时间和空闲时间,计算空闲百分比。这部分可能用于性能监控或者功耗管理。 然后进入一个do-while循环,遍历定时器链表,执行每个定时器的回调函数。这里有个timer_deleted和timer_created的标志,如果在执行过程中有定时器被删除或创建,就会中断当前循环,重新从头开始遍历,防止链表结构变化导致的错误。 之后,计算下一个定时器需要执行的时间间隔time_till_next,遍历链表找出最近要触发的定时器,返回这个时间。如果所有定时器都暂停或者没有定时器,返回LV_NO_TIMER_READY,可能是一个宏定义的值,比如0或者最大值。 最后,更新空闲时间的统计,释放互斥锁,记录日志并返回下一个定时器的时间间隔。 用户可能是在开发中使用LVGL时遇到了定时器相关的问题,或者想了解内部机制以优化性能。需要确保解释清楚各个部分的作用,比如互斥锁防止重入、定时器的遍历执行、时间计算和性能统计。同时,注意代码中的关键点,比如静态变量的使用、链表的遍历方式,以及如何处理定时器的创建和删除。 要确保用中文清晰解释每个部分的功能,可能用户需要了解如何正确使用定时器,或者调试定时器不触发的问题。此外,还要提到返回值的意义,帮助用户理解如何处理这个函数的返回值,比如在任务调度中等待适当的时间再次调用。</think>该函数是LVGL轻量级图形库中的定时器处理核心,用于管理和执行所有注册的定时器任务。以下是关键逻辑分析: $$ \text{LVGL定时器处理流程图} \rightarrow \text{防重入检查} \rightarrow \text{执行定时器} \rightarrow \text{计算下次触发时间} $$ ### 一、防重入机制 1. 通过`already_running`静态变量实现互斥锁: ```c static bool already_running = false; if(already_running) return 1; // 防止递归调用 already_running = true; // 获取锁 ``` ### 二、定时器执行阶段 1. **链表遍历**:使用`_lv_ll_get_head`获取定时器链表头节点 2. **双重循环保障**: - `do-while`循环处理链表动态变化 - `while`循环遍历当前链表节点 3. **动态调整机制**: ```c if(timer_created || timer_deleted) break; // 检测到结构变化时重新遍历 ``` ### 三、定时器执行函数 调用`lv_timer_exec()`时: $$ \text{执行条件} = (\text{当前时间} \geq \text{最后执行时间} + \text{周期}) $$ 若条件满足,则执行回调函数并更新最后执行时间戳。 ### 四、下次触发时间计算 1. 遍历所有定时器: ```c uint32_t delay = lv_timer_time_remaining(next); if(delay < time_till_next) time_till_next = delay; ``` 2. 返回值为最小剩余时间的定时器周期 ### 五、性能监控模块 1. 计算系统空闲率: $$ \text{空闲率} = 100\% - \frac{\text{忙碌时间}}{\text{测量周期}} \times 100\% $$ 2. 每`IDLE_MEAS_PERIOD`毫秒更新一次统计数据 ### 六、返回值说明 | 返回值 | 含义 | |---------|------| | 1 | 定时器未运行或存在并发调用 | | N | 下次定时器触发的毫秒数 | | LV_NO_TIMER_READY | 无活跃定时器 | 该函数需在系统主循环中定期调用,典型调用方式: ```c uint32_t sleep_time = lv_timer_handler(); lv_delay_ms(sleep_time); // 根据返回值进行休眠优化 ``` 注意:定时器精度取决于调用频率,建议在主循环中保持至少5-10ms的调用间隔以保证响应性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值