• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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