fuchsia_zircon/
port.rs

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
7use std::mem;
8
9use {AsHandleRef, HandleBased, Handle, HandleRef, Signals, Status, Time};
10use {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)]
17pub struct Port(Handle);
18impl_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)]
23pub struct Packet(sys::zx_port_packet_t);
24
25/// The contents of a `Packet`.
26#[derive(Debug, Copy, Clone)]
27pub 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)]
42pub 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)]
47pub struct SignalPacket(sys::zx_packet_signal_t);
48
49impl Packet {
50    /// Creates a new packet with `UserPacket` data.
51    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.
63    pub fn key(&self) -> u64 {
64        self.0.key
65    }
66
67    /// The packet's status.
68    // TODO: should this type be wrapped?
69    pub fn status(&self) -> i32 {
70        self.0.status
71    }
72
73    /// The contents of the packet.
74    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
87impl UserPacket {
88    pub fn from_u8_array(val: [u8; 32]) -> UserPacket {
89        UserPacket(val)
90    }
91
92    pub fn as_u8_array(&self) -> &[u8; 32] {
93        &self.0
94    }
95
96    pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] {
97        &mut self.0
98    }
99}
100
101impl SignalPacket {
102    /// The signals used in the call to `object_wait_async`.
103    pub fn trigger(&self) -> Signals {
104        Signals::from_bits_truncate(self.0.trigger)
105    }
106
107    /// The observed signals.
108    pub fn observed(&self) -> Signals {
109        Signals::from_bits_truncate(self.0.observed)
110    }
111
112    /// A per object count of pending operations.
113    pub fn count(&self) -> u64 {
114        self.0.count
115    }
116}
117
118impl 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.
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.
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.
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.
167    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)]
178pub enum WaitAsyncOpts {
179    Once = sys::ZX_WAIT_ASYNC_ONCE,
180    Repeating = sys::ZX_WAIT_ASYNC_REPEATING,
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186    use {DurationNum, Event};
187
188    #[test]
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]
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]
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}