将“易失性”缓冲区传递给不采用“易失性”的库函数

问题描述 投票:0回答:1

我有一个多处理器系统,具有用于通信的“共享”内存区域。在某些情况下,其中一个处理器需要处理共享内存中一些相当大的数据并将结果放回。 通常,我会使用

volatile
指针访问共享内存,以确保在收到指示时写入和读取数据,并且正确的数据对所有处理器都是可见的(考虑它不是缓存内存),但不幸的是,处理需要使用库函数来完成,而库的编写没有对共享内存进行任何特殊考虑(即不将
volatile
指针放在前面)。这是一个人工示例来说明:

struct request {
    size_t    data_size;
    uint8_t   data[MAX_REQ];
}

struct response {
    size_t    data_size;
    uint8_t   some_other_data[MAX_RESP];
}

volatile struct request req __attribute__((section(".shared_mem")));
volatile struct request resp __attribute__((section(".shared_mem")));

// The function that is provided by a library I have no control over
extern void library_function(uint8_t* data_in, size_t size_in, uint8_t* data_out, size_t size_out);


// The required usage
library_function(req.data_size, req.data, resp.data_size, req.some_other_data);
...... 

这显然会正确地给出类似于

的警告
expected 'uint8_t *' {aka 'unsigned char *'} but argument is of type 'volatile uint8_t *' {aka 'volatile unsigned char *'}
   20 | extern void library_function(uint8_t* data_in, size_t size_in, uint8_t* data_out, size_t size_out);

这是理所当然的。

首先,我没有完全了解代码可能出现的问题。由于该函数位于外部库中,编译器无法知道它对传递的缓冲区做了什么,因此可能永远不会优化调用。我想图书馆方面的优化不是一个问题。 LTO 是这里唯一潜在的麻烦制造者吗?
其次,如果确实存在潜在问题,但我的问题是,除了来回复制数据之外,是否有任何解决方法(不仅是警告,而且是内存未按预期正确访问的潜在问题)处理前后的本地缓冲区,并让函数使用本地内存(全局禁用优化也不是一个好的解决方案,此外我不确定它是否能提供任何保证)。

c gcc volatile
1个回答
0
投票

为什么您认为问题与链接或优化有关?该警告与这些步骤无关,并告诉您该类型缺少限定符。换句话说,您为函数提供了错误的类型。

在这种情况下,编译器向您发出警告肯定是在做正确的事情。当变量是易失性的时,这意味着它可以在任何地方更改 - 我们通常将事物定义为易失性,因为它们可以完全在程序运行的环境之外被硬件事件更改,例如通过引脚更改触发写入此变量的中断变量。

您应该确保任何此类变量始终由知道它是易失性的代码访问。然而,您正在调用的库函数不知道这一点。它将通过假设变量不是易失性的并且最终可能使用变量的过时值来优化。这甚至可能不在库构建的优化范围内 - 库代码本身可能被编写为最大限度地减少对该变量的读取,或者作者甚至可能在假设该变量不是易失性的情况下下意识地做出设计选择。易失性是一种特殊情况 - 主要假设是变量定义良好,以至于您的代码可以解释该变量发生的所有情况。

为了避免警告和问题,您应该将易失性值复制到常规变量中并使用它来调用函数。这样,您就可以确定地知道函数使用的值。如果函数执行期间值发生变化,原则上您可以检测到它并在您的应用程序需要时采取纠正措施。

© www.soinside.com 2019 - 2024. All rights reserved.