处理全局变量的生存期



我目前正在为嵌入式板编写一个板支持包,并希望通过USB设置串行输出。我的设计基于hifiveBSP。

这个过程分为三个步骤:

  1. 设置USB总线(UsbBusAllocator,指的是一个UsbPeripheral)
  2. 初始化SerialPort实例,指UsbBusAllocator
  3. 初始化UsbDevice实例,它引用UsbBusAllocator

为了使我的生活更简单,我将SerialPortUsbDevice包装在SerialWrapper结构体中:

pub struct SerialWrapper<'a> {
port: SerialPort<'a, Usbd<UsbPeripheral<'a>>>,
dev: UsbDevice<'a, Usbd<UsbPeripheral<'a>>>,
}
impl<'a> SerialWrapper<'a> {
pub fn new(bus: &'a UsbPort<'a>) -> Self {
// create the wrapper ...
}
}

我想有一种方法使SerialWrapper::new创建的结构全局

我尝试使用:

static mut STDOUT: Option<SerialWrapper<'a>> = None;

但是我不能使用这个,因为生命周期'a没有声明。

我想使用MaybeUninitPhantomData,但两者仍然需要将SerialWrapper<'a>作为类型参数,我将得到同样的问题。

我的目标是能够使用类似这样的代码:

struct A;
struct B<'a> {
s: &'a A,
}
static mut STDOUT: Option<B> = None;
fn init_stdout() {
let a = A {};
unsafe {
STDOUT = Some(B {s: &a});
}
}
// access_stdout is the important function
// all the rest can be changed without issue
fn access_stdout() -> Result<(), ()> {
unsafe {
if let Some(_stdout) = STDOUT {
// do stuff is system ready
Ok(())
} else {
// do stuff is system not ready
Err(())
}
}
}
fn main() {
init_stdout();
let _ = access_stdout();
}

你对如何进行有什么建议吗?我不介意有一个需要不安全代码的解决方案,只要我能有安全的功能来访问我的串口。

简短的回答:当你在静态变量类型中有一个生命周期时,这个生命周期需要是'static

Rust不允许悬空引用,所以如果在静态变量中有任何比静态生命周期短的东西,就有可能存在悬空引用。我认为你的代码需要大量的重构来满足这个要求。我建议找到一种方法来存储不需要引用的数据,因为这将使您的工作更轻松。如果绝对必须存储引用,则需要找出一种方法来泄漏数据以将其生命周期延长到'static

我对嵌入式开发不是很熟悉,我知道static mut在那里有一些用例,但是使用这个语言特性是非常普遍的。static mut非常不安全,甚至通过允许同时使用多个可变引用来绕过一些借用检查器机制。如果要在Rust的类型系统中对其进行正确编码,您可能希望将其设置为static STDOUT: SyncWrapperForUnsafeCell<Option<T>>,然后为包装器提供一个安全接口(可能涉及锁定),并提供注释,解释为什么当前环境使其安全。然而,如果你认为static mut是合适的选择,我相信你的判断。

最新更新