Skip to content

Commit f9c8974

Browse files
Merge pull request #836 from Keruspe/multitask
2 parents 820acc1 + abc2929 commit f9c8974

File tree

17 files changed

+139
-46
lines changed

17 files changed

+139
-46
lines changed

Diff for: .github/workflows/ci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ jobs:
8686
command: check
8787
args: --features attributes
8888

89+
- name: build unstable only
90+
uses: actions-rs/cargo@v1
91+
with:
92+
command: build
93+
args: --no-default-features --features unstable
94+
8995
- name: tests
9096
uses: actions-rs/cargo@v1
9197
with:

Diff for: Cargo.toml

+15-3
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ rustdoc-args = ["--cfg", "feature=\"docs\""]
2424
[features]
2525
default = [
2626
"std",
27+
"async-executor",
28+
"async-io",
2729
"async-task",
30+
"blocking",
31+
"futures-lite",
2832
"kv-log-macro",
2933
"log",
3034
"num_cpus",
3135
"pin-project-lite",
32-
"smol",
3336
]
3437
docs = ["attributes", "unstable", "default"]
3538
unstable = [
@@ -54,7 +57,7 @@ alloc = [
5457
"futures-core/alloc",
5558
"pin-project-lite",
5659
]
57-
tokio02 = ["smol/tokio02"]
60+
tokio02 = ["tokio"]
5861

5962
[dependencies]
6063
async-attributes = { version = "1.1.1", optional = true }
@@ -77,7 +80,10 @@ futures-timer = { version = "3.0.2", optional = true }
7780
surf = { version = "1.0.3", optional = true }
7881

7982
[target.'cfg(not(target_os = "unknown"))'.dependencies]
80-
smol = { version = "0.1.17", optional = true }
83+
async-executor = { version = "0.1.1", features = ["async-io"], optional = true }
84+
async-io = { version = "0.1.5", optional = true }
85+
blocking = { version = "0.5.0", optional = true }
86+
futures-lite = { version = "0.1.8", optional = true }
8187

8288
[target.'cfg(target_arch = "wasm32")'.dependencies]
8389
futures-timer = { version = "3.0.2", optional = true, features = ["wasm-bindgen"] }
@@ -87,6 +93,12 @@ futures-channel = { version = "0.3.4", optional = true }
8793
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
8894
wasm-bindgen-test = "0.3.10"
8995

96+
[dependencies.tokio]
97+
version = "0.2"
98+
default-features = false
99+
features = ["rt-threaded"]
100+
optional = true
101+
90102
[dev-dependencies]
91103
femme = "1.3.0"
92104
rand = "0.7.3"

Diff for: src/fs/file.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl Drop for File {
315315
// non-blocking fashion, but our only other option here is losing data remaining in the
316316
// write cache. Good task schedulers should be resilient to occasional blocking hiccups in
317317
// file destructors so we don't expect this to be a common problem in practice.
318-
let _ = smol::block_on(self.flush());
318+
let _ = futures_lite::future::block_on(self.flush());
319319
}
320320
}
321321

Diff for: src/net/tcp/listener.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::future::Future;
22
use std::net::SocketAddr;
33
use std::pin::Pin;
44

5-
use smol::Async;
5+
use async_io::Async;
66

77
use crate::io;
88
use crate::net::{TcpStream, ToSocketAddrs};
@@ -81,7 +81,7 @@ impl TcpListener {
8181
let addrs = addrs.to_socket_addrs().await?;
8282

8383
for addr in addrs {
84-
match Async::<std::net::TcpListener>::bind(&addr) {
84+
match Async::<std::net::TcpListener>::bind(addr) {
8585
Ok(listener) => {
8686
return Ok(TcpListener { watcher: listener });
8787
}
@@ -227,7 +227,7 @@ cfg_unix! {
227227

228228
impl IntoRawFd for TcpListener {
229229
fn into_raw_fd(self) -> RawFd {
230-
self.watcher.into_raw_fd()
230+
self.watcher.into_inner().unwrap().into_raw_fd()
231231
}
232232
}
233233
}
@@ -251,7 +251,7 @@ cfg_windows! {
251251

252252
impl IntoRawSocket for TcpListener {
253253
fn into_raw_socket(self) -> RawSocket {
254-
self.watcher.into_raw_socket()
254+
self.watcher.into_inner().unwrap().into_raw_socket()
255255
}
256256
}
257257
}

Diff for: src/net/tcp/stream.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::io::{IoSlice, IoSliceMut};
22
use std::net::SocketAddr;
33
use std::pin::Pin;
44

5-
use smol::Async;
5+
use async_io::Async;
66

77
use crate::io::{self, Read, Write};
88
use crate::net::ToSocketAddrs;
@@ -77,7 +77,7 @@ impl TcpStream {
7777
let addrs = addrs.to_socket_addrs().await?;
7878

7979
for addr in addrs {
80-
match Async::<std::net::TcpStream>::connect(&addr).await {
80+
match Async::<std::net::TcpStream>::connect(addr).await {
8181
Ok(stream) => {
8282
return Ok(TcpStream {
8383
watcher: Arc::new(stream),

Diff for: src/net/udp/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::io;
22
use std::net::SocketAddr;
33
use std::net::{Ipv4Addr, Ipv6Addr};
44

5-
use smol::Async;
5+
use async_io::Async;
66

77
use crate::net::ToSocketAddrs;
88
use crate::utils::Context as _;
@@ -74,7 +74,7 @@ impl UdpSocket {
7474
let addrs = addrs.to_socket_addrs().await?;
7575

7676
for addr in addrs {
77-
match Async::<std::net::UdpSocket>::bind(&addr) {
77+
match Async::<std::net::UdpSocket>::bind(addr) {
7878
Ok(socket) => {
7979
return Ok(UdpSocket { watcher: socket });
8080
}
@@ -506,7 +506,7 @@ cfg_unix! {
506506

507507
impl IntoRawFd for UdpSocket {
508508
fn into_raw_fd(self) -> RawFd {
509-
self.watcher.into_raw_fd()
509+
self.watcher.into_inner().unwrap().into_raw_fd()
510510
}
511511
}
512512
}
@@ -530,7 +530,7 @@ cfg_windows! {
530530

531531
impl IntoRawSocket for UdpSocket {
532532
fn into_raw_socket(self) -> RawSocket {
533-
self.watcher.into_raw_socket()
533+
self.watcher.into_inner().unwrap().into_raw_socket()
534534
}
535535
}
536536
}

Diff for: src/os/unix/net/datagram.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt;
44
use std::net::Shutdown;
55
use std::os::unix::net::UnixDatagram as StdUnixDatagram;
66

7-
use smol::Async;
7+
use async_io::Async;
88

99
use super::SocketAddr;
1010
use crate::io;
@@ -335,6 +335,6 @@ impl FromRawFd for UnixDatagram {
335335

336336
impl IntoRawFd for UnixDatagram {
337337
fn into_raw_fd(self) -> RawFd {
338-
self.watcher.into_raw_fd()
338+
self.watcher.into_inner().unwrap().into_raw_fd()
339339
}
340340
}

Diff for: src/os/unix/net/listener.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::future::Future;
55
use std::os::unix::net::UnixListener as StdUnixListener;
66
use std::pin::Pin;
77

8-
use smol::Async;
8+
use async_io::Async;
99

1010
use super::SocketAddr;
1111
use super::UnixStream;
@@ -217,6 +217,6 @@ impl FromRawFd for UnixListener {
217217

218218
impl IntoRawFd for UnixListener {
219219
fn into_raw_fd(self) -> RawFd {
220-
self.watcher.into_raw_fd()
220+
self.watcher.into_inner().unwrap().into_raw_fd()
221221
}
222222
}

Diff for: src/os/unix/net/stream.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::net::Shutdown;
55
use std::os::unix::net::UnixStream as StdUnixStream;
66
use std::pin::Pin;
77

8-
use smol::Async;
8+
use async_io::Async;
99

1010
use super::SocketAddr;
1111
use crate::io::{self, Read, Write};

Diff for: src/os/windows/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ cfg_std! {
55
}
66

77
cfg_unstable! {
8+
#[cfg(feature = "default")]
89
pub mod fs;
910
}

Diff for: src/rt/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub static RUNTIME: Lazy<Runtime> = Lazy::new(|| {
2727
for _ in 0..thread_count {
2828
thread::Builder::new()
2929
.name(thread_name.clone())
30-
.spawn(|| crate::task::block_on(future::pending::<()>()))
30+
.spawn(|| crate::task::executor::run_global(future::pending::<()>()))
3131
.expect("cannot start a runtime thread");
3232
}
3333
Runtime {}

Diff for: src/task/builder.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::task::{Context, Poll};
77
use pin_project_lite::pin_project;
88

99
use crate::io;
10-
use crate::task::{JoinHandle, Task, TaskLocalsWrapper};
10+
use crate::task::{self, JoinHandle, Task, TaskLocalsWrapper};
1111

1212
/// Task builder that configures the settings of a new task.
1313
#[derive(Debug, Default)]
@@ -61,9 +61,9 @@ impl Builder {
6161
});
6262

6363
let task = wrapped.tag.task().clone();
64-
let smol_task = smol::Task::spawn(wrapped).into();
64+
let handle = task::executor::spawn(wrapped);
6565

66-
Ok(JoinHandle::new(smol_task, task))
66+
Ok(JoinHandle::new(handle, task))
6767
}
6868

6969
/// Spawns a task locally with the configured settings.
@@ -81,9 +81,9 @@ impl Builder {
8181
});
8282

8383
let task = wrapped.tag.task().clone();
84-
let smol_task = smol::Task::local(wrapped).into();
84+
let handle = task::executor::local(wrapped);
8585

86-
Ok(JoinHandle::new(smol_task, task))
86+
Ok(JoinHandle::new(handle, task))
8787
}
8888

8989
/// Spawns a task locally with the configured settings.
@@ -166,10 +166,10 @@ impl Builder {
166166
unsafe {
167167
TaskLocalsWrapper::set_current(&wrapped.tag, || {
168168
let res = if should_run {
169-
// The first call should use run.
170-
smol::run(wrapped)
169+
// The first call should run the executor
170+
task::executor::run(wrapped)
171171
} else {
172-
smol::block_on(wrapped)
172+
futures_lite::future::block_on(wrapped)
173173
};
174174
num_nested_blocking.replace(num_nested_blocking.get() - 1);
175175
res

Diff for: src/task/executor.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use std::cell::RefCell;
2+
use std::future::Future;
3+
4+
static GLOBAL_EXECUTOR: once_cell::sync::Lazy<async_executor::Executor> = once_cell::sync::Lazy::new(async_executor::Executor::new);
5+
6+
thread_local! {
7+
static EXECUTOR: RefCell<async_executor::LocalExecutor> = RefCell::new(async_executor::LocalExecutor::new());
8+
}
9+
10+
pub(crate) fn spawn<F, T>(future: F) -> async_executor::Task<T>
11+
where
12+
F: Future<Output = T> + Send + 'static,
13+
T: Send + 'static,
14+
{
15+
GLOBAL_EXECUTOR.spawn(future)
16+
}
17+
18+
#[cfg(feature = "unstable")]
19+
pub(crate) fn local<F, T>(future: F) -> async_executor::Task<T>
20+
where
21+
F: Future<Output = T> + 'static,
22+
T: 'static,
23+
{
24+
EXECUTOR.with(|executor| executor.borrow().spawn(future))
25+
}
26+
27+
pub(crate) fn run<F, T>(future: F) -> T
28+
where
29+
F: Future<Output = T>,
30+
{
31+
EXECUTOR.with(|executor| enter(|| GLOBAL_EXECUTOR.enter(|| executor.borrow().run(future))))
32+
}
33+
34+
pub(crate) fn run_global<F, T>(future: F) -> T
35+
where
36+
F: Future<Output = T>,
37+
{
38+
enter(|| GLOBAL_EXECUTOR.run(future))
39+
}
40+
41+
/// Enters the tokio context if the `tokio` feature is enabled.
42+
fn enter<T>(f: impl FnOnce() -> T) -> T {
43+
#[cfg(not(feature = "tokio02"))]
44+
return f();
45+
46+
#[cfg(feature = "tokio02")]
47+
{
48+
use std::cell::Cell;
49+
use tokio::runtime::Runtime;
50+
51+
thread_local! {
52+
/// The level of nested `enter` calls we are in, to ensure that the outermost always
53+
/// has a runtime spawned.
54+
static NESTING: Cell<usize> = Cell::new(0);
55+
}
56+
57+
/// The global tokio runtime.
58+
static RT: once_cell::sync::Lazy<Runtime> = once_cell::sync::Lazy::new(|| Runtime::new().expect("cannot initialize tokio"));
59+
60+
NESTING.with(|nesting| {
61+
let res = if nesting.get() == 0 {
62+
nesting.replace(1);
63+
RT.enter(f)
64+
} else {
65+
nesting.replace(nesting.get() + 1);
66+
f()
67+
};
68+
nesting.replace(nesting.get() - 1);
69+
res
70+
})
71+
}
72+
}

Diff for: src/task/join_handle.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub struct JoinHandle<T> {
1818
}
1919

2020
#[cfg(not(target_os = "unknown"))]
21-
type InnerHandle<T> = async_task::JoinHandle<T, ()>;
21+
type InnerHandle<T> = async_executor::Task<T>;
2222
#[cfg(target_arch = "wasm32")]
2323
type InnerHandle<T> = futures_channel::oneshot::Receiver<T>;
2424

@@ -54,8 +54,7 @@ impl<T> JoinHandle<T> {
5454
#[cfg(not(target_os = "unknown"))]
5555
pub async fn cancel(mut self) -> Option<T> {
5656
let handle = self.handle.take().unwrap();
57-
handle.cancel();
58-
handle.await
57+
handle.cancel().await
5958
}
6059

6160
/// Cancel this task.
@@ -67,15 +66,19 @@ impl<T> JoinHandle<T> {
6766
}
6867
}
6968

69+
#[cfg(not(target_os = "unknown"))]
70+
impl<T> Drop for JoinHandle<T> {
71+
fn drop(&mut self) {
72+
if let Some(handle) = self.handle.take() {
73+
handle.detach();
74+
}
75+
}
76+
}
77+
7078
impl<T> Future for JoinHandle<T> {
7179
type Output = T;
7280

7381
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
74-
match Pin::new(&mut self.handle.as_mut().unwrap()).poll(cx) {
75-
Poll::Pending => Poll::Pending,
76-
Poll::Ready(output) => {
77-
Poll::Ready(output.expect("cannot await the result of a panicked task"))
78-
}
79-
}
82+
Pin::new(&mut self.handle.as_mut().unwrap()).poll(cx)
8083
}
8184
}

Diff for: src/task/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ cfg_default! {
148148
mod block_on;
149149
mod builder;
150150
mod current;
151+
#[cfg(not(target_os = "unknown"))]
152+
pub(crate) mod executor;
151153
mod join_handle;
152154
mod sleep;
153155
#[cfg(not(target_os = "unknown"))]

0 commit comments

Comments
 (0)