dler(void *unused)
2 {
3 ARG_UNUSED(unused);
4
5 sys_trace_isr_enter();
6
7 /* accumulate total counter value */
8 clock_accumulated_count += sys_clock_hw_cycles_per_tick;
9
10 /*
11 * one more tick has occurred -- don't need to do anything special since
12 * timer is already configured to interrupt on the following tick
13 */
14 _sys_clock_tick_announce();
15
16 extern void _ExcExit(void);
17 _ExcExit();
18 }
第8行,累加系统启动后经历了多少个时钟计数,注意这里不是累加系统ticks的个数,因为累加时钟计数会更加精确。
第14行,调用_sys_clock_tick_announce()函数,定义在zephyr-zephyr-v1.13.0\include\drivers\ system_timer.h:
#define _sys_clock_tick_announce() \
_nano_sys_clock_tick_announce(_sys_idle_elapsed_ticks)
在没有使能TICKLESS_KERNEL配置的情况下参数_sys_idle_elapsed_ticks的值为1,实际上调用的是_nano_sys_clock_tick_announce()函数,定义在zephyr-zephyr-v1.13.0\kernel\ sys_clock.c:
1 void _nano_sys_clock_tick_announce(s32_t ticks)
2 {
3 unsigned int key;
4
5 K_DEBUG("ticks: %d\n", ticks);
6
7 /* 64-bit value, ensure atomic access with irq lock */
8 key = irq_lock();
9 _sys_clock_tick_count += ticks;
10 irq_unlock(key);
11
12 handle_timeouts(ticks);
13
14 /* time slicing is basically handled like just yet another timeout */
15 handle_time_slicing(ticks);
16}
第9行,累加系统启动后所经历的ticks个数。
在分析第12行的handle_timeouts()函数之前,先说一下线程加入到超时队列的过程。线程通过调用k_sleep()等函数后,系统会将该线程加入到超时队列里,然后调度其他线程。k_sleep()对应的实现函数为_impl_k_sleep(),定义在zephyr-zephyr-v1.13.0\kernel\ sched.c:
1 void _impl_k_sleep(s32_t duration)
2 {
3 /* volatile to guarantee that irq_lock() is executed after ticks is
4 * populated
5 */
6 volatile s32_t ticks;
7 unsigned int key;
8
9 __ASSERT(!_is_in_isr(), "");
10 __ASSERT(duration != K_FOREVER, "");
11
12 K_DEBUG("thread %p for %d ns\n", _current, duration);
13
14 /* wait of 0 ms is treated as a 'yield' */
15 if (duration == 0) {
16 k_yield();
17 return;
18 }
19
20 ticks = _TICK_ALIGN + _ms_to_ticks(duration);
21 key = irq_lock();
22
23 _remove_thread_from_ready_q(_current);
24 _add_thread_timeout(_current, NULL, ticks);
25
26 _Swap(key);
27}
第15行,如果传进来的时参数为0,则直接调用k_yield()函数,切换到其他线程,具体实现的话在下一篇随笔里再分析。
第20行,_TICK_ALIGN的值为1,即将睡眠时间以tick为单位补齐。
第23行,调用_remove_thread_from_ready_q()函数,定义在zephyr-zephyr-v1.13.0\kernel\ sched.c:
1 void _remove_thread_from_ready_q(struct k_thread *thread)
2 {
3 LOCKED(&sched_lock) {
4 if (_is_thread_queued(thread)) {
5 _priq_run_remove(&_kernel.ready_q.runq, thread);
6 _mark_thread_as_not_queued(thread);
7 update_cache(thread == _current);
8 }
9 }
10 }
第4行,线程能够运行,那它的状态必须是已经_THREAD_QUEUED了的。
第5行,将线程从运行队列移除,那么线程就不会参与线程调度了。
第6行,设置线程状态不为_THREAD_QUEUED。
第7行,调用update_cache()函数,在上一篇随笔已经分析过了,这里不再重复。
回到_impl_k_sleep()函数,第24行,调用_add_thread_timeout()函数,定义在zephyr-zephyr-v1.13.0\kernel\include\timeout_q.h:
1 static inline void _add_thread_timeout(struct k_thread *thread,
2 _wait_q_t *wait_q,
3 s32_t timeout_in_ticks)
4 {
5 _add_timeout(thread, &thread->base.timeout, wait_q, timeout_in_ticks);
6 }
实际上调用的是_add_timeout()函数,定义在zephyr-zephyr-v1.13.0\kernel\include\timeout_q.h:
1 static inline void _add_timeout(struct k_thread *thread,
2 struct _timeout *timeout,
3 _wait_q_t *wait_q,
4 s32_t timeout_in_ticks)
5 {