#shared-memory #memory-region #queue #communication #cortex-m4 #write

no-std shared-mem-queue

一个单写单读队列,可用于在共享内存区域中进行处理器间通信

1 个不稳定版本

0.1.0 2024年2月16日

#378嵌入式开发


memcom 中使用

OLFL-1.3

18KB
109 代码行

shared-mem-queue

此库实现了一个简单的单写单读队列,可用于在共享内存区域中进行处理器间通信。最初,它被开发为一个简单的解决方案,具有最小的开销,用于在STM32MP1微处理器上的Cortex-M4和Cortex-A7之间进行通信,但它也可以用于不同的场景。

实现细节

队列在共享内存区域上运行,并跟踪一个写指针和一个读指针。为了从两个处理器中访问这两个指针,写指针和读指针存储在共享内存区域本身中,因此队列的容量小于内存区域的大小 2*size_of::<usize>()

这里的主要合同是只有写者可以写入写指针,只有读者可以写入读指针,写指针前面的内存区域和直到读指针的区域归写者所有,读指针前面的内存区域和直到写指针的区域归读者所有。为了初始化,两个指针必须一开始都设置为0。这违反了合同,因此必须在处理器A初始化队列时,保证处理器B尚未访问队列,以防止竞态条件。

因为处理器A必须初始化队列,而处理器B不应重置写指针和读指针,因此有两种初始化方法:第一个处理器应调用 create() 将两个指针都设置为0,第二个处理器应调用 attach()

SharedMemQueue 实现了读写方法,但每个处理器都应该分配给它写入端或读取端,并且不能调用其他方法。也可以有 SharedMemWriterSharedMemReader,但这种设计最初选择是为了使队列也可以在单个处理器上作为简单的环形缓冲区使用。

使用示例

单处理器环形缓冲区

let mut buffer = [0u8; 100];
let mut queue = unsafe { SharedMemQueue::create(buffer.as_mut_ptr(), 100) };
let tx = [1, 2, 3, 4];
queue.blocking_write(&tx);
let mut rx = [0u8; 4];
queue.blocking_read(&mut rx);
assert_eq!(&tx, &rx);

单处理器队列

一个更现实的例子是分别创建读取器和写入器

let mut buffer = [0u8; 100];
let mut writer = unsafe { SharedMemQueue::create(buffer.as_mut_ptr(), 100) };
let mut reader = unsafe { SharedMemQueue::attach(buffer.as_mut_ptr(), 100) };
let tx = [1, 2, 3, 4];
writer.blocking_write(&tx);
let mut rx = [0u8; 4];
reader.blocking_read(&mut rx);
assert_eq!(&tx, &rx);

共享内存队列

通常,从Linux系统访问队列需要调用 mmap。这可以使用 memmap crate 完成。以下示例在无脑执行时可能会崩溃,因为访问 /dev/mem 需要 root 权限。此外,使用的示例区域在大多数系统中可能不适合此队列

let shared_mem_start = 0x10048000; // example
let shared_mem_len = 0x00008000;   // region
let dev_mem = std::fs::OpenOptions::new()
    .read(true)
    .write(true)
    .open("/dev/mem")
    .expect("Could not open /dev/mem, do you have root privileges?");
let mut mmap = unsafe {
    memmap::MmapOptions::new()
        .len(shared_mem_len)
        .offset(shared_mem_start.try_into().unwrap())
        .map_mut(&dev_mem)
        .unwrap()
};
let mut channel = unsafe {
    SharedMemQueue::attach(mmap.as_mut_ptr(), shared_mem_len)
};

双向共享内存通信

在大多数处理器间通信场景中,双向通信需要两个队列。一个 mmap 调用就足够了,之后可以手动拆分内存区域

let shared_mem_start = 0x10048000; // example
let shared_mem_len = 0x00008000;   // region
let dev_mem = std::fs::OpenOptions::new()
    .read(true)
    .write(true)
    .open("/dev/mem")
    .expect("Could not open /dev/mem, do you have root privileges?");
let mut mmap = unsafe {
    memmap::MmapOptions::new()
        .len(shared_mem_len)
        .offset(shared_mem_start.try_into().unwrap())
        .map_mut(&dev_mem)
        .unwrap()
};
let mut channel_write = unsafe {
    SharedMemQueue::attach(mmap.as_mut_ptr(), shared_mem_len / 2)
};
let mut channel_read = unsafe {
    SharedMemQueue::attach(mmap.as_mut_ptr().add(shared_mem_len / 2), shared_mem_len / 2)
};

许可证

开放物流基金会许可证
版本 1.3,2023 年 1 月

请参阅顶级目录中的 LICENSE 文件。

联系方式

弗劳恩霍夫 IML 嵌入式 Rust 组 - [email protected]

无运行时依赖