refactor: split syscall handlers into modules
This commit is contained in:
parent
c9a344966b
commit
992f66b5a0
@ -64,7 +64,7 @@ fn generate_syscall_dispatcher<A: AsRef<Path>, P: AsRef<Path>>(abi_path: A, out_
|
||||
|
||||
let generated_dispatcher = out_dir.as_ref().join("generated_dispatcher.rs");
|
||||
let file = prettyplease::unparse(
|
||||
&abi.emit_syscall_dispatcher("handle_syscall", "impls")
|
||||
&abi.emit_syscall_dispatcher("handle_syscall", "imp")
|
||||
.expect("Could not generate syscall dispatcher"),
|
||||
);
|
||||
|
||||
|
@ -306,7 +306,6 @@ impl PseudoTerminal {
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
match req {
|
||||
DeviceRequest::SetTerminalGroup(group_id) => {
|
||||
log::info!("SetTerminalGroup {}", group_id);
|
||||
self.master_to_slave
|
||||
.signal_pgroup
|
||||
.write()
|
||||
|
81
kernel/src/syscall/imp/mod.rs
Normal file
81
kernel/src/syscall/imp/mod.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use abi::process::{ExecveOptions, ProcessId};
|
||||
pub(crate) use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DirectoryEntry, FileAttr, FileMode, MountOptions, OpenOptions, PollControl, RawFd,
|
||||
TerminalOptions, TerminalSize, UnmountOptions,
|
||||
},
|
||||
mem::MappingSource,
|
||||
net::SocketType,
|
||||
process::{Signal, SignalEntryData, SpawnOptions},
|
||||
system::SystemInfo,
|
||||
};
|
||||
use libk::task::thread::Thread;
|
||||
use libk_mm::phys;
|
||||
|
||||
use crate::{debug::LogLevel, fs, proc::random};
|
||||
|
||||
use super::run_with_io;
|
||||
|
||||
pub(super) mod sys_io;
|
||||
pub(super) mod sys_net;
|
||||
pub(super) mod sys_process;
|
||||
|
||||
pub(super) use sys_io::*;
|
||||
pub(super) use sys_net::*;
|
||||
pub(super) use sys_process::*;
|
||||
|
||||
// Misc
|
||||
pub(crate) fn debug_trace(message: &str) {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
log_print_raw!(
|
||||
LogLevel::Debug,
|
||||
"[{}:{}] TRACE: {}\n",
|
||||
process.id,
|
||||
thread.id,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn get_random(buffer: &mut [u8]) {
|
||||
random::read(buffer);
|
||||
}
|
||||
|
||||
pub(crate) fn mount(options: &MountOptions<'_>) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let fs_root = fs::create_filesystem(options)?;
|
||||
io.ioctx_mut().mount(options.target, fs_root)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn unmount(_options: &UnmountOptions) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn get_system_info(element: &mut SystemInfo) -> Result<(), Error> {
|
||||
match element {
|
||||
SystemInfo::MemoryStats(stats) => {
|
||||
*stats = phys::stats();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handled outside
|
||||
pub(crate) fn exit_signal(_frame: &SignalEntryData) -> ! {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn fork() -> Result<ProcessId, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn execve(_options: &ExecveOptions<'_>) -> Result<(), Error> {
|
||||
unreachable!()
|
||||
}
|
394
kernel/src/syscall/imp/sys_io.rs
Normal file
394
kernel/src/syscall/imp/sys_io.rs
Normal file
@ -0,0 +1,394 @@
|
||||
use core::{mem::MaybeUninit, time::Duration};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
ChannelPublisherId, DeviceRequest, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMode,
|
||||
MessageDestination, OpenOptions, PollControl, RawFd, ReceivedMessageMetadata, SeekFrom,
|
||||
SentMessage, TerminalOptions, TerminalSize,
|
||||
},
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use libk::{
|
||||
block,
|
||||
task::thread::Thread,
|
||||
vfs::{self, File, MessagePayload, Read, Seek, Write},
|
||||
};
|
||||
|
||||
use crate::syscall::{run_with_io, run_with_io_at};
|
||||
|
||||
// I/O
|
||||
pub(crate) fn open(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
opts: OpenOptions,
|
||||
mode: FileMode,
|
||||
) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let file = io.ioctx_mut().open(Some(at), path, opts, mode)?;
|
||||
|
||||
// TODO NO_CTTY?
|
||||
if process.session_terminal().is_none()
|
||||
&& let Some(node) = file.node()
|
||||
&& node.is_terminal()
|
||||
{
|
||||
debugln!("Session terminal set for #{}: {}", process.id, path);
|
||||
process.set_session_terminal(node.clone());
|
||||
}
|
||||
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn close(fd: RawFd) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let res = io.files.close_file(fd);
|
||||
|
||||
if res == Err(Error::InvalidFile) {
|
||||
warnln!("Double close of fd {:?} in process {}", fd, process.id);
|
||||
}
|
||||
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn write(fd: RawFd, buffer: &[u8]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.write(buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn read(fd: RawFd, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.read(buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn seek(fd: RawFd, pos: SeekFrom) -> Result<u64, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.seek(pos))
|
||||
}
|
||||
|
||||
pub(crate) fn open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let node = io.ioctx_mut().find(Some(at), path, true, true)?;
|
||||
let access = io.ioctx_mut().check_access(vfs::Action::Read, &node)?;
|
||||
let file = node.open_directory(access)?;
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn read_directory_entries(
|
||||
fd: RawFd,
|
||||
entries: &mut [MaybeUninit<DirectoryEntry>],
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.read_dir(entries))
|
||||
}
|
||||
|
||||
pub(crate) fn create_directory(at: Option<RawFd>, path: &str, mode: FileMode) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
io.ioctx_mut().create_directory(Some(at), path, mode)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn remove_directory(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn remove(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
io.ioctx_mut().remove_file(Some(at), path)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn clone_fd(source_fd: RawFd, target_fd: Option<RawFd>) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(source_fd)?.clone();
|
||||
|
||||
let fd = match target_fd {
|
||||
Some(target_fd) => {
|
||||
io.files.set_file(target_fd, file)?;
|
||||
target_fd
|
||||
}
|
||||
None => io.files.place_file(file, true)?,
|
||||
};
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update_metadata(
|
||||
at: Option<RawFd>,
|
||||
_path: &str,
|
||||
_update: &FileMetadataUpdate,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |_at, _io| {
|
||||
todo!();
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_metadata(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
buffer: &mut MaybeUninit<FileAttr>,
|
||||
follow: bool,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let node = if path.is_empty() {
|
||||
at
|
||||
// at.ok_or(Error::InvalidArgument)?
|
||||
} else {
|
||||
io.ioctx_mut().find(Some(at), path, follow, true)?
|
||||
};
|
||||
|
||||
let metadata = node.metadata()?;
|
||||
let size = node.size()?;
|
||||
|
||||
buffer.write(FileAttr {
|
||||
size,
|
||||
ty: node.ty(),
|
||||
mode: metadata.mode,
|
||||
uid: metadata.uid,
|
||||
gid: metadata.gid,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn device_request(fd: RawFd, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.device_request(req))
|
||||
}
|
||||
|
||||
// Misc I/O
|
||||
pub(crate) fn open_channel(name: &str, subscribe: bool) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_message_channel(name, subscribe);
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_timer(repeat: bool) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_timer(repeat);
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_pty(
|
||||
options: &TerminalOptions,
|
||||
size: &TerminalSize,
|
||||
output: &mut [MaybeUninit<RawFd>; 2],
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let (master, slave) = File::new_pseudo_terminal(*options, *size)?;
|
||||
let master_fd = io.files.place_file(master, true)?;
|
||||
let slave_fd = io.files.place_file(slave, true)?;
|
||||
|
||||
output[0].write(master_fd);
|
||||
output[1].write(slave_fd);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_shared_memory(size: usize) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_shared_memory(size)?;
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_poll_channel() -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let poll = File::new_poll_channel();
|
||||
let fd = io.files.place_file(poll, true)?;
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let read_fd = io.files.place_file(read, true)?;
|
||||
let write_fd = io.files.place_file(write, true)?;
|
||||
|
||||
ends[0].write(read_fd);
|
||||
ends[1].write(write_fd);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn poll_channel_wait(
|
||||
poll_fd: RawFd,
|
||||
timeout: &Option<Duration>,
|
||||
output: &mut Option<(RawFd, Result<(), Error>)>,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let poll_file = io.files.file(poll_fd)?;
|
||||
let poll = poll_file.as_poll_channel()?;
|
||||
|
||||
*output = block! {
|
||||
poll.wait(*timeout).await
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn poll_channel_control(
|
||||
poll_fd: RawFd,
|
||||
control: PollControl,
|
||||
fd: RawFd,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let poll_file = io.files.file(poll_fd)?;
|
||||
let poll = poll_file.as_poll_channel()?;
|
||||
|
||||
match control {
|
||||
PollControl::AddFd => {
|
||||
let polled_file = io.files.file(fd)?.clone();
|
||||
poll.add(fd, polled_file);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn send_message(
|
||||
fd: RawFd,
|
||||
message: &SentMessage<'_>,
|
||||
destination: MessageDestination,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(fd)?;
|
||||
let channel = file.as_message_channel()?;
|
||||
|
||||
match message {
|
||||
&SentMessage::File(fd) => {
|
||||
let sent_file = io.files.file(fd)?;
|
||||
|
||||
channel.send_message(MessagePayload::File(sent_file.clone()), destination)?;
|
||||
}
|
||||
&SentMessage::Data(data) => {
|
||||
channel.send_message(MessagePayload::Data(Box::from(data)), destination)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn receive_message(
|
||||
fd: RawFd,
|
||||
metadata: &mut MaybeUninit<ReceivedMessageMetadata>,
|
||||
buf: &mut [u8],
|
||||
from: &mut MaybeUninit<ChannelPublisherId>,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(fd)?;
|
||||
let channel = file.as_message_channel()?;
|
||||
|
||||
let message = channel.receive_message()?;
|
||||
|
||||
from.write(message.source);
|
||||
|
||||
match &message.payload {
|
||||
MessagePayload::Data(data) => {
|
||||
// TODO allow truncated messages?
|
||||
let len = data.len();
|
||||
if buf.len() < len {
|
||||
return Err(Error::MissingData);
|
||||
}
|
||||
|
||||
metadata.write(ReceivedMessageMetadata::Data(len));
|
||||
buf[..len].copy_from_slice(data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
MessagePayload::File(file) => {
|
||||
let fd = io.files.place_file(file.clone(), true)?;
|
||||
|
||||
metadata.write(ReceivedMessageMetadata::File(fd));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
127
kernel/src/syscall/imp/sys_net.rs
Normal file
127
kernel/src/syscall/imp/sys_net.rs
Normal file
@ -0,0 +1,127 @@
|
||||
use core::{mem::MaybeUninit, net::SocketAddr};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::RawFd,
|
||||
net::{SocketOption, SocketType},
|
||||
};
|
||||
use libk::{task::thread::Thread, vfs::File};
|
||||
use ygg_driver_net_core::socket::{RawSocket, TcpListener, TcpSocket, UdpSocket};
|
||||
|
||||
use crate::syscall::run_with_io;
|
||||
|
||||
// Network
|
||||
pub(crate) fn connect_socket(
|
||||
socket_fd: Option<RawFd>,
|
||||
remote: &SocketAddr,
|
||||
ty: SocketType,
|
||||
local_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<RawFd, Error> {
|
||||
assert!(socket_fd.is_none());
|
||||
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let (local, file) = match ty {
|
||||
SocketType::TcpStream => {
|
||||
let (local, socket) = TcpSocket::connect((*remote).into())?;
|
||||
(local, File::from_stream_socket(socket))
|
||||
}
|
||||
_ => return Err(Error::InvalidArgument),
|
||||
};
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
local_result.write(local.into());
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn bind_socket(listen: &SocketAddr, ty: SocketType) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = match ty {
|
||||
SocketType::UdpPacket => File::from_packet_socket(UdpSocket::bind((*listen).into())?),
|
||||
SocketType::RawPacket => File::from_packet_socket(RawSocket::bind()?),
|
||||
SocketType::TcpStream => {
|
||||
File::from_listener_socket(TcpListener::bind((*listen).into())?)
|
||||
}
|
||||
};
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn accept(
|
||||
socket_fd: RawFd,
|
||||
remote_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let mut remote = MaybeUninit::uninit();
|
||||
let accepted_file = file.accept(&mut remote)?;
|
||||
let accepted_fd = io.files.place_file(accepted_file, true)?;
|
||||
unsafe {
|
||||
remote_result.write(remote.assume_init().into());
|
||||
}
|
||||
Ok(accepted_fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn send_to(
|
||||
socket_fd: RawFd,
|
||||
buffer: &[u8],
|
||||
recepient: &Option<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
|
||||
file.send_to(buffer, recepient.map(Into::into))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn receive_from(
|
||||
socket_fd: RawFd,
|
||||
buffer: &mut [u8],
|
||||
remote_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let mut remote = MaybeUninit::uninit();
|
||||
let len = file.receive_from(buffer, &mut remote)?;
|
||||
remote_result.write(unsafe { remote.assume_init() }.into());
|
||||
Ok(len)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_socket_option(socket_fd: RawFd, option: &SocketOption) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let socket = file.as_socket()?;
|
||||
socket.set_option(option)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_socket_option(socket_fd: RawFd, option: &mut SocketOption) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let socket = file.as_socket()?;
|
||||
socket.get_option(option)
|
||||
})
|
||||
}
|
223
kernel/src/syscall/imp/sys_process.rs
Normal file
223
kernel/src/syscall/imp/sys_process.rs
Normal file
@ -0,0 +1,223 @@
|
||||
use core::{num::NonZeroUsize, sync::atomic::AtomicU32, time::Duration};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::DeviceRequest,
|
||||
mem::MappingSource,
|
||||
process::{
|
||||
ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnOption, SpawnOptions,
|
||||
},
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use libk::{
|
||||
block,
|
||||
task::{process::Process, runtime, thread::Thread},
|
||||
vfs::IoContext,
|
||||
};
|
||||
use libk_mm::{
|
||||
process::VirtualRangeBacking,
|
||||
table::{EntryLevelExt, MapAttributes},
|
||||
};
|
||||
|
||||
use crate::{arch::L3, proc, syscall::run_with_io};
|
||||
|
||||
// Memory management
|
||||
pub(crate) fn map_memory(
|
||||
_hint: Option<NonZeroUsize>,
|
||||
len: usize,
|
||||
source: &MappingSource,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let space = thread.address_space();
|
||||
|
||||
let len = len.page_align_up::<L3>();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let backing = match source {
|
||||
MappingSource::Anonymous => VirtualRangeBacking::anonymous(),
|
||||
&MappingSource::File(fd, offset) => {
|
||||
let file = io.files.file(fd)?;
|
||||
VirtualRangeBacking::file(offset, file.clone())?
|
||||
}
|
||||
};
|
||||
|
||||
space.allocate(
|
||||
None,
|
||||
len,
|
||||
backing,
|
||||
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn unmap_memory(address: usize, len: usize) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let space = thread.address_space();
|
||||
|
||||
if len & 0xFFF != 0 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
space.unmap(address, len)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Process/thread management
|
||||
pub(crate) fn create_process_group() -> ProcessGroupId {
|
||||
Process::create_group()
|
||||
}
|
||||
|
||||
pub(crate) fn get_process_group_id() -> ProcessGroupId {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
process.group_id()
|
||||
}
|
||||
|
||||
pub(crate) fn exit_process(code: ExitCode) -> ! {
|
||||
let thread = Thread::current();
|
||||
thread.exit_process(code)
|
||||
}
|
||||
|
||||
pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
// Setup a new process from the file
|
||||
let (child_process, child_main) = proc::load_binary(
|
||||
io.ioctx_mut(),
|
||||
process.group_id(),
|
||||
Some(Arc::downgrade(&process)),
|
||||
options.program,
|
||||
options.arguments,
|
||||
options.environment,
|
||||
)?;
|
||||
let pid = child_process.id;
|
||||
|
||||
// Inherit group and session from the creator
|
||||
child_process.inherit(&process)?;
|
||||
|
||||
// Inherit root from the creator
|
||||
// let child_ioctx = IoContext::new(io.ioctx().root().clone());
|
||||
let child_ioctx = IoContext::inherit(io.ioctx_mut());
|
||||
let mut child_io = child_process.io.lock();
|
||||
child_io.set_ioctx(child_ioctx);
|
||||
|
||||
for opt in options.optional {
|
||||
match opt {
|
||||
&SpawnOption::InheritFile { source, child } => {
|
||||
if let Ok(src_file) = io.files.file(source) {
|
||||
child_io.files.set_file(child, src_file.clone())?;
|
||||
}
|
||||
}
|
||||
&SpawnOption::SetProcessGroup(pgroup) => {
|
||||
let pgroup = if pgroup.into_raw() == 0 {
|
||||
todo!()
|
||||
} else {
|
||||
pgroup
|
||||
};
|
||||
child_process.set_group_id(pgroup);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fd) = options.optional.iter().find_map(|item| {
|
||||
if let &SpawnOption::GainTerminal(fd) = item {
|
||||
Some(fd)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
debugln!("{} requested terminal {:?}", pid, fd);
|
||||
let file = child_io.files.file(fd)?;
|
||||
// let node = file.node().ok_or(Error::InvalidFile)?;
|
||||
let mut req = DeviceRequest::SetTerminalGroup(child_process.group_id());
|
||||
file.device_request(&mut req)?;
|
||||
|
||||
if let Some(node) = file.node() {
|
||||
child_process.set_session_terminal(node.clone());
|
||||
}
|
||||
// node.device_request(&mut req)?;
|
||||
}
|
||||
|
||||
drop(child_io);
|
||||
child_main.enqueue();
|
||||
|
||||
Ok(pid as _)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<(), Error> {
|
||||
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
|
||||
*status = block!(target.wait_for_exit().await)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_pid() -> ProcessId {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
process.id
|
||||
}
|
||||
|
||||
pub(crate) fn nanosleep(duration: &Duration) -> Result<(), Error> {
|
||||
block! {
|
||||
runtime::sleep(*duration).await
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_signal_entry(ip: usize, sp: usize) {
|
||||
let thread = Thread::current();
|
||||
thread.set_signal_entry(ip, sp);
|
||||
}
|
||||
|
||||
pub(crate) fn send_signal(pid: ProcessId, signal: Signal) -> Result<(), Error> {
|
||||
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
|
||||
target.raise_signal(signal);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let mutex = process.get_or_insert_mutex((mutex as *const AtomicU32).addr());
|
||||
|
||||
match op {
|
||||
&MutexOperation::Wait(value, _timeout) => block! { mutex.wait(value).await }.unwrap(),
|
||||
MutexOperation::Wake => mutex.wake(),
|
||||
MutexOperation::WakeAll => mutex.wake_all(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn start_session() -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let session_terminal = process.clear_session_terminal();
|
||||
|
||||
if let Some(ctty) = session_terminal {
|
||||
// Drop all FDs referring to the old session terminal
|
||||
run_with_io(&process, |mut io| {
|
||||
io.files.retain(|_, f| {
|
||||
f.node()
|
||||
.map(|node| !Arc::ptr_eq(node, &ctty))
|
||||
.unwrap_or(true)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let group_id = Process::create_group();
|
||||
|
||||
process.set_session_id(process.id);
|
||||
process.set_group_id(group_id);
|
||||
|
||||
Ok(())
|
||||
}
|
@ -8,6 +8,7 @@ use libk::{
|
||||
use libk_util::sync::IrqSafeSpinlockGuard;
|
||||
|
||||
mod arg;
|
||||
mod imp;
|
||||
|
||||
fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(proc: &Process, f: F) -> T {
|
||||
let io = proc.io.lock();
|
||||
@ -33,812 +34,6 @@ fn run_with_io_at<T, F: FnOnce(NodeRef, IrqSafeSpinlockGuard<ProcessIo>) -> Resu
|
||||
f(at, io)
|
||||
}
|
||||
|
||||
mod impls {
|
||||
pub(crate) use abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DeviceRequest, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMode,
|
||||
MessageDestination, MountOptions, OpenOptions, PollControl, RawFd,
|
||||
ReceivedMessageMetadata, SeekFrom, SentMessage, TerminalOptions, TerminalSize,
|
||||
UnmountOptions,
|
||||
},
|
||||
mem::MappingSource,
|
||||
net::{SocketOption, SocketType},
|
||||
process::{ExitCode, MutexOperation, Signal, SignalEntryData, SpawnOptions},
|
||||
system::SystemInfo,
|
||||
};
|
||||
use abi::{
|
||||
io::ChannelPublisherId,
|
||||
process::{ExecveOptions, ProcessGroupId, ProcessId, SpawnOption},
|
||||
};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use libk::{
|
||||
block,
|
||||
task::{process::Process, runtime, thread::Thread},
|
||||
vfs::{self, File, IoContext, MessagePayload, Read, Seek, Write},
|
||||
};
|
||||
use ygg_driver_net_core::socket::{RawSocket, TcpListener, TcpSocket, UdpSocket};
|
||||
|
||||
use core::{
|
||||
mem::MaybeUninit, net::SocketAddr, num::NonZeroUsize, sync::atomic::AtomicU32,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use libk_mm::{
|
||||
phys,
|
||||
process::VirtualRangeBacking,
|
||||
table::{EntryLevelExt, MapAttributes},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::L3,
|
||||
debug::LogLevel,
|
||||
fs,
|
||||
proc::{self, random},
|
||||
};
|
||||
|
||||
use super::{run_with_io, run_with_io_at};
|
||||
|
||||
// Misc
|
||||
pub(crate) fn debug_trace(message: &str) {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
log_print_raw!(
|
||||
LogLevel::Debug,
|
||||
"[{}:{}] TRACE: {}\n",
|
||||
process.id,
|
||||
thread.id,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn get_random(buffer: &mut [u8]) {
|
||||
random::read(buffer);
|
||||
}
|
||||
|
||||
pub(crate) fn mount(options: &MountOptions<'_>) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let fs_root = fs::create_filesystem(options)?;
|
||||
io.ioctx_mut().mount(options.target, fs_root)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn unmount(_options: &UnmountOptions) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// Memory management
|
||||
pub(crate) fn map_memory(
|
||||
_hint: Option<NonZeroUsize>,
|
||||
len: usize,
|
||||
source: &MappingSource,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let space = thread.address_space();
|
||||
|
||||
let len = len.page_align_up::<L3>();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let backing = match source {
|
||||
MappingSource::Anonymous => VirtualRangeBacking::anonymous(),
|
||||
&MappingSource::File(fd, offset) => {
|
||||
let file = io.files.file(fd)?;
|
||||
VirtualRangeBacking::file(offset, file.clone())?
|
||||
}
|
||||
};
|
||||
|
||||
space.allocate(
|
||||
None,
|
||||
len,
|
||||
backing,
|
||||
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn unmap_memory(address: usize, len: usize) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let space = thread.address_space();
|
||||
|
||||
if len & 0xFFF != 0 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
space.unmap(address, len)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_system_info(element: &mut SystemInfo) -> Result<(), Error> {
|
||||
match element {
|
||||
SystemInfo::MemoryStats(stats) => {
|
||||
*stats = phys::stats();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process/thread management
|
||||
pub(crate) fn create_process_group() -> ProcessGroupId {
|
||||
let id = Process::create_group();
|
||||
log::info!("CREATED PROCESS GROUP {}", id);
|
||||
id
|
||||
}
|
||||
|
||||
pub(crate) fn get_process_group_id() -> ProcessGroupId {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
process.group_id()
|
||||
}
|
||||
|
||||
pub(crate) fn exit_process(code: ExitCode) -> ! {
|
||||
let thread = Thread::current();
|
||||
thread.exit_process(code)
|
||||
}
|
||||
|
||||
pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
// Setup a new process from the file
|
||||
let (child_process, child_main) = proc::load_binary(
|
||||
io.ioctx_mut(),
|
||||
process.group_id(),
|
||||
Some(Arc::downgrade(&process)),
|
||||
options.program,
|
||||
options.arguments,
|
||||
options.environment,
|
||||
)?;
|
||||
let pid = child_process.id;
|
||||
|
||||
// Inherit group and session from the creator
|
||||
child_process.inherit(&process)?;
|
||||
|
||||
// Inherit root from the creator
|
||||
// let child_ioctx = IoContext::new(io.ioctx().root().clone());
|
||||
let child_ioctx = IoContext::inherit(io.ioctx_mut());
|
||||
let mut child_io = child_process.io.lock();
|
||||
child_io.set_ioctx(child_ioctx);
|
||||
|
||||
for opt in options.optional {
|
||||
match opt {
|
||||
&SpawnOption::InheritFile { source, child } => {
|
||||
if let Ok(src_file) = io.files.file(source) {
|
||||
child_io.files.set_file(child, src_file.clone())?;
|
||||
}
|
||||
}
|
||||
&SpawnOption::SetProcessGroup(pgroup) => {
|
||||
let pgroup = if pgroup.into_raw() == 0 {
|
||||
todo!()
|
||||
} else {
|
||||
pgroup
|
||||
};
|
||||
child_process.set_group_id(pgroup);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fd) = options.optional.iter().find_map(|item| {
|
||||
if let &SpawnOption::GainTerminal(fd) = item {
|
||||
Some(fd)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
debugln!("{} requested terminal {:?}", pid, fd);
|
||||
let file = child_io.files.file(fd)?;
|
||||
// let node = file.node().ok_or(Error::InvalidFile)?;
|
||||
let mut req = DeviceRequest::SetTerminalGroup(child_process.group_id());
|
||||
file.device_request(&mut req)?;
|
||||
|
||||
if let Some(node) = file.node() {
|
||||
child_process.set_session_terminal(node.clone());
|
||||
}
|
||||
// node.device_request(&mut req)?;
|
||||
}
|
||||
|
||||
drop(child_io);
|
||||
child_main.enqueue();
|
||||
|
||||
Ok(pid as _)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<(), Error> {
|
||||
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
|
||||
*status = block!(target.wait_for_exit().await)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_pid() -> ProcessId {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
process.id
|
||||
}
|
||||
|
||||
pub(crate) fn nanosleep(duration: &Duration) -> Result<(), Error> {
|
||||
block! {
|
||||
runtime::sleep(*duration).await
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_signal_entry(ip: usize, sp: usize) {
|
||||
let thread = Thread::current();
|
||||
thread.set_signal_entry(ip, sp);
|
||||
}
|
||||
|
||||
pub(crate) fn send_signal(pid: ProcessId, signal: Signal) -> Result<(), Error> {
|
||||
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
|
||||
target.raise_signal(signal);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let mutex = process.get_or_insert_mutex((mutex as *const AtomicU32).addr());
|
||||
|
||||
match op {
|
||||
&MutexOperation::Wait(value, _timeout) => block! { mutex.wait(value).await }.unwrap(),
|
||||
MutexOperation::Wake => mutex.wake(),
|
||||
MutexOperation::WakeAll => mutex.wake_all(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn start_session() -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
let session_terminal = process.clear_session_terminal();
|
||||
|
||||
if let Some(ctty) = session_terminal {
|
||||
// Drop all FDs referring to the old session terminal
|
||||
run_with_io(&process, |mut io| {
|
||||
io.files.retain(|_, f| {
|
||||
f.node()
|
||||
.map(|node| !Arc::ptr_eq(node, &ctty))
|
||||
.unwrap_or(true)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let group_id = Process::create_group();
|
||||
|
||||
process.set_session_id(process.id);
|
||||
process.set_group_id(group_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// I/O
|
||||
pub(crate) fn open(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
opts: OpenOptions,
|
||||
mode: FileMode,
|
||||
) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let file = io.ioctx_mut().open(Some(at), path, opts, mode)?;
|
||||
|
||||
// TODO NO_CTTY?
|
||||
if process.session_terminal().is_none()
|
||||
&& let Some(node) = file.node()
|
||||
&& node.is_terminal()
|
||||
{
|
||||
debugln!("Session terminal set for #{}: {}", process.id, path);
|
||||
process.set_session_terminal(node.clone());
|
||||
}
|
||||
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn close(fd: RawFd) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let res = io.files.close_file(fd);
|
||||
|
||||
if res == Err(Error::InvalidFile) {
|
||||
warnln!("Double close of fd {:?} in process {}", fd, process.id);
|
||||
}
|
||||
|
||||
res
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn write(fd: RawFd, buffer: &[u8]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.write(buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn read(fd: RawFd, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.read(buffer))
|
||||
}
|
||||
|
||||
pub(crate) fn seek(fd: RawFd, pos: SeekFrom) -> Result<u64, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.seek(pos))
|
||||
}
|
||||
|
||||
pub(crate) fn open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let node = io.ioctx_mut().find(Some(at), path, true, true)?;
|
||||
let access = io.ioctx_mut().check_access(vfs::Action::Read, &node)?;
|
||||
let file = node.open_directory(access)?;
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn read_directory_entries(
|
||||
fd: RawFd,
|
||||
entries: &mut [MaybeUninit<DirectoryEntry>],
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.read_dir(entries))
|
||||
}
|
||||
|
||||
pub(crate) fn create_directory(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
mode: FileMode,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
io.ioctx_mut().create_directory(Some(at), path, mode)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn remove_directory(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) fn remove(at: Option<RawFd>, path: &str) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
io.ioctx_mut().remove_file(Some(at), path)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn clone_fd(source_fd: RawFd, target_fd: Option<RawFd>) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(source_fd)?.clone();
|
||||
|
||||
let fd = match target_fd {
|
||||
Some(target_fd) => {
|
||||
io.files.set_file(target_fd, file)?;
|
||||
target_fd
|
||||
}
|
||||
None => io.files.place_file(file, true)?,
|
||||
};
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update_metadata(
|
||||
at: Option<RawFd>,
|
||||
_path: &str,
|
||||
_update: &FileMetadataUpdate,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |_at, _io| {
|
||||
todo!();
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_metadata(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
buffer: &mut MaybeUninit<FileAttr>,
|
||||
follow: bool,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io_at(&process, at, |at, mut io| {
|
||||
let node = if path.is_empty() {
|
||||
at
|
||||
// at.ok_or(Error::InvalidArgument)?
|
||||
} else {
|
||||
io.ioctx_mut().find(Some(at), path, follow, true)?
|
||||
};
|
||||
|
||||
let metadata = node.metadata()?;
|
||||
let size = node.size()?;
|
||||
|
||||
buffer.write(FileAttr {
|
||||
size,
|
||||
ty: node.ty(),
|
||||
mode: metadata.mode,
|
||||
uid: metadata.uid,
|
||||
gid: metadata.gid,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn device_request(fd: RawFd, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| io.files.file(fd)?.device_request(req))
|
||||
}
|
||||
|
||||
// Misc I/O
|
||||
pub(crate) fn open_channel(name: &str, subscribe: bool) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_message_channel(name, subscribe);
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_timer(repeat: bool) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_timer(repeat);
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_pty(
|
||||
options: &TerminalOptions,
|
||||
size: &TerminalSize,
|
||||
output: &mut [MaybeUninit<RawFd>; 2],
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let (master, slave) = File::new_pseudo_terminal(*options, *size)?;
|
||||
let master_fd = io.files.place_file(master, true)?;
|
||||
let slave_fd = io.files.place_file(slave, true)?;
|
||||
|
||||
output[0].write(master_fd);
|
||||
output[1].write(slave_fd);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_shared_memory(size: usize) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = File::new_shared_memory(size)?;
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_poll_channel() -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let poll = File::new_poll_channel();
|
||||
let fd = io.files.place_file(poll, true)?;
|
||||
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let read_fd = io.files.place_file(read, true)?;
|
||||
let write_fd = io.files.place_file(write, true)?;
|
||||
|
||||
ends[0].write(read_fd);
|
||||
ends[1].write(write_fd);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn poll_channel_wait(
|
||||
poll_fd: RawFd,
|
||||
timeout: &Option<Duration>,
|
||||
output: &mut Option<(RawFd, Result<(), Error>)>,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let poll_file = io.files.file(poll_fd)?;
|
||||
let poll = poll_file.as_poll_channel()?;
|
||||
|
||||
*output = block! {
|
||||
poll.wait(*timeout).await
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn poll_channel_control(
|
||||
poll_fd: RawFd,
|
||||
control: PollControl,
|
||||
fd: RawFd,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let poll_file = io.files.file(poll_fd)?;
|
||||
let poll = poll_file.as_poll_channel()?;
|
||||
|
||||
match control {
|
||||
PollControl::AddFd => {
|
||||
let polled_file = io.files.file(fd)?.clone();
|
||||
poll.add(fd, polled_file);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn send_message(
|
||||
fd: RawFd,
|
||||
message: &SentMessage<'_>,
|
||||
destination: MessageDestination,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(fd)?;
|
||||
let channel = file.as_message_channel()?;
|
||||
|
||||
match message {
|
||||
&SentMessage::File(fd) => {
|
||||
let sent_file = io.files.file(fd)?;
|
||||
|
||||
channel.send_message(MessagePayload::File(sent_file.clone()), destination)?;
|
||||
}
|
||||
&SentMessage::Data(data) => {
|
||||
channel.send_message(MessagePayload::Data(Box::from(data)), destination)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn receive_message(
|
||||
fd: RawFd,
|
||||
metadata: &mut MaybeUninit<ReceivedMessageMetadata>,
|
||||
buf: &mut [u8],
|
||||
from: &mut MaybeUninit<ChannelPublisherId>,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(fd)?;
|
||||
let channel = file.as_message_channel()?;
|
||||
|
||||
let message = channel.receive_message()?;
|
||||
|
||||
from.write(message.source);
|
||||
|
||||
match &message.payload {
|
||||
MessagePayload::Data(data) => {
|
||||
// TODO allow truncated messages?
|
||||
let len = data.len();
|
||||
if buf.len() < len {
|
||||
return Err(Error::MissingData);
|
||||
}
|
||||
|
||||
metadata.write(ReceivedMessageMetadata::Data(len));
|
||||
buf[..len].copy_from_slice(data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
MessagePayload::File(file) => {
|
||||
let fd = io.files.place_file(file.clone(), true)?;
|
||||
|
||||
metadata.write(ReceivedMessageMetadata::File(fd));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Network
|
||||
pub(crate) fn connect_socket(
|
||||
socket_fd: Option<RawFd>,
|
||||
remote: &SocketAddr,
|
||||
ty: SocketType,
|
||||
local_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<RawFd, Error> {
|
||||
assert!(socket_fd.is_none());
|
||||
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let (local, file) = match ty {
|
||||
SocketType::TcpStream => {
|
||||
let (local, socket) = TcpSocket::connect((*remote).into())?;
|
||||
(local, File::from_stream_socket(socket))
|
||||
}
|
||||
_ => return Err(Error::InvalidArgument),
|
||||
};
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
local_result.write(local.into());
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn bind_socket(listen: &SocketAddr, ty: SocketType) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = match ty {
|
||||
SocketType::UdpPacket => {
|
||||
File::from_packet_socket(UdpSocket::bind((*listen).into())?)
|
||||
}
|
||||
SocketType::RawPacket => File::from_packet_socket(RawSocket::bind()?),
|
||||
SocketType::TcpStream => {
|
||||
File::from_listener_socket(TcpListener::bind((*listen).into())?)
|
||||
}
|
||||
};
|
||||
let fd = io.files.place_file(file, true)?;
|
||||
Ok(fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn accept(
|
||||
socket_fd: RawFd,
|
||||
remote_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<RawFd, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |mut io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let mut remote = MaybeUninit::uninit();
|
||||
let accepted_file = file.accept(&mut remote)?;
|
||||
let accepted_fd = io.files.place_file(accepted_file, true)?;
|
||||
unsafe {
|
||||
remote_result.write(remote.assume_init().into());
|
||||
}
|
||||
Ok(accepted_fd)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn send_to(
|
||||
socket_fd: RawFd,
|
||||
buffer: &[u8],
|
||||
recepient: &Option<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
|
||||
file.send_to(buffer, recepient.map(Into::into))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn receive_from(
|
||||
socket_fd: RawFd,
|
||||
buffer: &mut [u8],
|
||||
remote_result: &mut MaybeUninit<SocketAddr>,
|
||||
) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let mut remote = MaybeUninit::uninit();
|
||||
let len = file.receive_from(buffer, &mut remote)?;
|
||||
remote_result.write(unsafe { remote.assume_init() }.into());
|
||||
Ok(len)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_socket_option(socket_fd: RawFd, option: &SocketOption) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let socket = file.as_socket()?;
|
||||
socket.set_option(option)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_socket_option(
|
||||
socket_fd: RawFd,
|
||||
option: &mut SocketOption,
|
||||
) -> Result<(), Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
||||
run_with_io(&process, |io| {
|
||||
let file = io.files.file(socket_fd)?;
|
||||
let socket = file.as_socket()?;
|
||||
socket.get_option(option)
|
||||
})
|
||||
}
|
||||
|
||||
// Handled outside
|
||||
pub(crate) fn exit_signal(_frame: &SignalEntryData) -> ! {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn fork() -> Result<ProcessId, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn execve(_options: &ExecveOptions<'_>) -> Result<(), Error> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
mod generated {
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
@ -851,7 +46,7 @@ mod generated {
|
||||
|
||||
use super::{
|
||||
arg,
|
||||
impls::{self, *},
|
||||
imp::{self, *},
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_dispatcher.rs"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user