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