繁体   English   中英

中断和用户代码之间的以下“标志”变量访问是否安全?

[英]Is the following “flag” variable access safe between interrupt and user code?

我们继承了一个针对瑞萨RX231微控制器的项目,我一直在关注它。

该uC只有一条指令锁定总线的原子性(XCHG)。

因为处理器是访问RAM存储器的唯一组件(没有使用DMA或DTC),要操纵用户代码中与中断共享的变量,所以中断被禁用(在处理器状态字寄存器中)以获取访问时间,即

disable_interrupts(); /* set_psw(get_psw() & ~(1 << 16)); */
/* access or modify shared variables */
enable_interrupts();  /* set_psw(get_psw() | (1 << 16)); */

但是,还有“标志”在没有保护的情况下共享,这些标志在中断中设置并以下列方式在用户代码中轮询:

volatile unsigned char event_request_message = 0;
unsigned char condition_sending_message = 0;

#pragma interrupt
void on_request_message()
{
     ...
     event_request_message = 1; // mov.l   #0x3df5, r14
                                // mov.b   #1, [r14]
     ... 
}

void user_code()
{
     for(;;)
     {
         ...
         /* might be evaluated multiple times before transmit message is completed */
         if(event_request_message && !condition_sending_message) // mov.l   #0x3df5, r14
                                                                 // movu.b  [r14], r14
                                                                 // cmp     #0, r14
                                                                 // beq.b   0xfff8e17b <user_code+185>
                                                                 // mov.l   #0x5990, r14
                                                                 // movu.b  [r14], r14
                                                                 // cmp     #0, r14
                                                                 // bne.b   0xfff8e16f <user_code+173>
         {
              event_request_message = 0;     // mov.l   #0x3df5, r14  
                                             // mov.b   #0, [r14]                  
              condition_sending_message = 1; // mov.l   #0x5990, r14               
                                             // mov.b   #1, [r14]
              /* transmit message */ 
              ... 
         }
         ...
     }
}

在这种情况下,我对无保护(通过禁用用户代码中的中断)的理解是:

  • 要读取,设置或清除“标志”,总是使用两条指令,一条用于将存储器地址放入寄存器,另一条用于读取/设置/清除
  • 内存地址总是相同的,因此可以从中考虑丢弃
  • 然后,每个读取/设置/清除操作都是单个指令,因此访问/操作是原子的

问题是:我的理解是否正确? 在这种情况下,这样的“标志”变量是否可以访问和操作?
或者可能存在任何可能的错误/错误?

  • 假设使用的编译器和编译器选项始终相同。
  • 假设所描述的操作是访问/操作这些“标志”的唯一方式(设置为0或1,读取(所有显示在汇编代码中))(无添加,乘法等)

如果我们需要升级编译器或更改编译器选项怎么办?
这样简单的操作能不仅仅产生“一条指令”?

在没有防护的情况下使用这种“标志”的理由限制了中断被禁用的时间量。

查看代码逻辑,预期的行为是您可以请求一次或多次消息,但只能获得一个答案。

PS。 我尝试使用以下附加标签:“cc-rx”,“rxv2-instruction-set”,“rx231”。

根据您的目标,即您是仅为特定平台编写还是想确保可移植性,您需要记住以下几点:

  1. 启用优化后,只要操作的最终结果与单线程方案无法区分,许多编译器就会很乐意通过访问非易失性变量来重新排序对volatile变量的访问。 这意味着代码如下:

     int a = 0; volatile int b = 0; void interrupt_a(void) { a = b + 1; b = 0; // set b to zero when done } 

    可以由编译器重新排列为:

     load acc from [b] store 0 into [b] // set b to zero *before* updating a, to mess with you a bit add 1 to acc store acc into [a] 

    阻止优化编译器重新排序的方法是使两个变量都是易变的。 (如果可用,使用C11 _Atomicmemory_order_release商店和memory_order_acquire负载相对于非原子变量的操作来订购吧。)

    如果您使用的是多核uC,它可以对内存操作进行重新排序,因此这并不能解决问题,而实际的解决方案是为编译器和CPU发出一个栅栏,如果您关心其他人的观察者核心(或甚至在单核uC上的MMIO)。 单核或单线程上不需要硬件围栏指令,因为即使是无序执行CPU也会看到它自己的操作按程序顺序发生。

    同样,如果您使用特定嵌入式系统的工具链获得的编译器对栅栏一无所知,那么它很可能不会做这样的事情。 因此,您需要检查文档并检查已编译的程序集。

    例如, ARM文档声明处理器“允许”重新排序指令,程序员应注意添加内存屏障,但在此之后它还指出(在“实现细节”下)Cortex M处理器不重新排序指令。 但是,他们仍然坚持应该插入适当的障碍,因为它将简化移植到更新版本的处理器。

  2. 根据您的管道长度,在您发出请求后,可能需要几个指令才能完全启用或禁用中断。 同样,您需要检查此特定uC /编译器的文档,但有时在写入寄存器后需要有某种类型的栅栏。 例如,在ARM Cortex上,您需要在禁用中断后发出DSB和ISB指令,以确保中断不会在下几条指令中输入

     // you would have to do this on an ARM Cortex uC DisableIRQ(device_IRQn); // Disable certain interrupt by writing to NVIC_CLRENA DSB(); // data memory barrier ISB(); // instruction synchronization barrier // <-- this is where the interrupt is "really disabled" 

    当然,当你调用disable_interrupts();时,你的库本身可能包含所有必需的fence指令disable_interrupts(); ,或者对于这种架构可能根本不需要它们。

  3. 增值业务( x++ ), 应该被认为是原子的,甚至可能“不小心”变成是一定的单核CPU上的原子。 正如您所注意到的,它在您的特定uC上不是原子的,并且保证原子性的唯一方法是禁用此操作的中断。

因此,最终,您应该确保阅读此平台的文档,并了解编译器可以做什么和不可以做什么。 如果编译器在您添加了看似微小的更改之后决定重新排序指令,那么今天有用的东西可能明天不起作用,特别是因为竞争条件可能不够频繁而无法立即检测到它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM