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::Result;
12 use crate::event::EventWaitResult;
13 use crate::sys::unix::RawDescriptor;
14 use crate::unix::duration_to_timespec;
15 use crate::SafeDescriptor;
16
17 #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
18 pub struct PlatformEvent {
19 // TODO(schuffelen): Implement a more complete kqueue abstraction?
20 queue: SafeDescriptor,
21 }
22
23 // Only accepts the subset of parameters we actually use
make_kevent(filter: i16, flags: u16, fflags: u32) -> libc::kevent24 fn make_kevent(filter: i16, flags: u16, fflags: u32) -> libc::kevent {
25 libc::kevent {
26 ident: 0, /* hopefully not global? */
27 filter,
28 flags,
29 fflags,
30 data: 0,
31 udata: ptr::null_mut(),
32 }
33 }
34
35 impl PlatformEvent {
new() -> Result<PlatformEvent>36 pub fn new() -> Result<PlatformEvent> {
37 // SAFETY: Trivially safe
38 let raw_queue = unsafe { libc::kqueue() };
39 if raw_queue < 0 {
40 return crate::errno::errno_result();
41 }
42 // SAFETY: Tested whether it was a valid file descriptor
43 let queue = unsafe { SafeDescriptor::from_raw_descriptor(raw_queue) };
44 let event = PlatformEvent { queue };
45 let reg = make_kevent(
46 libc::EVFILT_USER,
47 libc::EV_ADD | libc::EV_CLEAR,
48 libc::NOTE_FFNOP,
49 );
50 event.kevent(&[reg], &mut [], None)?;
51 Ok(event)
52 }
53
kevent( &self, changelist: &[libc::kevent], eventlist: &mut [libc::kevent], timeout: Option<Duration>, ) -> Result<libc::c_int>54 fn kevent(
55 &self,
56 changelist: &[libc::kevent],
57 eventlist: &mut [libc::kevent],
58 timeout: Option<Duration>,
59 ) -> Result<libc::c_int> {
60 let timespec = timeout.map(duration_to_timespec);
61 // SAFETY: `queue` is a valid kqueue, `changelist` and `eventlist` are supplied with lengths
62 // based on valid slices
63 let res = unsafe {
64 libc::kevent(
65 self.queue.as_raw_descriptor(),
66 changelist.as_ptr(),
67 changelist.len() as i32,
68 eventlist.as_mut_ptr(),
69 eventlist.len() as i32,
70 if let Some(timeout) = timespec {
71 &timeout
72 } else {
73 ptr::null()
74 },
75 )
76 };
77 if res < 0 {
78 errno_result()
79 } else {
80 Ok(res)
81 }
82 }
83
signal(&self) -> Result<()>84 pub fn signal(&self) -> Result<()> {
85 let event = make_kevent(libc::EVFILT_USER, 0, libc::NOTE_TRIGGER);
86 self.kevent(&[event], &mut [], None)?;
87 Ok(())
88 }
89
wait(&self) -> Result<()>90 pub fn wait(&self) -> Result<()> {
91 let mut event = [make_kevent(0, 0, 0)];
92 self.kevent(&[], &mut event[..], None)?;
93 Ok(())
94 }
95
wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult>96 pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> {
97 let mut event = [make_kevent(0, 0, 0)];
98 if self.kevent(&[], &mut event[..], Some(timeout))? == 0 {
99 Ok(EventWaitResult::TimedOut)
100 } else {
101 Ok(EventWaitResult::Signaled)
102 }
103 }
104
reset(&self) -> Result<()>105 pub fn reset(&self) -> Result<()> {
106 self.wait_timeout(Duration::ZERO)?;
107 Ok(())
108 }
109
try_clone(&self) -> Result<PlatformEvent>110 pub fn try_clone(&self) -> Result<PlatformEvent> {
111 self.queue.try_clone().map(|queue| PlatformEvent { queue })
112 }
113 }
114
115 impl crate::AsRawDescriptor for PlatformEvent {
as_raw_descriptor(&self) -> RawDescriptor116 fn as_raw_descriptor(&self) -> RawDescriptor {
117 self.queue.as_raw_descriptor()
118 }
119 }
120
121 impl crate::FromRawDescriptor for PlatformEvent {
from_raw_descriptor(descriptor: RawDescriptor) -> Self122 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
123 PlatformEvent {
124 queue: SafeDescriptor::from_raw_descriptor(descriptor),
125 }
126 }
127 }
128
129 impl crate::IntoRawDescriptor for PlatformEvent {
into_raw_descriptor(self) -> RawDescriptor130 fn into_raw_descriptor(self) -> RawDescriptor {
131 self.queue.into_raw_descriptor()
132 }
133 }
134
135 impl From<PlatformEvent> for crate::SafeDescriptor {
from(evt: PlatformEvent) -> Self136 fn from(evt: PlatformEvent) -> Self {
137 evt.queue
138 }
139 }
140
141 impl From<SafeDescriptor> for PlatformEvent {
from(queue: SafeDescriptor) -> Self142 fn from(queue: SafeDescriptor) -> Self {
143 PlatformEvent { queue }
144 }
145 }
146