Skip to main content

starnix_core/signals/
signalfd.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::signals::SignalDetail;
6use crate::task::{CurrentTask, EventHandler, WaitCanceler, Waiter};
7use crate::vfs::buffers::{InputBuffer, OutputBuffer};
8use crate::vfs::{
9    Anon, FileHandle, FileObject, FileOps, fileops_impl_nonseekable, fileops_impl_noop_sync,
10};
11use starnix_sync::{LockDepMutex, SignalFdMaskLock};
12use starnix_uapi::errors::Errno;
13use starnix_uapi::open_flags::OpenFlags;
14use starnix_uapi::signals::SigSet;
15use starnix_uapi::vfs::FdEvents;
16use starnix_uapi::{SFD_NONBLOCK, errno, error, signalfd_siginfo};
17use zerocopy::IntoBytes;
18
19pub struct SignalFd {
20    mask: LockDepMutex<SigSet, SignalFdMaskLock>,
21}
22
23impl SignalFd {
24    pub fn new_file(current_task: &CurrentTask, mask: SigSet, flags: u32) -> FileHandle {
25        let mut open_flags = OpenFlags::RDONLY;
26        if flags & SFD_NONBLOCK != 0 {
27            open_flags |= OpenFlags::NONBLOCK;
28        }
29        Anon::new_private_file(
30            current_task,
31            Box::new(SignalFd { mask: mask.into() }),
32            open_flags,
33            "[signalfd]",
34        )
35    }
36
37    pub fn set_mask(&self, mask: SigSet) {
38        *self.mask.lock() = mask;
39    }
40}
41
42impl FileOps for SignalFd {
43    fileops_impl_nonseekable!();
44    fileops_impl_noop_sync!();
45
46    fn read(
47        &self,
48        file: &FileObject,
49        current_task: &CurrentTask,
50        offset: usize,
51        data: &mut dyn OutputBuffer,
52    ) -> Result<usize, Errno> {
53        debug_assert!(offset == 0);
54        file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
55            let mask = *self.mask.lock();
56            let data_len = data.available();
57            let mut buf = Vec::new();
58            while buf.len() + std::mem::size_of::<signalfd_siginfo>() <= data_len {
59                let signal = current_task
60                    .write()
61                    .take_signal_with_mask(!mask)
62                    .ok_or_else(|| errno!(EAGAIN))?;
63                let mut siginfo = signalfd_siginfo {
64                    ssi_signo: signal.signal.number(),
65                    ssi_errno: signal.errno,
66                    ssi_code: signal.code,
67                    ..Default::default()
68                };
69                // Any future variants of SignalDetail need a match arm here that copies the relevant
70                // fields into the signalfd_siginfo.
71                match &signal.detail {
72                    SignalDetail::None => {}
73                    SignalDetail::Kill { pid, uid } => {
74                        siginfo.ssi_pid = *pid as u32;
75                        siginfo.ssi_uid = *uid;
76                    }
77                    SignalDetail::SIGCHLD { pid, uid, status } => {
78                        siginfo.ssi_pid = *pid as u32;
79                        siginfo.ssi_uid = *uid;
80                        siginfo.ssi_status = *status;
81                    }
82                    SignalDetail::SigFault { addr } => {
83                        siginfo.ssi_addr = *addr;
84                    }
85                    SignalDetail::SIGSYS { call_addr, syscall, arch } => {
86                        siginfo.ssi_call_addr = (*call_addr).into();
87                        siginfo.ssi_syscall = *syscall;
88                        siginfo.ssi_arch = *arch;
89                    }
90                    SignalDetail::Raw { data } => {
91                        // these offsets are taken from the gVisor offsets in the SignalInfo struct
92                        // in //pkg/abi/linux/signal.go and the definition of __sifields in
93                        // /usr/include/asm-generic/siginfo.h
94                        siginfo.ssi_uid = u32::from_ne_bytes(data[4..8].try_into().unwrap());
95                        siginfo.ssi_pid = u32::from_ne_bytes(data[0..4].try_into().unwrap());
96                        siginfo.ssi_fd = i32::from_ne_bytes(data[8..12].try_into().unwrap());
97                        siginfo.ssi_tid = u32::from_ne_bytes(data[0..4].try_into().unwrap());
98                        siginfo.ssi_band = u32::from_ne_bytes(data[0..4].try_into().unwrap());
99                        siginfo.ssi_overrun = u32::from_ne_bytes(data[4..8].try_into().unwrap());
100                        siginfo.ssi_status = i32::from_ne_bytes(data[8..12].try_into().unwrap());
101                        siginfo.ssi_int = i32::from_ne_bytes(data[8..12].try_into().unwrap());
102                        siginfo.ssi_ptr = u64::from_ne_bytes(data[8..16].try_into().unwrap());
103                        siginfo.ssi_addr = u64::from_ne_bytes(data[0..8].try_into().unwrap());
104                        siginfo.ssi_syscall = i32::from_ne_bytes(data[8..12].try_into().unwrap());
105                        siginfo.ssi_call_addr = u64::from_ne_bytes(data[0..8].try_into().unwrap());
106                        siginfo.ssi_arch = u32::from_ne_bytes(data[12..16].try_into().unwrap());
107                        siginfo.ssi_utime = u64::from_ne_bytes(data[12..20].try_into().unwrap());
108                        siginfo.ssi_stime = u64::from_ne_bytes(data[20..28].try_into().unwrap());
109                    }
110                    SignalDetail::Timer { timer } => {
111                        siginfo.ssi_tid = timer.timer_id as u32;
112                        siginfo.ssi_overrun = timer.overrun_cur() as u32;
113                        siginfo.ssi_int = timer.signal_event.value.0 as i32;
114                        siginfo.ssi_ptr = timer.signal_event.value.0;
115                    }
116                }
117                buf.extend_from_slice(siginfo.as_bytes());
118            }
119            data.write_all(&buf)
120        })
121    }
122
123    fn wait_async(
124        &self,
125        _file: &FileObject,
126        current_task: &CurrentTask,
127        waiter: &Waiter,
128        _events: FdEvents,
129        handler: EventHandler,
130    ) -> Option<WaitCanceler> {
131        let mask = *self.mask.lock();
132        Some(current_task.read().wait_on_signal_fd_events(waiter, mask, handler))
133    }
134
135    fn query_events(
136        &self,
137        _file: &FileObject,
138        current_task: &CurrentTask,
139    ) -> Result<FdEvents, Errno> {
140        let mut events = FdEvents::empty();
141        if current_task.read().is_any_signal_allowed_by_mask(!*self.mask.lock()) {
142            events |= FdEvents::POLLIN;
143        }
144        Ok(events)
145    }
146
147    fn write(
148        &self,
149        _file: &FileObject,
150        _current_task: &CurrentTask,
151        offset: usize,
152        _data: &mut dyn InputBuffer,
153    ) -> Result<usize, Errno> {
154        debug_assert!(offset == 0);
155        error!(EINVAL)
156    }
157}