Appearance
资源管理
独占的访问临界资源有三种方式
- 公平竞争: 使用互斥量, 谁先获得谁就使用
- 屏蔽中断
- 屏蔽任务切换
屏蔽中断
屏蔽中断有两套宏:任务中使用、ISR中使用:
c
任务中使用: taskENTER_CRITICA()/taskEXIT_CRITICAL()
ISR中使用:taskENTER_CRITICAL_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR()
低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
这个宏会操作中断屏蔽寄存器, stm32只使用了八位寄存器的高四位
- 但是,这些中断ISR里,不允许使用FreeRTOS的API函数(这些中断需要在上面的宏的范围里面)
任务调度依赖于中断、依赖于API函数,所以:这两段代码之间,不会有任务调度产生
c
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
* section. */
/* *INDENT-OFF* */
msr basepri, ulNewBASEPRI //设置这个寄存器设置屏蔽的等级
dsb
isb
/* *INDENT-ON* */
}
}
- 在中断中使用
c
void vAnInterruptServiceRoutine( void )
{
/* 用来记录当前中断是否使能 */
UBaseType_t uxSavedInterruptStatus;
/* 在ISR中,当前时刻中断可能是使能的,也可能是禁止的
* 所以要记录当前状态, 后面要恢复为原先的状态
* 执行这句代码后,屏蔽中断
*/
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
/* 访问临界资源 */
/* 恢复中断状态 */
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
/* 现在,当前ISR可以被更高优先级的中断打断了 */
}
在屏蔽以后需要保持当前函数的状态, 返回的是当前的屏蔽的等级, 默认设置的是11优先级
禁止任务调度
直接暂停调度器就可以了
c
/* 暂停调度器 */
void vTaskSuspendAll( void );
/* 恢复调度器
* 返回值: pdTRUE表示在暂定期间有更高优先级的任务就绪了
* 可以不理会这个返回值
*/
BaseType_t xTaskResumeAll( void );
c
void vTaskSuspendAll( void )
{
/* A critical section is not required as the variable is of type
* BaseType_t. Please read Richard Barry's reply in the following link to a
* post in the FreeRTOS support forum before reporting this as a bug! -
* https://goo.gl/wu4acr */
/* portSOFRWARE_BARRIER() is only implemented for emulated/simulated ports that
* do not otherwise exhibit real time behaviour. */
portSOFTWARE_BARRIER();
/* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
* is used to allow calls to vTaskSuspendAll() to nest. */
++uxSchedulerSuspended;//主要就是这一个全局变量
/* Enforces ordering for ports and optimised compilers that may otherwise place
* the above increment elsewhere. */
portMEMORY_BARRIER();
}
这些个函数可以进行递归使用, 内部会记录嵌套的深度, 只有深度为0的时候, taskEXIT_CRITICAL()才会重新使能中断