zx/
handle.rs

1// Copyright 2018 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 handles.
6
7use crate::{
8    MonotonicInstant, Name, ObjectQuery, Port, Property, PropertyQuery, Rights, Signals, Status,
9    Topic, WaitAsyncOpts, object_get_info_single, object_get_property, object_set_property, ok,
10    sys,
11};
12use std::marker::PhantomData;
13use std::mem::{self, ManuallyDrop};
14use std::num::NonZeroU32;
15
16/// An owned and valid Zircon
17/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles) to a kernel object.
18///
19/// This type can be interconverted to and from more specific types. Those conversions are not
20/// enforced in the type system; attempting to use them will result in errors returned by the
21/// kernel. These conversions don't change the underlying representation, but do change the type and
22/// what operations are available.
23///
24/// # Lifecycle
25///
26/// This type closes the handle it owns when dropped.
27///
28/// # Layout
29///
30/// `Option<Handle>` is guaranteed to have the same layout and bit patterns as `zx_handle_t`.
31/// Unlike many types in this crate it does not implement `zerocopy` traits because those are not
32/// appropriate for types with real `Drop` implementations.
33#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
34#[repr(transparent)]
35pub struct Handle(NonZeroU32);
36
37// Ensure ABI-compatibility with zx_handle_t with the following static assertions. NonZeroU32 lets
38// Option store the None variant in the all-zeroes bit pattern, which is ZX_HANDLE_INVALID. By
39// banning use of ZX_HANDLE_INVALID inside a Handle, we ensure that Option<Handle> is ABI-compatible
40// with sys::zx_handle_t while providing statically checkable nullability.
41static_assertions::const_assert_eq!(sys::ZX_HANDLE_INVALID, 0);
42static_assertions::assert_eq_size!(Handle, sys::zx_handle_t);
43static_assertions::assert_eq_align!(Handle, sys::zx_handle_t);
44static_assertions::assert_eq_size!(Option<Handle>, sys::zx_handle_t);
45static_assertions::assert_eq_align!(Option<Handle>, sys::zx_handle_t);
46
47impl Handle {
48    /// Take exclusive ownership over a raw handle.
49    ///
50    /// # Safety
51    ///
52    /// `raw` must be a valid handle present in the current handle table that will not be closed by
53    /// another owner.
54    ///
55    /// # Panics
56    ///
57    /// If `ZX_HANDLE_INVALID` is passed.
58    pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
59        debug_assert!(Self::check_raw_valid(raw).is_ok());
60        Self(NonZeroU32::new(raw).unwrap())
61    }
62
63    /// Wraps the
64    /// [zx_handle_check_valid](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_check_valid.md)
65    /// syscall.
66    ///
67    /// Note that this does *not* guarantee that the handle is safe to pass to `Handle::from_raw`
68    /// in cases where another function may close the handle.
69    pub fn check_raw_valid(raw: sys::zx_handle_t) -> Result<(), Status> {
70        // SAFETY: basic FFI call.
71        ok(unsafe { sys::zx_handle_check_valid(raw) })
72    }
73
74    /// Returns the raw handle's integer value.
75    pub const fn raw_handle(&self) -> sys::zx_handle_t {
76        self.0.get()
77    }
78
79    /// Return the raw handle's integer value without closing it when `self` is dropped.
80    pub const fn into_raw(self) -> sys::zx_handle_t {
81        let ret = self.0.get();
82        std::mem::forget(self);
83        ret
84    }
85
86    /// Wraps the
87    /// [zx_handle_replace](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace.md)
88    /// syscall.
89    pub fn replace(self, rights: Rights) -> Result<Self, Status> {
90        let mut out = 0;
91
92        // SAFETY: basic FFI call.
93        let status = unsafe { sys::zx_handle_replace(self.into_raw(), rights.bits(), &mut out) };
94        ok(status)?;
95
96        // SAFETY: zx_handle_replace gives us a valid owned handle if the call succeeded.
97        unsafe { Ok(Self::from_raw(out)) }
98    }
99}
100
101impl Drop for Handle {
102    fn drop(&mut self) {
103        // SAFETY: basic FFI call.
104        unsafe { sys::zx_handle_close(self.0.get()) };
105    }
106}
107
108#[derive(
109    Debug,
110    Copy,
111    Clone,
112    Eq,
113    PartialEq,
114    Ord,
115    PartialOrd,
116    Hash,
117    zerocopy::FromBytes,
118    zerocopy::KnownLayout,
119    zerocopy::Immutable,
120)]
121#[repr(transparent)]
122pub struct Koid(sys::zx_koid_t);
123
124impl Koid {
125    pub const fn from_raw(raw: sys::zx_koid_t) -> Koid {
126        Koid(raw)
127    }
128
129    pub const fn raw_koid(&self) -> sys::zx_koid_t {
130        self.0
131    }
132}
133
134/// An object representing a Zircon
135/// [handle](https://fuchsia.dev/fuchsia-src/concepts/objects/handles).
136///
137/// Internally, it is represented as a 32-bit integer, but this wrapper enforces
138/// strict ownership semantics. The `Drop` implementation closes the handle.
139///
140/// This type represents the most general reference to a kernel object, and can
141/// be interconverted to and from more specific types. Those conversions are not
142/// enforced in the type system; attempting to use them will result in errors
143/// returned by the kernel. These conversions don't change the underlying
144/// representation, but do change the type and thus what operations are available.
145// TODO(https://fxbug.dev/465766514): remove
146#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
147#[repr(transparent)]
148pub struct NullableHandle(Option<Handle>);
149
150impl AsHandleRef for NullableHandle {
151    fn as_handle_ref(&self) -> HandleRef<'_> {
152        if let Some(inner) = &self.0 {
153            // SAFETY: inner is a guaranteed valid handle.
154            unsafe { Unowned::from_raw_handle(inner.raw_handle()) }
155        } else {
156            // SAFETY: ZX_HANDLE_INVALID is a valid handle for Unowned::from_raw_handle.
157            unsafe { Unowned::from_raw_handle(sys::ZX_HANDLE_INVALID) }
158        }
159    }
160
161    fn raw_handle(&self) -> sys::zx_handle_t {
162        self.0.as_ref().map(|h| h.raw_handle()).unwrap_or(sys::ZX_HANDLE_INVALID)
163    }
164}
165
166impl HandleBased for NullableHandle {
167    fn into_raw(self) -> sys::zx_handle_t {
168        if let Some(inner) = self.0 { inner.into_raw() } else { sys::ZX_HANDLE_INVALID }
169    }
170}
171
172impl NullableHandle {
173    /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle.
174    #[inline(always)]
175    pub const fn invalid() -> Self {
176        Self(None)
177    }
178
179    /// If a raw handle is obtained from some other source, this method converts
180    /// it into a type-safe owned handle.
181    ///
182    /// # Safety
183    ///
184    /// `raw` must either be a valid handle (i.e. not dangling), or
185    /// `ZX_HANDLE_INVALID`. If `raw` is a valid handle, then either:
186    /// - `raw` may be closed manually and the returned `NullableHandle` must not be
187    ///   dropped.
188    /// - Or `raw` must not be closed until the returned `NullableHandle` is dropped, at
189    ///   which time it will close `raw`.
190    pub const unsafe fn from_raw(raw: sys::zx_handle_t) -> Self {
191        // We need to manually construct the inner `Handle` because its constructor is not
192        // const since the only valid way to call this function in a `const` context is to pass
193        // `ZX_HANDLE_INVALID`.
194        if let Some(inner) = NonZeroU32::new(raw) { Self(Some(Handle(inner))) } else { Self(None) }
195    }
196
197    pub fn is_invalid(&self) -> bool {
198        self.0.is_none()
199    }
200
201    pub fn replace(mut self, rights: Rights) -> Result<Self, Status> {
202        if let Some(inner) = self.0.take() {
203            let inner = inner.replace(rights)?;
204            Ok(Self(Some(inner)))
205        } else {
206            Ok(Self(None))
207        }
208    }
209}
210struct NameProperty();
211unsafe impl PropertyQuery for NameProperty {
212    const PROPERTY: Property = Property::NAME;
213    // SAFETY: this type is correctly sized and the kernel guarantees that it will be
214    // null-terminated like the type requires.
215    type PropTy = Name;
216}
217
218/// A borrowed value of type `T`.
219///
220/// This is primarily used for working with borrowed values of `HandleBased` types.
221#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
222#[repr(transparent)]
223pub struct Unowned<'a, T: Into<NullableHandle>> {
224    inner: ManuallyDrop<T>,
225    marker: PhantomData<&'a T>,
226}
227
228impl<T: Into<NullableHandle>> Drop for Unowned<'_, T> {
229    fn drop(&mut self) {
230        // SAFETY: This is safe because we don't use this ManuallyDrop again.
231        let handle: NullableHandle = unsafe { ManuallyDrop::take(&mut self.inner).into() };
232        mem::forget(handle);
233    }
234}
235
236impl<'a, T: Into<NullableHandle>> ::std::ops::Deref for Unowned<'a, T> {
237    type Target = T;
238
239    fn deref(&self) -> &Self::Target {
240        &*self.inner
241    }
242}
243
244impl<T: HandleBased> Clone for Unowned<'_, T> {
245    fn clone(&self) -> Self {
246        unsafe { Self::from_raw_handle(self.inner.as_handle_ref().raw_handle()) }
247    }
248}
249
250pub type HandleRef<'a> = Unowned<'a, NullableHandle>;
251
252impl<'a, T: Into<NullableHandle>> Unowned<'a, T> {
253    /// Returns a new object that borrows the underyling handle.  This will work for any type that
254    /// implements `From<U>` where `U` is handle-like i.e. it implements `AsHandleRef` and
255    /// `From<Handle>`.
256    pub fn new<U: AsHandleRef + From<NullableHandle>>(inner: &'a U) -> Self
257    where
258        T: From<U>,
259    {
260        // SAFETY: This is safe because we are converting from &U to U to allow us to create T, and
261        // then when we drop, we convert T into a handle that we forget.
262        Unowned {
263            inner: ManuallyDrop::new(T::from(U::from(unsafe {
264                NullableHandle::from_raw(inner.as_handle_ref().raw_handle())
265            }))),
266            marker: PhantomData,
267        }
268    }
269}
270
271impl<'a, T: HandleBased> Unowned<'a, T> {
272    /// Create a `HandleRef` from a raw handle. Use this method when you are given a raw handle but
273    /// should not take ownership of it. Examples include process-global handles like the root
274    /// VMAR. This method should be called with an explicitly provided lifetime that must not
275    /// outlive the lifetime during which the handle is owned by the current process. It is unsafe
276    /// because most of the time, it is better to use a `Handle` to prevent leaking resources.
277    ///
278    /// # Safety
279    ///
280    /// `handle` must be a valid handle (i.e. not dangling), or
281    /// `ZX_HANDLE_INVALID`. If `handle` is a valid handle, then it must not be
282    /// closed for the lifetime `'a`.
283    pub unsafe fn from_raw_handle(handle: sys::zx_handle_t) -> Self {
284        Unowned {
285            inner: ManuallyDrop::new(T::from(unsafe { NullableHandle::from_raw(handle) })),
286            marker: PhantomData,
287        }
288    }
289
290    pub fn raw_handle(&self) -> sys::zx_handle_t {
291        self.inner.raw_handle()
292    }
293
294    pub fn duplicate(&self, rights: Rights) -> Result<T, Status> {
295        let mut out = 0;
296        // SAFETY: basic FFI call.
297        let status =
298            unsafe { sys::zx_handle_duplicate(self.raw_handle(), rights.bits(), &mut out) };
299        ok(status)?;
300
301        // SAFETY: zx_handle_duplicate returns a valid handle that this function owns.
302        Ok(T::from(unsafe { NullableHandle::from_raw(out) }))
303    }
304
305    pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
306        let status =
307            unsafe { sys::zx_object_signal(self.raw_handle(), clear_mask.bits(), set_mask.bits()) };
308        ok(status)
309    }
310
311    pub fn wait(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
312        let mut pending = Signals::empty().bits();
313        let status = unsafe {
314            sys::zx_object_wait_one(
315                self.raw_handle(),
316                signals.bits(),
317                deadline.into_nanos(),
318                &mut pending,
319            )
320        };
321        let signals = Signals::from_bits_truncate(pending);
322        match ok(status) {
323            Ok(()) => WaitResult::Ok(signals),
324            Err(Status::TIMED_OUT) => WaitResult::TimedOut(signals),
325            Err(Status::CANCELED) => WaitResult::Canceled(signals),
326            Err(e) => WaitResult::Err(e),
327        }
328    }
329
330    pub fn wait_async(
331        &self,
332        port: &Port,
333        key: u64,
334        signals: Signals,
335        options: WaitAsyncOpts,
336    ) -> Result<(), Status> {
337        let status = unsafe {
338            sys::zx_object_wait_async(
339                self.raw_handle(),
340                port.raw_handle(),
341                key,
342                signals.bits(),
343                options.bits(),
344            )
345        };
346        ok(status)
347    }
348}
349
350/// Result from `HandleRef::wait` and `AsHandleRef::wait_handle`. Conveys the
351/// result of the
352/// [zx_object_wait_one](https://fuchsia.dev/reference/syscalls/object_wait_one)
353/// syscall and the signals that were asserted on the object when the syscall
354/// completed.
355#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
356pub enum WaitResult {
357    /// The syscall completed with `ZX_OK` and the provided signals were observed.
358    Ok(Signals),
359
360    /// The syscall completed with `ZX_ERR_TIMED_OUT` and the provided signals
361    /// were observed. These signals may reflect state changes that occurred
362    /// after the deadline passed, but before the syscall returned.
363    TimedOut(Signals),
364
365    /// The syscall completed with `ZX_ERR_CANCELED` and the provided signals
366    /// were observed. The signals will include `ZX_SIGNAL_HANDLE_CLOSED`.
367    ///
368    /// Note that the state of these signals may be racy and difficult to
369    /// interpret. Often, the correct behavior in this case is to treat this as
370    /// an error.
371    Canceled(Signals),
372
373    /// The syscall completed with a status other than `ZX_OK`, `ZX_ERR_TIMED_OUT`,
374    /// or `ZX_ERR_CANCELED`. No signals are returned in this scenario.
375    Err(Status),
376}
377
378impl WaitResult {
379    /// Convert this `WaitResult` into a `Result<Signals, Status>`. The signals
380    /// are discarded in all cases except `WaitResult::Ok`.
381    pub const fn to_result(self) -> Result<Signals, Status> {
382        match self {
383            WaitResult::Ok(signals) => Ok(signals),
384            WaitResult::TimedOut(_signals) => Err(Status::TIMED_OUT),
385            WaitResult::Canceled(_signals) => Err(Status::CANCELED),
386            WaitResult::Err(status) => Err(status),
387        }
388    }
389
390    // The following definitions are all copied from `std::result::Result`. They
391    // allow a `WaitResult` to be treated like a `Result` in many circumstance. All
392    // simply delegate to `to_result()`.
393
394    #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"]
395    #[inline]
396    pub const fn is_ok(&self) -> bool {
397        self.to_result().is_ok()
398    }
399
400    #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"]
401    #[inline]
402    pub const fn is_err(&self) -> bool {
403        self.to_result().is_err()
404    }
405
406    #[inline]
407    pub fn map<U, F: FnOnce(Signals) -> U>(self, op: F) -> Result<U, Status> {
408        self.to_result().map(op)
409    }
410
411    #[inline]
412    pub fn map_err<F, O: FnOnce(Status) -> F>(self, op: O) -> Result<Signals, F> {
413        self.to_result().map_err(op)
414    }
415
416    #[inline]
417    #[track_caller]
418    pub fn expect(self, msg: &str) -> Signals {
419        self.to_result().expect(msg)
420    }
421
422    #[inline]
423    #[track_caller]
424    pub fn expect_err(self, msg: &str) -> Status {
425        self.to_result().expect_err(msg)
426    }
427
428    #[inline(always)]
429    #[track_caller]
430    pub fn unwrap(self) -> Signals {
431        self.to_result().unwrap()
432    }
433}
434
435impl<'a> Unowned<'a, NullableHandle> {
436    /// Convert this HandleRef to one of a specific type.
437    pub fn cast<T: HandleBased>(self) -> Unowned<'a, T> {
438        // SAFETY: this function's guarantees are upheld by the self input.
439        unsafe { Unowned::from_raw_handle(self.raw_handle()) }
440    }
441}
442
443/// A trait to get a reference to the underlying handle of an object.
444pub trait AsHandleRef {
445    /// Get a reference to the handle. One important use of such a reference is
446    /// for `object_wait_many`.
447    fn as_handle_ref(&self) -> HandleRef<'_>;
448
449    /// Interpret the reference as a raw handle (an integer type). Two distinct
450    /// handles will have different raw values (so it can perhaps be used as a
451    /// key in a data structure).
452    fn raw_handle(&self) -> sys::zx_handle_t {
453        self.as_handle_ref().inner.raw_handle()
454    }
455
456    /// Set and clear userspace-accessible signal bits on an object. Wraps the
457    /// [zx_object_signal](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal.md)
458    /// syscall.
459    fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
460        self.as_handle_ref().signal(clear_mask, set_mask)
461    }
462
463    /// Waits on a handle. Wraps the
464    /// [zx_object_wait_one](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_one.md)
465    /// syscall.
466    fn wait_handle(&self, signals: Signals, deadline: MonotonicInstant) -> WaitResult {
467        self.as_handle_ref().wait(signals, deadline)
468    }
469
470    /// Causes packet delivery on the given port when the object changes state and matches signals.
471    /// [zx_object_wait_async](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_wait_async.md)
472    /// syscall.
473    fn wait_async_handle(
474        &self,
475        port: &Port,
476        key: u64,
477        signals: Signals,
478        options: WaitAsyncOpts,
479    ) -> Result<(), Status> {
480        self.as_handle_ref().wait_async(port, key, signals, options)
481    }
482
483    /// Get the [Property::NAME] property for this object.
484    ///
485    /// Wraps a call to the
486    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
487    /// syscall for the ZX_PROP_NAME property.
488    fn get_name(&self) -> Result<Name, Status> {
489        object_get_property::<NameProperty>(self.as_handle_ref())
490    }
491
492    /// Set the [Property::NAME] property for this object.
493    ///
494    /// The name's length must be less than [sys::ZX_MAX_NAME_LEN], i.e.
495    /// name.[to_bytes_with_nul()](CStr::to_bytes_with_nul()).len() <= [sys::ZX_MAX_NAME_LEN], or
496    /// Err([Status::INVALID_ARGS]) will be returned.
497    ///
498    /// Wraps a call to the
499    /// [zx_object_get_property](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_property.md)
500    /// syscall for the ZX_PROP_NAME property.
501    fn set_name(&self, name: &Name) -> Result<(), Status> {
502        object_set_property::<NameProperty>(self.as_handle_ref(), &name)
503    }
504
505    /// Wraps the
506    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
507    /// syscall for the ZX_INFO_HANDLE_BASIC topic.
508    fn basic_info(&self) -> Result<HandleBasicInfo, Status> {
509        Ok(HandleBasicInfo::from(object_get_info_single::<HandleBasicInfoQuery>(
510            self.as_handle_ref(),
511        )?))
512    }
513
514    /// Wraps the
515    /// [zx_object_get_info](https://fuchsia.dev/fuchsia-src/reference/syscalls/object_get_info.md)
516    /// syscall for the ZX_INFO_HANDLE_COUNT topic.
517    fn count_info(&self) -> Result<HandleCountInfo, Status> {
518        Ok(HandleCountInfo::from(object_get_info_single::<HandleCountInfoQuery>(
519            self.as_handle_ref(),
520        )?))
521    }
522
523    /// Returns the koid (kernel object ID) for this handle.
524    fn get_koid(&self) -> Result<Koid, Status> {
525        self.basic_info().map(|info| info.koid)
526    }
527}
528
529impl<'a, T: HandleBased> AsHandleRef for Unowned<'a, T> {
530    fn as_handle_ref(&self) -> HandleRef<'_> {
531        self.inner.as_handle_ref()
532    }
533}
534
535impl<T: AsHandleRef> AsHandleRef for &T {
536    fn as_handle_ref(&self) -> HandleRef<'_> {
537        (*self).as_handle_ref()
538    }
539}
540
541/// A trait implemented by all handle-based types.
542///
543/// Note: it is reasonable for user-defined objects wrapping a handle to implement
544/// this trait. For example, a specific interface in some protocol might be
545/// represented as a newtype of `Channel`, and implement the `as_handle_ref`
546/// method and the `From<Handle>` trait to facilitate conversion from and to the
547/// interface.
548pub trait HandleBased: AsHandleRef + From<NullableHandle> + Into<NullableHandle> {
549    /// Duplicate a handle, possibly reducing the rights available. Wraps the
550    /// [zx_handle_duplicate](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_duplicate.md)
551    /// syscall.
552    fn duplicate_handle(&self, rights: Rights) -> Result<Self, Status> {
553        self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle))
554    }
555
556    /// Create a replacement for a handle, possibly reducing the rights available. This invalidates
557    /// the original handle. Wraps the
558    /// [zx_handle_replace](https://fuchsia.dev/fuchsia-src/reference/syscalls/handle_replace.md)
559    /// syscall.
560    fn replace_handle(self, rights: Rights) -> Result<Self, Status> {
561        <Self as Into<NullableHandle>>::into(self).replace(rights).map(|handle| Self::from(handle))
562    }
563
564    /// Converts the value into its inner handle.
565    ///
566    /// This is a convenience function which simply forwards to the `Into` trait.
567    fn into_handle(self) -> NullableHandle {
568        self.into()
569    }
570
571    /// Converts the handle into it's raw representation.
572    ///
573    /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak.
574    fn into_raw(self) -> sys::zx_handle_t {
575        self.into_handle().into_raw()
576    }
577
578    /// Creates an instance of this type from a handle.
579    ///
580    /// This is a convenience function which simply forwards to the `From` trait.
581    fn from_handle(handle: NullableHandle) -> Self {
582        Self::from(handle)
583    }
584
585    /// Creates an instance of another handle-based type from this value's inner handle.
586    fn into_handle_based<H: HandleBased>(self) -> H {
587        H::from_handle(self.into_handle())
588    }
589
590    /// Creates an instance of this type from the inner handle of another
591    /// handle-based type.
592    fn from_handle_based<H: HandleBased>(h: H) -> Self {
593        Self::from_handle(h.into_handle())
594    }
595
596    fn is_invalid_handle(&self) -> bool {
597        self.as_handle_ref().is_invalid()
598    }
599}
600
601/// A trait implemented by all handles for objects which have a peer.
602pub trait Peered: HandleBased {
603    /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the
604    /// [zx_object_signal_peer][osp] syscall.
605    ///
606    /// [osp]: https://fuchsia.dev/fuchsia-src/reference/syscalls/object_signal_peer.md
607    fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> {
608        let handle = self.raw_handle();
609        let status =
610            unsafe { sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) };
611        ok(status)
612    }
613
614    /// Returns true if the handle has received the `PEER_CLOSED` signal.
615    ///
616    /// # Errors
617    ///
618    /// See https://fuchsia.dev/reference/syscalls/object_wait_one?hl=en#errors for a full list of
619    /// errors. Note that `Status::TIMED_OUT` errors are converted to `Ok(false)` and all other
620    /// errors are propagated.
621    fn is_closed(&self) -> Result<bool, Status> {
622        match self.wait_handle(Signals::OBJECT_PEER_CLOSED, MonotonicInstant::INFINITE_PAST) {
623            WaitResult::Ok(signals) => Ok(signals.contains(Signals::OBJECT_PEER_CLOSED)),
624            WaitResult::TimedOut(_) => Ok(false),
625            WaitResult::Canceled(_) => Err(Status::CANCELED),
626            WaitResult::Err(e) => Err(e),
627        }
628    }
629}
630
631/// Zircon object types.
632#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
633#[repr(transparent)]
634pub struct ObjectType(sys::zx_obj_type_t);
635
636assoc_values!(ObjectType, [
637    NONE            = sys::ZX_OBJ_TYPE_NONE;
638    PROCESS         = sys::ZX_OBJ_TYPE_PROCESS;
639    THREAD          = sys::ZX_OBJ_TYPE_THREAD;
640    VMO             = sys::ZX_OBJ_TYPE_VMO;
641    CHANNEL         = sys::ZX_OBJ_TYPE_CHANNEL;
642    EVENT           = sys::ZX_OBJ_TYPE_EVENT;
643    PORT            = sys::ZX_OBJ_TYPE_PORT;
644    INTERRUPT       = sys::ZX_OBJ_TYPE_INTERRUPT;
645    PCI_DEVICE      = sys::ZX_OBJ_TYPE_PCI_DEVICE;
646    DEBUGLOG        = sys::ZX_OBJ_TYPE_DEBUGLOG;
647    SOCKET          = sys::ZX_OBJ_TYPE_SOCKET;
648    RESOURCE        = sys::ZX_OBJ_TYPE_RESOURCE;
649    EVENTPAIR       = sys::ZX_OBJ_TYPE_EVENTPAIR;
650    JOB             = sys::ZX_OBJ_TYPE_JOB;
651    VMAR            = sys::ZX_OBJ_TYPE_VMAR;
652    FIFO            = sys::ZX_OBJ_TYPE_FIFO;
653    GUEST           = sys::ZX_OBJ_TYPE_GUEST;
654    VCPU            = sys::ZX_OBJ_TYPE_VCPU;
655    TIMER           = sys::ZX_OBJ_TYPE_TIMER;
656    IOMMU           = sys::ZX_OBJ_TYPE_IOMMU;
657    BTI             = sys::ZX_OBJ_TYPE_BTI;
658    PROFILE         = sys::ZX_OBJ_TYPE_PROFILE;
659    PMT             = sys::ZX_OBJ_TYPE_PMT;
660    SUSPEND_TOKEN   = sys::ZX_OBJ_TYPE_SUSPEND_TOKEN;
661    PAGER           = sys::ZX_OBJ_TYPE_PAGER;
662    EXCEPTION       = sys::ZX_OBJ_TYPE_EXCEPTION;
663    CLOCK           = sys::ZX_OBJ_TYPE_CLOCK;
664    STREAM          = sys::ZX_OBJ_TYPE_STREAM;
665    MSI             = sys::ZX_OBJ_TYPE_MSI;
666    IOB             = sys::ZX_OBJ_TYPE_IOB;
667    COUNTER         = sys::ZX_OBJ_TYPE_COUNTER;
668]);
669
670impl ObjectType {
671    /// Creates an `ObjectType` from the underlying zircon type.
672    pub const fn from_raw(raw: sys::zx_obj_type_t) -> Self {
673        Self(raw)
674    }
675
676    /// Converts `ObjectType` into the underlying zircon type.
677    pub const fn into_raw(self) -> sys::zx_obj_type_t {
678        self.0
679    }
680}
681
682/// Basic information about a handle.
683///
684/// Wrapper for data returned from [Handle::basic_info()].
685#[derive(Debug, Copy, Clone, Eq, PartialEq)]
686pub struct HandleBasicInfo {
687    pub koid: Koid,
688    pub rights: Rights,
689    pub object_type: ObjectType,
690    pub related_koid: Koid,
691}
692
693impl Default for HandleBasicInfo {
694    fn default() -> Self {
695        Self::from(sys::zx_info_handle_basic_t::default())
696    }
697}
698
699impl From<sys::zx_info_handle_basic_t> for HandleBasicInfo {
700    fn from(info: sys::zx_info_handle_basic_t) -> Self {
701        let sys::zx_info_handle_basic_t { koid, rights, type_, related_koid, .. } = info;
702
703        // Note lossy conversion of Rights and HandleProperty here if either of those types are out
704        // of date or incomplete.
705        HandleBasicInfo {
706            koid: Koid(koid),
707            rights: Rights::from_bits_truncate(rights),
708            object_type: ObjectType(type_),
709            related_koid: Koid(related_koid),
710        }
711    }
712}
713
714// zx_info_handle_basic_t is able to be safely replaced with a byte representation and is a PoD
715// type.
716struct HandleBasicInfoQuery;
717unsafe impl ObjectQuery for HandleBasicInfoQuery {
718    const TOPIC: Topic = Topic::HANDLE_BASIC;
719    type InfoTy = sys::zx_info_handle_basic_t;
720}
721
722sys::zx_info_handle_count_t!(HandleCountInfo);
723
724impl From<sys::zx_info_handle_count_t> for HandleCountInfo {
725    fn from(sys::zx_info_handle_count_t { handle_count }: sys::zx_info_handle_count_t) -> Self {
726        HandleCountInfo { handle_count }
727    }
728}
729
730// zx_info_handle_count_t is able to be safely replaced with a byte representation and is a PoD
731// type.
732struct HandleCountInfoQuery;
733unsafe impl ObjectQuery for HandleCountInfoQuery {
734    const TOPIC: Topic = Topic::HANDLE_COUNT;
735    type InfoTy = sys::zx_info_handle_count_t;
736}
737
738/// Handle operation.
739#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
740pub enum HandleOp<'a> {
741    Move(NullableHandle),
742    Duplicate(HandleRef<'a>),
743}
744
745/// Operation to perform on handles during write. ABI-compatible with `zx_handle_disposition_t`.
746#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
747#[repr(C)]
748pub struct HandleDisposition<'a> {
749    // Must be either ZX_HANDLE_OP_MOVE or ZX_HANDLE_OP_DUPLICATE.
750    operation: sys::zx_handle_op_t,
751    // ZX_HANDLE_OP_MOVE==owned, ZX_HANDLE_OP_DUPLICATE==borrowed.
752    handle: sys::zx_handle_t,
753    // Preserve a borrowed handle's lifetime. Does not occupy any layout.
754    _handle_lifetime: std::marker::PhantomData<&'a ()>,
755
756    pub object_type: ObjectType,
757    pub rights: Rights,
758    pub result: Status,
759}
760
761static_assertions::assert_eq_size!(HandleDisposition<'_>, sys::zx_handle_disposition_t);
762static_assertions::const_assert_eq!(
763    std::mem::offset_of!(HandleDisposition<'_>, operation),
764    std::mem::offset_of!(sys::zx_handle_disposition_t, operation)
765);
766static_assertions::const_assert_eq!(
767    std::mem::offset_of!(HandleDisposition<'_>, handle),
768    std::mem::offset_of!(sys::zx_handle_disposition_t, handle)
769);
770static_assertions::const_assert_eq!(
771    std::mem::offset_of!(HandleDisposition<'_>, object_type),
772    std::mem::offset_of!(sys::zx_handle_disposition_t, type_)
773);
774static_assertions::const_assert_eq!(
775    std::mem::offset_of!(HandleDisposition<'_>, rights),
776    std::mem::offset_of!(sys::zx_handle_disposition_t, rights)
777);
778static_assertions::const_assert_eq!(
779    std::mem::offset_of!(HandleDisposition<'_>, result),
780    std::mem::offset_of!(sys::zx_handle_disposition_t, result)
781);
782
783impl<'a> HandleDisposition<'a> {
784    #[inline]
785    pub fn new(
786        handle_op: HandleOp<'a>,
787        object_type: ObjectType,
788        rights: Rights,
789        status: Status,
790    ) -> Self {
791        let (operation, handle) = match handle_op {
792            HandleOp::Move(h) => (sys::ZX_HANDLE_OP_MOVE, h.into_raw()),
793            HandleOp::Duplicate(h) => (sys::ZX_HANDLE_OP_DUPLICATE, h.raw_handle()),
794        };
795
796        Self {
797            operation,
798            handle,
799            _handle_lifetime: std::marker::PhantomData,
800            object_type,
801            rights: rights,
802            result: status,
803        }
804    }
805
806    pub fn raw_handle(&self) -> sys::zx_handle_t {
807        self.handle
808    }
809
810    pub fn is_move(&self) -> bool {
811        self.operation == sys::ZX_HANDLE_OP_MOVE
812    }
813
814    pub fn is_duplicate(&self) -> bool {
815        self.operation == sys::ZX_HANDLE_OP_DUPLICATE
816    }
817
818    pub fn take_op(&mut self) -> HandleOp<'a> {
819        match self.operation {
820            sys::ZX_HANDLE_OP_MOVE => {
821                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
822                // type's public API and the kernel's guarantees.
823                HandleOp::Move(unsafe {
824                    NullableHandle::from_raw(std::mem::replace(
825                        &mut self.handle,
826                        sys::ZX_HANDLE_INVALID,
827                    ))
828                })
829            }
830            sys::ZX_HANDLE_OP_DUPLICATE => {
831                // SAFETY: this is guaranteed to be a valid handle number by a combination of this
832                // type's public API and the kernel's guarantees.
833                HandleOp::Duplicate(unsafe { Unowned::from_raw_handle(self.handle) })
834            }
835            _ => unreachable!(),
836        }
837    }
838
839    pub fn into_raw(mut self) -> sys::zx_handle_disposition_t {
840        match self.take_op() {
841            HandleOp::Move(mut handle) => sys::zx_handle_disposition_t {
842                operation: sys::ZX_HANDLE_OP_MOVE,
843                handle: std::mem::replace(&mut handle, NullableHandle::invalid()).into_raw(),
844                type_: self.object_type.0,
845                rights: self.rights.bits(),
846                result: self.result.into_raw(),
847            },
848            HandleOp::Duplicate(handle_ref) => sys::zx_handle_disposition_t {
849                operation: sys::ZX_HANDLE_OP_DUPLICATE,
850                handle: handle_ref.raw_handle(),
851                type_: self.object_type.0,
852                rights: self.rights.bits(),
853                result: self.result.into_raw(),
854            },
855        }
856    }
857}
858
859impl<'a> Drop for HandleDisposition<'a> {
860    fn drop(&mut self) {
861        // Ensure we clean up owned handle variants.
862        if self.operation == sys::ZX_HANDLE_OP_MOVE {
863            unsafe { drop(NullableHandle::from_raw(self.handle)) };
864        }
865    }
866}
867
868/// Information on handles that were read.
869///
870/// ABI-compatible with zx_handle_info_t.
871#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
872#[repr(C)]
873pub struct HandleInfo {
874    pub handle: NullableHandle,
875    pub object_type: ObjectType,
876    pub rights: Rights,
877
878    // Necessary for ABI compatibility with zx_handle_info_t.
879    pub(crate) _unused: u32,
880}
881
882static_assertions::assert_eq_size!(HandleInfo, sys::zx_handle_info_t);
883static_assertions::const_assert_eq!(
884    std::mem::offset_of!(HandleInfo, handle),
885    std::mem::offset_of!(sys::zx_handle_info_t, handle)
886);
887static_assertions::const_assert_eq!(
888    std::mem::offset_of!(HandleInfo, object_type),
889    std::mem::offset_of!(sys::zx_handle_info_t, ty)
890);
891static_assertions::const_assert_eq!(
892    std::mem::offset_of!(HandleInfo, rights),
893    std::mem::offset_of!(sys::zx_handle_info_t, rights)
894);
895static_assertions::const_assert_eq!(
896    std::mem::offset_of!(HandleInfo, _unused),
897    std::mem::offset_of!(sys::zx_handle_info_t, unused)
898);
899
900impl HandleInfo {
901    /// Make a new `HandleInfo`.
902    pub const fn new(handle: NullableHandle, object_type: ObjectType, rights: Rights) -> Self {
903        Self { handle, object_type, rights, _unused: 0 }
904    }
905
906    /// # Safety
907    ///
908    /// See [`Handle::from_raw`] for requirements about the validity and closing
909    /// of `raw.handle`.
910    ///
911    /// Note that while `raw.ty` _should_ correspond to the type of the handle,
912    /// that this is not required for safety.
913    pub const unsafe fn from_raw(raw: sys::zx_handle_info_t) -> HandleInfo {
914        HandleInfo::new(
915            // SAFETY: invariants to not double-close are upheld by the caller.
916            unsafe { NullableHandle::from_raw(raw.handle) },
917            ObjectType(raw.ty),
918            Rights::from_bits_retain(raw.rights),
919        )
920    }
921}
922
923#[cfg(test)]
924mod tests {
925    use super::*;
926    // The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
927    // zx::Vmar that we need to use.
928    use zx::{
929        AsHandleRef, Channel, HandleBased, HandleDisposition, HandleInfo, HandleOp, Name,
930        NullableHandle, ObjectType, Rights, Vmo,
931    };
932    use zx_sys as sys;
933
934    #[test]
935    fn into_raw() {
936        let vmo = Vmo::create(1).unwrap();
937        let h = vmo.into_raw();
938        let vmo2 = Vmo::from(unsafe { NullableHandle::from_raw(h) });
939        assert!(vmo2.write(b"1", 0).is_ok());
940    }
941
942    #[test]
943    fn check_raw_valid() {
944        assert!(Handle::check_raw_valid(sys::ZX_HANDLE_INVALID).is_err());
945        let vmo = Vmo::create(1).unwrap();
946        let vmo_raw = vmo.raw_handle();
947        assert!(Handle::check_raw_valid(vmo_raw).is_ok());
948        drop(vmo);
949        assert!(Handle::check_raw_valid(vmo_raw).is_err());
950    }
951
952    /// Test duplication by means of a VMO
953    #[test]
954    fn duplicate() {
955        let hello_length: usize = 5;
956
957        // Create a VMO and write some data to it.
958        let vmo = Vmo::create(hello_length as u64).unwrap();
959        assert!(vmo.write(b"hello", 0).is_ok());
960
961        // Replace, reducing rights to read.
962        let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap();
963        // Make sure we can read but not write.
964        let mut read_vec = vec![0; hello_length];
965        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
966        assert_eq!(read_vec, b"hello");
967        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
968
969        // Write new data to the original handle, and read it from the new handle
970        assert!(vmo.write(b"bye", 0).is_ok());
971        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
972        assert_eq!(read_vec, b"byelo");
973    }
974
975    // Test replace by means of a VMO
976    #[test]
977    fn replace() {
978        let hello_length: usize = 5;
979
980        // Create a VMO and write some data to it.
981        let vmo = Vmo::create(hello_length as u64).unwrap();
982        assert!(vmo.write(b"hello", 0).is_ok());
983
984        // Replace, reducing rights to read.
985        let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap();
986        // Make sure we can read but not write.
987        let mut read_vec = vec![0; hello_length];
988        assert!(readonly_vmo.read(&mut read_vec, 0).is_ok());
989        assert_eq!(read_vec, b"hello");
990        assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED));
991    }
992
993    #[test]
994    fn set_get_name() {
995        // We need some concrete object to exercise the AsHandleRef<'_> set/get_name functions.
996        let vmo = Vmo::create(1).unwrap();
997        let short_name = Name::new("v").unwrap();
998        assert!(vmo.set_name(&short_name).is_ok());
999        assert_eq!(vmo.get_name().unwrap(), short_name);
1000    }
1001
1002    #[test]
1003    fn set_get_max_len_name() {
1004        let vmo = Vmo::create(1).unwrap();
1005        let max_len_name = Name::new("a_great_maximum_length_vmo_name").unwrap(); // 31 bytes
1006        assert!(vmo.set_name(&max_len_name).is_ok());
1007        assert_eq!(vmo.get_name().unwrap(), max_len_name);
1008    }
1009
1010    #[test]
1011    fn basic_info_channel() {
1012        let (side1, side2) = Channel::create();
1013        let info1 = side1.basic_info().expect("side1 basic_info failed");
1014        let info2 = side2.basic_info().expect("side2 basic_info failed");
1015
1016        assert_eq!(info1.koid, info2.related_koid);
1017        assert_eq!(info2.koid, info1.related_koid);
1018
1019        for info in &[info1, info2] {
1020            assert!(info.koid.raw_koid() >= sys::ZX_KOID_FIRST);
1021            assert_eq!(info.object_type, ObjectType::CHANNEL);
1022            assert!(info.rights.contains(Rights::READ | Rights::WRITE | Rights::WAIT));
1023        }
1024
1025        let side1_repl = side1.replace_handle(Rights::READ).expect("side1 replace_handle failed");
1026        let info1_repl = side1_repl.basic_info().expect("side1_repl basic_info failed");
1027        assert_eq!(info1_repl.koid, info1.koid);
1028        assert_eq!(info1_repl.rights, Rights::READ);
1029    }
1030
1031    #[test]
1032    fn basic_info_vmar() {
1033        // VMARs aren't waitable.
1034        let root_vmar = fuchsia_runtime::vmar_root_self();
1035        let info = root_vmar.basic_info().expect("vmar basic_info failed");
1036        assert_eq!(info.object_type, ObjectType::VMAR);
1037        assert!(!info.rights.contains(Rights::WAIT));
1038    }
1039
1040    #[test]
1041    fn count_info() {
1042        let vmo0 = Vmo::create(1).unwrap();
1043        let count_info = vmo0.count_info().expect("vmo0 count_info failed");
1044        assert_eq!(count_info.handle_count, 1);
1045
1046        let vmo1 = vmo0.duplicate_handle(Rights::SAME_RIGHTS).expect("vmo duplicate_handle failed");
1047        let count_info = vmo1.count_info().expect("vmo1 count_info failed");
1048        assert_eq!(count_info.handle_count, 2);
1049    }
1050
1051    #[test]
1052    fn raw_handle_disposition() {
1053        const RAW_HANDLE: sys::zx_handle_t = 1;
1054        let hd = HandleDisposition::new(
1055            HandleOp::Move(unsafe { NullableHandle::from_raw(RAW_HANDLE) }),
1056            ObjectType::VMO,
1057            Rights::EXECUTE,
1058            Status::OK,
1059        );
1060        let raw_hd = hd.into_raw();
1061        assert_eq!(raw_hd.operation, sys::ZX_HANDLE_OP_MOVE);
1062        assert_eq!(raw_hd.handle, RAW_HANDLE);
1063        assert_eq!(raw_hd.rights, sys::ZX_RIGHT_EXECUTE);
1064        assert_eq!(raw_hd.type_, sys::ZX_OBJ_TYPE_VMO);
1065        assert_eq!(raw_hd.result, sys::ZX_OK);
1066    }
1067
1068    #[test]
1069    fn regression_nullable_handle_into_raw_recursion() {
1070        let h = NullableHandle::invalid();
1071        // This should not stack overflow
1072        assert_eq!(h.into_raw(), sys::ZX_HANDLE_INVALID);
1073
1074        let vmo = Vmo::create(1).unwrap();
1075        let raw = vmo.raw_handle();
1076        let h = vmo.into_handle();
1077        // This should not stack overflow
1078        assert_eq!(h.into_raw(), raw);
1079    }
1080
1081    #[test]
1082    fn handle_info_from_raw() {
1083        const RAW_HANDLE: sys::zx_handle_t = 1;
1084        let raw_hi = sys::zx_handle_info_t {
1085            handle: RAW_HANDLE,
1086            ty: sys::ZX_OBJ_TYPE_VMO,
1087            rights: sys::ZX_RIGHT_EXECUTE,
1088            unused: 128,
1089        };
1090        let hi = unsafe { HandleInfo::from_raw(raw_hi) };
1091        assert_eq!(hi.handle.into_raw(), RAW_HANDLE);
1092        assert_eq!(hi.object_type, ObjectType::VMO);
1093        assert_eq!(hi.rights, Rights::EXECUTE);
1094    }
1095
1096    #[test]
1097    fn basic_peer_closed() {
1098        let (lhs, rhs) = crate::EventPair::create();
1099        assert!(!lhs.is_closed().unwrap());
1100        assert!(!rhs.is_closed().unwrap());
1101        drop(rhs);
1102        assert!(lhs.is_closed().unwrap());
1103    }
1104}