Restaged repo, allocator and runtime implemented, ioring-backed async fs/net/channel/timer primitives
This commit is contained in:
147
lib/runtime/src/op/completion.rs
Normal file
147
lib/runtime/src/op/completion.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
use crate::platform::linux_x86_64::runtime::{ThreadHandle, current_thread_handle};
|
||||
|
||||
type CancelCallback = Box<dyn FnOnce() + Send + 'static>;
|
||||
|
||||
struct CompletionState<T> {
|
||||
owner: ThreadHandle,
|
||||
interested: AtomicBool,
|
||||
finished: AtomicBool,
|
||||
wake_queued: AtomicBool,
|
||||
result: Mutex<Option<T>>,
|
||||
waker: Mutex<Option<Waker>>,
|
||||
cancel: Mutex<Option<CancelCallback>>,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> CompletionState<T> {
|
||||
fn queue_wake(self: &Arc<Self>) {
|
||||
if self.wake_queued.swap(true, Ordering::AcqRel) {
|
||||
return;
|
||||
}
|
||||
|
||||
let state = Arc::clone(self);
|
||||
if !self.owner.queue_microtask(move || {
|
||||
state.wake_queued.store(false, Ordering::Release);
|
||||
if let Some(waker) = state.waker.lock().unwrap().take() {
|
||||
waker.wake();
|
||||
}
|
||||
}) {
|
||||
self.wake_queued.store(false, Ordering::Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CompletionFuture<T> {
|
||||
state: Arc<CompletionState<T>>,
|
||||
}
|
||||
|
||||
pub(crate) struct CompletionHandle<T> {
|
||||
state: Arc<CompletionState<T>>,
|
||||
}
|
||||
|
||||
impl<T> Clone for CompletionHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: Arc::clone(&self.state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn completion<T: Send + 'static>(
|
||||
owner: ThreadHandle,
|
||||
) -> (CompletionFuture<T>, CompletionHandle<T>) {
|
||||
owner.begin_async_operation();
|
||||
let state = Arc::new(CompletionState {
|
||||
owner,
|
||||
interested: AtomicBool::new(true),
|
||||
finished: AtomicBool::new(false),
|
||||
wake_queued: AtomicBool::new(false),
|
||||
result: Mutex::new(None),
|
||||
waker: Mutex::new(None),
|
||||
cancel: Mutex::new(None),
|
||||
});
|
||||
|
||||
(
|
||||
CompletionFuture {
|
||||
state: Arc::clone(&state),
|
||||
},
|
||||
CompletionHandle { state },
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn completion_for_current_thread<T: Send + 'static>()
|
||||
-> (CompletionFuture<T>, CompletionHandle<T>) {
|
||||
completion(current_thread_handle())
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> CompletionHandle<T> {
|
||||
pub(crate) fn complete(self, value: T) {
|
||||
self.finish(Some(value));
|
||||
}
|
||||
|
||||
pub(crate) fn finish(self, value: Option<T>) {
|
||||
if self.state.finished.swap(true, Ordering::AcqRel) {
|
||||
return;
|
||||
}
|
||||
|
||||
let interested = self.state.interested.load(Ordering::Acquire);
|
||||
if interested {
|
||||
*self.state.result.lock().unwrap() = value;
|
||||
self.state.queue_wake();
|
||||
}
|
||||
|
||||
let _ = self.state.cancel.lock().unwrap().take();
|
||||
self.state.owner.finish_async_operation();
|
||||
}
|
||||
|
||||
pub(crate) fn set_cancel(&self, cancel: impl FnOnce() + Send + 'static) {
|
||||
*self.state.cancel.lock().unwrap() = Some(Box::new(cancel));
|
||||
}
|
||||
|
||||
pub(crate) fn is_interested(&self) -> bool {
|
||||
self.state.interested.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for CompletionFuture<T> {
|
||||
type Output = T;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
if let Some(value) = self.state.result.lock().unwrap().take() {
|
||||
return Poll::Ready(value);
|
||||
}
|
||||
|
||||
*self.state.waker.lock().unwrap() = Some(cx.waker().clone());
|
||||
|
||||
if let Some(value) = self.state.result.lock().unwrap().take() {
|
||||
let _ = self.state.waker.lock().unwrap().take();
|
||||
return Poll::Ready(value);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for CompletionFuture<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.state.interested.swap(false, Ordering::AcqRel) {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = self.state.result.lock().unwrap().take();
|
||||
let _ = self.state.waker.lock().unwrap().take();
|
||||
|
||||
if !self.state.finished.load(Ordering::Acquire)
|
||||
&& let Some(cancel) = self.state.cancel.lock().unwrap().take()
|
||||
{
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
105
lib/runtime/src/op/fs.rs
Normal file
105
lib/runtime/src/op/fs.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
//! Logical filesystem operations.
|
||||
//!
|
||||
//! This layer owns request data so the public API can keep borrowed buffers while platform
|
||||
//! backends pin, stage, or offload as needed.
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::os::fd::RawFd;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct OpenOptions {
|
||||
pub read: bool,
|
||||
pub write: bool,
|
||||
pub append: bool,
|
||||
pub truncate: bool,
|
||||
pub create: bool,
|
||||
pub create_new: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MetadataTarget {
|
||||
Path(PathBuf),
|
||||
File(RawFd),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum FileType {
|
||||
File,
|
||||
Directory,
|
||||
Symlink,
|
||||
BlockDevice,
|
||||
CharacterDevice,
|
||||
Fifo,
|
||||
Socket,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawMetadata {
|
||||
pub file_type: FileType,
|
||||
pub mode: u16,
|
||||
pub len: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct RawDirEntry {
|
||||
pub path: PathBuf,
|
||||
pub file_name: OsString,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FsOp {
|
||||
Open {
|
||||
path: PathBuf,
|
||||
options: OpenOptions,
|
||||
},
|
||||
Read {
|
||||
fd: RawFd,
|
||||
offset: Option<u64>,
|
||||
len: usize,
|
||||
},
|
||||
Write {
|
||||
fd: RawFd,
|
||||
offset: Option<u64>,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
Metadata {
|
||||
target: MetadataTarget,
|
||||
follow_symlinks: bool,
|
||||
},
|
||||
SetLen {
|
||||
fd: RawFd,
|
||||
len: u64,
|
||||
},
|
||||
SyncAll {
|
||||
fd: RawFd,
|
||||
},
|
||||
SyncData {
|
||||
fd: RawFd,
|
||||
},
|
||||
Duplicate {
|
||||
fd: RawFd,
|
||||
},
|
||||
CreateDir {
|
||||
path: PathBuf,
|
||||
recursive: bool,
|
||||
mode: u32,
|
||||
},
|
||||
RemoveFile {
|
||||
path: PathBuf,
|
||||
},
|
||||
RemoveDir {
|
||||
path: PathBuf,
|
||||
},
|
||||
Rename {
|
||||
from: PathBuf,
|
||||
to: PathBuf,
|
||||
},
|
||||
ReadDir {
|
||||
path: PathBuf,
|
||||
},
|
||||
Close {
|
||||
fd: RawFd,
|
||||
},
|
||||
}
|
||||
8
lib/runtime/src/op/mod.rs
Normal file
8
lib/runtime/src/op/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
//! Internal and public operation-layer building blocks.
|
||||
//!
|
||||
//! The operation layer defines logical work units that bridge user-facing APIs and platform
|
||||
//! backends without leaking platform details upward.
|
||||
|
||||
pub(crate) mod completion;
|
||||
pub mod fs;
|
||||
pub mod net;
|
||||
69
lib/runtime/src/op/net.rs
Normal file
69
lib/runtime/src/op/net.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
//! Logical networking operations shared between the public API and Linux backend.
|
||||
|
||||
use std::net::{Shutdown, SocketAddr};
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NetOp {
|
||||
Socket {
|
||||
domain: i32,
|
||||
socket_type: i32,
|
||||
protocol: i32,
|
||||
flags: u32,
|
||||
},
|
||||
Connect {
|
||||
fd: RawFd,
|
||||
addr: SocketAddr,
|
||||
},
|
||||
Bind {
|
||||
fd: RawFd,
|
||||
addr: SocketAddr,
|
||||
},
|
||||
Listen {
|
||||
fd: RawFd,
|
||||
backlog: i32,
|
||||
},
|
||||
Accept {
|
||||
fd: RawFd,
|
||||
},
|
||||
Send {
|
||||
fd: RawFd,
|
||||
data: Vec<u8>,
|
||||
flags: i32,
|
||||
},
|
||||
SendTo {
|
||||
fd: RawFd,
|
||||
target: SocketAddr,
|
||||
data: Vec<u8>,
|
||||
flags: i32,
|
||||
},
|
||||
Recv {
|
||||
fd: RawFd,
|
||||
len: usize,
|
||||
flags: i32,
|
||||
},
|
||||
RecvFrom {
|
||||
fd: RawFd,
|
||||
len: usize,
|
||||
flags: i32,
|
||||
},
|
||||
Shutdown {
|
||||
fd: RawFd,
|
||||
how: Shutdown,
|
||||
},
|
||||
Close {
|
||||
fd: RawFd,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AcceptedSocket {
|
||||
pub fd: RawFd,
|
||||
pub peer_addr: SocketAddr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ReceivedDatagram {
|
||||
pub data: Vec<u8>,
|
||||
pub peer_addr: SocketAddr,
|
||||
}
|
||||
Reference in New Issue
Block a user