abi: file options, remove NonBlocking socket option
This commit is contained in:
parent
ed9bbea189
commit
2e3af98822
@ -14,9 +14,12 @@ use libk::{
|
||||
};
|
||||
use libk_mm::PageBox;
|
||||
use libk_util::{queue::BoundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock};
|
||||
use yggdrasil_abi::net::{
|
||||
options::{self, RawSocketOptionVariant, SocketOption},
|
||||
SocketAddr, SocketInterfaceQuery,
|
||||
use yggdrasil_abi::{
|
||||
net::{
|
||||
options::{self, RawSocketOptionVariant},
|
||||
SocketAddr, SocketInterfaceQuery,
|
||||
},
|
||||
option::OptionValue,
|
||||
};
|
||||
|
||||
use crate::{ethernet::L2Packet, interface::NetworkInterface};
|
||||
|
@ -14,9 +14,12 @@ use libk::{
|
||||
vfs::{ConnectionSocket, FileReadiness, Socket},
|
||||
};
|
||||
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
||||
use yggdrasil_abi::net::{
|
||||
options::{self, SocketOption, TcpSocketOptionVariant},
|
||||
SocketAddr,
|
||||
use yggdrasil_abi::{
|
||||
net::{
|
||||
options::{self, TcpSocketOptionVariant},
|
||||
SocketAddr,
|
||||
},
|
||||
option::OptionValue,
|
||||
};
|
||||
|
||||
mod listener;
|
||||
|
@ -16,9 +16,12 @@ use libk_util::{
|
||||
queue::BoundedMpmcQueue,
|
||||
sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard},
|
||||
};
|
||||
use yggdrasil_abi::net::{
|
||||
options::{self, SocketOption, UdpSocketOptionVariant},
|
||||
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr,
|
||||
use yggdrasil_abi::{
|
||||
net::{
|
||||
options::{self, UdpSocketOptionVariant},
|
||||
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr,
|
||||
},
|
||||
option::OptionValue,
|
||||
};
|
||||
|
||||
use crate::l4;
|
||||
|
@ -1,5 +1,3 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use yggdrasil_abi::{error::Error, io::SeekFrom};
|
||||
|
||||
@ -8,11 +6,6 @@ use crate::{
|
||||
vfs::{CommonImpl, NodeRef},
|
||||
};
|
||||
|
||||
// use crate::vfs::{
|
||||
// device::{BlockDeviceWrapper, CharDeviceWrapper},
|
||||
// node::NodeRef,
|
||||
// };
|
||||
|
||||
pub struct BlockFile {
|
||||
pub(super) device: BlockDeviceFile,
|
||||
pub(super) node: NodeRef,
|
||||
@ -21,12 +14,12 @@ pub struct BlockFile {
|
||||
pub(super) write: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CharFile {
|
||||
pub(super) device: CharDeviceFile,
|
||||
pub(super) node: NodeRef,
|
||||
pub(super) read: bool,
|
||||
pub(super) write: bool,
|
||||
pub(super) blocking: AtomicBool,
|
||||
}
|
||||
|
||||
impl BlockFile {
|
||||
@ -82,27 +75,27 @@ impl BlockFile {
|
||||
}
|
||||
|
||||
impl CharFile {
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
|
||||
if !self.read {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
if self.blocking.load(Ordering::Acquire) {
|
||||
block!(self.device.0.read(buf).await)?
|
||||
} else {
|
||||
if non_blocking {
|
||||
self.device.0.read_nonblocking(buf)
|
||||
} else {
|
||||
block!(self.device.0.read(buf).await)?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
pub fn write(&self, buf: &[u8], non_blocking: bool) -> Result<usize, Error> {
|
||||
if !self.write {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
if self.blocking.load(Ordering::Acquire) {
|
||||
block!(self.device.0.write(buf).await)?
|
||||
} else {
|
||||
if non_blocking {
|
||||
self.device.0.write_nonblocking(buf)
|
||||
} else {
|
||||
block!(self.device.0.write(buf).await)?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ use core::{
|
||||
any::Any,
|
||||
fmt,
|
||||
mem::MaybeUninit,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
@ -16,14 +15,16 @@ use device::{BlockFile, CharFile};
|
||||
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
|
||||
use libk_util::{
|
||||
io::{ReadAt, WriteAt},
|
||||
sync::IrqSafeSpinlock,
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, PipeOptions, RawFd, SeekFrom,
|
||||
TerminalOptions, TerminalSize, TimerOptions,
|
||||
options::{self, FileOptionVariant},
|
||||
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, RawFd, SeekFrom, TerminalOptions,
|
||||
TerminalSize, TimerOptions,
|
||||
},
|
||||
option::OptionValue,
|
||||
process::{ProcessWait, WaitFlags},
|
||||
};
|
||||
|
||||
@ -78,16 +79,23 @@ pub enum DirectoryOpenPosition {
|
||||
/// Wrapper type for a [File] shared reference
|
||||
pub type FileRef = Arc<File>;
|
||||
|
||||
// TODO some kind of a mutex instead?
|
||||
/// Describes an open file
|
||||
#[allow(missing_docs)]
|
||||
pub enum File {
|
||||
#[derive(Clone)]
|
||||
struct FileOptions {
|
||||
non_blocking: bool,
|
||||
}
|
||||
|
||||
pub struct File {
|
||||
options: IrqSafeRwLock<FileOptions>,
|
||||
inner: FileInner,
|
||||
}
|
||||
|
||||
enum FileInner {
|
||||
Directory(DirectoryFile),
|
||||
Regular(RegularFile),
|
||||
Block(BlockFile),
|
||||
Char(CharFile),
|
||||
Socket(SocketWrapper),
|
||||
AnonymousPipe(PipeEnd, AtomicBool),
|
||||
AnonymousPipe(PipeEnd),
|
||||
Poll(FdPoll),
|
||||
Timer(TimerFile),
|
||||
Channel(ChannelDescriptor),
|
||||
@ -106,8 +114,8 @@ pub trait TerminalHalf {
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TerminalHalfWrapper<T: TerminalHalf> {
|
||||
blocking: AtomicBool,
|
||||
half: Arc<T>,
|
||||
node: NodeRef,
|
||||
}
|
||||
@ -118,36 +126,38 @@ pub struct FileSet {
|
||||
}
|
||||
|
||||
impl File {
|
||||
fn from_inner(inner: FileInner) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
options: IrqSafeRwLock::new(FileOptions {
|
||||
non_blocking: false,
|
||||
}),
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs a pipe pair, returning its `(read, write)` ends
|
||||
pub fn new_pipe_pair(capacity: usize, options: PipeOptions) -> (Arc<Self>, Arc<Self>) {
|
||||
pub fn new_pipe_pair(capacity: usize) -> (Arc<Self>, Arc<Self>) {
|
||||
let (read, write) = PipeEnd::new_pair(capacity);
|
||||
(
|
||||
Arc::new(Self::AnonymousPipe(
|
||||
read,
|
||||
AtomicBool::new(options.contains(PipeOptions::READ_NONBLOCKING)),
|
||||
)),
|
||||
Arc::new(Self::AnonymousPipe(
|
||||
write,
|
||||
AtomicBool::new(options.contains(PipeOptions::WRITE_NONBLOCKING)),
|
||||
)),
|
||||
)
|
||||
let read = FileInner::AnonymousPipe(read);
|
||||
let write = FileInner::AnonymousPipe(write);
|
||||
(Self::from_inner(read), Self::from_inner(write))
|
||||
}
|
||||
|
||||
/// Constructs a new poll channel file
|
||||
pub fn new_poll_channel() -> Arc<Self> {
|
||||
Arc::new(Self::Poll(FdPoll::new()))
|
||||
Self::from_inner(FileInner::Poll(FdPoll::new()))
|
||||
}
|
||||
|
||||
/// Opens a new message channel, optionally subscribing to it as well
|
||||
pub fn new_message_channel(name: &str, with_sub: bool) -> Arc<Self> {
|
||||
let channel = ChannelDescriptor::open(name, with_sub);
|
||||
Arc::new(Self::Channel(channel))
|
||||
Self::from_inner(FileInner::Channel(channel))
|
||||
}
|
||||
|
||||
/// Creates a buffer of shared memory and associates a [File] with it
|
||||
pub fn new_shared_memory(size: usize) -> Result<Arc<Self>, Error> {
|
||||
let shm = SharedMemory::new(size)?;
|
||||
Ok(Arc::new(Self::SharedMemory(Arc::new(shm))))
|
||||
Ok(Self::from_inner(FileInner::SharedMemory(Arc::new(shm))))
|
||||
}
|
||||
|
||||
/// Creates a pair of PTY master/slave
|
||||
@ -160,41 +170,34 @@ impl File {
|
||||
let slave = Arc::new(slave);
|
||||
let (master_node, slave_node) =
|
||||
Node::pseudo_terminal_nodes(&master, &slave, Metadata::now_root(FileMode::new(0o644)));
|
||||
Ok((
|
||||
Arc::new(Self::PtyMaster(TerminalHalfWrapper {
|
||||
blocking: AtomicBool::new(true),
|
||||
half: master,
|
||||
node: master_node,
|
||||
})),
|
||||
Arc::new(Self::PtySlave(TerminalHalfWrapper {
|
||||
blocking: AtomicBool::new(true),
|
||||
half: slave,
|
||||
node: slave_node,
|
||||
})),
|
||||
))
|
||||
|
||||
let master = Self::from_inner(FileInner::PtyMaster(TerminalHalfWrapper {
|
||||
half: master,
|
||||
node: master_node,
|
||||
}));
|
||||
let slave = Self::from_inner(FileInner::PtySlave(TerminalHalfWrapper {
|
||||
half: slave,
|
||||
node: slave_node,
|
||||
}));
|
||||
Ok((master, slave))
|
||||
}
|
||||
|
||||
pub fn open_pty_master(pty: Arc<PseudoTerminalMaster>, node: Arc<Node>) -> Arc<Self> {
|
||||
Arc::new(Self::PtyMaster(TerminalHalfWrapper {
|
||||
blocking: AtomicBool::new(true),
|
||||
Self::from_inner(FileInner::PtyMaster(TerminalHalfWrapper {
|
||||
half: pty,
|
||||
node,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn open_pty_slave(pty: Arc<PseudoTerminalSlave>, node: Arc<Node>) -> Arc<Self> {
|
||||
Arc::new(Self::PtySlave(TerminalHalfWrapper {
|
||||
blocking: AtomicBool::new(true),
|
||||
half: pty,
|
||||
node,
|
||||
}))
|
||||
Self::from_inner(FileInner::PtySlave(TerminalHalfWrapper { half: pty, node }))
|
||||
}
|
||||
|
||||
/// Creates a new [TimerFile]-backed File
|
||||
pub fn new_timer(options: TimerOptions) -> FileRef {
|
||||
let repeat = options.contains(TimerOptions::REPEAT);
|
||||
let blocking = !options.contains(TimerOptions::NON_BLOCKING);
|
||||
Arc::new(Self::Timer(TimerFile::new(repeat, blocking)))
|
||||
let timer = TimerFile::new(repeat);
|
||||
Self::from_inner(FileInner::Timer(timer))
|
||||
}
|
||||
|
||||
/// Creates a new [PidFile]-backed file
|
||||
@ -204,18 +207,18 @@ impl File {
|
||||
flags: WaitFlags,
|
||||
) -> Result<FileRef, Error> {
|
||||
PidFile::new(parent, wait, flags)
|
||||
.map(Self::Pid)
|
||||
.map(Arc::new)
|
||||
.map(FileInner::Pid)
|
||||
.map(Self::from_inner)
|
||||
}
|
||||
|
||||
/// Constructs a [File] from a [PacketSocket], [ConnectionSocket] or a [ListenerSocket].
|
||||
pub fn from_socket<S: Into<SocketWrapper>>(socket: S) -> Arc<Self> {
|
||||
Arc::new(Self::Socket(socket.into()))
|
||||
Self::from_inner(FileInner::Socket(socket.into()))
|
||||
}
|
||||
|
||||
pub(crate) fn directory(node: NodeRef, position: DirectoryOpenPosition) -> Arc<Self> {
|
||||
let position = IrqSafeSpinlock::new(position.into());
|
||||
Arc::new(Self::Directory(DirectoryFile { node, position }))
|
||||
Self::from_inner(FileInner::Directory(DirectoryFile { node, position }))
|
||||
}
|
||||
|
||||
pub(crate) fn regular(
|
||||
@ -227,7 +230,7 @@ impl File {
|
||||
let read = opts.contains(OpenOptions::READ);
|
||||
let write = opts.contains(OpenOptions::WRITE);
|
||||
|
||||
Arc::new(Self::Regular(RegularFile {
|
||||
Self::from_inner(FileInner::Regular(RegularFile {
|
||||
node,
|
||||
read,
|
||||
write,
|
||||
@ -251,7 +254,7 @@ impl File {
|
||||
return Err(Error::ReadOnly);
|
||||
}
|
||||
|
||||
Ok(Arc::new(Self::Block(BlockFile {
|
||||
Ok(Self::from_inner(FileInner::Block(BlockFile {
|
||||
device,
|
||||
node,
|
||||
position: IrqSafeSpinlock::new(0),
|
||||
@ -275,67 +278,81 @@ impl File {
|
||||
return Err(Error::ReadOnly);
|
||||
}
|
||||
|
||||
Ok(Arc::new(Self::Char(CharFile {
|
||||
Ok(Self::from_inner(FileInner::Char(CharFile {
|
||||
device,
|
||||
node,
|
||||
read,
|
||||
write,
|
||||
blocking: AtomicBool::new(true),
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn is_non_blocking(&self) -> bool {
|
||||
self.options.read().non_blocking
|
||||
}
|
||||
|
||||
/// Clones an open file for sending it to another process
|
||||
pub fn send(self: &Arc<Self>) -> Result<Arc<Self>, Error> {
|
||||
match self.as_ref() {
|
||||
Self::Char(_) => Ok(self.clone()),
|
||||
Self::Block(_) => todo!(),
|
||||
Self::Regular(file) => Ok(Arc::new(Self::Regular(file.clone()))),
|
||||
Self::SharedMemory(shm) => Ok(Arc::new(Self::SharedMemory(shm.clone()))),
|
||||
Self::Pid(pid) => Ok(Arc::new(Self::Pid(pid.clone()))),
|
||||
let options = self.options.read().clone();
|
||||
Ok(Arc::new(Self {
|
||||
inner: self.inner.send()?,
|
||||
options: IrqSafeRwLock::new(options),
|
||||
}))
|
||||
}
|
||||
|
||||
Self::PtySlave(half) => Ok(Arc::new(Self::PtySlave(half.clone()))),
|
||||
Self::PtyMaster(half) => Ok(Arc::new(Self::PtyMaster(half.clone()))),
|
||||
pub fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> {
|
||||
let option = FileOptionVariant::try_from(option)?;
|
||||
let mut options = self.options.write();
|
||||
match option {
|
||||
FileOptionVariant::NonBlocking => {
|
||||
options.non_blocking = options::NonBlocking::load(buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
log::info!("Invalid file send(): {:?}", self);
|
||||
Err(Error::InvalidOperation)
|
||||
pub fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let option = FileOptionVariant::try_from(option)?;
|
||||
let options = self.options.read();
|
||||
match option {
|
||||
FileOptionVariant::NonBlocking => {
|
||||
options::NonBlocking::store(&options.non_blocking, buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads entries from the directory
|
||||
pub fn read_dir(&self, entries: &mut [MaybeUninit<DirectoryEntry>]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Directory(dir) => dir.read_entries(entries),
|
||||
match &self.inner {
|
||||
FileInner::Directory(dir) => dir.read_entries(entries),
|
||||
_ => Err(Error::NotADirectory),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the underlying [Node] the file contains
|
||||
pub fn node(&self) -> Option<&NodeRef> {
|
||||
match self {
|
||||
Self::Directory(file) => Some(&file.node),
|
||||
Self::Regular(file) => Some(&file.node),
|
||||
Self::Block(file) => Some(&file.node),
|
||||
Self::Char(file) => Some(&file.node),
|
||||
Self::PtyMaster(half) => Some(&half.node),
|
||||
Self::PtySlave(half) => Some(&half.node),
|
||||
match &self.inner {
|
||||
FileInner::Directory(file) => Some(&file.node),
|
||||
FileInner::Regular(file) => Some(&file.node),
|
||||
FileInner::Block(file) => Some(&file.node),
|
||||
FileInner::Char(file) => Some(&file.node),
|
||||
FileInner::PtyMaster(half) => Some(&half.node),
|
||||
FileInner::PtySlave(half) => Some(&half.node),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Polls a file for "read-readiness"
|
||||
pub fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
match self {
|
||||
Self::Char(f) => f.device.poll_read(cx),
|
||||
Self::Channel(ch) => ch.poll_read(cx),
|
||||
Self::Poll(ch) => ch.poll_read(cx),
|
||||
Self::PtyMaster(half) => half.half.poll_read(cx),
|
||||
Self::PtySlave(half) => half.half.poll_read(cx),
|
||||
Self::Socket(socket) => socket.poll_read(cx),
|
||||
Self::Timer(timer) => timer.poll_read(cx),
|
||||
Self::Pid(pid) => pid.poll_read(cx),
|
||||
Self::AnonymousPipe(pipe, _) => pipe.poll_read(cx),
|
||||
match &self.inner {
|
||||
FileInner::Char(f) => f.device.poll_read(cx),
|
||||
FileInner::Channel(ch) => ch.poll_read(cx),
|
||||
FileInner::Poll(ch) => ch.poll_read(cx),
|
||||
FileInner::PtyMaster(half) => half.half.poll_read(cx),
|
||||
FileInner::PtySlave(half) => half.half.poll_read(cx),
|
||||
FileInner::Socket(socket) => socket.poll_read(cx),
|
||||
FileInner::Timer(timer) => timer.poll_read(cx),
|
||||
FileInner::Pid(pid) => pid.poll_read(cx),
|
||||
FileInner::AnonymousPipe(pipe) => pipe.poll_read(cx),
|
||||
// Polling not implemented, return ready immediately (XXX ?)
|
||||
_ => Poll::Ready(Err(Error::NotImplemented)),
|
||||
}
|
||||
@ -348,18 +365,18 @@ impl File {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Char(f) => f.device.device_request(req),
|
||||
Self::Block(f) => f.device.device_request(req),
|
||||
Self::PtySlave(half) => half.half.device_request(req),
|
||||
Self::PtyMaster(half) => half.half.device_request(req),
|
||||
match &self.inner {
|
||||
FileInner::Char(f) => f.device.device_request(req),
|
||||
FileInner::Block(f) => f.device.device_request(req),
|
||||
FileInner::PtySlave(half) => half.half.device_request(req),
|
||||
FileInner::PtyMaster(half) => half.half.device_request(req),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
/// Interprets the file as a poll channel
|
||||
pub fn as_poll_channel(&self) -> Result<&FdPoll, Error> {
|
||||
if let Self::Poll(poll) = self {
|
||||
if let FileInner::Poll(poll) = &self.inner {
|
||||
Ok(poll)
|
||||
} else {
|
||||
Err(Error::InvalidOperation)
|
||||
@ -368,7 +385,7 @@ impl File {
|
||||
|
||||
/// Interprets the file as a message channel
|
||||
pub fn as_message_channel(&self) -> Result<&ChannelDescriptor, Error> {
|
||||
if let Self::Channel(ch) = self {
|
||||
if let FileInner::Channel(ch) = &self.inner {
|
||||
Ok(ch)
|
||||
} else {
|
||||
Err(Error::InvalidOperation)
|
||||
@ -377,16 +394,16 @@ impl File {
|
||||
|
||||
/// Interprets the file as a socket
|
||||
pub fn as_socket(&self) -> Result<&SocketWrapper, Error> {
|
||||
match self {
|
||||
Self::Socket(socket) => Ok(socket),
|
||||
match &self.inner {
|
||||
FileInner::Socket(socket) => Ok(socket),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
match self {
|
||||
Self::Char(dev) => dev.is_terminal(),
|
||||
Self::PtySlave(_) | Self::PtyMaster(_) => true,
|
||||
match &self.inner {
|
||||
FileInner::Char(dev) => dev.is_terminal(),
|
||||
FileInner::PtySlave(_) | FileInner::PtyMaster(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -394,17 +411,17 @@ impl File {
|
||||
|
||||
impl PageProvider for File {
|
||||
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
|
||||
match self {
|
||||
Self::Block(f) => f.device.get_page(offset),
|
||||
Self::SharedMemory(f) => f.get_page(offset),
|
||||
match &self.inner {
|
||||
FileInner::Block(f) => f.device.get_page(offset),
|
||||
FileInner::SharedMemory(f) => f.get_page(offset),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
|
||||
match self {
|
||||
Self::Block(f) => f.device.release_page(offset, phys),
|
||||
Self::SharedMemory(f) => f.release_page(offset, phys),
|
||||
match &self.inner {
|
||||
FileInner::Block(f) => f.device.release_page(offset, phys),
|
||||
FileInner::SharedMemory(f) => f.release_page(offset, phys),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
@ -421,57 +438,55 @@ impl PageProvider for File {
|
||||
|
||||
impl Read for File {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Regular(file) => file.read(buf),
|
||||
Self::Block(file) => file.read(buf),
|
||||
Self::Char(file) => file.read(buf),
|
||||
Self::AnonymousPipe(pipe, nonblocking) => {
|
||||
pipe.read(buf, nonblocking.load(Ordering::Acquire))
|
||||
let non_blocking = self.options.read().non_blocking;
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => file.read(buf),
|
||||
FileInner::Block(file) => file.read(buf),
|
||||
FileInner::Char(file) => file.read(buf, non_blocking),
|
||||
FileInner::AnonymousPipe(pipe) => pipe.read(buf, non_blocking),
|
||||
FileInner::PtySlave(half) => half.read(buf, non_blocking),
|
||||
FileInner::PtyMaster(half) => half.read(buf, non_blocking),
|
||||
FileInner::Timer(timer) => timer.read(buf, non_blocking),
|
||||
FileInner::Pid(pid) => pid.read(buf, non_blocking),
|
||||
// TODO allow reads from sockets
|
||||
FileInner::Socket(socket) => {
|
||||
let (len, _) = socket.receive_from(buf, non_blocking)?;
|
||||
Ok(len)
|
||||
}
|
||||
Self::PtySlave(half) => half.read(buf),
|
||||
Self::PtyMaster(half) => half.read(buf),
|
||||
Self::Timer(timer) => timer.read(buf),
|
||||
Self::Pid(pid) => pid.read(buf),
|
||||
// TODO maybe allow reading FDs from poll channels as if they were regular streams?
|
||||
Self::Poll(_) => Err(Error::InvalidOperation),
|
||||
// TODO maybe allow reading messages from Channels?
|
||||
Self::Channel(_) => Err(Error::InvalidOperation),
|
||||
Self::SharedMemory(_) => Err(Error::InvalidOperation),
|
||||
// TODO maybe allow reading messages from Packet/Stream sockets?
|
||||
Self::Socket(_) => Err(Error::InvalidOperation),
|
||||
Self::Directory(_) => Err(Error::IsADirectory),
|
||||
FileInner::Directory(_)
|
||||
| FileInner::Poll(_)
|
||||
| FileInner::SharedMemory(_)
|
||||
| FileInner::Channel(_) => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for File {
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Regular(file) => file.write(buf),
|
||||
Self::Block(file) => file.write(buf),
|
||||
Self::Char(file) => file.write(buf),
|
||||
Self::AnonymousPipe(pipe, _) => pipe.write(buf),
|
||||
Self::PtySlave(half) => half.write(buf),
|
||||
Self::PtyMaster(half) => half.write(buf),
|
||||
Self::Timer(timer) => timer.write(buf),
|
||||
// TODO allow sending signals via writes to PID FDs?
|
||||
Self::Pid(_) => Err(Error::InvalidOperation),
|
||||
// TODO maybe allow adding FDs to poll channels this way
|
||||
Self::Poll(_) => Err(Error::InvalidOperation),
|
||||
// TODO maybe allow writing messages to Channels?
|
||||
Self::Channel(_) => Err(Error::InvalidOperation),
|
||||
Self::SharedMemory(_) => Err(Error::InvalidOperation),
|
||||
// TODO maybe allow writing messages to Packet/Stream sockets?
|
||||
Self::Socket(_) => Err(Error::InvalidOperation),
|
||||
Self::Directory(_) => Err(Error::IsADirectory),
|
||||
let non_blocking = self.options.read().non_blocking;
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => file.write(buf),
|
||||
FileInner::Block(file) => file.write(buf),
|
||||
FileInner::Char(file) => file.write(buf, non_blocking),
|
||||
FileInner::AnonymousPipe(pipe) => pipe.write(buf),
|
||||
FileInner::PtySlave(half) => half.write(buf),
|
||||
FileInner::PtyMaster(half) => half.write(buf),
|
||||
FileInner::Timer(timer) => timer.write(buf),
|
||||
FileInner::Socket(socket) => socket.send_to(buf, None, non_blocking),
|
||||
FileInner::Pid(_)
|
||||
| FileInner::Poll(_)
|
||||
| FileInner::SharedMemory(_)
|
||||
| FileInner::Directory(_)
|
||||
| FileInner::Channel(_) => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadAt for File {
|
||||
fn read_at(&self, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Regular(file) => file.read_at(pos, buf),
|
||||
// let non_blocking = self.options.read().non_blocking;
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => file.read_at(pos, buf),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -479,8 +494,9 @@ impl ReadAt for File {
|
||||
|
||||
impl WriteAt for File {
|
||||
fn write_at(&self, pos: u64, buf: &[u8]) -> Result<usize, Error> {
|
||||
match self {
|
||||
Self::Regular(file) => file.write_at(pos, buf),
|
||||
// let non_blocking = self.options.read().non_blocking;
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => file.write_at(pos, buf),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -488,10 +504,10 @@ impl WriteAt for File {
|
||||
|
||||
impl Seek for File {
|
||||
fn tell(&self) -> Result<u64, Error> {
|
||||
match self {
|
||||
Self::Regular(file) => Ok(*file.position.lock()),
|
||||
Self::Block(file) => Ok(*file.position.lock()),
|
||||
Self::Directory(_) => Err(Error::IsADirectory),
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => Ok(*file.position.lock()),
|
||||
FileInner::Block(file) => Ok(*file.position.lock()),
|
||||
FileInner::Directory(_) => Err(Error::IsADirectory),
|
||||
_ => Ok(0),
|
||||
}
|
||||
}
|
||||
@ -501,10 +517,10 @@ impl Seek for File {
|
||||
return self.tell();
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Regular(file) => file.seek(from),
|
||||
Self::Block(file) => file.seek(from),
|
||||
Self::Directory(_) => Err(Error::IsADirectory),
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => file.seek(from),
|
||||
FileInner::Block(file) => file.seek(from),
|
||||
FileInner::Directory(_) => Err(Error::IsADirectory),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
@ -512,44 +528,58 @@ impl Seek for File {
|
||||
|
||||
impl fmt::Debug for File {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Regular(file) => f
|
||||
match &self.inner {
|
||||
FileInner::Regular(file) => f
|
||||
.debug_struct("RegularFile")
|
||||
.field("position", &*file.position.lock())
|
||||
.field("read", &file.read)
|
||||
.field("write", &file.write)
|
||||
.finish_non_exhaustive(),
|
||||
Self::Block(file) => f
|
||||
FileInner::Block(file) => f
|
||||
.debug_struct("BlockFile")
|
||||
.field("position", &*file.position.lock())
|
||||
.field("read", &file.read)
|
||||
.field("write", &file.write)
|
||||
.finish_non_exhaustive(),
|
||||
Self::Char(file) => f
|
||||
FileInner::Char(file) => f
|
||||
.debug_struct("CharFile")
|
||||
.field("read", &file.read)
|
||||
.field("write", &file.write)
|
||||
.finish_non_exhaustive(),
|
||||
Self::Directory(_) => f.debug_struct("DirectoryFile").finish_non_exhaustive(),
|
||||
Self::AnonymousPipe(_, _) => f.debug_struct("AnonymousPipe").finish_non_exhaustive(),
|
||||
Self::Poll(_) => f.debug_struct("Poll").finish_non_exhaustive(),
|
||||
Self::Channel(_) => f.debug_struct("Channel").finish_non_exhaustive(),
|
||||
Self::SharedMemory(_) => f.debug_struct("SharedMemory").finish_non_exhaustive(),
|
||||
Self::PtySlave(_) => f.debug_struct("PtySlave").finish_non_exhaustive(),
|
||||
Self::PtyMaster(_) => f.debug_struct("PtyMaster").finish_non_exhaustive(),
|
||||
Self::Socket(socket) => fmt::Debug::fmt(socket, f),
|
||||
Self::Pid(pid) => fmt::Debug::fmt(pid, f),
|
||||
Self::Timer(_) => f.debug_struct("Timer").finish_non_exhaustive(),
|
||||
FileInner::Directory(_) => f.debug_struct("DirectoryFile").finish_non_exhaustive(),
|
||||
FileInner::AnonymousPipe(_) => f.debug_struct("AnonymousPipe").finish_non_exhaustive(),
|
||||
FileInner::Poll(_) => f.debug_struct("Poll").finish_non_exhaustive(),
|
||||
FileInner::Channel(_) => f.debug_struct("Channel").finish_non_exhaustive(),
|
||||
FileInner::SharedMemory(_) => f.debug_struct("SharedMemory").finish_non_exhaustive(),
|
||||
FileInner::PtySlave(_) => f.debug_struct("PtySlave").finish_non_exhaustive(),
|
||||
FileInner::PtyMaster(_) => f.debug_struct("PtyMaster").finish_non_exhaustive(),
|
||||
FileInner::Socket(socket) => fmt::Debug::fmt(socket, f),
|
||||
FileInner::Pid(pid) => fmt::Debug::fmt(pid, f),
|
||||
FileInner::Timer(_) => f.debug_struct("Timer").finish_non_exhaustive(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FileInner {
|
||||
pub fn send(&self) -> Result<Self, Error> {
|
||||
match self {
|
||||
Self::Char(char) => Ok(Self::Char(char.clone())),
|
||||
Self::Regular(file) => Ok(Self::Regular(file.clone())),
|
||||
Self::SharedMemory(shm) => Ok(Self::SharedMemory(shm.clone())),
|
||||
Self::Pid(pid) => Ok(Self::Pid(pid.clone())),
|
||||
Self::PtySlave(half) => Ok(Self::PtySlave(half.clone())),
|
||||
Self::PtyMaster(half) => Ok(Self::PtyMaster(half.clone())),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TerminalHalf> TerminalHalfWrapper<T> {
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
if self.blocking.load(Ordering::Acquire) {
|
||||
block!(self.half.read(buf).await)?
|
||||
} else {
|
||||
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
|
||||
if non_blocking {
|
||||
self.half.read_nonblocking(buf)
|
||||
} else {
|
||||
block!(self.half.read(buf).await)?
|
||||
}
|
||||
}
|
||||
|
||||
@ -558,16 +588,6 @@ impl<T: TerminalHalf> TerminalHalfWrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TerminalHalf> Clone for TerminalHalfWrapper<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
half: self.half.clone(),
|
||||
node: self.node.clone(),
|
||||
blocking: AtomicBool::new(self.blocking.load(Ordering::Acquire)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FileSet {
|
||||
/// Creates an empty [FileSet]
|
||||
pub fn new() -> Self {
|
||||
|
@ -4,7 +4,6 @@ use core::{
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use libk_util::io::Read;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
process::{ExitCode, ProcessId, ProcessWait, WaitFlags},
|
||||
@ -92,10 +91,8 @@ impl PidFile {
|
||||
}
|
||||
size_of::<u32>() + size_of::<i32>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for PidFile {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read(&self, buf: &mut [u8], _non_blocking: bool) -> Result<usize, Error> {
|
||||
if buf.len() < size_of::<u32>() + size_of::<i32>() {
|
||||
return Err(Error::BufferTooSmall);
|
||||
}
|
||||
@ -106,6 +103,9 @@ impl Read for PidFile {
|
||||
}
|
||||
}
|
||||
|
||||
// impl Read for PidFile {
|
||||
// }
|
||||
|
||||
impl FileReadiness for PidFile {
|
||||
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
match self {
|
||||
|
@ -10,9 +10,10 @@ use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
net::{
|
||||
options::{self, SocketOption, SocketOptionVariant},
|
||||
options::{self, SocketOptionVariant},
|
||||
SocketAddr, SocketShutdown,
|
||||
},
|
||||
option::OptionValue,
|
||||
};
|
||||
|
||||
use crate::vfs::FileReadiness;
|
||||
@ -28,7 +29,6 @@ struct InnerOptions {
|
||||
connect_timeout: Option<Duration>,
|
||||
recv_timeout: Option<Duration>,
|
||||
send_timeout: Option<Duration>,
|
||||
non_blocking: bool,
|
||||
}
|
||||
|
||||
pub struct SocketWrapper {
|
||||
@ -177,8 +177,13 @@ impl SocketWrapper {
|
||||
block!(self.connect_inner(remote).await)?
|
||||
}
|
||||
|
||||
pub fn send_to(&self, data: &[u8], remote: Option<SocketAddr>) -> Result<usize, Error> {
|
||||
if self.options.read().non_blocking {
|
||||
pub fn send_to(
|
||||
&self,
|
||||
data: &[u8],
|
||||
remote: Option<SocketAddr>,
|
||||
non_blocking: bool,
|
||||
) -> Result<usize, Error> {
|
||||
if non_blocking {
|
||||
match &self.inner {
|
||||
SocketInner::Packet(socket) => socket.clone().send_nonblocking(remote, data),
|
||||
SocketInner::Connection(socket) => socket.clone().send_nonblocking(data),
|
||||
@ -188,8 +193,12 @@ impl SocketWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive_from(&self, data: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
|
||||
if self.options.read().non_blocking {
|
||||
pub fn receive_from(
|
||||
&self,
|
||||
data: &mut [u8],
|
||||
non_blocking: bool,
|
||||
) -> Result<(usize, SocketAddr), Error> {
|
||||
if non_blocking {
|
||||
match &self.inner {
|
||||
SocketInner::Packet(socket) => socket.clone().receive_nonblocking(data),
|
||||
SocketInner::Connection(socket) => socket.receive_nonblocking(data),
|
||||
@ -213,12 +222,12 @@ impl SocketWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> Result<(FileRef, SocketAddr), Error> {
|
||||
pub fn accept(&self, non_blocking: bool) -> Result<(FileRef, SocketAddr), Error> {
|
||||
let SocketInner::Connection(socket) = &self.inner else {
|
||||
return Err(Error::InvalidOperation);
|
||||
};
|
||||
|
||||
let (remote, stream) = if self.options.read().non_blocking {
|
||||
let (remote, stream) = if non_blocking {
|
||||
socket.accept_nonblocking()?
|
||||
} else {
|
||||
block!(socket.accept().await)??
|
||||
@ -272,10 +281,6 @@ impl SocketWrapper {
|
||||
options.connect_timeout = options::ConnectTimeout::load(buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
SocketOptionVariant::NonBlocking => {
|
||||
options.non_blocking = options::NonBlocking::load(buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
SocketOptionVariant::LocalAddress | SocketOptionVariant::PeerAddress => {
|
||||
Err(Error::InvalidArgument)
|
||||
}
|
||||
@ -310,9 +315,6 @@ impl SocketWrapper {
|
||||
SocketOptionVariant::ConnectTimeout => {
|
||||
options::ConnectTimeout::store(&options.connect_timeout, buffer)
|
||||
}
|
||||
SocketOptionVariant::NonBlocking => {
|
||||
options::NonBlocking::store(&options.non_blocking, buffer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -360,7 +362,6 @@ impl Default for InnerOptions {
|
||||
connect_timeout: None,
|
||||
recv_timeout: None,
|
||||
send_timeout: None,
|
||||
non_blocking: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use core::{
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use futures_util::FutureExt;
|
||||
use libk_util::{io::Read, sync::LockMethod};
|
||||
use libk_util::sync::LockMethod;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
@ -21,29 +21,23 @@ use crate::{
|
||||
/// File-like structure to generate periodic or one-shit events at certain intervals
|
||||
pub struct TimerFile {
|
||||
inner: Box<Mutex<Option<SleepFuture>>>,
|
||||
blocking: bool,
|
||||
_repeat: bool,
|
||||
}
|
||||
|
||||
impl TimerFile {
|
||||
/// Creates a new inert timer
|
||||
pub fn new(repeat: bool, blocking: bool) -> Self {
|
||||
pub fn new(repeat: bool) -> Self {
|
||||
Self {
|
||||
_repeat: repeat,
|
||||
blocking,
|
||||
inner: Box::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for TimerFile {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
|
||||
if buf.len() < size_of::<u8>() {
|
||||
return Err(Error::BufferTooSmall);
|
||||
}
|
||||
if self.blocking {
|
||||
todo!()
|
||||
} else {
|
||||
if non_blocking {
|
||||
let inner = self.inner.lock()?;
|
||||
if inner.as_ref().and_then(SleepFuture::remaining).is_some() {
|
||||
return Err(Error::WouldBlock);
|
||||
@ -51,6 +45,8 @@ impl Read for TimerFile {
|
||||
|
||||
buf[0] = 1;
|
||||
Ok(1)
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ pub(crate) use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, MountOptions, OpenOptions,
|
||||
PipeOptions, PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions,
|
||||
PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions,
|
||||
UnmountOptions,
|
||||
},
|
||||
mem::{MappingFlags, MappingSource},
|
||||
|
@ -5,8 +5,8 @@ use abi::{
|
||||
io::{
|
||||
AccessMode, ChannelPublisherId, DeviceRequest, DirectoryEntry, FileAttr, FileControl,
|
||||
FileMetadataUpdate, FileMode, FileSync, FilesystemControl, MessageDestination, OpenOptions,
|
||||
PipeOptions, PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom,
|
||||
SentMessage, TerminalOptions, TerminalSize, TimerOptions,
|
||||
PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom, SentMessage,
|
||||
TerminalOptions, TerminalSize, TimerOptions,
|
||||
},
|
||||
process::{ProcessWait, WaitFlags},
|
||||
};
|
||||
@ -131,6 +131,20 @@ pub(crate) fn seek(fd: RawFd, pos: SeekFrom, output: &mut u64) -> Result<(), Err
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_file_option(fd: RawFd, option: u32, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.get_option(option, buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn set_file_option(fd: RawFd, option: u32, buffer: &[u8]) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.set_option(option, buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
@ -368,15 +382,12 @@ pub(crate) fn create_poll_channel() -> Result<RawFd, Error> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_pipe(
|
||||
ends: &mut [MaybeUninit<RawFd>; 2],
|
||||
options: PipeOptions,
|
||||
) -> Result<(), Error> {
|
||||
pub(crate) fn create_pipe(ends: &mut [MaybeUninit<RawFd>; 2]) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let (read, write) = File::new_pipe_pair(256, options);
|
||||
let (read, write) = File::new_pipe_pair(256);
|
||||
|
||||
let read_fd = io.files.place_file(read, true)?;
|
||||
let write_fd = io.files.place_file(write, true)?;
|
||||
|
@ -58,9 +58,10 @@ pub(crate) fn accept(sock_fd: RawFd, remote: &mut MaybeUninit<SocketAddr>) -> Re
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let listener = io.files.file(sock_fd)?;
|
||||
let non_blocking = listener.is_non_blocking();
|
||||
let listener = listener.as_socket()?;
|
||||
|
||||
let (stream_file, stream_remote) = listener.accept()?;
|
||||
let (stream_file, stream_remote) = listener.accept(non_blocking)?;
|
||||
let stream_fd = io.files.place_file(stream_file, true)?;
|
||||
|
||||
remote.write(stream_remote.into());
|
||||
@ -80,7 +81,9 @@ pub(crate) fn send_to(
|
||||
remote: &Option<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let file = get_socket(sock_fd)?;
|
||||
file.as_socket()?.send_to(data, remote.map(Into::into))
|
||||
let non_blocking = file.is_non_blocking();
|
||||
file.as_socket()?
|
||||
.send_to(data, remote.map(Into::into), non_blocking)
|
||||
}
|
||||
|
||||
pub(crate) fn receive_from(
|
||||
@ -89,7 +92,8 @@ pub(crate) fn receive_from(
|
||||
remote: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let file = get_socket(sock_fd)?;
|
||||
let (len, remote_) = file.as_socket()?.receive_from(data)?;
|
||||
let non_blocking = file.is_non_blocking();
|
||||
let (len, remote_) = file.as_socket()?.receive_from(data, non_blocking)?;
|
||||
remote.write(remote_.into());
|
||||
Ok(len)
|
||||
}
|
||||
|
@ -65,13 +65,6 @@ bitfield OpenOptions(u32) {
|
||||
CREATE_EXCL: 5,
|
||||
}
|
||||
|
||||
bitfield PipeOptions(u32) {
|
||||
/// If set, read end of the pipe will return WouldBlock if there's no data in the pipe
|
||||
READ_NONBLOCKING: 0,
|
||||
/// If set, write end of the pipe will return WouldBlock if the pipe is full
|
||||
WRITE_NONBLOCKING: 1,
|
||||
}
|
||||
|
||||
enum FileType(u32) {
|
||||
/// Regular file
|
||||
File = 1,
|
||||
@ -134,7 +127,6 @@ enum PollControl(u32) {
|
||||
|
||||
bitfield TimerOptions(u32) {
|
||||
REPEAT: 0,
|
||||
NON_BLOCKING: 1,
|
||||
}
|
||||
|
||||
// abi::io::terminal
|
||||
|
@ -128,7 +128,7 @@ syscall truncate(fd: RawFd, size: u64) -> Result<()>;
|
||||
syscall fsync(fd: RawFd, what: FileSync) -> Result<()>;
|
||||
syscall read_at(fd: RawFd, pos: u64, data: &mut [u8]) -> Result<usize>;
|
||||
syscall write_at(fd: RawFd, pos: u64, data: &[u8]) -> Result<usize>;
|
||||
syscall get_file_option(fd: RawFd, option: u32, data: &mut [u8]) -> Result<()>;
|
||||
syscall get_file_option(fd: RawFd, option: u32, data: &mut [u8]) -> Result<usize>;
|
||||
syscall set_file_option(fd: RawFd, option: u32, data: &[u8]) -> Result<()>;
|
||||
|
||||
syscall open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd>;
|
||||
@ -151,7 +151,7 @@ syscall create_pid(target: &ProcessWait, flags: WaitFlags) -> Result<RawFd>;
|
||||
syscall create_pty(opts: &TerminalOptions, size: &TerminalSize, fds: &mut [MaybeUninit<RawFd>; 2]) -> Result<()>;
|
||||
syscall create_shared_memory(size: usize) -> Result<RawFd>;
|
||||
syscall create_poll_channel() -> Result<RawFd>;
|
||||
syscall create_pipe(fds: &mut [MaybeUninit<RawFd>; 2], options: PipeOptions) -> Result<()>;
|
||||
syscall create_pipe(fds: &mut [MaybeUninit<RawFd>; 2]) -> Result<()>;
|
||||
|
||||
syscall poll_channel_wait(
|
||||
poll_fd: RawFd,
|
||||
|
@ -1,5 +1,7 @@
|
||||
//! I/O-related definitions
|
||||
|
||||
pub mod options;
|
||||
|
||||
mod channel;
|
||||
mod device;
|
||||
mod file;
|
||||
@ -9,8 +11,7 @@ mod terminal;
|
||||
|
||||
pub use crate::generated::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, FileType, GroupId, MountOptions,
|
||||
OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions,
|
||||
UserId,
|
||||
OpenOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions, UserId,
|
||||
};
|
||||
pub use channel::{ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage};
|
||||
pub use device::{DeviceRequest, Framebuffer};
|
||||
|
12
lib/abi/src/io/options.rs
Normal file
12
lib/abi/src/io/options.rs
Normal file
@ -0,0 +1,12 @@
|
||||
//! File option definitions
|
||||
|
||||
option_group!(
|
||||
#[doc = "Common file options"]
|
||||
pub enum FileOptionVariant<'de> {
|
||||
#[doc = "
|
||||
If `true`, makes certain access operations return an error if no data is available
|
||||
for reading or no buffer space is available for writing.
|
||||
"]
|
||||
0x1000: NonBlocking # 4 (bool),
|
||||
}
|
||||
);
|
@ -44,6 +44,9 @@ pub mod error {
|
||||
|
||||
pub use generated::SyscallFunction;
|
||||
|
||||
#[macro_use]
|
||||
pub mod option;
|
||||
|
||||
pub mod arch;
|
||||
pub mod debug;
|
||||
pub mod io;
|
||||
|
@ -1,72 +1,9 @@
|
||||
//! Socket option definitions
|
||||
use core::{net::SocketAddr, time::Duration};
|
||||
|
||||
use abi_serde::{wire, Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
use super::{MacAddress, SocketInterfaceQuery};
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait SocketOption<'de> {
|
||||
type Value: Deserialize<'de> + Serialize;
|
||||
type Variant: Copy + Into<u32> + TryFrom<u32, Error = Error>;
|
||||
const VARIANT: Self::Variant;
|
||||
|
||||
fn store(value: &Self::Value, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
Ok(wire::to_slice(value, buffer)?)
|
||||
}
|
||||
|
||||
fn load(buffer: &'de [u8]) -> Result<Self::Value, Error> {
|
||||
Ok(wire::from_slice(buffer)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub trait SocketOptionSizeHint {
|
||||
const SIZE_HINT: usize;
|
||||
}
|
||||
|
||||
macro_rules! socket_option_group {
|
||||
(
|
||||
$(#[$enum_meta:meta])*
|
||||
$vis:vis enum $variant_ty:ident<$lifetime:lifetime> {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$discriminant:literal: $variant:ident $(# $size_hint:literal)? ($value:ty)
|
||||
),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$crate::primitive_enum! {
|
||||
$(#[$enum_meta])*
|
||||
$vis enum $variant_ty: u32 {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$variant = $discriminant
|
||||
),*
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$vis struct $variant;
|
||||
|
||||
impl<$lifetime> $crate::net::options::SocketOption<$lifetime> for $variant {
|
||||
type Variant = $variant_ty;
|
||||
type Value = $value;
|
||||
const VARIANT: Self::Variant = $variant_ty::$variant;
|
||||
}
|
||||
|
||||
$(
|
||||
impl $crate::net::options::SocketOptionSizeHint for $variant {
|
||||
const SIZE_HINT: usize = $size_hint;
|
||||
}
|
||||
)?
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
socket_option_group!(
|
||||
option_group!(
|
||||
#[doc = "Common socket options"]
|
||||
pub enum SocketOptionVariant<'de> {
|
||||
#[doc = "(Read-only) Local address of the socket"]
|
||||
@ -79,15 +16,10 @@ socket_option_group!(
|
||||
0x1003: SendTimeout # 32 (Option<Duration>),
|
||||
#[doc = "If not [None], connect operations time out after a certain amount"]
|
||||
0x1004: ConnectTimeout # 32 (Option<Duration>),
|
||||
#[doc = "
|
||||
If `true`, receive/accept/send operations return an error if no
|
||||
data/buffer space is immediately available.
|
||||
"]
|
||||
0x1005: NonBlocking # 4 (bool),
|
||||
}
|
||||
);
|
||||
|
||||
socket_option_group!(
|
||||
option_group!(
|
||||
#[doc = "UDP socket protocol-level options"]
|
||||
pub enum UdpSocketOptionVariant<'de> {
|
||||
#[doc = "UDP unicast packet Time-to-Live"]
|
||||
@ -103,7 +35,7 @@ socket_option_group!(
|
||||
}
|
||||
);
|
||||
|
||||
socket_option_group!(
|
||||
option_group!(
|
||||
#[doc = "TCP socket protocol-level options"]
|
||||
pub enum TcpSocketOptionVariant<'de> {
|
||||
#[doc = "If `true`, disables the Nagle's algorithm (which is not yet implemented)"]
|
||||
@ -113,7 +45,7 @@ socket_option_group!(
|
||||
}
|
||||
);
|
||||
|
||||
socket_option_group!(
|
||||
option_group!(
|
||||
#[doc = "Raw socket options"]
|
||||
pub enum RawSocketOptionVariant<'de> {
|
||||
#[doc = "
|
||||
|
63
lib/abi/src/option.rs
Normal file
63
lib/abi/src/option.rs
Normal file
@ -0,0 +1,63 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use abi_serde::{wire, Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
pub trait OptionValue<'de> {
|
||||
type Value: Deserialize<'de> + Serialize;
|
||||
type Variant: Copy + Into<u32> + TryFrom<u32, Error = Error>;
|
||||
const VARIANT: Self::Variant;
|
||||
|
||||
fn store(value: &Self::Value, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
Ok(wire::to_slice(value, buffer)?)
|
||||
}
|
||||
|
||||
fn load(buffer: &'de [u8]) -> Result<Self::Value, Error> {
|
||||
Ok(wire::from_slice(buffer)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OptionSizeHint {
|
||||
const SIZE_HINT: usize;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! option_group {
|
||||
(
|
||||
$(#[$enum_meta:meta])*
|
||||
$vis:vis enum $variant_ty:ident<$lifetime:lifetime> {
|
||||
$(
|
||||
$(#[$variant_meta:meta])*
|
||||
$discriminant:literal: $variant:ident $(# $size_hint:literal)? ($value:ty)
|
||||
),* $(,)?
|
||||
}
|
||||
) => {
|
||||
$crate::primitive_enum! {
|
||||
$(#[$enum_meta])*
|
||||
$vis enum $variant_ty: u32 {
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$variant = $discriminant
|
||||
),*
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
$(#[$variant_meta])*
|
||||
$vis struct $variant;
|
||||
|
||||
impl<$lifetime> $crate::option::OptionValue<$lifetime> for $variant {
|
||||
type Variant = $variant_ty;
|
||||
type Value = $value;
|
||||
const VARIANT: Self::Variant = $variant_ty::$variant;
|
||||
}
|
||||
|
||||
$(
|
||||
impl $crate::option::OptionSizeHint for $variant {
|
||||
const SIZE_HINT: usize = $size_hint;
|
||||
}
|
||||
)?
|
||||
)*
|
||||
};
|
||||
}
|
@ -21,16 +21,19 @@ pub mod poll {
|
||||
pub use abi::io::PollControl;
|
||||
}
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
pub use abi::io::{
|
||||
AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode,
|
||||
FileSync, FileTimesUpdate, FileType, OpenOptions, PipeOptions, RawFd, RemoveFlags, Rename,
|
||||
options, AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode,
|
||||
FileMode, FileSync, FileTimesUpdate, FileType, OpenOptions, RawFd, RemoveFlags, Rename,
|
||||
SeekFrom, TimerOptions,
|
||||
};
|
||||
pub use abi::option::OptionSizeHint;
|
||||
|
||||
pub mod paths;
|
||||
pub use paths::*;
|
||||
|
||||
use abi::error::Error;
|
||||
use abi::{error::Error, option::OptionValue};
|
||||
|
||||
use device::DeviceRequest;
|
||||
|
||||
@ -51,3 +54,73 @@ pub fn remove_directory(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
pub fn remove_directory_recursive(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn configure_pipe(
|
||||
read: RawFd,
|
||||
write: RawFd,
|
||||
read_nonblocking: bool,
|
||||
write_nonblocking: bool,
|
||||
) -> Result<(), Error> {
|
||||
if read_nonblocking {
|
||||
set_file_option::<options::NonBlocking>(read, &true)?;
|
||||
}
|
||||
if write_nonblocking {
|
||||
set_file_option::<options::NonBlocking>(write, &true)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_pipe_pair(
|
||||
read_nonblocking: bool,
|
||||
write_nonblocking: bool,
|
||||
) -> Result<(RawFd, RawFd), Error> {
|
||||
let mut fds = MaybeUninit::uninit_array();
|
||||
unsafe { crate::sys::create_pipe(&mut fds) }?;
|
||||
let fds = unsafe { MaybeUninit::array_assume_init(fds) };
|
||||
let read = fds[0];
|
||||
let write = fds[1];
|
||||
|
||||
match configure_pipe(read, write, read_nonblocking, write_nonblocking) {
|
||||
Ok(()) => Ok((read, write)),
|
||||
Err(error) => {
|
||||
unsafe {
|
||||
crate::sys::close(read).ok();
|
||||
crate::sys::close(write).ok();
|
||||
}
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub macro get_file_option($fd:expr, $variant_ty:ty) {{
|
||||
let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT];
|
||||
$crate::io::get_file_option::<$variant_ty>($fd, &mut buffer)
|
||||
}}
|
||||
|
||||
pub fn get_file_option<'de, T: OptionValue<'de>>(
|
||||
fd: RawFd,
|
||||
buffer: &'de mut [u8],
|
||||
) -> Result<T::Value, Error> {
|
||||
let len = unsafe { crate::sys::get_file_option(fd, T::VARIANT.into(), buffer) }?;
|
||||
T::load(&buffer[..len])
|
||||
}
|
||||
|
||||
pub fn set_file_option<'de, T: OptionValue<'de> + OptionSizeHint>(
|
||||
fd: RawFd,
|
||||
value: &T::Value,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
[u8; T::SIZE_HINT]: Sized,
|
||||
{
|
||||
let mut buffer = [0; T::SIZE_HINT];
|
||||
set_file_option_with::<T>(fd, &mut buffer, value)
|
||||
}
|
||||
|
||||
pub fn set_file_option_with<'de, T: OptionValue<'de>>(
|
||||
fd: RawFd,
|
||||
buffer: &mut [u8],
|
||||
value: &T::Value,
|
||||
) -> Result<(), Error> {
|
||||
let len = T::store(value, buffer)?;
|
||||
unsafe { crate::sys::set_file_option(fd, T::VARIANT.into(), &buffer[..len]) }
|
||||
}
|
||||
|
@ -6,7 +6,9 @@
|
||||
linkage,
|
||||
naked_functions,
|
||||
thread_local,
|
||||
generic_const_exprs
|
||||
generic_const_exprs,
|
||||
maybe_uninit_uninit_array,
|
||||
maybe_uninit_array_assume_init
|
||||
)]
|
||||
#![no_std]
|
||||
#![warn(missing_docs)]
|
||||
|
@ -4,44 +4,41 @@ use core::{net::SocketAddr, time::Duration};
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::RawFd,
|
||||
net::{
|
||||
options::{self, SocketOption, SocketOptionSizeHint},
|
||||
SocketInterfaceQuery, SocketType,
|
||||
},
|
||||
net::{options, SocketInterfaceQuery, SocketType},
|
||||
option::{OptionSizeHint, OptionValue},
|
||||
};
|
||||
use abi_serde::wire;
|
||||
|
||||
/// Short-hand macro for [get_socket_option].
|
||||
///
|
||||
/// Automatically sets up the `buffer` argument for socket options which implement
|
||||
/// [SocketOptionSizeHint].
|
||||
pub macro get_socket_option($fd:expr, $variant_ty:ty) {{
|
||||
let mut buffer = [0; <$variant_ty as $crate::net::options::SocketOptionSizeHint>::SIZE_HINT];
|
||||
let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT];
|
||||
$crate::net::get_socket_option::<$variant_ty>($fd, &mut buffer)
|
||||
}}
|
||||
|
||||
/// Retrieves the value of a socket's option
|
||||
pub fn get_socket_option<'de, T: SocketOption<'de>>(
|
||||
pub fn get_socket_option<'de, T: OptionValue<'de>>(
|
||||
fd: RawFd,
|
||||
buffer: &'de mut [u8],
|
||||
) -> Result<T::Value, Error> {
|
||||
let len = unsafe { crate::sys::get_socket_option(fd, T::VARIANT.into(), buffer) }?;
|
||||
Ok(wire::from_slice(&buffer[..len])?)
|
||||
T::load(&buffer[..len])
|
||||
}
|
||||
|
||||
/// Sets the value of a socket's option, using the buffer provided to marshall the payload
|
||||
pub fn set_socket_option_with<'de, T: SocketOption<'de>>(
|
||||
pub fn set_socket_option_with<'de, T: OptionValue<'de>>(
|
||||
fd: RawFd,
|
||||
buffer: &mut [u8],
|
||||
value: &T::Value,
|
||||
) -> Result<(), Error> {
|
||||
let len = wire::to_slice(value, buffer)?;
|
||||
let len = T::store(value, buffer)?;
|
||||
unsafe { crate::sys::set_socket_option(fd, T::VARIANT.into(), &buffer[..len]) }
|
||||
}
|
||||
|
||||
/// Sets the value of a socket's option, using a buffer set up automatically based on
|
||||
/// [SocketOptionSizeHint]. See [set_socket_option_with].
|
||||
pub fn set_socket_option<'de, T: SocketOption<'de> + SocketOptionSizeHint>(
|
||||
pub fn set_socket_option<'de, T: OptionValue<'de> + OptionSizeHint>(
|
||||
fd: RawFd,
|
||||
value: &T::Value,
|
||||
) -> Result<(), Error>
|
||||
|
@ -17,8 +17,8 @@ mod generated {
|
||||
error::Error,
|
||||
io::{
|
||||
AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMode, FileSync,
|
||||
MountOptions, OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags,
|
||||
TerminalOptions, TerminalSize, TimerOptions, UnmountOptions,
|
||||
MountOptions, OpenOptions, PollControl, RawFd, RemoveFlags, TerminalOptions,
|
||||
TerminalSize, TimerOptions, UnmountOptions,
|
||||
},
|
||||
mem::{MappingFlags, MappingSource},
|
||||
net::{SocketShutdown, SocketType},
|
||||
|
Loading…
x
Reference in New Issue
Block a user