Skip to content

Commit 6fed1c3

Browse files
fakeshadowrobjtede
andauthored
add support for io-uring (#374)
Co-authored-by: Rob Ede <robjtede@icloud.com>
1 parent c3d697d commit 6fed1c3

File tree

13 files changed

+185
-51
lines changed

13 files changed

+185
-51
lines changed

.cargo/config.toml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
[alias]
22
chk = "check --workspace --all-features --tests --examples --bins"
33
lint = "clippy --workspace --all-features --tests --examples --bins -- -Dclippy::todo"
4-
ci-test = "test --workspace --all-features --lib --tests --no-fail-fast -- --nocapture"
4+
55
ci-doctest = "test --workspace --all-features --doc --no-fail-fast -- --nocapture"
6+
7+
# just check the library (without dev deps)
8+
ci-check-min = "hack --workspace check --no-default-features"
9+
ci-check-lib = "hack --workspace --feature-powerset --exclude-features io-uring check"
10+
ci-check-lib-linux = "hack --workspace --feature-powerset check"
11+
12+
# check everything
13+
ci-check = "hack --workspace --feature-powerset --exclude-features io-uring check --tests --examples"
14+
ci-check-linux = "hack --workspace --feature-powerset check --tests --examples"
15+
16+
# tests avoiding io-uring feature
17+
ci-test = "hack test --workspace --exclude=actix-rt --exclude=actix-server --all-features --lib --tests --no-fail-fast -- --nocapture"
18+
ci-test-rt = " hack --feature-powerset --exclude-features io-uring test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture"
19+
ci-test-server = "hack --feature-powerset --exclude-features io-uring test --package=actix-server --lib --tests --no-fail-fast -- --nocapture"
20+
21+
# test with io-uring feature
22+
ci-test-rt-linux = " hack --feature-powerset test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture"
23+
ci-test-server-linux = "hack --feature-powerset test --package=actix-server --lib --tests --no-fail-fast -- --nocapture"

.github/workflows/ci.yml

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -75,36 +75,47 @@ jobs:
7575
command: install
7676
args: cargo-hack
7777

78-
- name: check minimal
78+
- name: check lib
79+
if: >
80+
matrix.target.os != 'ubuntu-latest'
81+
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
7982
uses: actions-rs/cargo@v1
80-
with:
81-
command: hack
82-
args: check --workspace --no-default-features
83-
84-
- name: check minimal + tests
83+
with: { command: ci-check-lib }
84+
- name: check lib
85+
if: matrix.target.os == 'ubuntu-latest'
8586
uses: actions-rs/cargo@v1
86-
with:
87-
command: hack
88-
args: check --workspace --no-default-features --tests --examples
89-
90-
- name: check default
87+
with: { command: ci-check-lib-linux }
88+
- name: check lib
89+
if: matrix.target.triple == 'x86_64-pc-windows-gnu'
9190
uses: actions-rs/cargo@v1
92-
with:
93-
command: check
94-
args: --workspace --tests --examples
95-
91+
with: { command: ci-check-min }
92+
9693
- name: check full
9794
# TODO: compile OpenSSL and run tests on MinGW
98-
if: matrix.target.triple != 'x86_64-pc-windows-gnu'
95+
if: >
96+
matrix.target.os != 'ubuntu-latest'
97+
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
9998
uses: actions-rs/cargo@v1
100-
with:
101-
command: check
102-
args: --workspace --all-features --tests --examples
99+
with: { command: ci-check }
100+
- name: check all
101+
if: matrix.target.os == 'ubuntu-latest'
102+
uses: actions-rs/cargo@v1
103+
with: { command: ci-check-linux }
103104

104105
- name: tests
105-
if: matrix.target.triple != 'x86_64-pc-windows-gnu'
106-
uses: actions-rs/cargo@v1
107-
with: { command: ci-test }
106+
if: >
107+
matrix.target.os != 'ubuntu-latest'
108+
&& matrix.target.triple != 'x86_64-pc-windows-gnu'
109+
run: |
110+
cargo ci-test
111+
cargo ci-test-rt
112+
cargo ci-test-server
113+
- name: tests
114+
if: matrix.target.os == 'ubuntu-latest'
115+
run: |
116+
cargo ci-test
117+
cargo ci-test-rt-linux
118+
cargo ci-test-server-linux
108119
109120
- name: Generate coverage file
110121
if: >
@@ -120,8 +131,7 @@ jobs:
120131
&& matrix.version == 'stable'
121132
&& github.ref == 'refs/heads/master'
122133
uses: codecov/codecov-action@v1
123-
with:
124-
file: cobertura.xml
134+
with: { file: cobertura.xml }
125135

126136
- name: Clear the cargo caches
127137
run: |

actix-rt/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Changes
22

33
## Unreleased - 2021-xx-xx
4+
* Add `io-uring` feature for enabling async file I/O on linux. [#374]
45
* The `spawn` method can now resolve with non-unit outputs. [#369]
56

67
[#369]: https://github.com/actix/actix-net/pull/369
8+
[#374]: https://github.com/actix/actix-net/pull/374
79

810

911
## 2.2.0 - 2021-03-29

actix-rt/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@ path = "src/lib.rs"
2121
[features]
2222
default = ["macros"]
2323
macros = ["actix-macros"]
24+
io-uring = ["tokio-uring"]
2425

2526
[dependencies]
2627
actix-macros = { version = "0.2.0", optional = true }
2728

2829
futures-core = { version = "0.3", default-features = false }
2930
tokio = { version = "1.3", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] }
3031

32+
[target.'cfg(target_os = "linux")'.dependencies]
33+
tokio-uring = { version = "0.1", optional = true }
34+
3135
[dev-dependencies]
3236
tokio = { version = "1.2", features = ["full"] }
3337
hyper = { version = "0.14", default-features = false, features = ["server", "tcp", "http1"] }

actix-rt/src/arbiter.rs

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ use std::{
99
};
1010

1111
use futures_core::ready;
12-
use tokio::{sync::mpsc, task::LocalSet};
12+
use tokio::sync::mpsc;
1313

14-
use crate::{
15-
runtime::{default_tokio_runtime, Runtime},
16-
system::{System, SystemCommand},
17-
};
14+
use crate::system::{System, SystemCommand};
1815

1916
pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0);
2017

@@ -98,16 +95,19 @@ impl Arbiter {
9895
///
9996
/// # Panics
10097
/// Panics if a [System] is not registered on the current thread.
98+
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
10199
#[allow(clippy::new_without_default)]
102100
pub fn new() -> Arbiter {
103101
Self::with_tokio_rt(|| {
104-
default_tokio_runtime().expect("Cannot create new Arbiter's Runtime.")
102+
crate::runtime::default_tokio_runtime()
103+
.expect("Cannot create new Arbiter's Runtime.")
105104
})
106105
}
107106

108107
/// Spawn a new Arbiter using the [Tokio Runtime](tokio-runtime) returned from a closure.
109108
///
110109
/// [tokio-runtime]: tokio::runtime::Runtime
110+
#[cfg(not(all(target_os = "linux", feature = "io-uring")))]
111111
#[doc(hidden)]
112112
pub fn with_tokio_rt<F>(runtime_factory: F) -> Arbiter
113113
where
@@ -127,7 +127,7 @@ impl Arbiter {
127127
.spawn({
128128
let tx = tx.clone();
129129
move || {
130-
let rt = Runtime::from(runtime_factory());
130+
let rt = crate::runtime::Runtime::from(runtime_factory());
131131
let hnd = ArbiterHandle::new(tx);
132132

133133
System::set_current(sys);
@@ -159,15 +159,67 @@ impl Arbiter {
159159
Arbiter { tx, thread_handle }
160160
}
161161

162-
/// Sets up an Arbiter runner in a new System using the provided runtime local task set.
163-
pub(crate) fn in_new_system(local: &LocalSet) -> ArbiterHandle {
162+
/// Spawn a new Arbiter thread and start its event loop with `tokio-uring` runtime.
163+
///
164+
/// # Panics
165+
/// Panics if a [System] is not registered on the current thread.
166+
#[cfg(all(target_os = "linux", feature = "io-uring"))]
167+
#[allow(clippy::new_without_default)]
168+
pub fn new() -> Arbiter {
169+
let sys = System::current();
170+
let system_id = sys.id();
171+
let arb_id = COUNT.fetch_add(1, Ordering::Relaxed);
172+
173+
let name = format!("actix-rt|system:{}|arbiter:{}", system_id, arb_id);
174+
let (tx, rx) = mpsc::unbounded_channel();
175+
176+
let (ready_tx, ready_rx) = std::sync::mpsc::channel::<()>();
177+
178+
let thread_handle = thread::Builder::new()
179+
.name(name.clone())
180+
.spawn({
181+
let tx = tx.clone();
182+
move || {
183+
let hnd = ArbiterHandle::new(tx);
184+
185+
System::set_current(sys);
186+
187+
HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone()));
188+
189+
// register arbiter
190+
let _ = System::current()
191+
.tx()
192+
.send(SystemCommand::RegisterArbiter(arb_id, hnd));
193+
194+
ready_tx.send(()).unwrap();
195+
196+
// run arbiter event processing loop
197+
tokio_uring::start(ArbiterRunner { rx });
198+
199+
// deregister arbiter
200+
let _ = System::current()
201+
.tx()
202+
.send(SystemCommand::DeregisterArbiter(arb_id));
203+
}
204+
})
205+
.unwrap_or_else(|err| {
206+
panic!("Cannot spawn Arbiter's thread: {:?}. {:?}", &name, err)
207+
});
208+
209+
ready_rx.recv().unwrap();
210+
211+
Arbiter { tx, thread_handle }
212+
}
213+
214+
/// Sets up an Arbiter runner in a new System using the environment's local set.
215+
pub(crate) fn in_new_system() -> ArbiterHandle {
164216
let (tx, rx) = mpsc::unbounded_channel();
165217

166218
let hnd = ArbiterHandle::new(tx);
167219

168220
HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone()));
169221

170-
local.spawn_local(ArbiterRunner { rx });
222+
crate::spawn(ArbiterRunner { rx });
171223

172224
hnd
173225
}

actix-rt/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,20 @@
3232
//! arbiter.stop();
3333
//! arbiter.join().unwrap();
3434
//! ```
35+
//!
36+
//! # `io-uring` Support
37+
//! There is experimental support for using io-uring with this crate by enabling the
38+
//! `io-uring` feature. For now, it is semver exempt.
3539
3640
#![deny(rust_2018_idioms, nonstandard_style)]
3741
#![allow(clippy::type_complexity)]
3842
#![warn(missing_docs)]
3943
#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
4044
#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
4145

46+
#[cfg(all(not(target_os = "linux"), feature = "io-uring"))]
47+
compile_error!("io_uring is a linux only feature.");
48+
4249
use std::future::Future;
4350

4451
use tokio::task::JoinHandle;

actix-rt/src/runtime.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ impl Runtime {
3131
})
3232
}
3333

34-
/// Reference to local task set.
35-
pub(crate) fn local_set(&self) -> &LocalSet {
36-
&self.local
37-
}
38-
3934
/// Offload a future onto the single-threaded runtime.
4035
///
4136
/// The returned join handle can be used to await the future's result.

actix-rt/src/system.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl System {
5454
let (sys_tx, sys_rx) = mpsc::unbounded_channel();
5555

5656
let rt = Runtime::from(runtime_factory());
57-
let sys_arbiter = Arbiter::in_new_system(rt.local_set());
57+
let sys_arbiter = rt.block_on(async { Arbiter::in_new_system() });
5858
let system = System::construct(sys_tx, sys_arbiter.clone());
5959

6060
system

actix-rt/tests/tests.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
use std::{
22
future::Future,
3-
sync::{
4-
atomic::{AtomicBool, Ordering},
5-
mpsc::channel,
6-
Arc,
7-
},
3+
sync::mpsc::channel,
84
thread,
95
time::{Duration, Instant},
106
};
@@ -221,8 +217,8 @@ fn system_stop_stops_arbiters() {
221217
System::current().stop();
222218
sys.run().unwrap();
223219

224-
// account for slightly slow thread de-spawns (only observed on windows)
225-
thread::sleep(Duration::from_millis(100));
220+
// account for slightly slow thread de-spawns
221+
thread::sleep(Duration::from_millis(500));
226222

227223
// arbiter should be dead and return false
228224
assert!(!Arbiter::current().spawn_fn(|| {}));
@@ -231,6 +227,7 @@ fn system_stop_stops_arbiters() {
231227
arb.join().unwrap();
232228
}
233229

230+
#[cfg(not(feature = "io-uring"))]
234231
#[test]
235232
fn new_system_with_tokio() {
236233
let (tx, rx) = channel();
@@ -263,8 +260,14 @@ fn new_system_with_tokio() {
263260
assert_eq!(rx.recv().unwrap(), 42);
264261
}
265262

263+
#[cfg(not(feature = "io-uring"))]
266264
#[test]
267265
fn new_arbiter_with_tokio() {
266+
use std::sync::{
267+
atomic::{AtomicBool, Ordering},
268+
Arc,
269+
};
270+
268271
let _ = System::new();
269272

270273
let arb = Arbiter::with_tokio_rt(|| {
@@ -323,3 +326,32 @@ fn spawn_local() {
323326
h(actix_rt::spawn(async { 1 }));
324327
})
325328
}
329+
330+
#[cfg(all(target_os = "linux", feature = "io-uring"))]
331+
#[test]
332+
fn tokio_uring_arbiter() {
333+
let system = System::new();
334+
let (tx, rx) = std::sync::mpsc::channel();
335+
336+
Arbiter::new().spawn(async move {
337+
let handle = actix_rt::spawn(async move {
338+
let f = tokio_uring::fs::File::create("test.txt").await.unwrap();
339+
let buf = b"Hello World!";
340+
341+
let (res, _) = f.write_at(&buf[..], 0).await;
342+
assert!(res.is_ok());
343+
344+
f.sync_all().await.unwrap();
345+
f.close().await.unwrap();
346+
347+
std::fs::remove_file("test.txt").unwrap();
348+
});
349+
350+
handle.await.unwrap();
351+
tx.send(true).unwrap();
352+
});
353+
354+
assert!(rx.recv().unwrap());
355+
356+
drop(system);
357+
}

actix-server/CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
## Unreleased - 2021-xx-xx
44
* Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to this change. [#349]
55
* Remove `ServerBuilder::configure` [#349]
6+
* Add `io-uring` feature for enabling async file I/O on linux. [#374]
67
* Server no long listens to SIGHUP signal.
78
It actually did not take any action when receiving SIGHUP, the only thing SIGHUP did was to stop
89
the Server from receiving any future signal, because the `Signals` future stops on the first
910
signal received [#389]
1011

12+
[#374]: https://github.com/actix/actix-net/pull/374
1113
[#349]: https://github.com/actix/actix-net/pull/349
1214
[#389]: https://github.com/actix/actix-net/pull/389
1315

0 commit comments

Comments
 (0)