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