Skip to content

Commit 0d883ed

Browse files
committed
Add the ability to spawn futures
Add a way to spawn tasks with a returned `Future`. The task is immediately queued for the thread pool to execute.
1 parent 3ffed8e commit 0d883ed

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

rayon-core/src/future.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#![allow(missing_docs)]
2+
3+
use crate::job::JobResult;
4+
use crate::unwind;
5+
use crate::ThreadPool;
6+
use crate::{spawn, spawn_fifo};
7+
use crate::{Scope, ScopeFifo};
8+
9+
use std::future::Future;
10+
use std::mem;
11+
use std::pin::Pin;
12+
use std::sync::{Arc, Mutex};
13+
use std::task::{Context, Poll, Waker};
14+
15+
struct RayonFuture<T> {
16+
state: Arc<Mutex<State<T>>>,
17+
}
18+
19+
struct RayonFutureJob<T> {
20+
state: Arc<Mutex<State<T>>>,
21+
}
22+
23+
struct State<T> {
24+
result: JobResult<T>,
25+
waker: Option<Waker>,
26+
}
27+
28+
fn new<T>() -> (RayonFuture<T>, RayonFutureJob<T>) {
29+
let state = Arc::new(Mutex::new(State {
30+
result: JobResult::None,
31+
waker: None,
32+
}));
33+
(
34+
RayonFuture {
35+
state: state.clone(),
36+
},
37+
RayonFutureJob { state },
38+
)
39+
}
40+
41+
impl<T> Future for RayonFuture<T> {
42+
type Output = T;
43+
44+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
45+
let mut guard = self.state.lock().expect("rayon future lock");
46+
match mem::replace(&mut guard.result, JobResult::None) {
47+
JobResult::None => {
48+
guard.waker = Some(cx.waker().clone());
49+
Poll::Pending
50+
}
51+
JobResult::Ok(x) => Poll::Ready(x),
52+
JobResult::Panic(p) => {
53+
drop(guard); // don't poison the lock
54+
unwind::resume_unwinding(p);
55+
}
56+
}
57+
}
58+
}
59+
60+
impl<T> RayonFutureJob<T> {
61+
fn execute(self, func: impl FnOnce() -> T) {
62+
let result = unwind::halt_unwinding(func);
63+
let mut guard = self.state.lock().expect("rayon future lock");
64+
guard.result = match result {
65+
Ok(x) => JobResult::Ok(x),
66+
Err(p) => JobResult::Panic(p),
67+
};
68+
if let Some(waker) = guard.waker.take() {
69+
waker.wake();
70+
}
71+
}
72+
}
73+
74+
pub fn spawn_future<F, T>(func: F) -> impl Future<Output = T>
75+
where
76+
F: FnOnce() -> T + Send + 'static,
77+
T: Send + 'static,
78+
{
79+
let (future, job) = new();
80+
spawn(move || job.execute(func));
81+
future
82+
}
83+
84+
pub fn spawn_fifo_future<F, T>(func: F) -> impl Future<Output = T>
85+
where
86+
F: FnOnce() -> T + Send + 'static,
87+
T: Send + 'static,
88+
{
89+
let (future, job) = new();
90+
spawn_fifo(move || job.execute(func));
91+
future
92+
}
93+
94+
impl ThreadPool {
95+
pub fn spawn_future<F, T>(&self, func: F) -> impl Future<Output = T>
96+
where
97+
F: FnOnce() -> T + Send + 'static,
98+
T: Send + 'static,
99+
{
100+
let (future, job) = new();
101+
self.spawn(move || job.execute(func));
102+
future
103+
}
104+
105+
pub fn spawn_fifo_future<F, T>(&self, func: F) -> impl Future<Output = T>
106+
where
107+
F: FnOnce() -> T + Send + 'static,
108+
T: Send + 'static,
109+
{
110+
let (future, job) = new();
111+
self.spawn_fifo(move || job.execute(func));
112+
future
113+
}
114+
}
115+
116+
impl<'scope> Scope<'scope> {
117+
pub fn spawn_future<F, T>(&self, func: F) -> impl Future<Output = T>
118+
where
119+
F: FnOnce(&Self) -> T + Send + 'scope,
120+
T: Send + 'scope,
121+
{
122+
let (future, job) = new();
123+
self.spawn(|scope| job.execute(move || func(scope)));
124+
future
125+
}
126+
}
127+
128+
impl<'scope> ScopeFifo<'scope> {
129+
pub fn spawn_fifo_future<F, T>(&self, func: F) -> impl Future<Output = T>
130+
where
131+
F: FnOnce(&Self) -> T + Send + 'scope,
132+
T: Send + 'scope,
133+
{
134+
let (future, job) = new();
135+
self.spawn_fifo(|scope| job.execute(move || func(scope)));
136+
future
137+
}
138+
}

rayon-core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ mod log;
8080
mod private;
8181

8282
mod broadcast;
83+
mod future;
8384
mod job;
8485
mod join;
8586
mod latch;
@@ -94,6 +95,7 @@ mod compile_fail;
9495
mod test;
9596

9697
pub use self::broadcast::{broadcast, spawn_broadcast, BroadcastContext};
98+
pub use self::future::{spawn_fifo_future, spawn_future};
9799
pub use self::join::{join, join_context};
98100
pub use self::registry::ThreadBuilder;
99101
pub use self::scope::{in_place_scope, scope, Scope};

0 commit comments

Comments
 (0)