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