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

目录

一、让出调度函数
二、测试代码
三、总结

根据之前的理解,rtems可以在一定条件下主动调度,同样的,也可以在某些条件下调用yield,让出调度。这种让出和主动调度不一样的点在于,让出调度是将当前任务挂起一段时间(以系统时钟滴答 ticks 为单位),使其进入延迟状态,并在指定时间后自动唤醒并恢复就绪状态。

一、让出调度函数

让出调度通过函数_Scheduler_Yield实现,其实先基于_Scheduler_Schedule,但与其不同的是,schedule不会修改就绪队列,而yield会将自己任务从就绪队列删除, 然后从tail再次加入。这样每次调用yield的情况下,自身任务永远在队尾

二、测试代码

让出调度可以在多个场景下测试,只要能够体现让出调度相比于主动调度情况下,让出调度会将自己就绪队列拿出并重新插入。本文还是基于信号的测试来验证让出调度。其函数为

rtems_status_code rtems_task_wake_after( rtems_interval ticks ) { /* * It is critical to obtain the executing thread after thread dispatching is * disabled on SMP configurations. */ Thread_Control *executing; Per_CPU_Control *cpu_self; cpu_self = _Thread_Dispatch_disable(); executing = _Per_CPU_Get_executing( cpu_self ); if ( ticks == 0 ) { _Thread_Yield( executing ); } else { _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 ); } _Thread_Dispatch_direct( cpu_self ); return RTEMS_SUCCESSFUL; }

可以看到,如果ticks不为0,及时等待,如为0,则开始让出。根据上面的代码展示,其测试代码如下

rtems_asr Process_asr( rtems_signal_set the_signal_set ) { rtems_status_code status; printf( "ASR - ENTRY - signal => %08" PRIxrtems_signal_set "\n", the_signal_set ); switch( the_signal_set ) { case RTEMS_SIGNAL_16: case RTEMS_SIGNAL_17: case RTEMS_SIGNAL_18 | RTEMS_SIGNAL_19: break; case RTEMS_SIGNAL_0: case RTEMS_SIGNAL_1: puts( "ASR - rtems_task_wake_after - yield processor" ); status = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ); directive_failed( status, "rtems_task_wake_after yield" ); break; case RTEMS_SIGNAL_3: Asr_fired = TRUE; break; } printf( "ASR - EXIT - signal => %08" PRIxrtems_signal_set "\n", the_signal_set ); }

此代码需要结合RTEMS调度器-主动调度的测试代码,此文章仅提供了信号回调函数Process_asr的实现

可以发现,对于0,1信号,默认会让出cpu,从而使得其他task正常运行。

为了体现两个task之间的相互让出,测试代码可以在task2上发送信号并主动让出,如下

rtems_task Task_2( rtems_task_argument argument ) { rtems_status_code status; puts( "TA2 - rtems_signal_send - RTEMS_SIGNAL_17 to TA1" ); status = rtems_signal_send( Task_id[ 1 ], RTEMS_SIGNAL_17 ); directive_failed( status, "rtems_signal_send" ); puts( "TA2 - rtems_task_wake_after - yield processor" ); status = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ); directive_failed( status, "rtems_task_wake_after" ); puts("TA2 - rtems_signal_send - RTEMS_SIGNAL_18 and RTEMS_SIGNAL_19 to TA1"); status = rtems_signal_send( Task_id[ 1 ], RTEMS_SIGNAL_18 | RTEMS_SIGNAL_19 ); directive_failed( status, "rtems_signal_send" ); TEST_END(); rtems_test_exit( 0 ); }

可以发现,task2会发送signal 17,然后主动让出后再发送信号18和19.我们查看运行后的日志

TA1 - rtems_signal_catch - RTEMS_INTERRUPT_LEVEL( 0 ) TA1 - rtems_signal_send - RTEMS_SIGNAL_16 to self ASR - ENTRY - signal => 00010000 ASR - EXIT - signal => 00010000 TA1 - rtems_signal_send - RTEMS_SIGNAL_0 to self ASR - ENTRY - signal => 00000001 ASR - rtems_task_wake_after - yield processor TA2 - rtems_signal_send - RTEMS_SIGNAL_17 to TA1 TA2 - rtems_task_wake_after - yield processor ASR - ENTRY - signal => 00020000 ASR - EXIT - signal => 00020000 ASR - EXIT - signal => 00000001

上面日志可以发现,TA1默认发送RTEMS_SIGNAL_0 后,主动让出了,然后此时TA2任务得到执行,如上发送信号RTEMS_SIGNAL_17 to TA1,然后TA2主动让出,此时Process_asr的顺序是

先发送RTEMS_SIGNAL_1,在RTEMS_SIGNAL_0中,主动让出了,所以有日志 ENTRY - signal => 00000001 。等RTEMS_SIGNAL_17 发送完成后 asr handler得到日志ASR - ENTRY - signal => 00020000 和ASR - EXIT - signal => 00020000 。最后因为让出调度会插入调度队列的tail,所以最后打印

ASR - EXIT - signal => 00000001

三、总结

至此,根据上面的测试代码和测试日志,可以非常清楚的了解了主动调度的逻辑。主动调度会放弃cpu,并将自己插入就绪队列的尾部。