1 // Copyright 2017 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::mem; 6 use std::ptr; 7 use std::time::Duration; 8 9 use libc::c_void; 10 use libc::eventfd; 11 use libc::read; 12 use libc::write; 13 use libc::POLLIN; 14 use serde::Deserialize; 15 use serde::Serialize; 16 17 use super::errno_result; 18 use super::RawDescriptor; 19 use super::Result; 20 use crate::descriptor::AsRawDescriptor; 21 use crate::descriptor::FromRawDescriptor; 22 use crate::descriptor::IntoRawDescriptor; 23 use crate::descriptor::SafeDescriptor; 24 use crate::unix::duration_to_timespec; 25 use crate::EventWaitResult; 26 27 /// A safe wrapper around a Linux eventfd (man 2 eventfd). 28 /// 29 /// An eventfd is useful because it is sendable across processes and can be used for signaling in 30 /// and out of the KVM API. They can also be polled like any other file descriptor. 31 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] 32 #[serde(transparent)] 33 pub(crate) struct PlatformEvent { 34 event_handle: SafeDescriptor, 35 } 36 37 /// Linux specific extensions to `Event`. 38 pub trait EventExt { 39 /// Adds `v` to the eventfd's count, blocking until this won't overflow the count. write_count(&self, v: u64) -> Result<()>40 fn write_count(&self, v: u64) -> Result<()>; 41 /// Blocks until the the eventfd's count is non-zero, then resets the count to zero. read_count(&self) -> Result<u64>42 fn read_count(&self) -> Result<u64>; 43 } 44 45 impl EventExt for crate::Event { write_count(&self, v: u64) -> Result<()>46 fn write_count(&self, v: u64) -> Result<()> { 47 self.0.write_count(v) 48 } 49 read_count(&self) -> Result<u64>50 fn read_count(&self) -> Result<u64> { 51 self.0.read_count() 52 } 53 } 54 55 impl PlatformEvent { 56 /// Creates a new blocking eventfd with an initial value of 0. new() -> Result<PlatformEvent>57 pub fn new() -> Result<PlatformEvent> { 58 // SAFETY: 59 // This is safe because eventfd merely allocated an eventfd for our process and we handle 60 // the error case. 61 let ret = unsafe { eventfd(0, 0) }; 62 if ret < 0 { 63 return errno_result(); 64 } 65 Ok(PlatformEvent { 66 // SAFETY: 67 // This is safe because we checked ret for success and know the kernel gave us an fd 68 // that we own. 69 event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) }, 70 }) 71 } 72 73 /// See `EventExt::write_count`. write_count(&self, v: u64) -> Result<()>74 pub fn write_count(&self, v: u64) -> Result<()> { 75 // SAFETY: 76 // This is safe because we made this fd and the pointer we pass can not overflow because we 77 // give the syscall's size parameter properly. 78 let ret = unsafe { 79 write( 80 self.as_raw_descriptor(), 81 &v as *const u64 as *const c_void, 82 mem::size_of::<u64>(), 83 ) 84 }; 85 if ret <= 0 { 86 return errno_result(); 87 } 88 Ok(()) 89 } 90 91 /// See `EventExt::read_count`. read_count(&self) -> Result<u64>92 pub fn read_count(&self) -> Result<u64> { 93 let mut buf: u64 = 0; 94 // SAFETY: 95 // This is safe because we made this fd and the pointer we pass can not overflow because 96 // we give the syscall's size parameter properly. 97 let ret = unsafe { 98 read( 99 self.as_raw_descriptor(), 100 &mut buf as *mut u64 as *mut c_void, 101 mem::size_of::<u64>(), 102 ) 103 }; 104 if ret <= 0 { 105 return errno_result(); 106 } 107 Ok(buf) 108 } 109 110 /// See `Event::signal`. signal(&self) -> Result<()>111 pub fn signal(&self) -> Result<()> { 112 self.write_count(1) 113 } 114 115 /// See `Event::wait`. wait(&self) -> Result<()>116 pub fn wait(&self) -> Result<()> { 117 self.read_count().map(|_| ()) 118 } 119 120 /// See `Event::wait_timeout`. wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult>121 pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> { 122 let mut pfd = libc::pollfd { 123 fd: self.as_raw_descriptor(), 124 events: POLLIN, 125 revents: 0, 126 }; 127 let timeoutspec: libc::timespec = duration_to_timespec(timeout); 128 // SAFETY: 129 // Safe because this only modifies |pfd| and we check the return value 130 let ret = unsafe { 131 libc::ppoll( 132 &mut pfd as *mut libc::pollfd, 133 1, 134 &timeoutspec, 135 ptr::null_mut(), 136 ) 137 }; 138 if ret < 0 { 139 return errno_result(); 140 } 141 142 // no return events (revents) means we got a timeout 143 if pfd.revents == 0 { 144 return Ok(EventWaitResult::TimedOut); 145 } 146 147 self.wait()?; 148 Ok(EventWaitResult::Signaled) 149 } 150 151 /// See `Event::reset`. reset(&self) -> Result<()>152 pub fn reset(&self) -> Result<()> { 153 // If the eventfd is currently signaled (counter > 0), `wait_timeout()` will `read()` it to 154 // reset the count. Otherwise (if the eventfd is not signaled), `wait_timeout()` will return 155 // immediately since we pass a zero duration. We don't care about the EventWaitResult; we 156 // just want a non-blocking read to reset the counter. 157 let _: EventWaitResult = self.wait_timeout(Duration::ZERO)?; 158 Ok(()) 159 } 160 161 /// Clones this eventfd, internally creating a new file descriptor. The new eventfd will share 162 /// the same underlying count within the kernel. try_clone(&self) -> Result<PlatformEvent>163 pub fn try_clone(&self) -> Result<PlatformEvent> { 164 self.event_handle 165 .try_clone() 166 .map(|event_handle| PlatformEvent { event_handle }) 167 } 168 } 169 170 impl AsRawDescriptor for PlatformEvent { as_raw_descriptor(&self) -> RawDescriptor171 fn as_raw_descriptor(&self) -> RawDescriptor { 172 self.event_handle.as_raw_descriptor() 173 } 174 } 175 176 impl FromRawDescriptor for PlatformEvent { from_raw_descriptor(descriptor: RawDescriptor) -> Self177 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self { 178 PlatformEvent { 179 event_handle: SafeDescriptor::from_raw_descriptor(descriptor), 180 } 181 } 182 } 183 184 impl IntoRawDescriptor for PlatformEvent { into_raw_descriptor(self) -> RawDescriptor185 fn into_raw_descriptor(self) -> RawDescriptor { 186 self.event_handle.into_raw_descriptor() 187 } 188 } 189 190 impl From<PlatformEvent> for SafeDescriptor { from(evt: PlatformEvent) -> Self191 fn from(evt: PlatformEvent) -> Self { 192 evt.event_handle 193 } 194 } 195 196 impl From<SafeDescriptor> for PlatformEvent { from(sd: SafeDescriptor) -> Self197 fn from(sd: SafeDescriptor) -> Self { 198 PlatformEvent { event_handle: sd } 199 } 200 } 201 202 #[cfg(test)] 203 mod tests { 204 use super::*; 205 use crate::Event; 206 use crate::EventExt; 207 208 #[test] new()209 fn new() { 210 Event::new().unwrap(); 211 } 212 213 #[test] read_write()214 fn read_write() { 215 let evt = Event::new().unwrap(); 216 evt.write_count(55).unwrap(); 217 assert_eq!(evt.read_count(), Ok(55)); 218 } 219 220 #[test] clone()221 fn clone() { 222 let evt = Event::new().unwrap(); 223 let evt_clone = evt.try_clone().unwrap(); 224 evt.write_count(923).unwrap(); 225 assert_eq!(evt_clone.read_count(), Ok(923)); 226 } 227 228 #[test] timeout()229 fn timeout() { 230 let evt = Event::new().expect("failed to create eventfd"); 231 assert_eq!( 232 evt.wait_timeout(Duration::from_millis(1)) 233 .expect("failed to read from eventfd with timeout"), 234 EventWaitResult::TimedOut 235 ); 236 } 237 } 238