1
0
Fork 0
forked from wry/wry

io: use io_uring for all io

There should no longer be any

- read
- write
- connect
- sendmsg
- recvmsg
- accept

calls in the codebase. Previously we were using a mix of io_uring and
these calls which had some negative effects: Since we were using the old
system calls, we had to set the file descriptors to non-blocking. But
our io_uring code did not handle EAGAIN. This lead to programs sometimes
being killed when the wayland IO was actually blocking.

Now all file descriptors are set to blocking, but io_uring makes it
non-blocking from our perspective. The one exception are evdev files
because they are read via libinput and libinput uses the old system
calls.
This commit is contained in:
Julian Orth 2022-12-31 17:55:58 +01:00
parent 2db0ee8995
commit 9812a02f87
55 changed files with 900 additions and 672 deletions

View file

@ -1,16 +1,15 @@
use {
crate::{
dbus::{incoming::handle_incoming, outgoing::handle_outgoing, DbusError, DbusSocket},
utils::{errorfmt::ErrorFmt, hex},
utils::{buf::Buf, errorfmt::ErrorFmt, hex},
},
std::{io::Write, rc::Rc},
uapi::{c, Errno},
std::{ops::Deref, rc::Rc},
};
pub(super) async fn handle_auth(socket: Rc<DbusSocket>) {
let mut auth = Auth {
socket: socket.clone(),
buf: Box::new([0; BUF_SIZE]),
buf: Buf::new(BUF_SIZE),
buf_start: 0,
buf_stop: 0,
};
@ -22,7 +21,7 @@ const BUF_SIZE: usize = 128;
struct Auth {
socket: Rc<DbusSocket>,
buf: Box<[u8; BUF_SIZE]>,
buf: Buf,
buf_start: usize,
buf_stop: usize,
}
@ -50,61 +49,77 @@ impl Auth {
async fn handle_auth(&mut self) -> Result<(), DbusError> {
let uid = hex::to_hex(&uapi::getuid().to_string());
let mut out_buf = Vec::new();
let _ = write!(out_buf, "\0AUTH EXTERNAL {}\r\n", uid);
self.write_buf(&mut out_buf).await?;
let mut out_buf = Buf::new(128);
{
let buf = out_buf
.write_fmt(format_args!("\0AUTH EXTERNAL {}\r\n", uid))
.unwrap();
self.write_buf(buf).await?;
}
let line = self.readline().await?;
let (cmd, _) = line_to_cmd(&line);
if cmd != "OK" {
return Err(DbusError::Auth);
}
let _ = write!(out_buf, "NEGOTIATE_UNIX_FD\r\n");
self.write_buf(&mut out_buf).await?;
{
let buf = out_buf
.write_fmt(format_args!("NEGOTIATE_UNIX_FD\r\n"))
.unwrap();
self.write_buf(buf).await?;
}
let line = self.readline().await?;
let (cmd, _) = line_to_cmd(&line);
if cmd != "AGREE_UNIX_FD" {
return Err(DbusError::UnixFd);
}
let _ = write!(out_buf, "BEGIN\r\n");
self.write_buf(&mut out_buf).await?;
{
let buf = out_buf.write_fmt(format_args!("BEGIN\r\n")).unwrap();
self.write_buf(buf).await?;
}
Ok(())
}
async fn readline(&mut self) -> Result<String, DbusError> {
let mut s = String::new();
loop {
for i in self.buf_start..self.buf_stop {
let c = self.buf[i % BUF_SIZE] as char;
s.push(c);
if c == '\n' {
self.buf_start = i + 1;
return Ok(s);
{
let buf = self.buf.deref();
for i in self.buf_start..self.buf_stop {
let c = buf[i % BUF_SIZE] as char;
s.push(c);
if c == '\n' {
self.buf_start = i + 1;
return Ok(s);
}
}
}
self.buf_start = 0;
self.buf_stop = 0;
match uapi::read(self.socket.fd.raw(), &mut self.buf[..]) {
Ok(n) => self.buf_stop = n.len(),
Err(Errno(c::EAGAIN)) => {
self.socket.ring.readable(&self.socket.fd).await?;
}
Err(e) => return Err(DbusError::ReadError(e.into())),
let res = self
.socket
.ring
.read(&self.socket.fd, self.buf.clone())
.await;
match res {
Ok(n) => self.buf_stop = n,
Err(e) => return Err(DbusError::ReadError(e)),
}
}
}
async fn write_buf(&mut self, buf: &mut Vec<u8>) -> Result<(), DbusError> {
async fn write_buf(&mut self, mut buf: Buf) -> Result<(), DbusError> {
let mut start = 0;
while start < buf.len() {
match uapi::write(self.socket.fd.raw(), &buf[start..]) {
let res = self
.socket
.ring
.write(&self.socket.fd, buf.slice(start..), None)
.await;
match res {
Ok(n) => start += n,
Err(Errno(c::EAGAIN)) => {
self.socket.ring.writable(&self.socket.fd).await?;
}
Err(e) => return Err(DbusError::WriteError(e.into())),
Err(e) => return Err(DbusError::WriteError(e)),
}
}
buf.clear();
Ok(())
}
}

View file

@ -3,7 +3,10 @@ use {
TY_ARRAY, TY_BOOLEAN, TY_BYTE, TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH,
TY_SIGNATURE, TY_STRING, TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
},
crate::dbus::{types::Variant, DbusError, DynamicType, Parser},
crate::{
dbus::{types::Variant, DbusError, DynamicType, Parser},
utils::buf::DynamicBuf,
},
std::ops::Deref,
};
@ -88,7 +91,7 @@ impl DynamicType {
}
}
pub fn write_signature(&self, w: &mut Vec<u8>) {
pub fn write_signature(&self, w: &mut DynamicBuf) {
let c = match self {
DynamicType::U8 => TY_BYTE,
DynamicType::Bool => TY_BOOLEAN,

View file

@ -1,11 +1,14 @@
use {
crate::dbus::{types::Variant, DbusType, Formatter},
crate::{
dbus::{types::Variant, DbusType, Formatter},
utils::buf::DynamicBuf,
},
std::rc::Rc,
uapi::{OwnedFd, Packed},
};
impl<'a> Formatter<'a> {
pub fn new(fds: &'a mut Vec<Rc<OwnedFd>>, buf: &'a mut Vec<u8>) -> Self {
pub fn new(fds: &'a mut Vec<Rc<OwnedFd>>, buf: &'a mut DynamicBuf) -> Self {
Self { fds, buf }
}

View file

@ -11,7 +11,7 @@ use {
};
impl DbusHolder {
pub(super) fn get(
pub(super) async fn get(
self: &Rc<Self>,
eng: &Rc<AsyncEngine>,
ring: &Rc<IoUring>,
@ -25,39 +25,35 @@ impl DbusHolder {
return Ok(c);
}
}
let socket = connect(eng, ring, addr, name, &self.run_toplevel)?;
let socket = connect(eng, ring, addr, name, &self.run_toplevel).await?;
self.socket.set(Some(socket.clone()));
Ok(socket)
}
}
fn connect(
async fn connect(
eng: &Rc<AsyncEngine>,
ring: &Rc<IoUring>,
addr: &str,
name: &'static str,
run_toplevel: &Rc<RunToplevel>,
) -> Result<Rc<DbusSocket>, DbusError> {
let socket = match uapi::socket(
c::AF_UNIX,
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
0,
) {
Ok(s) => s,
let fd = match uapi::socket(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0) {
Ok(s) => Rc::new(s),
Err(e) => return Err(DbusError::Socket(e.into())),
};
let mut sadr: c::sockaddr_un = uapi::pod_zeroed();
sadr.sun_family = c::AF_UNIX as _;
let sun_path = uapi::as_bytes_mut(&mut sadr.sun_path[..]);
sun_path[..addr.len()].copy_from_slice(addr.as_bytes());
if let Err(e) = uapi::connect(socket.raw(), &sadr) {
return Err(DbusError::Connect(e.into()));
if let Err(e) = ring.connect(&fd, &sadr).await {
return Err(DbusError::Connect(e));
}
let fd = Rc::new(socket);
let socket = Rc::new(DbusSocket {
bus_name: name,
fd: fd.clone(),
ring: ring.clone(),
in_bufs: Default::default(),
bufio: Rc::new(BufIo::new(&fd, ring)),
eng: eng.clone(),
next_serial: NumCell::new(1),

View file

@ -52,8 +52,9 @@ impl Incoming {
}
async fn handle_msg(&mut self) -> Result<(), DbusError> {
let msg_buf_data = UnsafeCell::new(self.socket.bufio.buf());
let msg_buf_data = UnsafeCell::new(self.socket.in_bufs.pop().unwrap_or_default());
let msg_buf = unsafe { msg_buf_data.get().deref_mut() };
msg_buf.clear();
const FIXED_HEADER_SIZE: usize = 16;
self.incoming
.fill_msg_buf(FIXED_HEADER_SIZE, msg_buf)
@ -235,7 +236,7 @@ impl Incoming {
}
let msg_buf = msg_buf_data.into_inner();
if msg_buf.capacity() > 0 {
self.socket.bufio.add_buf(msg_buf);
self.socket.in_bufs.push(msg_buf);
}
Ok(())
}

View file

@ -404,7 +404,13 @@ impl DbusSocket {
msg.marshal(&mut fmt);
let body_len = (buf.len() - body_start) as u32;
buf[4..8].copy_from_slice(uapi::as_bytes(&body_len));
(BufIoMessage { fds, buf }, serial)
(
BufIoMessage {
fds,
buf: buf.unwrap(),
},
serial,
)
}
fn format_header(
@ -489,7 +495,7 @@ where
) -> Result<(), DbusError> {
let msg = <T::Generic<'a> as Message>::unmarshal(parser)?;
(self.0)(Ok(&msg));
socket.bufio.add_buf(buf);
socket.in_bufs.push(buf);
Ok(())
}
}

View file

@ -1,8 +1,11 @@
use {
crate::dbus::{
DbusError, DbusType, DynamicType, Formatter, Parser, TY_ARRAY, TY_BOOLEAN, TY_BYTE,
TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING,
TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
crate::{
dbus::{
DbusError, DbusType, DynamicType, Formatter, Parser, TY_ARRAY, TY_BOOLEAN, TY_BYTE,
TY_DOUBLE, TY_INT16, TY_INT32, TY_INT64, TY_OBJECT_PATH, TY_SIGNATURE, TY_STRING,
TY_UINT16, TY_UINT32, TY_UINT64, TY_UNIX_FD, TY_VARIANT,
},
utils::buf::DynamicBuf,
},
std::{borrow::Cow, ops::Deref, rc::Rc},
uapi::{OwnedFd, Packed, Pod},
@ -458,7 +461,7 @@ impl<'a> Variant<'a> {
}
}
pub fn write_signature(&self, w: &mut Vec<u8>) {
pub fn write_signature(&self, w: &mut DynamicBuf) {
let c = match self {
Variant::U8(..) => TY_BYTE,
Variant::Bool(..) => TY_BOOLEAN,