xref: /aosp_15_r20/external/crosvm/base/src/sys/macos/kqueue.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::ptr;
6 use std::time::Duration;
7 
8 use crate::descriptor::AsRawDescriptor;
9 use crate::descriptor::FromRawDescriptor;
10 use crate::errno::errno_result;
11 use crate::errno::Error;
12 use crate::errno::Result;
13 use crate::sys::unix::RawDescriptor;
14 use crate::unix::duration_to_timespec;
15 use crate::unix::set_descriptor_cloexec;
16 use crate::SafeDescriptor;
17 
18 #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19 pub(in crate::sys::macos) struct Kqueue {
20     queue: SafeDescriptor,
21 }
22 
23 // Only accepts the subset of parameters we actually use
make_kevent(filter: i16, flags: u16, fflags: u32) -> libc::kevent64_s24 pub(in crate::sys::macos) fn make_kevent(filter: i16, flags: u16, fflags: u32) -> libc::kevent64_s {
25     libc::kevent64_s {
26         ident: 0, /* hopefully not global? */
27         filter,
28         flags,
29         fflags,
30         data: 0,
31         udata: 0,
32         ext: [0, 0],
33     }
34 }
35 
36 impl Kqueue {
new() -> Result<Kqueue>37     pub(in crate::sys::macos) fn new() -> Result<Kqueue> {
38         // SAFETY: Trivially safe
39         let raw_queue = unsafe { libc::kqueue() };
40         if raw_queue < 0 {
41             return crate::errno::errno_result();
42         }
43         // SAFETY: Tested whether it was a valid file descriptor
44         let queue = unsafe { SafeDescriptor::from_raw_descriptor(raw_queue) };
45         set_descriptor_cloexec(&queue)?;
46         Ok(Kqueue { queue })
47     }
48 
kevent<'a>( &self, changelist: &[libc::kevent64_s], eventlist: &'a mut [libc::kevent64_s], timeout: Option<Duration>, ) -> Result<&'a mut [libc::kevent64_s]>49     pub(in crate::sys::macos) fn kevent<'a>(
50         &self,
51         changelist: &[libc::kevent64_s],
52         eventlist: &'a mut [libc::kevent64_s],
53         timeout: Option<Duration>,
54     ) -> Result<&'a mut [libc::kevent64_s]> {
55         let timespec = timeout.map(duration_to_timespec);
56         // SAFETY: `queue` is a valid kqueue, `changelist` and `eventlist` are supplied with lengths
57         // based on valid slices
58         let res = unsafe {
59             libc::kevent64(
60                 self.queue.as_raw_descriptor(),
61                 changelist.as_ptr(),
62                 changelist.len() as i32,
63                 eventlist.as_mut_ptr(),
64                 eventlist.len() as i32,
65                 0,
66                 if let Some(timeout) = timespec {
67                     &timeout
68                 } else {
69                     ptr::null()
70                 },
71             )
72         };
73         if res < 0 {
74             return errno_result();
75         }
76         let returned_events = eventlist.split_at_mut(res as usize).0;
77         for event in returned_events.iter() {
78             if event.flags & libc::EV_ERROR != 0 {
79                 return Err(Error::new(event.data));
80             }
81         }
82         Ok(returned_events)
83     }
84 
try_clone(&self) -> Result<Kqueue>85     pub(in crate::sys::macos) fn try_clone(&self) -> Result<Kqueue> {
86         self.queue.try_clone().map(|queue| Kqueue { queue })
87     }
88 }
89 
90 impl crate::AsRawDescriptor for Kqueue {
as_raw_descriptor(&self) -> RawDescriptor91     fn as_raw_descriptor(&self) -> RawDescriptor {
92         self.queue.as_raw_descriptor()
93     }
94 }
95 
96 impl crate::FromRawDescriptor for Kqueue {
from_raw_descriptor(descriptor: RawDescriptor) -> Self97     unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
98         Kqueue {
99             queue: SafeDescriptor::from_raw_descriptor(descriptor),
100         }
101     }
102 }
103 
104 impl crate::IntoRawDescriptor for Kqueue {
into_raw_descriptor(self) -> RawDescriptor105     fn into_raw_descriptor(self) -> RawDescriptor {
106         self.queue.into_raw_descriptor()
107     }
108 }
109 
110 impl From<Kqueue> for crate::SafeDescriptor {
from(queue: Kqueue) -> Self111     fn from(queue: Kqueue) -> Self {
112         queue.queue
113     }
114 }
115 
116 impl From<SafeDescriptor> for Kqueue {
from(queue: SafeDescriptor) -> Self117     fn from(queue: SafeDescriptor) -> Self {
118         Kqueue { queue }
119     }
120 }
121