yash_env/system/concurrency/
signal.rs1use super::Concurrent;
20use crate::signal::Number;
21use crate::system::signal::Sigset as _;
22use crate::system::{Disposition, Errno, Sigaction, Sigmask, SigmaskOp};
23use crate::trap::SignalSystem;
24use std::rc::Rc;
25
26impl<S> SignalSystem for Rc<Concurrent<S>>
31where
32 S: Sigmask + Sigaction,
33{
34 fn get_disposition(&self, signal: Number) -> Result<Disposition, Errno> {
40 self.inner.get_sigaction(signal)
41 }
42
43 fn set_disposition(
55 &self,
56 signal: Number,
57 disposition: Disposition,
58 ) -> impl Future<Output = Result<Disposition, Errno>> + use<S> {
59 let this = Rc::clone(self);
60 async move {
61 if disposition == Disposition::Catch {
62 this.update_sigmask_and_select_mask(SigmaskOp::Add, signal)
65 .await?;
66 }
67
68 let old_action = this.inner.sigaction(signal, disposition)?;
69
70 if disposition != Disposition::Catch {
71 this.update_sigmask_and_select_mask(SigmaskOp::Remove, signal)
74 .await?;
75 }
76
77 Ok(old_action)
78 }
79 }
80}
81
82impl<S> Concurrent<S>
83where
84 S: Sigmask,
85{
86 async fn update_sigmask_and_select_mask(
89 &self,
90 op: SigmaskOp,
91 signal: Number,
92 ) -> Result<(), Errno> {
93 let mut mask_of_signal = S::Sigset::new();
94 mask_of_signal.insert(signal)?;
95 let mut old_mask = S::Sigset::new();
96 self.inner
97 .sigmask(Some((op, &mask_of_signal)), Some(&mut old_mask))
98 .await?;
99
100 self.state
101 .borrow_mut()
102 .select_mask
103 .get_or_insert(old_mask)
104 .remove(signal)
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::job::{ProcessResult, ProcessState};
112 use crate::system::SendSignal as _;
113 use crate::system::r#virtual::sigset::Sigset;
114 use crate::system::r#virtual::{SIGQUIT, SIGTERM, SIGUSR1, VirtualSystem};
115 use futures_util::FutureExt as _;
116 use std::num::NonZero;
117
118 #[test]
119 fn setting_disposition_from_default_to_catch() {
120 let inner = VirtualSystem::new();
121 let system = Rc::new(Concurrent::new(inner.clone()));
122 let result = system
123 .set_disposition(SIGTERM, Disposition::Catch)
124 .now_or_never()
125 .unwrap();
126 assert_eq!(result, Ok(Disposition::Default));
127 assert_eq!(system.get_disposition(SIGTERM), Ok(Disposition::Catch));
128
129 inner.raise(SIGTERM).now_or_never().unwrap().unwrap();
131 assert_eq!(inner.current_process().state(), ProcessState::Running);
133 }
134
135 #[test]
136 fn setting_disposition_from_default_to_ignore() {
137 let inner = VirtualSystem::new();
138 let system = Rc::new(Concurrent::new(inner.clone()));
139 let result = system
140 .set_disposition(SIGTERM, Disposition::Ignore)
141 .now_or_never()
142 .unwrap();
143 assert_eq!(result, Ok(Disposition::Default));
144 assert_eq!(system.get_disposition(SIGTERM), Ok(Disposition::Ignore));
145
146 inner.raise(SIGTERM).now_or_never().unwrap().unwrap();
148 assert_eq!(inner.current_process().state(), ProcessState::Running);
149 }
150
151 #[test]
152 fn setting_disposition_from_ignore_to_catch() {
153 let system = Rc::new(Concurrent::new(VirtualSystem::new()));
154 system
155 .set_disposition(SIGQUIT, Disposition::Ignore)
156 .now_or_never()
157 .unwrap()
158 .unwrap();
159
160 let result = system
161 .set_disposition(SIGQUIT, Disposition::Catch)
162 .now_or_never()
163 .unwrap();
164 assert_eq!(result, Ok(Disposition::Ignore));
165 assert_eq!(system.get_disposition(SIGQUIT), Ok(Disposition::Catch));
166 }
167
168 #[test]
169 fn setting_disposition_from_catch_to_default() {
170 let inner = VirtualSystem::new();
171 let system = Rc::new(Concurrent::new(inner.clone()));
172 system
173 .set_disposition(SIGQUIT, Disposition::Catch)
174 .now_or_never()
175 .unwrap()
176 .unwrap();
177 system.raise(SIGQUIT).now_or_never().unwrap().unwrap();
179
180 let result = system
183 .set_disposition(SIGQUIT, Disposition::Default)
184 .now_or_never();
185 assert_eq!(result, None);
186 assert_eq!(
187 inner.current_process().state(),
188 ProcessState::Halted(ProcessResult::Signaled {
189 signal: SIGQUIT,
190 core_dump: true
191 })
192 );
193 }
194
195 #[test]
196 fn first_update_sigmask_and_select_mask_updates_blocking_mask() {
197 let inner = VirtualSystem::new();
198 _ = inner
199 .current_process_mut()
200 .block_signals(SigmaskOp::Set, [SIGQUIT, SIGTERM, SIGUSR1]);
201 let system = Rc::new(Concurrent::new(inner.clone()));
202
203 let result = system
204 .update_sigmask_and_select_mask(SigmaskOp::Add, SIGTERM)
205 .now_or_never()
206 .unwrap();
207 assert_eq!(result, Ok(()));
208 let blocked_signals = inner
209 .current_process()
210 .blocked_signals()
211 .iter()
212 .copied()
213 .collect::<Vec<_>>();
214 assert_eq!(blocked_signals, [SIGQUIT, SIGTERM, SIGUSR1]);
215 }
216
217 #[test]
218 fn first_update_sigmask_and_select_mask_sets_select_mask() {
219 let inner = VirtualSystem::new();
220 _ = inner
221 .current_process_mut()
222 .block_signals(SigmaskOp::Set, [SIGQUIT, SIGTERM, SIGUSR1]);
223 let system = Rc::new(Concurrent::new(inner.clone()));
224
225 system
226 .update_sigmask_and_select_mask(SigmaskOp::Add, SIGTERM)
227 .now_or_never()
228 .unwrap()
229 .unwrap();
230 assert_eq!(
231 system.state.borrow().select_mask,
232 Some(Sigset::from_iter([SIGQUIT, SIGUSR1]))
233 );
234 }
235
236 #[ignore = "current VirtualSystem::sigmask silently ignores invalid signals"]
237 #[test]
238 fn first_update_sigmask_and_select_mask_leaves_select_mask_unchanged_on_error() {
239 let system = Rc::new(Concurrent::new(VirtualSystem::new()));
240 let invalid_signal = Number::from_raw_unchecked(NonZero::new(-1).unwrap());
241 let result = system
242 .update_sigmask_and_select_mask(SigmaskOp::Add, invalid_signal)
243 .now_or_never()
244 .unwrap();
245 assert_eq!(result, Err(Errno::EINVAL));
246 assert_eq!(system.state.borrow().select_mask, None);
247 }
248
249 #[test]
250 fn second_update_sigmask_and_select_mask_updates_select_mask() {
251 let inner = VirtualSystem::new();
252 _ = inner
253 .current_process_mut()
254 .block_signals(SigmaskOp::Set, [SIGQUIT, SIGTERM, SIGUSR1]);
255 let system = Rc::new(Concurrent::new(inner.clone()));
256
257 system
258 .update_sigmask_and_select_mask(SigmaskOp::Add, SIGTERM)
259 .now_or_never()
260 .unwrap()
261 .unwrap();
262 system
263 .update_sigmask_and_select_mask(SigmaskOp::Remove, SIGQUIT)
264 .now_or_never()
265 .unwrap()
266 .unwrap();
267 assert_eq!(
268 system.state.borrow().select_mask,
269 Some(Sigset::from(SIGUSR1))
270 );
271 }
272}