Skip to main content

relibc/platform/redox/
signal.rs

1use super::{
2    super::{Pal, PalSignal, types::*},
3    Sys,
4};
5#[allow(deprecated)]
6use crate::header::sys_time::{ITIMER_REAL, itimerval};
7use crate::{
8    error::{Errno, Result},
9    header::{
10        bits_sigset_t::sigset_t,
11        errno::{EINVAL, ENOSYS},
12        signal::{
13            SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
14            sigaction, siginfo_t, sigval, stack_t, ucontext_t,
15        },
16        time::timespec,
17    },
18};
19use core::mem::offset_of;
20use redox_protocols::protocol::ProcKillTarget;
21use redox_rt::signal::{
22    PosixStackt, SigStack, Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler,
23};
24
25const _: () = {
26    #[track_caller]
27    const fn assert_eq(a: usize, b: usize) {
28        if a != b {
29            panic!("compile-time struct verification failed");
30        }
31    }
32    assert_eq(offset_of!(ucontext_t, uc_link), offset_of!(SigStack, link));
33    assert_eq(
34        offset_of!(ucontext_t, uc_stack),
35        offset_of!(SigStack, old_stack),
36    );
37    assert_eq(
38        offset_of!(ucontext_t, uc_sigmask),
39        offset_of!(SigStack, old_mask),
40    );
41    assert_eq(
42        offset_of!(ucontext_t, uc_mcontext),
43        offset_of!(SigStack, regs),
44    );
45};
46
47impl PalSignal for Sys {
48    #[allow(deprecated)]
49    fn getitimer(which: c_int, out: &mut itimerval) -> Result<()> {
50        let path = match which {
51            ITIMER_REAL => "/scheme/itimer/1",
52            _ => return Err(Errno(EINVAL)),
53        };
54        // TODO: implement setitimer
55        // let fd = FdGuard::new(redox_rt::sys::open(path, syscall::O_RDONLY | syscall::O_CLOEXEC)?);
56        // let count = syscall::read(*fd, &mut spec)?;
57
58        let spec = syscall::ITimerSpec::default();
59        out.it_interval.tv_sec = spec.it_interval.tv_sec as time_t;
60        out.it_interval.tv_usec = spec.it_interval.tv_nsec / 1000;
61        out.it_value.tv_sec = spec.it_value.tv_sec as time_t;
62        out.it_value.tv_usec = spec.it_value.tv_nsec / 1000;
63
64        Ok(())
65    }
66
67    fn kill(pid: pid_t, sig: c_int) -> Result<()> {
68        redox_rt::sys::posix_kill(ProcKillTarget::from_raw(pid as usize), sig as usize)?;
69        Ok(())
70    }
71    fn sigqueue(pid: pid_t, sig: c_int, val: sigval) -> Result<()> {
72        Ok(redox_rt::sys::posix_sigqueue(
73            pid as usize,
74            sig as usize,
75            unsafe { val.sival_ptr } as usize,
76        )?)
77    }
78
79    fn killpg(pgrp: pid_t, sig: c_int) -> Result<()> {
80        if pgrp == 1 {
81            return Err(Errno(EINVAL));
82        }
83        Self::kill(-pgrp, sig)
84    }
85
86    fn raise(sig: c_int) -> Result<()> {
87        // TODO: Bypass kernel?
88        unsafe { Self::rlct_kill(Self::current_os_tid(), sig as _) }
89    }
90
91    #[allow(deprecated)]
92    fn setitimer(which: c_int, _new: &itimerval, old: Option<&mut itimerval>) -> Result<()> {
93        // TODO: setitimer is no longer part of POSIX and should not be implemented in Redox
94        // Change the platform-independent implementation to use POSIX timers.
95        // For Redox, the timer should probably use "/scheme/time"
96        todo_skip!(0, "setitimer not implemented");
97        Err(Errno(ENOSYS))
98    }
99
100    fn sigaction(
101        sig: c_int,
102        c_act: Option<&sigaction>,
103        c_oact: Option<&mut sigaction>,
104    ) -> Result<(), Errno> {
105        let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?;
106
107        let new_action = c_act.map(|c_act| {
108            let handler = c_act.sa_handler.map_or(0, |f| f as usize);
109
110            let kind = if handler == SIG_DFL {
111                SigactionKind::Default
112            } else if handler == SIG_IGN {
113                SigactionKind::Ignore
114            } else {
115                SigactionKind::Handled {
116                    handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_int != 0 {
117                        SignalHandler {
118                            sigaction: unsafe { core::mem::transmute(c_act.sa_handler) },
119                        }
120                    } else {
121                        SignalHandler {
122                            handler: c_act.sa_handler,
123                        }
124                    },
125                }
126            };
127
128            Sigaction {
129                kind,
130                mask: c_act.sa_mask,
131                flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32),
132            }
133        });
134        let mut old_action = c_oact.as_ref().map(|_| Sigaction::default());
135
136        redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?;
137
138        if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
139            *c_oact = match old_action.kind {
140                SigactionKind::Ignore => sigaction {
141                    sa_handler: unsafe { core::mem::transmute(SIG_IGN) },
142                    sa_flags: 0,
143                    sa_restorer: None,
144                    sa_mask: 0,
145                },
146                SigactionKind::Default => sigaction {
147                    sa_handler: unsafe { core::mem::transmute(SIG_DFL) },
148                    sa_flags: 0,
149                    sa_restorer: None,
150                    sa_mask: 0,
151                },
152                SigactionKind::Handled { handler } => sigaction {
153                    sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) {
154                        unsafe { core::mem::transmute(handler.sigaction) }
155                    } else {
156                        unsafe { handler.handler }
157                    },
158                    sa_restorer: None,
159                    sa_flags: old_action.flags.bits() as c_int,
160                    sa_mask: old_action.mask,
161                },
162            };
163        }
164        Ok(())
165    }
166
167    unsafe fn sigaltstack(
168        new_c: Option<&stack_t>,
169        old_c: Option<&mut stack_t>,
170    ) -> Result<(), Errno> {
171        let new = new_c
172            .map(|c_stack| {
173                let flags = usize::try_from(c_stack.ss_flags).map_err(|_| Errno(EINVAL))?;
174                if flags != flags & (SS_DISABLE | SS_ONSTACK) {
175                    return Err(Errno(EINVAL));
176                }
177
178                Ok(if flags & SS_DISABLE == SS_DISABLE {
179                    Sigaltstack::Disabled
180                } else {
181                    Sigaltstack::Enabled {
182                        onstack: false,
183                        base: c_stack.ss_sp.cast(),
184                        size: c_stack.ss_size,
185                    }
186                })
187            })
188            .transpose()?;
189
190        let mut old = old_c.as_ref().map(|_| Sigaltstack::default());
191        (unsafe { redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut()) })?;
192
193        if let (Some(old_c_stack), Some(old)) = (old_c, old) {
194            let c_stack = PosixStackt::from(old);
195            *old_c_stack = stack_t {
196                ss_sp: c_stack.sp.cast(),
197                ss_size: c_stack.size,
198                ss_flags: c_stack.flags,
199            };
200        }
201        Ok(())
202    }
203
204    fn sigpending(set: &mut sigset_t) -> Result<(), Errno> {
205        *set = redox_rt::signal::currently_pending_blocked();
206        Ok(())
207    }
208
209    fn sigprocmask(
210        how: c_int,
211        set: Option<&sigset_t>,
212        oset: Option<&mut sigset_t>,
213    ) -> Result<(), Errno> {
214        match how {
215            _ if set.is_none() => {
216                if let Some(oset) = oset {
217                    *oset = redox_rt::signal::get_sigmask()?;
218                }
219            }
220            SIG_SETMASK => redox_rt::signal::set_sigmask(set.copied(), oset)?,
221            SIG_BLOCK => redox_rt::signal::or_sigmask(set.copied(), oset)?,
222            SIG_UNBLOCK => redox_rt::signal::andn_sigmask(set.copied(), oset)?,
223
224            _ => return Err(Errno(EINVAL)),
225        }
226        Ok(())
227    }
228
229    fn sigsuspend(mask: &sigset_t) -> Errno {
230        match redox_rt::signal::await_signal_async(!*mask) {
231            Ok(_) => unreachable!(),
232            Err(err) => err.into(),
233        }
234    }
235
236    fn sigtimedwait(
237        set: &sigset_t,
238        info_out: Option<&mut siginfo_t>,
239        timeout: Option<&timespec>,
240    ) -> Result<c_int, Errno> {
241        // TODO: deadline-based API
242        let timeout = timeout.map(|timeout| syscall::TimeSpec {
243            tv_sec: timeout.tv_sec,
244            tv_nsec: timeout.tv_nsec as _,
245        });
246        let info = redox_rt::signal::await_signal_sync(*set, timeout.as_ref())?.into();
247        if let Some(out) = info_out {
248            *out = info;
249        }
250        Ok(info.si_signo)
251    }
252}