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    ok, sys, AsHandleRef, BootTimeline, Handle, HandleBased, HandleRef, Instant, MonotonicTimeline,
9    Port, Status, Timeline,
10};
11use std::marker::PhantomData;
12
13/// An object representing a Zircon interrupt.
14///
15/// As essentially a subtype of `Handle`, it can be freely interconverted.
16#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
17#[repr(transparent)]
18pub struct Interrupt<K = RealInterruptKind, T = BootTimeline>(Handle, 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
58pub trait InterruptTimeline: Timeline {
59    const CREATE_FLAGS: u32;
60}
61
62impl InterruptTimeline for MonotonicTimeline {
63    const CREATE_FLAGS: u32 = sys::ZX_INTERRUPT_TIMESTAMP_MONO;
64}
65
66impl InterruptTimeline for BootTimeline {
67    const CREATE_FLAGS: u32 = 0;
68}
69
70impl<T: InterruptTimeline> Interrupt<VirtualInterruptKind, T> {
71    /// Create a virtual interrupt.
72    ///
73    /// Wraps [zx_interrupt_create](https://fuchsia.dev/reference/syscalls/interrupt_create).
74    pub fn create_virtual() -> Result<Self, Status> {
75        // SAFETY: We are sure that the handle has a valid address.
76        let handle = unsafe {
77            let mut handle = sys::ZX_HANDLE_INVALID;
78            ok(sys::zx_interrupt_create(
79                sys::ZX_HANDLE_INVALID,
80                T::CREATE_FLAGS,
81                sys::ZX_INTERRUPT_VIRTUAL,
82                &mut handle,
83            ))?;
84            Handle::from_raw(handle)
85        };
86        Ok(Interrupt(handle, PhantomData))
87    }
88
89    /// Triggers a virtual interrupt object.
90    ///
91    /// Wraps [zx_interrupt_trigger](https://fuchsia.dev/reference/syscalls/interrupt_trigger).
92    pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
93        // SAFETY: this is a basic FFI call.
94        let status = unsafe { sys::zx_interrupt_trigger(self.raw_handle(), 0, time.into_nanos()) };
95        ok(status)
96    }
97}
98
99impl<K: InterruptKind, T: Timeline> AsHandleRef for Interrupt<K, T> {
100    fn as_handle_ref(&self) -> HandleRef<'_> {
101        self.0.as_handle_ref()
102    }
103}
104
105impl<K: InterruptKind, T: Timeline> From<Handle> for Interrupt<K, T> {
106    fn from(handle: Handle) -> Self {
107        Interrupt::<K, T>(handle, PhantomData)
108    }
109}
110
111impl<K: InterruptKind, T: Timeline> From<Interrupt<K, T>> for Handle {
112    fn from(x: Interrupt<K, T>) -> Handle {
113        x.0
114    }
115}
116
117impl<K: InterruptKind> HandleBased for Interrupt<K> {}
118
119mod private {
120    pub trait Sealed {}
121}
122
123#[cfg(test)]
124mod tests {
125    use crate::{
126        BootInstant, Handle, Interrupt, MonotonicInstant, MonotonicTimeline, Port, PortOptions,
127        Status, VirtualInterrupt, VirtualInterruptKind,
128    };
129
130    #[test]
131    fn bind() {
132        let interrupt: Interrupt = Handle::invalid().into();
133        let port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
134        let key = 1;
135        let result = interrupt.bind_port(&port, key);
136        assert_eq!(result.err(), Some(Status::BAD_HANDLE));
137    }
138
139    #[test]
140    fn ack() {
141        let interrupt: Interrupt = Handle::invalid().into();
142        let result = interrupt.ack();
143        assert_eq!(result.err(), Some(Status::BAD_HANDLE));
144    }
145
146    #[test]
147    fn trigger() {
148        let interrupt = VirtualInterrupt::create_virtual().unwrap();
149        let result = interrupt.trigger(BootInstant::from_nanos(10));
150        assert_eq!(result, Ok(()));
151    }
152
153    #[test]
154    fn trigger_monotimeline() {
155        let interrupt =
156            Interrupt::<VirtualInterruptKind, MonotonicTimeline>::create_virtual().unwrap();
157        let result = interrupt.trigger(MonotonicInstant::from_nanos(10));
158        assert_eq!(result, Ok(()));
159    }
160}