编辑
2025-04-03
工作知识
0
请注意,本文编写于 64 天前,最后修改于 64 天前,其中某些信息可能已经过时。

目录

一、测试程序
二、代码解析
三、测试结果
四、结果

还是基于rtems_task_wake_after的测试例子,如果我们设置tick不为0,那么线程将进行休眠等待。当等待事件超过,会主动触发thread unlock,此时会调用调度器的_Scheduler_Unblock函数。本文延续之前的测试例子,演示一下rtems的恢复阻塞调度函数

一、测试程序

还是在rtems_task_wake_after中,我们原子的设置了thread的flag,然后设置了ticks的timeout 如下

_Thread_Set_state( executing, STATES_WAITING_FOR_TIME ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); _Thread_Add_timeout_ticks( executing, cpu_self, ticks );

二、代码解析

对于设置timeout,我们可以看到函数回调_Thread_Timeout,如下

static inline void _Thread_Add_timeout_ticks( Thread_Control *the_thread, Per_CPU_Control *cpu, Watchdog_Interval ticks ) { ISR_lock_Context lock_context; _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context ); the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_TICKS ]; the_thread->Timer.Watchdog.routine = _Thread_Timeout; _Watchdog_Per_CPU_insert_ticks( &the_thread->Timer.Watchdog, cpu, ticks ); _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context ); }

_Thread_Timeout函数如下

void _Thread_Timeout( Watchdog_Control *the_watchdog ) { Thread_Control *the_thread; the_thread = RTEMS_CONTAINER_OF( the_watchdog, Thread_Control, Timer.Watchdog ); _Thread_Continue( the_thread, STATUS_TIMEOUT ); }

当超时的时候,就会进入关键函数_Thread_Continue,如下

void _Thread_Continue( Thread_Control *the_thread, Status_Control status ) { Thread_queue_Context queue_context; Thread_Wait_flags wait_flags; bool unblock; _Thread_queue_Context_initialize( &queue_context ); _Thread_queue_Context_clear_priority_updates( &queue_context ); _Thread_Wait_acquire( the_thread, &queue_context ); wait_flags = _Thread_Wait_flags_get( the_thread ); if ( wait_flags != THREAD_WAIT_STATE_READY ) { Thread_Wait_flags wait_class; bool success; _Thread_Wait_cancel( the_thread, &queue_context ); the_thread->Wait.return_code = status; wait_class = wait_flags & THREAD_WAIT_CLASS_MASK; success = _Thread_Wait_flags_try_change_release( the_thread, wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK, THREAD_WAIT_STATE_READY ); if ( success ) { unblock = false; } else { _Assert( _Thread_Wait_flags_get( the_thread ) == ( wait_class | THREAD_WAIT_STATE_BLOCKED ) ); _Thread_Wait_flags_set( the_thread, THREAD_WAIT_STATE_READY ); unblock = true; } } else { unblock = false; } _Thread_Wait_release( the_thread, &queue_context ); _Thread_Priority_update( &queue_context ); if ( unblock ) { _Thread_Wait_tranquilize( the_thread ); _Thread_Unblock( the_thread ); #if defined(RTEMS_MULTIPROCESSING) if ( !_Objects_Is_local_id( the_thread->Object.id ) ) { _Thread_MP_Free_proxy( the_thread ); } #endif } }

这里我们清楚的看到wait_flags != THREAD_WAIT_STATE_READY 如果线程不是就绪态,则通过等待success = _Thread_Wait_flags_try_change_release,如果原子操作成功,则设置线程为就绪态,_Thread_Wait_flags_set( the_thread, THREAD_WAIT_STATE_READY );。

在设置线程的就绪态之后,会将unblock标准设置为true。unblock = true; 这样,最后根据此标志位调用_Thread_Unblock( the_thread );

_Thread_Unblock的调用流程是:_Thread_Unblock--->_Thread_Clear_state--->_Thread_Clear_state_locked--->_Scheduler_Unblock

_Scheduler_Unblock的作用就是将本任务加入就绪队列。

三、测试结果

对于thread设置的timeout,其堆栈如下

#0 _Thread_Timeout (the_watchdog=0x105be0 <_RTEMS_tasks_Objects+2024>) at ../../../cpukit/score/src/threadtimeout.c:110 #1 0x0000000000022234 in _Watchdog_Do_tickle (header=header@entry=0x1023a8 <_Per_CPU_Information+808>, first=0x105be0 <_RTEMS_tasks_Objects+2024>, now=102, lock=lock@entry=0x102398 <_Per_CPU_Information+792>, lock_context=lock_context@entry=0x105178 <_ISR_Stack_area_begin+8056>) at ../../../cpukit/score/src/watchdogtick.c:66 #2 0x00000000000222f4 in _Watchdog_Tick (cpu=0x102080 <_Per_CPU_Information>) at ../../../cpukit/score/src/watchdogtick.c:105 #3 0x0000000000026c3c in rtems_timecounter_tick () at ../../../cpukit/include/rtems/timecounter.h:101 #4 Clock_driver_timecounter_tick (arg=<optimized out>) at ../../../bsps/aarch64/include/../../shared/dev/clock/clockimpl.h:124 #5 Clock_isr (arg=<optimized out>) at ../../../bsps/aarch64/include/../../shared/dev/clock/clockimpl.h:237 #6 0x0000000000026d9c in bsp_interrupt_dispatch_entries (entry=0x1026e8 <arm_gt_interrupt_entry>) at ../../../bsps/include/bsp/irq-generic.h:571 #7 bsp_interrupt_handler_dispatch_unchecked (vector=30) at ../../../bsps/include/bsp/irq-generic.h:627 #8 bsp_interrupt_dispatch () at ../../../bsps/shared/dev/irq/arm-gicv2.c:98 #9 0x0000000000029410 in .AArch64_Interrupt_Handler () at ../../../cpukit/score/cpu/aarch64/aarch64-exception-interrupt.S:87

当_Thread_Timeout 之后,其调用堆栈如下

#0 _Scheduler_priority_Unblock (scheduler=0x2d248 <_Scheduler_Table>, the_thread=0x1059e0 <_RTEMS_tasks_Objects+1512>, node=0x105de0 <_RTEMS_tasks_Objects+2536>) at ../../../cpukit/include/rtems/score/schedulerimpl.h:108 #1 0x0000000000025008 in _Scheduler_Unblock (the_thread=0x1059e0 <_RTEMS_tasks_Objects+1512>) at ../../../cpukit/include/rtems/score/schedulerimpl.h:344 #2 _Thread_Clear_state_locked (the_thread=the_thread@entry=0x1059e0 <_RTEMS_tasks_Objects+1512>, state=state@entry=805396479) at ../../../cpukit/score/src/threadclearstate.c:65 #3 0x0000000000025070 in _Thread_Clear_state (the_thread=the_thread@entry=0x1059e0 <_RTEMS_tasks_Objects+1512>, state=805396479) at ../../../cpukit/score/src/threadclearstate.c:81 #4 0x0000000000021b18 in _Thread_Unblock (the_thread=0x1059e0 <_RTEMS_tasks_Objects+1512>) at ../../../cpukit/include/rtems/score/threadimpl.h:1098 #5 _Thread_Continue (the_thread=0x1059e0 <_RTEMS_tasks_Objects+1512>, status=STATUS_TIMEOUT) at ../../../cpukit/score/src/threadtimeout.c:91

四、结果

至此,我们通过测试rtems_task_wake_after函数,将其设置了1s的timeout,可以验证调度器的 block和unblock。unblock会在超时函数之后,清楚block标志位后,直接调用_Scheduler_Unblock函数