zx/
interrupt.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 interrupts.
6
7use crate::{
8    AsHandleRef, BootTimeline, HandleBased, HandleRef, Instant, MonotonicTimeline, NullableHandle,
9    Port, Status, Timeline, ok, sys,
10};
11use std::marker::PhantomData;
12
13/// An object representing a Zircon interrupt.
14///
15/// As essentially a subtype of `NullableHandle`, it can be freely interconverted.
16#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
17#[repr(transparent)]
18pub struct Interrupt<K = RealInterruptKind, T = BootTimeline>(NullableHandle, PhantomData<(K, T)>);
19
20pub trait InterruptKind: private::Sealed {}
21
22#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
23pub struct VirtualInterruptKind;
24
25impl InterruptKind for VirtualInterruptKind {}
26impl private::Sealed for VirtualInterruptKind {}
27
28#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
29pub struct RealInterruptKind;
30
31impl InterruptKind for RealInterruptKind {}
32impl private::Sealed for RealInterruptKind {}
33
34pub type VirtualInterrupt = Interrupt<VirtualInterruptKind>;
35
36impl<K: InterruptKind, T: Timeline> Interrupt<K, T> {
37    /// Bind the given port with the given key.
38    ///
39    /// Wraps [zx_interrupt_bind](https://fuchsia.dev/reference/syscalls/interrupt_bind).
40    pub fn bind_port(&self, port: &Port, key: u64) -> Result<(), Status> {
41        let options = sys::ZX_INTERRUPT_BIND;
42        // SAFETY: This is a basic FFI call.
43        let status =
44            unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), key, options) };
45        ok(status)
46    }
47
48    /// Acknowledge the interrupt.
49    ///
50    /// Wraps [zx_interrupt_ack](https://fuchsia.dev/reference/syscalls/interrupt_ack).
51    pub fn ack(&self) -> Result<(), Status> {
52        // SAFETY: This is a basic FFI call.
53        let status = unsafe { sys::zx_interrupt_ack(self.raw_handle()) };
54        ok(status)
55    }
56
57    delegated_concrete_handle_based_impls!(|h| Self(h, PhantomData));
58}
59
60pub trait InterruptTimeline: Timeline {
61    const CREATE_FLAGS: u32;
62}
63
64impl InterruptTimeline for MonotonicTimeline {
65    const CREATE_FLAGS: u32 = sys::ZX_INTERRUPT_TIMESTAMP_MONO;
66}
67
68impl InterruptTimeline for BootTimeline {
69    const CREATE_FLAGS: u32 = 0;
70}
71
72impl<T: InterruptTimeline> Interrupt<VirtualInterruptKind, T> {
73    /// Create a virtual interrupt.
74    ///
75    /// Wraps [zx_interrupt_create](https://fuchsia.dev/reference/syscalls/interrupt_create).
76    pub fn create_virtual() -> Result<Self, Status> {
77        // SAFETY: We are sure that the handle has a valid address.
78        let handle = unsafe {
79            let mut handle = sys::ZX_HANDLE_INVALID;
80            ok(sys::zx_interrupt_create(
81                sys::ZX_HANDLE_INVALID,
82                T::CREATE_FLAGS,
83                sys::ZX_INTERRUPT_VIRTUAL,
84                &mut handle,
85            ))?;
86            NullableHandle::from_raw(handle)
87        };
88        Ok(Interrupt(handle, PhantomData))
89    }
90
91    /// Triggers a virtual interrupt object.
92    ///
93    /// Wraps [zx_interrupt_trigger](https://fuchsia.dev/reference/syscalls/interrupt_trigger).
94    pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
95        // SAFETY: this is a basic FFI call.
96        let status = unsafe { sys::zx_interrupt_trigger(self.raw_handle(), 0, time.into_nanos()) };
97        ok(status)
98    }
99}
100
101impl<K: InterruptKind, T: Timeline> AsHandleRef for Interrupt<K, T> {
102    fn as_handle_ref(&self) -> HandleRef<'_> {
103        self.0.as_handle_ref()
104    }
105}
106
107impl<K: InterruptKind, T: Timeline> From<NullableHandle> for Interrupt<K, T> {
108    fn from(handle: NullableHandle) -> Self {
109        Interrupt::<K, T>(handle, PhantomData)
110    }
111}
112
113impl<K: InterruptKind, T: Timeline> From<Interrupt<K, T>> for NullableHandle {
114    fn from(x: Interrupt<K, T>) -> NullableHandle {
115        x.0
116    }
117}
118
119impl<K: InterruptKind, T: Timeline> HandleBased for Interrupt<K, T> {}
120
121mod private {
122    pub trait Sealed {}
123}
124
125#[cfg(test)]
126mod tests {
127    use zx_status::Status;
128
129    use crate::{
130        BootInstant, Interrupt, MonotonicInstant, MonotonicTimeline, Port, PortOptions,
131        VirtualInterrupt, VirtualInterruptKind,
132    };
133
134    #[test]
135    fn bind() {
136        let interrupt = VirtualInterrupt::create_virtual().unwrap();
137        let port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
138        let key = 1;
139        let result = interrupt.bind_port(&port, key);
140        assert_eq!(result, Ok(()));
141    }
142
143    #[test]
144    fn ack() {
145        let interrupt = VirtualInterrupt::create_virtual().unwrap();
146        let result = interrupt.ack();
147        assert_eq!(result.err(), Some(Status::BAD_STATE));
148    }
149
150    #[test]
151    fn trigger() {
152        let interrupt = VirtualInterrupt::create_virtual().unwrap();
153        let result = interrupt.trigger(BootInstant::from_nanos(10));
154        assert_eq!(result, Ok(()));
155    }
156
157    #[test]
158    fn trigger_monotimeline() {
159        let interrupt =
160            Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
161        let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
162        assert_eq!(result, Ok(()));
163    }
164}