1use crate::{
8 AsHandleRef, BootTimeline, HandleBased, HandleRef, Instant, MonotonicTimeline, NullableHandle,
9 Port, Status, Timeline, ok, sys,
10};
11use std::marker::PhantomData;
12
13#[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 pub fn bind_port(&self, port: &Port, key: u64) -> Result<(), Status> {
41 let options = sys::ZX_INTERRUPT_BIND;
42 let status =
44 unsafe { sys::zx_interrupt_bind(self.raw_handle(), port.raw_handle(), key, options) };
45 ok(status)
46 }
47
48 pub fn ack(&self) -> Result<(), Status> {
52 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 pub fn create_virtual() -> Result<Self, Status> {
77 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 pub fn trigger(&self, time: Instant<T>) -> Result<(), Status> {
95 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}