sycl_rs/
event.rs

1//
2// Copyright (C) 2026 Intel Corporation
3//
4// Under the MIT License or the Apache License v2.0.
5// See LICENSE-MIT and LICENSE-APACHE for license information.
6// SPDX-License-Identifier: MIT OR Apache-2.0
7//
8
9use std::{
10    pin::Pin,
11    sync::{Arc, atomic::Ordering::Relaxed},
12    task::{Context, Poll},
13};
14
15use sycl_rs_sys::{event::ffi, types::SharedWaker};
16
17use pin_project::pin_project;
18
19use crate::{Result, info::InfoTarget, private::Sealed, queue::Queue};
20
21pub struct Event(pub(crate) cxx::UniquePtr<ffi::Event>);
22
23impl Event {
24    /// Performs a blocking wait for the event to complete. Returns an error if a synchronous SYCL
25    /// exception occurs.
26    ///
27    /// Dropping the event does not wait for its completion.
28    pub fn wait(&mut self) -> Result<()> {
29        ffi::wait(&mut self.0)
30    }
31}
32
33impl Sealed for Event {}
34impl InfoTarget for Event {}
35
36impl From<cxx::UniquePtr<ffi::Event>> for Event {
37    fn from(value: cxx::UniquePtr<ffi::Event>) -> Self {
38        Self(value)
39    }
40}
41
42impl Clone for Event {
43    fn clone(&self) -> Self {
44        ffi::clone(&self.0).into()
45    }
46}
47
48#[pin_project]
49pub struct EventFuture {
50    event: Event,
51    shared: Arc<SharedWaker>,
52    set_callback: bool,
53    queue: Option<Queue>,
54}
55
56impl Future for EventFuture {
57    type Output = Result<()>;
58
59    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
60        let this = self.project();
61
62        // Set the callback on first Future poll (Futures can't be active until polled)
63        if *this.set_callback == false {
64            *this.set_callback = true;
65            let mut queue = Queue::new_immediate();
66            this.shared.waker.register(cx.waker());
67
68            // Safety: registered callback will decrement the Arc strong reference count, which is
69            // large enough because it was increased by the previous clone().
70            let ptr = Arc::into_raw(this.shared.clone());
71            let result = unsafe { ffi::register_callback(&mut queue.0, &this.event.0, ptr) };
72            match result {
73                Ok(_) => {
74                    this.queue.replace(queue);
75                }
76                Err(_) => {
77                    return Poll::Ready(result);
78                }
79            }
80        } else {
81            // Quick check before registering to avoid wasting time
82            if this.shared.done.load(Relaxed) {
83                // The event finished - waiting for it returns immediately
84                return Poll::Ready(this.event.wait());
85            }
86
87            this.shared.waker.register(cx.waker());
88        }
89
90        // Check the event again to avoid a race condition
91        // https://docs.rs/futures/latest/futures/task/struct.AtomicWaker.html#examples
92        if this.shared.done.load(Relaxed) {
93            // The event finished - waiting for it returns immediately
94            Poll::Ready(this.event.wait())
95        } else {
96            Poll::Pending
97        }
98    }
99}
100
101impl IntoFuture for Event {
102    type Output = Result<()>;
103    type IntoFuture = EventFuture;
104
105    fn into_future(self) -> Self::IntoFuture {
106        EventFuture {
107            event: self,
108            shared: Arc::new(SharedWaker::new()),
109            set_callback: false,
110            queue: None,
111        }
112    }
113}