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.
328 lines
7.8 KiB
Rust
328 lines
7.8 KiB
Rust
use {
|
|
crate::utils::{numcell::NumCell, ptr_ext::PtrExt},
|
|
std::{
|
|
alloc::Layout,
|
|
cmp,
|
|
collections::Bound,
|
|
fmt::Arguments,
|
|
io::{self, Write},
|
|
marker::PhantomData,
|
|
mem,
|
|
ops::{Deref, DerefMut, Range, RangeBounds},
|
|
ptr::NonNull,
|
|
slice,
|
|
},
|
|
uapi::Pod,
|
|
};
|
|
|
|
const METADATA_SIZE: u32 = 8;
|
|
const METADATA_ALIGN: usize = 4;
|
|
const SIZE_OFF: u32 = 0;
|
|
const RC_OFF: u32 = 4;
|
|
const RC_OFF_INV: u32 = METADATA_SIZE - RC_OFF;
|
|
const SIZE_OFF_INV: u32 = METADATA_SIZE - SIZE_OFF;
|
|
|
|
pub struct Buf {
|
|
storage: NonNull<u8>,
|
|
range: Range<u32>,
|
|
}
|
|
|
|
impl Buf {
|
|
pub fn from_slice(vec: &[u8]) -> Buf {
|
|
let len = vec.len();
|
|
assert!(len <= (u32::MAX - METADATA_SIZE) as usize);
|
|
let len = len as u32;
|
|
let size = len + METADATA_SIZE;
|
|
let layout = Layout::from_size_align(size as _, METADATA_ALIGN).unwrap();
|
|
let ptr = unsafe { std::alloc::alloc(layout) };
|
|
if ptr.is_null() {
|
|
std::alloc::handle_alloc_error(layout);
|
|
}
|
|
unsafe {
|
|
*ptr.cast::<u32>() = size;
|
|
*ptr.add(RC_OFF as _).cast::<u32>() = 1;
|
|
let mut buf = Buf {
|
|
storage: NonNull::new_unchecked(ptr.add(METADATA_SIZE as _)),
|
|
range: Range { start: 0, end: len },
|
|
};
|
|
buf[..].copy_from_slice(vec);
|
|
buf
|
|
}
|
|
}
|
|
|
|
pub fn new(len: usize) -> Buf {
|
|
assert!(len <= (u32::MAX - METADATA_SIZE) as usize);
|
|
let len = len as u32;
|
|
let size = len + METADATA_SIZE;
|
|
let layout = Layout::from_size_align(size as _, METADATA_ALIGN).unwrap();
|
|
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
|
|
if ptr.is_null() {
|
|
std::alloc::handle_alloc_error(layout);
|
|
}
|
|
unsafe {
|
|
*ptr.cast::<u32>() = size;
|
|
*ptr.add(RC_OFF as _).cast::<u32>() = 1;
|
|
Buf {
|
|
storage: NonNull::new_unchecked(ptr.add(METADATA_SIZE as _)),
|
|
range: Range { start: 0, end: len },
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn clone(&mut self) -> Buf {
|
|
self.rc().fetch_add(1);
|
|
Buf {
|
|
storage: self.storage,
|
|
range: self.range.clone(),
|
|
}
|
|
}
|
|
|
|
pub fn slice(&mut self, range: impl RangeBounds<usize>) -> Buf {
|
|
let start = match range.start_bound() {
|
|
Bound::Included(&n) => n,
|
|
Bound::Excluded(&n) => n.wrapping_add(1),
|
|
Bound::Unbounded => 0,
|
|
};
|
|
let end = match range.end_bound() {
|
|
Bound::Included(&n) => n.wrapping_add(1),
|
|
Bound::Excluded(&n) => n,
|
|
Bound::Unbounded => self.len(),
|
|
};
|
|
self.slice_(start as _, end as _)
|
|
}
|
|
|
|
fn slice_(&mut self, start: u32, end: u32) -> Buf {
|
|
assert!(start <= end);
|
|
assert!(end <= self.len32());
|
|
self.rc().fetch_add(1);
|
|
Buf {
|
|
storage: self.storage,
|
|
range: Range {
|
|
start: self.range.start + start,
|
|
end: self.range.start + end,
|
|
},
|
|
}
|
|
}
|
|
|
|
fn rc(&self) -> &NumCell<u32> {
|
|
unsafe {
|
|
self.storage
|
|
.as_ptr()
|
|
.sub(RC_OFF_INV as _)
|
|
.cast::<NumCell<u32>>()
|
|
.deref()
|
|
}
|
|
}
|
|
|
|
fn assert_unique(&self) {
|
|
assert_eq!(self.rc().get(), 1);
|
|
}
|
|
|
|
pub fn len32(&self) -> u32 {
|
|
self.range.end - self.range.start
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.len32() as _
|
|
}
|
|
|
|
fn size32(&self) -> u32 {
|
|
unsafe {
|
|
*self
|
|
.storage
|
|
.as_ptr()
|
|
.sub(SIZE_OFF_INV as _)
|
|
.cast::<u32>()
|
|
.deref()
|
|
}
|
|
}
|
|
|
|
pub fn cap32(&self) -> u32 {
|
|
self.size32() - METADATA_SIZE
|
|
}
|
|
|
|
pub fn as_ptr(&self) -> *mut u8 {
|
|
unsafe { self.storage.as_ptr().add(self.range.start as _) }
|
|
}
|
|
|
|
pub fn write_fmt(&mut self, args: Arguments) -> Result<Self, io::Error> {
|
|
let cap = self.len();
|
|
let mut buf = self.deref_mut();
|
|
buf.write_fmt(args)?;
|
|
let len = cap - buf.len();
|
|
Ok(self.slice(..len))
|
|
}
|
|
|
|
pub fn into_full(self) -> Self {
|
|
let new = Self {
|
|
storage: self.storage,
|
|
range: 0..self.cap32(),
|
|
};
|
|
mem::forget(self);
|
|
new
|
|
}
|
|
|
|
fn as_slice(&self) -> &[u8] {
|
|
unsafe { slice::from_raw_parts(self.as_ptr(), self.len()) }
|
|
}
|
|
|
|
fn as_slice_mut(&mut self) -> &mut [u8] {
|
|
unsafe { slice::from_raw_parts_mut(self.as_ptr(), self.len()) }
|
|
}
|
|
}
|
|
|
|
impl Default for Buf {
|
|
fn default() -> Self {
|
|
Self::new(0)
|
|
}
|
|
}
|
|
|
|
impl Deref for Buf {
|
|
type Target = [u8];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.assert_unique();
|
|
self.as_slice()
|
|
}
|
|
}
|
|
|
|
impl DerefMut for Buf {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
self.assert_unique();
|
|
self.as_slice_mut()
|
|
}
|
|
}
|
|
|
|
impl Drop for Buf {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
let prev = self.rc().fetch_sub(1);
|
|
if prev != 1 {
|
|
return;
|
|
}
|
|
let ptr = self.storage.as_ptr().sub(METADATA_SIZE as _).cast::<u32>();
|
|
let size = *ptr as _;
|
|
let layout = Layout::from_size_align_unchecked(size, METADATA_ALIGN);
|
|
std::alloc::dealloc(ptr as _, layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct DynamicBuf {
|
|
buf: Buf,
|
|
len: usize,
|
|
}
|
|
|
|
impl DynamicBuf {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
buf: Buf::new(0),
|
|
len: 0,
|
|
}
|
|
}
|
|
|
|
pub fn from_buf(buf: Buf) -> Self {
|
|
buf.assert_unique();
|
|
Self {
|
|
buf: buf.into_full(),
|
|
len: 0,
|
|
}
|
|
}
|
|
|
|
pub fn unwrap(mut self) -> Buf {
|
|
self.buf.slice(..self.len)
|
|
}
|
|
|
|
pub fn len(&self) -> usize {
|
|
self.len
|
|
}
|
|
|
|
pub fn reserve(&mut self, n: usize) {
|
|
if self.buf.len() - self.len < n {
|
|
let cap = self.len.checked_add(n).unwrap();
|
|
let cap = cmp::max(self.buf.len() * 2, cap);
|
|
let mut new = Buf::new(cap);
|
|
new[..self.len].copy_from_slice(&self.buf[..self.len]);
|
|
self.buf = new;
|
|
}
|
|
}
|
|
|
|
pub fn extend_from_slice(&mut self, buf: &[u8]) {
|
|
self.reserve(buf.len());
|
|
self.buf.as_slice_mut()[self.len..self.len + buf.len()].copy_from_slice(buf);
|
|
self.len += buf.len();
|
|
}
|
|
|
|
pub fn push(&mut self, b: u8) {
|
|
self.extend_from_slice(&[b]);
|
|
}
|
|
|
|
pub fn clear(&mut self) {
|
|
self.len = 0;
|
|
}
|
|
|
|
pub fn borrow(&mut self) -> BorrowedBuf<'_> {
|
|
BorrowedBuf {
|
|
buf: self.buf.slice(..self.len),
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct BorrowedBuf<'a> {
|
|
pub buf: Buf,
|
|
_phantom: PhantomData<&'a mut DynamicBuf>,
|
|
}
|
|
|
|
impl<'a> Drop for BorrowedBuf<'a> {
|
|
fn drop(&mut self) {
|
|
assert_eq!(self.buf.rc().get(), 2);
|
|
}
|
|
}
|
|
|
|
impl Write for DynamicBuf {
|
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
self.extend_from_slice(buf);
|
|
Ok(buf.len())
|
|
}
|
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Deref for DynamicBuf {
|
|
type Target = [u8];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.buf.as_slice()
|
|
}
|
|
}
|
|
|
|
impl DerefMut for DynamicBuf {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
self.buf.as_slice_mut()
|
|
}
|
|
}
|
|
|
|
pub struct TypedBuf<T: Pod> {
|
|
buf: Buf,
|
|
_phantom: PhantomData<T>,
|
|
}
|
|
|
|
impl<T: Pod> TypedBuf<T> {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
buf: Buf::new(mem::size_of::<T>()),
|
|
_phantom: Default::default(),
|
|
}
|
|
}
|
|
|
|
pub fn buf(&mut self) -> Buf {
|
|
self.buf.clone()
|
|
}
|
|
|
|
pub fn t(&self) -> T {
|
|
uapi::pod_read(&self.buf[..]).unwrap()
|
|
}
|
|
}
|