Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backend: Handle EINTR, partial writes when using sendmsg #647

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 32 additions & 23 deletions wayland-backend/src/rs/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@
let flags = socket::MsgFlags::MSG_DONTWAIT | socket::MsgFlags::MSG_NOSIGNAL;
let iov = [IoSlice::new(bytes)];

if !fds.is_empty() {
let cmsgs = [socket::ControlMessage::ScmRights(fds)];
Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &cmsgs, flags, None)?)
} else {
Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &[], flags, None)?)
let cmsgs = [socket::ControlMessage::ScmRights(fds)];
let cmsgs: &[_] = if !fds.is_empty() { &cmsgs } else { &[] };
loop {
let res = socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &cmsgs, flags, None);

Check failure on line 44 in wayland-backend/src/rs/socket.rs

View workflow job for this annotation

GitHub Actions / clippy-check

this expression creates a reference which is immediately dereferenced by the compiler
if res != Err(nix::errno::Errno::EINTR) {
return Ok(res?);
}
}
}

Expand Down Expand Up @@ -128,26 +130,28 @@
}

/// Flush the contents of the outgoing buffer into the socket
///
/// Returns `Ok(())` when all bytes have been flushed successfully. If it
/// returns `ErrorKind::WouldBlock`, at least some bytes weren't written.
pub fn flush(&mut self) -> IoResult<()> {
let written = {
let words = self.out_data.get_contents();
if words.is_empty() {
return Ok(());
}
let bytes = unsafe {
::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 4)
while !self.out_data.is_empty() {
let written = {
let words = self.out_data.get_contents();
let bytes = unsafe {
::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 4)
};
let fds = self.out_fds.get_contents();
let written = self.socket.send_msg(bytes, fds)?;
for &fd in fds {
// once the fds are sent, we can close them
let _ = ::nix::unistd::close(fd);
}
written
};
let fds = self.out_fds.get_contents();
let written = self.socket.send_msg(bytes, fds)?;
for &fd in fds {
// once the fds are sent, we can close them
let _ = ::nix::unistd::close(fd);
}
written
};
self.out_data.offset(written / 4);
self.out_data.move_to_front();
self.out_fds.clear();
self.out_data.offset(written / 4);
self.out_data.move_to_front();
self.out_fds.clear();
}
Ok(())
}

Expand Down Expand Up @@ -309,6 +313,11 @@
self.offset = 0;
}

/// All occupied space has been read
fn is_empty(&self) -> bool {
self.offset >= self.occupied
}

/// Get the current contents of the occupied space of the buffer
fn get_contents(&self) -> &[T] {
&self.storage[(self.offset)..(self.occupied)]
Expand Down
Loading