Skip to content

Commit ed91e7d

Browse files
authored
refactor: use compio-compat (#109)
* feat: adapt to new runtime APIs * feat(windows): refactor runtime * feat(windows): remove dep on compio directly * feat(win32): optimized adapter * feat: make compio fully optional * refactor(win32,winui): no global block_on * feat(appkit): refactor runtime * fix(appkit): clone run loop directly * fix(appkit): don't allow edit on ListBox * feat(qt): refactor runtime * feat: restore set_app_id * feat(gtk): refactor runtime * fix: cleanup meta * refactor: move `GlobalRuntime` to winio-pollable * fix(stub): build * feat: bump compio & cyper * refactor(win32): move compat.rs * fix(win32): make `get_message` modern * feat(win32): use `NtAlertThread` to wake up the thread * fix(gtk): cleanup comments * fix(qt): handle callback
1 parent 9240004 commit ed91e7d

56 files changed

Lines changed: 1410 additions & 1053 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ winio-ui-gtk = { path = "winio-ui-gtk", version = "0.5.0" }
3737
winio-ui-qt = { path = "winio-ui-qt", version = "0.5.0" }
3838
winio-ui-app-kit = { path = "winio-ui-app-kit", version = "0.5.0" }
3939

40-
compio = { version = "0.19.0-rc.1", default-features = false }
40+
compio = { version = "0.19.0-rc.2", default-features = false }
4141
compio-log = "0.1.0"
4242

43+
arrayvec = "0.7"
4344
bitflags = "2"
4445
cfg-if = "1"
4546
futures-util = "0.3"

winio-pollable/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ license = { workspace = true }
88
repository = { workspace = true }
99

1010
[dependencies]
11-
compio = { workspace = true, features = ["runtime"] }
11+
winio-callback = { workspace = true, optional = true }
1212

1313
futures-util = { workspace = true }
1414
scoped-tls = { workspace = true }
1515

16-
[target.'cfg(target_os = "linux")'.dependencies]
17-
rustix = { version = "1", features = ["event"] }
16+
[features]
17+
callback = ["dep:winio-callback"]

winio-pollable/src/lib.rs

Lines changed: 51 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -5,170 +5,63 @@
55
66
#![warn(missing_docs)]
77

8-
#[cfg(target_os = "linux")]
9-
use std::os::fd::OwnedFd;
108
use std::{
119
cell::RefCell,
1210
future::Future,
13-
io,
14-
ops::{Deref, DerefMut},
1511
pin::Pin,
16-
sync::Arc,
1712
task::{Context, Poll, Waker},
18-
time::Duration,
1913
};
2014

21-
use compio::{
22-
driver::{AsRawFd, RawFd},
23-
runtime::OptWaker,
24-
};
2515
use futures_util::FutureExt;
2616

27-
/// See [`Runtime`]
28-
///
29-
/// [`Runtime`]: compio::runtime::Runtime
30-
pub struct Runtime {
31-
runtime: compio::runtime::Runtime,
32-
#[cfg(target_os = "linux")]
33-
efd: Option<OwnedFd>,
34-
}
35-
36-
#[cfg(target_os = "linux")]
37-
impl Runtime {
38-
/// Create [`Runtime`].
39-
pub fn new() -> io::Result<Self> {
40-
use rustix::event::{EventfdFlags, eventfd};
41-
let efd = eventfd(0, EventfdFlags::CLOEXEC | EventfdFlags::NONBLOCK)?;
42-
let mut builder = compio::driver::ProactorBuilder::new();
43-
builder.register_eventfd(efd.as_raw_fd());
44-
let runtime = compio::runtime::RuntimeBuilder::new()
45-
.with_proactor(builder)
46-
.build()?;
47-
let efd = if runtime.driver_type().is_iouring() {
48-
Some(efd)
49-
} else {
50-
None
51-
};
52-
Ok(Self { runtime, efd })
53-
}
54-
55-
/// Clear the eventfd, if possible.
56-
pub(crate) fn clear(&self) -> io::Result<()> {
57-
if let Some(efd) = &self.efd {
58-
let mut buf = [0u8; 8];
59-
rustix::io::read(efd, &mut buf)?;
60-
}
61-
Ok(())
17+
/// Run the current task that is blocking on. Returns true if the task has
18+
/// completed, and false otherwise.
19+
pub fn run_current_task() -> bool {
20+
if MAIN_TASK.is_set() {
21+
MAIN_TASK.with(|task| task.poll())
22+
} else {
23+
false
6224
}
6325
}
6426

65-
#[cfg(not(target_os = "linux"))]
66-
impl Runtime {
67-
/// Create [`Runtime`].
68-
pub fn new() -> io::Result<Self> {
69-
Ok(Self {
70-
runtime: compio::runtime::Runtime::new()?,
71-
})
72-
}
73-
74-
/// Clear the eventfd, if possible.
75-
pub(crate) fn clear(&self) -> io::Result<()> {
76-
Ok(())
77-
}
27+
/// Set the current task that is going to be blocked on, and run the provided
28+
/// function.
29+
pub fn enter_block_on<F: Future<Output = ()>, T>(
30+
future: F,
31+
waker: Waker,
32+
f: impl FnOnce() -> T,
33+
) -> T {
34+
let task = unsafe { MainTask::new(future, waker) };
35+
MAIN_TASK.set(&task, f)
7836
}
7937

80-
impl Runtime {
81-
/// Run the scheduled tasks.
82-
pub fn run(&self) -> bool {
83-
let main_task_remaining = if MAIN_TASK.is_set() {
84-
MAIN_TASK.with(|task| task.poll())
85-
} else {
86-
false
87-
};
88-
89-
self.runtime.run() | main_task_remaining
90-
}
91-
92-
/// Poll the runtime. Returns the next timeout.
93-
pub fn poll_and_run(&self) -> Option<Duration> {
94-
self.runtime.poll_with(Some(Duration::ZERO));
95-
96-
let remaining_tasks = self.run();
97-
98-
if remaining_tasks {
99-
Some(Duration::ZERO)
100-
} else {
101-
self.runtime.current_timeout()
102-
}
103-
}
104-
105-
/// Set the current main task and wait for its completion.
106-
pub fn enter_block_on<F: Future<Output = ()>, T>(&self, future: F, f: impl FnOnce() -> T) -> T {
107-
let opt_waker = self.runtime.opt_waker();
108-
let task = unsafe { MainTask::new(future, opt_waker) };
109-
MAIN_TASK.set(&task, f)
110-
}
111-
112-
/// Block on the future till it completes. Users should enter the runtime
113-
/// before calling this function, and poll the runtime themselves.
114-
pub fn block_on<F: Future>(&self, future: F, poll: impl Fn(Option<Duration>)) -> F::Output {
115-
let result = RefCell::new(None);
116-
117-
self.enter_block_on(
118-
async {
119-
let res = Some(future.await);
120-
result.replace(res);
121-
},
122-
|| {
123-
loop {
124-
let timeout = self.poll_and_run();
125-
126-
if let Some(result) = result.take() {
127-
break result;
128-
}
129-
130-
poll(timeout);
131-
132-
self.clear().ok();
38+
/// Block on a future until it completes, while also running the provided poll
39+
/// function to drive the runtime.
40+
pub fn block_on<F: Future>(future: F, waker: Waker, poll: impl Fn()) -> F::Output {
41+
let result = RefCell::new(None);
42+
43+
enter_block_on(
44+
async {
45+
let res = Some(future.await);
46+
result.replace(res);
47+
},
48+
waker,
49+
|| {
50+
loop {
51+
if !run_current_task() {
52+
poll();
13353
}
134-
},
135-
)
136-
}
137-
}
138-
139-
impl Deref for Runtime {
140-
type Target = compio::runtime::Runtime;
141-
142-
fn deref(&self) -> &Self::Target {
143-
&self.runtime
144-
}
145-
}
14654

147-
impl DerefMut for Runtime {
148-
fn deref_mut(&mut self) -> &mut Self::Target {
149-
&mut self.runtime
150-
}
151-
}
152-
153-
impl AsRawFd for Runtime {
154-
fn as_raw_fd(&self) -> RawFd {
155-
#[cfg(target_os = "linux")]
156-
{
157-
self.efd
158-
.as_ref()
159-
.map(|f| f.as_raw_fd())
160-
.unwrap_or_else(|| self.runtime.as_raw_fd())
161-
}
162-
#[cfg(not(target_os = "linux"))]
163-
{
164-
self.runtime.as_raw_fd()
165-
}
166-
}
55+
if let Some(result) = result.take() {
56+
break result;
57+
}
58+
}
59+
},
60+
)
16761
}
16862

16963
struct MainTask {
17064
future: RefCell<Pin<Box<dyn Future<Output = ()>>>>,
171-
opt_waker: Arc<OptWaker>,
17265
waker: Waker,
17366
}
17467

@@ -185,13 +78,11 @@ unsafe fn reduce_lifetime<'a>(
18578
}
18679

18780
impl MainTask {
188-
pub unsafe fn new(future: impl Future<Output = ()>, opt_waker: Arc<OptWaker>) -> Self {
189-
let waker = Waker::from(opt_waker.clone());
81+
pub unsafe fn new(future: impl Future<Output = ()>, waker: Waker) -> Self {
19082
Self {
19183
// SAFETY: the future will only be polled within the scope of `enter_block_on`, which
19284
// guarantees that the future will not outlive the main task.
19385
future: RefCell::new(unsafe { reduce_lifetime(future.fuse()) }),
194-
opt_waker,
19586
waker,
19687
}
19788
}
@@ -204,7 +95,7 @@ impl MainTask {
20495
// anymore.
20596
true
20697
} else {
207-
self.opt_waker.reset()
98+
false
20899
}
209100
} else {
210101
false
@@ -213,3 +104,15 @@ impl MainTask {
213104
}
214105

215106
scoped_tls::scoped_thread_local!(static MAIN_TASK: MainTask);
107+
108+
/// An adapter for [`winio_callback::Runnable`] that runs the current task.
109+
#[cfg(feature = "callback")]
110+
pub struct GlobalRuntime;
111+
112+
#[cfg(feature = "callback")]
113+
impl winio_callback::Runnable for GlobalRuntime {
114+
#[inline]
115+
fn run() {
116+
run_current_task();
117+
}
118+
}

winio-ui-app-kit/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ repository = { workspace = true }
1111
winio-primitive = { workspace = true }
1212
winio-handle = { workspace = true }
1313
winio-callback = { workspace = true }
14-
winio-pollable = { workspace = true }
14+
winio-pollable = { workspace = true, features = ["callback"] }
1515

16-
compio = { workspace = true, features = ["arrayvec"] }
16+
compio = { workspace = true, default-features = false, optional = true }
1717
compio-log = { workspace = true }
1818

19+
arrayvec = { workspace = true }
1920
inherit-methods-macro = { workspace = true }
2021
image = { workspace = true }
2122
local-sync = { workspace = true }
22-
scoped-tls = { workspace = true }
2323
thiserror = { workspace = true }
2424

2525
block2 = "0.6"
@@ -43,6 +43,8 @@ objc2-web-kit = { version = "0.3", optional = true }
4343
media = ["dep:objc2-av-kit", "dep:objc2-av-foundation", "dep:objc2-core-media"]
4444
webview = ["dep:objc2-web-kit"]
4545

46+
compio-compat = ["compio/runtime", "compio/compat"]
47+
4648
objc-static = [
4749
"objc2/unstable-static-class-inlined",
4850
"objc2/unstable-static-sel-inlined",

0 commit comments

Comments
 (0)