dope-core 0.10.0

The manifold runtime
Documentation
use std::{io, ptr::NonNull, slice};

use io_uring::Submitter;
use io_uring::types::BufRingEntry;
use std::io::{Error, ErrorKind};

use crate::backend::uring::tail::Tail;

use super::ffi::Mmap;

struct Entries {
    mem: Mmap,
    count: u16,
}

impl Entries {
    fn new(count: u16) -> io::Result<Self> {
        let size = size_of::<BufRingEntry>()
            .checked_mul(count as usize)
            .ok_or_else(|| Error::new(ErrorKind::InvalidInput, "pbuf_ring size overflow"))?;
        Ok(Self {
            mem: Mmap::new_zeroed(size)?,
            count,
        })
    }

    fn raw_ptr(&self) -> NonNull<BufRingEntry> {
        unsafe { NonNull::new_unchecked(self.mem.as_ptr().cast_mut().cast()) }
    }

    fn as_mut_slice(&mut self) -> &mut [BufRingEntry] {
        unsafe { slice::from_raw_parts_mut(self.mem.as_mut_ptr().cast(), self.count as usize) }
    }

    unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut BufRingEntry {
        unsafe { self.as_mut_slice().get_unchecked_mut(index) }
    }
}

struct Buffers {
    mem: Mmap,
    buf_len: usize,
}

impl Buffers {
    fn new(count: u16, buf_len: usize) -> io::Result<Self> {
        let total = (count as usize)
            .checked_mul(buf_len)
            .ok_or_else(|| Error::new(ErrorKind::InvalidInput, "pbuf backing size overflow"))?;
        let mut mem = Mmap::new_zeroed(total)?;
        mem.prewarm();
        Ok(Self { mem, buf_len })
    }

    fn buf_len(&self) -> usize {
        self.buf_len
    }

    fn addr(&self, bid: u16) -> u64 {
        self.mem.as_ptr() as u64 + (bid as usize * self.buf_len) as u64
    }

    fn ptr_len(&self, bid: u16, len: usize) -> (*const u8, usize) {
        let len = len.min(self.buf_len);
        let ptr = unsafe { self.mem.as_ptr().add(bid as usize * self.buf_len) };
        (ptr, len)
    }
}

pub(crate) struct Ring {
    tail_pos: u16,
    last_published: u16,
    mask: u16,
    tail: Tail,
    buffers: Buffers,
    entries: Entries,
}

impl Ring {
    pub(crate) const BGID: u16 = 1;

    pub(crate) fn new(submitter: &Submitter<'_>, entries: u16, buf_len: usize) -> io::Result<Self> {
        if !entries.is_power_of_two() {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "pbuf_ring entries must be power-of-two",
            ));
        }

        let mut entries_mem = Entries::new(entries)?;
        let buffers = Buffers::new(entries, buf_len)?;

        for (bid, e) in entries_mem.as_mut_slice().iter_mut().enumerate() {
            let bid = bid as u16;
            let addr = buffers.addr(bid);
            e.set_addr(addr);
            e.set_len(buf_len as u32);
            e.set_bid(bid);
        }

        let tail = unsafe {
            Tail::new(BufRingEntry::tail(entries_mem.raw_ptr().as_ptr() as *const _) as *mut u16)
        };
        let ring = Self {
            tail_pos: entries,
            last_published: entries,
            mask: entries.wrapping_sub(1),
            tail,
            buffers,
            entries: entries_mem,
        };
        ring.store_tail(entries);

        unsafe {
            submitter.register_buf_ring_with_flags(
                ring.entries.raw_ptr().as_ptr() as u64,
                entries,
                Self::BGID,
                0,
            )?;
        }

        Ok(ring)
    }

    pub(crate) fn buf_len(&self) -> usize {
        self.buffers.buf_len()
    }

    pub(crate) fn ptr_len(&self, bid: u16, len: usize) -> (*const u8, usize) {
        self.buffers.ptr_len(bid & self.mask, len)
    }

    pub(crate) fn defer(&mut self, bid: u16) {
        let bid = bid & self.mask;
        let slot = (self.tail_pos & self.mask) as usize;
        let addr = self.buffers.addr(bid);
        let buf_len = self.buffers.buf_len() as u32;
        let e = unsafe { self.entries.get_unchecked_mut(slot) };
        e.set_addr(addr);
        e.set_len(buf_len);
        e.set_bid(bid);
        self.tail_pos = self.tail_pos.wrapping_add(1);
    }

    pub(crate) fn flush(&mut self) {
        if self.tail_pos == self.last_published {
            return;
        }
        self.store_tail(self.tail_pos);
        self.last_published = self.tail_pos;
    }

    fn store_tail(&self, value: u16) {
        self.tail.publish(value);
    }
}