Skip to content

Commit 8979fa5

Browse files
Replace Waker with AtomicWaker
1 parent c86a718 commit 8979fa5

6 files changed

Lines changed: 168 additions & 30 deletions

File tree

Cargo.lock

Lines changed: 101 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

oneapi-rs-sys/include/event.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ enum class EventCommandStatus : std::uint8_t;
2020

2121
namespace sycl_shims::event {
2222
void wait(std::unique_ptr<Event> &);
23-
void register_callback(std::unique_ptr<Queue> &, Event const &, rust::Box<Waker>);
23+
void register_callback(std::unique_ptr<Queue> &, Event const &, SharedWaker const *);
2424
EventCommandStatus get_command_execution_status(Event const &);
2525
std::unique_ptr<Event> clone(Event const &);
2626
} // namespace sycl_shims::event

oneapi-rs-sys/src/event-sys.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// SPDX-License-Identifier: MIT OR Apache-2.0
77
//
88

9-
use crate::types::Waker;
9+
use crate::types::SharedWaker;
1010

1111
#[cxx::bridge(namespace = "sycl_shims::event")]
1212
pub mod ffi {
@@ -26,17 +26,13 @@ pub mod ffi {
2626
type Queue = crate::types::ffi::Queue;
2727

2828
fn wait(event: &mut UniquePtr<Event>);
29-
fn register_callback(queue: &mut UniquePtr<Queue>, event: &Event, waker: Box<Waker>);
29+
unsafe fn register_callback(queue: &mut UniquePtr<Queue>, event: &Event, waker: *const SharedWaker);
3030
fn get_command_execution_status(event: &Event) -> EventCommandStatus;
3131
fn clone(event: &Event) -> UniquePtr<Event>;
3232
}
3333

3434
extern "Rust" {
35-
type Waker;
36-
fn wake(waker: &Box<Waker>);
35+
type SharedWaker;
36+
fn wake(&self);
3737
}
3838
}
39-
40-
fn wake(waker: &Box<Waker>) {
41-
waker.0.wake_by_ref();
42-
}

oneapi-rs-sys/src/event.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ EventCommandStatus get_command_execution_status(Event const & event) {
3232
return EventCommandStatus::Unknown;
3333
}
3434
}
35-
void register_callback(std::unique_ptr<Queue> & queue, Event const & event, rust::Box<Waker> waker) {
36-
queue->submit([waker = std::move(waker), event](sycl::handler& cgh) {
35+
void register_callback(std::unique_ptr<Queue> & queue, Event const & event, SharedWaker const * waker) {
36+
queue->submit([=](sycl::handler& cgh) {
3737
cgh.depends_on(event);
38-
cgh.host_task([&]() { wake(waker); });
38+
cgh.host_task([=]() { waker->wake(); });
3939
});
4040
}
4141
} // namespace sycl_shims::event

oneapi-rs-sys/src/types-sys.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,26 @@
66
// SPDX-License-Identifier: MIT OR Apache-2.0
77
//
88

9-
// cxx requires Rust opaque types to be defined in the current crate.
10-
pub struct Waker(pub std::task::Waker);
11-
impl From<std::task::Waker> for Waker {
12-
fn from(value: std::task::Waker) -> Self {
13-
Waker(value)
9+
use std::sync::atomic::{Ordering::Relaxed, AtomicBool};
10+
11+
use futures::task::AtomicWaker;
12+
13+
pub struct SharedWaker {
14+
pub waker: AtomicWaker,
15+
pub done: AtomicBool
16+
}
17+
18+
impl SharedWaker {
19+
pub fn new() -> Self {
20+
Self {
21+
waker: AtomicWaker::new(),
22+
done: AtomicBool::new(false)
23+
}
24+
}
25+
26+
pub fn wake(&self) {
27+
self.done.store(true, Relaxed);
28+
self.waker.wake();
1429
}
1530
}
1631

oneapi-rs/src/event.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
// SPDX-License-Identifier: MIT OR Apache-2.0
77
//
88

9-
use std::{pin::Pin, task::{Context, Poll}};
9+
use std::{pin::Pin, task::{Context, Poll}, sync::atomic::Ordering::Relaxed};
1010

11-
use oneapi_rs_sys::event::ffi;
11+
use oneapi_rs_sys::{event::ffi, types::SharedWaker};
1212

1313
use pin_project::pin_project;
1414

15-
use crate::{info::{EventCommandStatus, event::{CommandExecutionStatus, EventInfo}}, queue::Queue};
15+
use crate::{info::event::EventInfo, queue::Queue};
1616

1717
pub struct Event(pub(crate) cxx::UniquePtr<ffi::Event>);
1818

@@ -41,6 +41,7 @@ impl Clone for Event {
4141
#[pin_project]
4242
pub struct EventFuture {
4343
event: Event,
44+
shared: SharedWaker,
4445
set_callback: bool,
4546
queue: Queue,
4647
}
@@ -49,17 +50,41 @@ impl Future for EventFuture {
4950
type Output = ();
5051

5152
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
52-
if self.event.get_info::<CommandExecutionStatus>() == EventCommandStatus::Complete {
53-
Poll::Ready(())
53+
let this = self.project();
54+
55+
// Set the callback on first Future poll (Futures can't be active until polled)
56+
if *this.set_callback == false {
57+
*this.set_callback = true;
58+
this.shared.waker.register(cx.waker());
59+
unsafe { ffi::register_callback(&mut this.queue.0, &this.event.0, this.shared) };
60+
61+
// Check the event again to avoid a race condition
62+
// https://docs.rs/futures/latest/futures/task/struct.AtomicWaker.html#examples
63+
if this.shared.done.load(Relaxed) {
64+
Poll::Ready(())
65+
}
66+
else {
67+
Poll::Pending
68+
}
5469
}
5570
else {
56-
if self.set_callback == false {
57-
let this = self.project();
58-
*this.set_callback = true;
59-
let waker = Box::new(cx.waker().clone().into());
60-
ffi::register_callback(&mut this.queue.0, &this.event.0, waker);
71+
// Quick check before registering to avoid wasting time
72+
if this.shared.done.load(Relaxed) {
73+
return Poll::Ready(());
6174
}
62-
Poll::Pending
75+
76+
// Register the waker if result isn't ready. This is a slow atomic operation
77+
this.shared.waker.register(cx.waker());
78+
79+
// Check the event again to avoid a race condition
80+
// https://docs.rs/futures/latest/futures/task/struct.AtomicWaker.html#examples
81+
if this.shared.done.load(Relaxed) {
82+
Poll::Ready(())
83+
}
84+
else {
85+
Poll::Pending
86+
}
87+
6388
}
6489
}
6590
}
@@ -70,9 +95,10 @@ impl IntoFuture for Event {
7095

7196
fn into_future(self) -> Self::IntoFuture {
7297
EventFuture {
73-
queue: Queue::new_immediate(),
7498
event: self,
75-
set_callback: false
99+
shared: SharedWaker::new(),
100+
set_callback: false,
101+
queue: Queue::new_immediate(),
76102
}
77103
}
78104
}

0 commit comments

Comments
 (0)