我正在玩Rust和各种UNIX库。我现在有一个用例是我想对POSIX信号使用react。为了使事情合理,我想在信号处理上创建一个抽象,这样程序的其余部分就不必太担心它们了。

我们称之为抽象SignalHandler:

struct SignalHandler {
    pub signals: Arc<Vec<libc::c_int>>,
}

我希望这个signals向量被接收到的所有信号填充。我的真实状态更加复杂,但让我们以该向量为例。

我希望API的行为如下:
// ← No signals are being captured
let Some(h) = SignalHandler::try_create();
// ← Signals are added to h.signals

// Only one signal handler can be active at a time per process
assert_eq!(None, SignalHandler::try_create());

// ← Signals are added to h.signals
drop(h);
// ← No signals are being captured

问题是注册信号处理程序(例如使用nix crate )需要指向C函数的指针:
use nix::sys::signal;
let action = signal::SigAction::new(handle_signal, signal::SockFlag::empty(), signal::SigSet::empty());
signal::sigaction(signal::SIGINT, &action);

我不能将signals向量传递给handle_signal函数,因为它需要C ABI,因此不能作为闭包。我想以某种方式给出指向该函数的Weak<_>指针。这可能意味着使用全局状态。

所以问题是:对于全局状态,我应该使用哪种数据结构,可以“取消设置”(即没有signals向量),或者原子地“设置”为在try_create中初始化的某些可变状态?

最佳答案

对于这种类型的全局状态,我建议使用lazy_static条板箱。您可以使用宏来定义延迟评估,可变的全局引用。您可能可以使用带有全局Option<T>变量的方法。

但是,这是这种情况下的一个问题。您将遇到的一个大问题是,仅在信号处理程序内很难完成您想要的操作。由于信号处理程序必须是可重入的,因此任何类型的锁以及任何内存分配都将丢失(除非所使用的内存分配器也可重入)。这意味着Arc<Mutex<Vec<T>>>类型或类似的东西将不起作用。您可能已经知道并且正在以某种方式进行处理。

根据您的需求,我可能会向您介绍chan_signal crate ,它是对信号的抽象,它使用线程和sigwait syscall来接收信号。

希望有帮助的另一个值得关注的资源是signalfd函数,该函数创建文件描述符以使信号排队。 nix crate 也有一个绑定(bind)。

关于linux - 安全的全局状态以进行信号处理,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33467528/

10-16 11:20