1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Type-safe bindings for Zircon port objects. 6 7 use std::mem; 8 9 use {AsHandleRef, HandleBased, Handle, HandleRef, Signals, Status, Time}; 10 use {sys, ok}; 11 12 /// An object representing a Zircon 13 /// [port](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/port.md). 14 /// 15 /// As essentially a subtype of `Handle`, it can be freely interconverted. 16 #[derive(Debug, Eq, PartialEq)] 17 pub struct Port(Handle); 18 impl_handle_based!(Port); 19 20 /// A packet sent through a port. This is a type-safe wrapper for 21 /// [zx_port_packet_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). 22 #[derive(PartialEq, Eq, Debug)] 23 pub struct Packet(sys::zx_port_packet_t); 24 25 /// The contents of a `Packet`. 26 #[derive(Debug, Copy, Clone)] 27 pub enum PacketContents { 28 /// A user-generated packet. 29 User(UserPacket), 30 /// A one-shot signal packet generated via `object_wait_async`. 31 SignalOne(SignalPacket), 32 /// A repeating signal packet generated via `object_wait_async`. 33 SignalRep(SignalPacket), 34 35 #[doc(hidden)] 36 __Nonexhaustive 37 } 38 39 /// Contents of a user packet (one sent by `port_queue`). This is a type-safe wrapper for 40 /// [zx_packet_user_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). 41 #[derive(Debug, Copy, Clone)] 42 pub struct UserPacket(sys::zx_packet_user_t); 43 44 /// Contents of a signal packet (one generated by the kernel). This is a type-safe wrapper for 45 /// [zx_packet_signal_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). 46 #[derive(Debug, Copy, Clone)] 47 pub struct SignalPacket(sys::zx_packet_signal_t); 48 49 impl Packet { 50 /// Creates a new packet with `UserPacket` data. from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet51 pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet { 52 Packet( 53 sys::zx_port_packet_t { 54 key: key, 55 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_USER, 56 status: status, 57 union: user.0, 58 } 59 ) 60 } 61 62 /// The packet's key. key(&self) -> u6463 pub fn key(&self) -> u64 { 64 self.0.key 65 } 66 67 /// The packet's status. 68 // TODO: should this type be wrapped? status(&self) -> i3269 pub fn status(&self) -> i32 { 70 self.0.status 71 } 72 73 /// The contents of the packet. contents(&self) -> PacketContents74 pub fn contents(&self) -> PacketContents { 75 if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_USER { 76 PacketContents::User(UserPacket(self.0.union)) 77 } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_ONE { 78 PacketContents::SignalOne(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) 79 } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_REP { 80 PacketContents::SignalRep(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) 81 } else { 82 panic!("unexpected packet type"); 83 } 84 } 85 } 86 87 impl UserPacket { from_u8_array(val: [u8; 32]) -> UserPacket88 pub fn from_u8_array(val: [u8; 32]) -> UserPacket { 89 UserPacket(val) 90 } 91 as_u8_array(&self) -> &[u8; 32]92 pub fn as_u8_array(&self) -> &[u8; 32] { 93 &self.0 94 } 95 as_mut_u8_array(&mut self) -> &mut [u8; 32]96 pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] { 97 &mut self.0 98 } 99 } 100 101 impl SignalPacket { 102 /// The signals used in the call to `object_wait_async`. trigger(&self) -> Signals103 pub fn trigger(&self) -> Signals { 104 Signals::from_bits_truncate(self.0.trigger) 105 } 106 107 /// The observed signals. observed(&self) -> Signals108 pub fn observed(&self) -> Signals { 109 Signals::from_bits_truncate(self.0.observed) 110 } 111 112 /// A per object count of pending operations. count(&self) -> u64113 pub fn count(&self) -> u64 { 114 self.0.count 115 } 116 } 117 118 impl Port { 119 /// Create an IO port, allowing IO packets to be read and enqueued. 120 /// 121 /// Wraps the 122 /// [zx_port_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_create.md) 123 /// syscall. create() -> Result<Port, Status>124 pub fn create() -> Result<Port, Status> { 125 unsafe { 126 let mut handle = 0; 127 let opts = 0; 128 let status = sys::zx_port_create(opts, &mut handle); 129 ok(status)?; 130 Ok(Handle::from_raw(handle).into()) 131 } 132 } 133 134 /// Attempt to queue a user packet to the IO port. 135 /// 136 /// Wraps the 137 /// [zx_port_queue](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_queue.md) 138 /// syscall. queue(&self, packet: &Packet) -> Result<(), Status>139 pub fn queue(&self, packet: &Packet) -> Result<(), Status> { 140 let status = unsafe { 141 sys::zx_port_queue(self.raw_handle(), 142 &packet.0 as *const sys::zx_port_packet_t, 0) 143 }; 144 ok(status) 145 } 146 147 /// Wait for a packet to arrive on a (V2) port. 148 /// 149 /// Wraps the 150 /// [zx_port_wait](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md) 151 /// syscall. wait(&self, deadline: Time) -> Result<Packet, Status>152 pub fn wait(&self, deadline: Time) -> Result<Packet, Status> { 153 let mut packet = Default::default(); 154 let status = unsafe { 155 sys::zx_port_wait(self.raw_handle(), deadline.nanos(), 156 &mut packet as *mut sys::zx_port_packet_t, 0) 157 }; 158 ok(status)?; 159 Ok(Packet(packet)) 160 } 161 162 /// Cancel pending wait_async calls for an object with the given key. 163 /// 164 /// Wraps the 165 /// [zx_port_cancel](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/port_cancel.md) 166 /// syscall. cancel<H>(&self, source: &H, key: u64) -> Result<(), Status> where H: HandleBased167 pub fn cancel<H>(&self, source: &H, key: u64) -> Result<(), Status> where H: HandleBased { 168 let status = unsafe { 169 sys::zx_port_cancel(self.raw_handle(), source.raw_handle(), key) 170 }; 171 ok(status) 172 } 173 } 174 175 /// Options for wait_async. 176 #[repr(u32)] 177 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 178 pub enum WaitAsyncOpts { 179 Once = sys::ZX_WAIT_ASYNC_ONCE, 180 Repeating = sys::ZX_WAIT_ASYNC_REPEATING, 181 } 182 183 #[cfg(test)] 184 mod tests { 185 use super::*; 186 use {DurationNum, Event}; 187 188 #[test] port_basic()189 fn port_basic() { 190 let ten_ms = 10.millis(); 191 192 let port = Port::create().unwrap(); 193 194 // Waiting now should time out. 195 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 196 197 // Send a valid packet. 198 let packet = Packet::from_user_packet( 199 42, 200 123, 201 UserPacket::from_u8_array([13; 32]), 202 ); 203 assert!(port.queue(&packet).is_ok()); 204 205 // Waiting should succeed this time. We should get back the packet we sent. 206 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 207 assert_eq!(read_packet, packet); 208 } 209 210 #[test] wait_async_once()211 fn wait_async_once() { 212 let ten_ms = 10.millis(); 213 let key = 42; 214 215 let port = Port::create().unwrap(); 216 let event = Event::create().unwrap(); 217 218 assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, 219 WaitAsyncOpts::Once).is_ok()); 220 221 // Waiting without setting any signal should time out. 222 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 223 224 // If we set a signal, we should be able to wait for it. 225 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); 226 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 227 assert_eq!(read_packet.key(), key); 228 assert_eq!(read_packet.status(), 0); 229 match read_packet.contents() { 230 PacketContents::SignalOne(sig) => { 231 assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); 232 assert_eq!(sig.observed(), Signals::USER_0); 233 assert_eq!(sig.count(), 1); 234 } 235 _ => panic!("wrong packet type"), 236 } 237 238 // Shouldn't get any more packets. 239 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 240 241 // Calling wait_async again should result in another packet. 242 assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); 243 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 244 assert_eq!(read_packet.key(), key); 245 assert_eq!(read_packet.status(), 0); 246 match read_packet.contents() { 247 PacketContents::SignalOne(sig) => { 248 assert_eq!(sig.trigger(), Signals::USER_0); 249 assert_eq!(sig.observed(), Signals::USER_0); 250 assert_eq!(sig.count(), 1); 251 } 252 _ => panic!("wrong packet type"), 253 } 254 255 // Calling wait_async_handle then cancel, we should not get a packet as cancel will 256 // remove it from the queue. 257 assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); 258 assert!(port.cancel(&event, key).is_ok()); 259 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 260 261 // If the event is signalled after the cancel, we also shouldn't get a packet. 262 assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal 263 assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); 264 assert!(port.cancel(&event, key).is_ok()); 265 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); 266 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 267 } 268 269 #[test] wait_async_repeating()270 fn wait_async_repeating() { 271 let ten_ms = 10.millis(); 272 let key = 42; 273 274 let port = Port::create().unwrap(); 275 let event = Event::create().unwrap(); 276 277 assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, 278 WaitAsyncOpts::Repeating).is_ok()); 279 280 // Waiting without setting any signal should time out. 281 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 282 283 // If we set a signal, we should be able to wait for it. 284 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); 285 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 286 assert_eq!(read_packet.key(), key); 287 assert_eq!(read_packet.status(), 0); 288 match read_packet.contents() { 289 PacketContents::SignalRep(sig) => { 290 assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); 291 assert_eq!(sig.observed(), Signals::USER_0); 292 assert_eq!(sig.count(), 1); 293 } 294 _ => panic!("wrong packet type"), 295 } 296 297 // Should not get any more packets, as ZX_WAIT_ASYNC_REPEATING is edge triggered rather than 298 // level triggered. 299 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 300 301 // If we clear and resignal, we should get the same packet again, 302 // even though we didn't call event.wait_async again. 303 assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal 304 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); 305 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 306 assert_eq!(read_packet.key(), key); 307 assert_eq!(read_packet.status(), 0); 308 match read_packet.contents() { 309 PacketContents::SignalRep(sig) => { 310 assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); 311 assert_eq!(sig.observed(), Signals::USER_0); 312 assert_eq!(sig.count(), 1); 313 } 314 _ => panic!("wrong packet type"), 315 } 316 317 // Cancelling the wait should stop us getting packets... 318 assert!(port.cancel(&event, key).is_ok()); 319 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 320 // ... even if we clear and resignal 321 assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal 322 assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); 323 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 324 325 // Calling wait_async again should result in another packet. 326 assert!(event.wait_async_handle( 327 &port, key, Signals::USER_0, WaitAsyncOpts::Repeating).is_ok()); 328 let read_packet = port.wait(ten_ms.after_now()).unwrap(); 329 assert_eq!(read_packet.key(), key); 330 assert_eq!(read_packet.status(), 0); 331 match read_packet.contents() { 332 PacketContents::SignalRep(sig) => { 333 assert_eq!(sig.trigger(), Signals::USER_0); 334 assert_eq!(sig.observed(), Signals::USER_0); 335 assert_eq!(sig.count(), 1); 336 } 337 _ => panic!("wrong packet type"), 338 } 339 340 // Closing the handle should stop us getting packets. 341 drop(event); 342 assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); 343 } 344 } 345