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