Skip to content

Commit d7a06ea

Browse files
committed
use thread_select on macos only
- thread_select on linux performances very badly (input lagging) - async_fd works very well on linux, but there are too many "EXC_BAD_ACCESS (code=1, address=0x0)" on macOS. Also no input lagging like linux
1 parent 575f7f2 commit d7a06ea

File tree

6 files changed

+197
-136
lines changed

6 files changed

+197
-136
lines changed

src/wr/src/event_loop.rs

+10-89
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{cell::RefCell, os::unix::prelude::AsRawFd, ptr, sync::Mutex, time::Instant};
1+
use std::{cell::RefCell, ptr, sync::Mutex, time::Instant};
22

33
#[cfg(target_os = "macos")]
44
use copypasta::osx_clipboard::OSXClipboardContext;
@@ -11,10 +11,9 @@ use copypasta::{
1111
x11_clipboard::{Clipboard, X11ClipboardContext},
1212
};
1313

14-
use futures::future::FutureExt;
1514
use libc::{c_void, fd_set, pselect, sigset_t, timespec};
1615
use once_cell::sync::Lazy;
17-
use tokio::{io::unix::AsyncFd, io::Interest, runtime::Runtime, time::Duration};
16+
use tokio::{runtime::Runtime, time::Duration};
1817
#[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))]
1918
use winit::platform::unix::EventLoopWindowTargetExtUnix;
2019
use winit::{
@@ -26,14 +25,14 @@ use winit::{
2625
window::WindowId,
2726
};
2827

29-
use crate::future::batch_select;
30-
3128
use surfman::Connection;
3229
use surfman::SurfaceType;
3330
use webrender_surfman::WebrenderSurfman;
3431

3532
use lisp_types::bindings::{inhibit_window_system, thread_select};
3633

34+
use crate::select::tokio_select_fds;
35+
3736
pub type GUIEvent = Event<'static, i32>;
3837

3938
#[allow(dead_code)]
@@ -177,7 +176,7 @@ pub static TOKIO_RUNTIME: Lazy<Mutex<Runtime>> =
177176

178177
pub static EVENT_BUFFER: Lazy<Mutex<Vec<GUIEvent>>> = Lazy::new(|| Mutex::new(Vec::new()));
179178

180-
struct FdSet(*mut fd_set);
179+
pub struct FdSet(pub *mut fd_set);
181180

182181
unsafe impl Send for FdSet {}
183182
unsafe impl Sync for FdSet {}
@@ -190,7 +189,7 @@ impl FdSet {
190189
}
191190
}
192191

193-
struct Timespec(*mut timespec);
192+
pub struct Timespec(pub *mut timespec);
194193

195194
unsafe impl Send for Timespec {}
196195
unsafe impl Sync for Timespec {}
@@ -293,87 +292,9 @@ pub extern "C" fn wr_select(
293292
};
294293
});
295294

296-
return nfds_result.into_inner();
297-
}
298-
299-
fn fd_set_to_async_fds(nfds: i32, fds: &FdSet, interest: Interest) -> Vec<AsyncFd<i32>> {
300-
if fds.0 == ptr::null_mut() {
301-
return Vec::new();
302-
}
303-
304-
let mut async_fds = Vec::new();
305-
306-
for fd in 0..nfds {
307-
unsafe {
308-
if libc::FD_ISSET(fd, fds.0) {
309-
let async_fd_result = AsyncFd::with_interest(fd, interest);
310-
if async_fd_result.is_err() {
311-
println!("AsyncFd err: {:?}", async_fd_result.unwrap_err());
312-
continue;
313-
}
314-
315-
async_fds.push(async_fd_result.unwrap())
316-
}
317-
}
318-
}
319-
320-
async_fds
321-
}
322-
323-
fn async_fds_to_fd_set(fds: Vec<i32>, fd_set: &FdSet) {
324-
if fd_set.0 == ptr::null_mut() {
325-
return;
326-
}
327-
328-
unsafe { libc::FD_ZERO(fd_set.0) }
329-
330-
for f in fds {
331-
unsafe { libc::FD_SET(f, fd_set.0) }
332-
}
333-
}
334-
335-
async fn tokio_select_fds(
336-
nfds: i32,
337-
readfds: &FdSet,
338-
writefds: &FdSet,
339-
_timeout: &Timespec,
340-
) -> i32 {
341-
let read_fds = fd_set_to_async_fds(nfds, readfds, Interest::READABLE);
342-
let write_fds = fd_set_to_async_fds(nfds, writefds, Interest::WRITABLE);
343-
344-
let mut fd_futures = Vec::new();
345-
346-
for f in read_fds.iter() {
347-
fd_futures.push(f.readable().boxed())
348-
}
349-
350-
for f in write_fds.iter() {
351-
fd_futures.push(f.writable().boxed())
352-
}
353-
354-
let read_fds_count = read_fds.len();
355-
356-
let readliness = batch_select(fd_futures).await;
357-
358-
let mut readable_result = Vec::new();
359-
let mut writable_result = Vec::new();
360-
361-
for (result, index) in readliness {
362-
if result.is_err() {
363-
continue;
364-
}
365-
366-
if index < read_fds_count {
367-
readable_result.push(read_fds[index].as_raw_fd())
368-
} else {
369-
writable_result.push(write_fds[index - read_fds_count].as_raw_fd())
370-
}
371-
}
372-
373-
let nfds = readable_result.len() + writable_result.len();
374-
375-
async_fds_to_fd_set(readable_result, readfds);
376-
async_fds_to_fd_set(writable_result, writefds);
295+
// stop tokio select
296+
#[cfg(target_os = "macos")]
297+
let _ = select_stop_sender.send(());
377298

378-
nfds as i32
299+
return nfds_result.into_inner();
379300
}

src/wr/src/future.rs

-46
This file was deleted.

src/wr/src/lib.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,23 @@ mod event;
2222
mod event_loop;
2323
mod font_db;
2424
mod fringe;
25-
mod future;
2625
mod image;
2726
mod texture;
2827
mod util;
2928
mod wrterm;
3029

30+
pub mod select {
31+
#[cfg(not(target_os = "macos"))]
32+
pub use crate::select::future::tokio_select_fds;
33+
#[cfg(target_os = "macos")]
34+
pub use crate::select::thread::tokio_select_fds;
35+
36+
#[cfg(not(target_os = "macos"))]
37+
pub mod future;
38+
#[cfg(target_os = "macos")]
39+
pub mod thread;
40+
}
41+
3142
mod platform {
3243
#[cfg(target_os = "macos")]
3344
pub mod macos {

src/wr/src/select/README

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- thread_select on linux performances very badly (input lagging)
2+
- async_fd works very well on linux, but there are too many
3+
"EXC_BAD_ACCESS (code=1, address=0x0)" on macOS. Also no input
4+
lagging like linux

src/wr/src/select/future.rs

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use std::{
2+
future::Future,
3+
pin::Pin,
4+
task::{Context, Poll},
5+
};
6+
7+
use std::{os::unix::prelude::AsRawFd, ptr};
8+
9+
use futures::FutureExt;
10+
use tokio::io::{unix::AsyncFd, Interest};
11+
12+
use crate::event_loop::{FdSet, Timespec};
13+
14+
pub struct SelectBatch<Fut> {
15+
inner: Vec<Fut>,
16+
}
17+
18+
impl<Fut: Unpin> Unpin for SelectBatch<Fut> {}
19+
20+
fn batch_select<I>(iter: I) -> SelectBatch<I::Item>
21+
where
22+
I: IntoIterator,
23+
I::Item: Future + Unpin,
24+
{
25+
let ret = SelectBatch {
26+
inner: iter.into_iter().collect(),
27+
};
28+
ret
29+
}
30+
31+
impl<Fut: Future + Unpin> Future for SelectBatch<Fut> {
32+
type Output = Vec<(Fut::Output, usize)>;
33+
34+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
35+
let items = self
36+
.inner
37+
.iter_mut()
38+
.enumerate()
39+
.filter_map(|(i, f)| match f.poll_unpin(cx) {
40+
Poll::Pending => None,
41+
Poll::Ready(e) => Some((e, i)),
42+
})
43+
.collect::<Vec<_>>();
44+
45+
if items.is_empty() {
46+
return Poll::Pending;
47+
}
48+
49+
Poll::Ready(items)
50+
}
51+
}
52+
53+
fn fd_set_to_async_fds(nfds: i32, fds: &FdSet, interest: Interest) -> Vec<AsyncFd<i32>> {
54+
if fds.0 == ptr::null_mut() {
55+
return Vec::new();
56+
}
57+
58+
let mut async_fds = Vec::new();
59+
60+
for fd in 0..nfds {
61+
unsafe {
62+
if libc::FD_ISSET(fd, fds.0) {
63+
let async_fd_result = AsyncFd::with_interest(fd, interest);
64+
if async_fd_result.is_err() {
65+
println!("AsyncFd err: {:?}", async_fd_result.unwrap_err());
66+
continue;
67+
}
68+
69+
async_fds.push(async_fd_result.unwrap())
70+
}
71+
}
72+
}
73+
74+
async_fds
75+
}
76+
77+
fn async_fds_to_fd_set(fds: Vec<i32>, fd_set: &FdSet) {
78+
if fd_set.0 == ptr::null_mut() {
79+
return;
80+
}
81+
82+
unsafe { libc::FD_ZERO(fd_set.0) }
83+
84+
for f in fds {
85+
unsafe { libc::FD_SET(f, fd_set.0) }
86+
}
87+
}
88+
89+
pub async fn tokio_select_fds(
90+
nfds: i32,
91+
readfds: &FdSet,
92+
writefds: &FdSet,
93+
_timeout: &Timespec,
94+
) -> i32 {
95+
let read_fds = fd_set_to_async_fds(nfds, readfds, Interest::READABLE);
96+
let write_fds = fd_set_to_async_fds(nfds, writefds, Interest::WRITABLE);
97+
98+
let mut fd_futures = Vec::new();
99+
100+
for f in read_fds.iter() {
101+
fd_futures.push(f.readable().boxed())
102+
}
103+
104+
for f in write_fds.iter() {
105+
fd_futures.push(f.writable().boxed())
106+
}
107+
108+
let read_fds_count = read_fds.len();
109+
110+
let readliness = batch_select(fd_futures).await;
111+
112+
let mut readable_result = Vec::new();
113+
let mut writable_result = Vec::new();
114+
115+
for (result, index) in readliness {
116+
if result.is_err() {
117+
continue;
118+
}
119+
120+
if index < read_fds_count {
121+
readable_result.push(read_fds[index].as_raw_fd())
122+
} else {
123+
writable_result.push(write_fds[index - read_fds_count].as_raw_fd())
124+
}
125+
}
126+
127+
let nfds = readable_result.len() + writable_result.len();
128+
129+
async_fds_to_fd_set(readable_result, readfds);
130+
async_fds_to_fd_set(writable_result, writefds);
131+
132+
nfds as i32
133+
}

src/wr/src/select/thread.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::ptr;
2+
3+
use futures::Future;
4+
use libc::pselect;
5+
use lisp_types::bindings::thread_select;
6+
7+
use crate::event_loop::{FdSet, Timespec};
8+
9+
async fn async_thread_select(
10+
nfds: i32,
11+
readfds: &FdSet,
12+
writefds: &FdSet,
13+
timeout: &Timespec,
14+
) -> i32 {
15+
unsafe {
16+
thread_select(
17+
Some(pselect),
18+
nfds,
19+
readfds.0,
20+
writefds.0,
21+
ptr::null_mut(),
22+
timeout.0,
23+
ptr::null_mut(),
24+
)
25+
}
26+
}
27+
28+
pub fn tokio_select_fds<'a>(
29+
nfds: i32,
30+
readfds: &'a FdSet,
31+
writefds: &'a FdSet,
32+
timeout: &'a Timespec,
33+
) -> impl Future<Output = i32> + 'a {
34+
async move {
35+
let nfds: i32 = async_thread_select(nfds, readfds, writefds, timeout).await;
36+
nfds
37+
}
38+
}

0 commit comments

Comments
 (0)