WIP: proc: fork()/execve() implementation for c compat
This commit is contained in:
parent
0e8860c719
commit
e7a6243cb3
@ -186,11 +186,18 @@ impl File {
|
||||
}
|
||||
|
||||
/// Clones an open file for sending it to another process
|
||||
pub fn send(&self) -> Result<Arc<Self>, Error> {
|
||||
match self {
|
||||
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()))),
|
||||
_ => Err(Error::InvalidOperation),
|
||||
Self::PtySlave(pt) => Ok(Arc::new(Self::PtySlave(pt.clone()))),
|
||||
Self::PtyMaster(pt) => Ok(Arc::new(Self::PtyMaster(pt.clone()))),
|
||||
_ => {
|
||||
log::info!("Invalid file send(): {:?}", self);
|
||||
Err(Error::InvalidOperation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,6 +423,11 @@ impl FileSet {
|
||||
self.map.retain(predicate);
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&RawFd, &FileRef)> {
|
||||
self.map.iter()
|
||||
}
|
||||
|
||||
/// Closes all of the files
|
||||
pub fn close_all(&mut self) {
|
||||
self.map.clear();
|
||||
|
@ -40,13 +40,14 @@ pub struct PseudoTerminal {
|
||||
slave_to_master: PtyHalf,
|
||||
master_to_slave: PtyHalf,
|
||||
size: IrqSafeRwLock<TerminalSize>,
|
||||
eof: AtomicBool,
|
||||
}
|
||||
/// Slave part of a PTY device
|
||||
#[derive(Clone)]
|
||||
pub struct PseudoTerminalSlave {
|
||||
pty: Arc<PseudoTerminal>,
|
||||
}
|
||||
/// Master part of a PTY device
|
||||
#[derive(Clone)]
|
||||
pub struct PseudoTerminalMaster {
|
||||
pty: Arc<PseudoTerminal>,
|
||||
}
|
||||
@ -54,21 +55,23 @@ pub struct PseudoTerminalMaster {
|
||||
fn input_discipline(
|
||||
mut lock: IrqSafeSpinlockGuard<RingBuffer<u8, CAPACITY>>,
|
||||
config: &TerminalOptions,
|
||||
eof: &AtomicBool,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
let mut pos = 0;
|
||||
|
||||
if !config.is_canonical() {
|
||||
while !eof.load(Ordering::Acquire) && pos < buffer.len() && lock.is_readable() {
|
||||
while pos < buffer.len() && lock.is_readable() {
|
||||
buffer[pos] = unsafe { lock.read_single_unchecked() };
|
||||
pos += 1;
|
||||
}
|
||||
Ok(pos)
|
||||
} else {
|
||||
while !eof.load(Ordering::Acquire) && pos < buffer.len() && lock.is_readable() {
|
||||
while pos < buffer.len() && lock.is_readable() {
|
||||
let ch = unsafe { lock.read_single_unchecked() };
|
||||
|
||||
if ch == config.chars.eof {
|
||||
break;
|
||||
}
|
||||
if ch == config.chars.erase {
|
||||
pos = pos.saturating_sub(1);
|
||||
continue;
|
||||
@ -112,32 +115,25 @@ impl PtyHalf {
|
||||
}
|
||||
}
|
||||
|
||||
fn read(
|
||||
&self,
|
||||
config: &TerminalOptions,
|
||||
eof: &AtomicBool,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
if buffer.is_empty() || eof.load(Ordering::Acquire) {
|
||||
fn read(&self, config: &TerminalOptions, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
if buffer.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if let Some(lock) = self.try_begin_read(config) {
|
||||
input_discipline(lock, config, eof, buffer)
|
||||
input_discipline(lock, config, buffer)
|
||||
} else {
|
||||
block!(self.read_async(config, eof, buffer).await)?
|
||||
block!(self.read_async(config, buffer).await)?
|
||||
}
|
||||
}
|
||||
|
||||
fn read_async<'a>(
|
||||
&'a self,
|
||||
config: &'a TerminalOptions,
|
||||
eof: &'a AtomicBool,
|
||||
buffer: &'a mut [u8],
|
||||
) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||
struct F<'f> {
|
||||
config: &'f TerminalOptions,
|
||||
eof: &'f AtomicBool,
|
||||
half: &'f PtyHalf,
|
||||
buffer: &'f mut [u8],
|
||||
}
|
||||
@ -148,12 +144,9 @@ impl PtyHalf {
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.half.notify.register(cx.waker());
|
||||
|
||||
if self.eof.load(Ordering::Acquire) {
|
||||
if let Some(lock) = self.half.try_begin_read(self.config) {
|
||||
self.half.notify.remove(cx.waker());
|
||||
Poll::Ready(Ok(0))
|
||||
} else if let Some(lock) = self.half.try_begin_read(self.config) {
|
||||
self.half.notify.remove(cx.waker());
|
||||
Poll::Ready(input_discipline(lock, self.config, self.eof, self.buffer))
|
||||
Poll::Ready(input_discipline(lock, self.config, self.buffer))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
@ -162,21 +155,15 @@ impl PtyHalf {
|
||||
|
||||
F {
|
||||
half: self,
|
||||
eof,
|
||||
buffer,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_read(
|
||||
&self,
|
||||
config: &TerminalOptions,
|
||||
eof: &AtomicBool,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Result<(), Error>> {
|
||||
fn poll_read(&self, config: &TerminalOptions, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
self.notify.register(cx.waker());
|
||||
|
||||
if eof.load(Ordering::Acquire) || self.try_begin_read(config).is_some() {
|
||||
if self.try_begin_read(config).is_some() {
|
||||
self.notify.remove(cx.waker());
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
@ -184,15 +171,15 @@ impl PtyHalf {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_raw(&self, eof: &AtomicBool, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
if buffer.is_empty() || eof.load(Ordering::Acquire) {
|
||||
fn read_raw(&self, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
if buffer.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let mut lock = self.ring.lock();
|
||||
if lock.is_readable() {
|
||||
let mut pos = 0;
|
||||
while !eof.load(Ordering::Acquire) && lock.is_readable() {
|
||||
while lock.is_readable() {
|
||||
buffer[pos] = unsafe { lock.read_single_unchecked() };
|
||||
pos += 1;
|
||||
}
|
||||
@ -203,10 +190,10 @@ impl PtyHalf {
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_raw(&self, eof: &AtomicBool, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
fn poll_raw(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
self.notify.register(cx.waker());
|
||||
|
||||
if eof.load(Ordering::Acquire) || self.ring.lock().is_readable() {
|
||||
if self.ring.lock().is_readable() {
|
||||
self.notify.remove(cx.waker());
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
@ -234,7 +221,6 @@ impl PseudoTerminal {
|
||||
master_to_slave: PtyHalf::new(),
|
||||
slave_to_master: PtyHalf::new(),
|
||||
size: IrqSafeRwLock::new(size),
|
||||
eof: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
let master = PseudoTerminalMaster { pty: pty.clone() };
|
||||
@ -288,10 +274,7 @@ impl PseudoTerminal {
|
||||
}
|
||||
|
||||
if byte == config.chars.eof {
|
||||
self.slave_to_master.notify.wake_all();
|
||||
self.master_to_slave.notify.wake_all();
|
||||
self.eof.store(true, Ordering::Release);
|
||||
|
||||
self.master_to_slave.putc(byte, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -316,21 +299,21 @@ impl PseudoTerminal {
|
||||
}
|
||||
|
||||
fn read_from_slave(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
self.slave_to_master.read_raw(&self.eof, buf)
|
||||
self.slave_to_master.read_raw(buf)
|
||||
}
|
||||
|
||||
fn read_from_master(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let config = self.config.read();
|
||||
self.master_to_slave.read(&config, &self.eof, buf)
|
||||
self.master_to_slave.read(&config, buf)
|
||||
}
|
||||
|
||||
fn poll_from_slave(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
self.slave_to_master.poll_raw(&self.eof, cx)
|
||||
self.slave_to_master.poll_raw(cx)
|
||||
}
|
||||
|
||||
fn poll_from_master(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||
let config = self.config.read();
|
||||
self.master_to_slave.poll_read(&config, &self.eof, cx)
|
||||
self.master_to_slave.poll_read(&config, cx)
|
||||
}
|
||||
|
||||
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
@ -402,16 +385,14 @@ impl PseudoTerminalMaster {
|
||||
|
||||
impl Drop for PseudoTerminalMaster {
|
||||
fn drop(&mut self) {
|
||||
self.pty.eof.store(true, Ordering::Release);
|
||||
self.pty.master_to_slave.notify.wake_all();
|
||||
self.pty.slave_to_master.notify.wake_all();
|
||||
self.pty
|
||||
.master_to_slave
|
||||
.putc(self.pty.config.read().chars.eof, true);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PseudoTerminalSlave {
|
||||
fn drop(&mut self) {
|
||||
self.pty.eof.store(true, Ordering::Release);
|
||||
self.pty.master_to_slave.notify.wake_all();
|
||||
self.pty.slave_to_master.notify.wake_all();
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,14 @@ type PfnIndex = u64;
|
||||
|
||||
/// Metadata associated with an allocated memory region. The [Eq] trait is used to coalesce "equal"
|
||||
/// regions if they "touch".
|
||||
pub trait RangeData: Eq {}
|
||||
pub trait RangeData: Eq + Clone {}
|
||||
|
||||
fn ie(from: PfnIndex, to: PfnIndex) -> InclusiveInterval<PfnIndex> {
|
||||
InclusiveInterval::from(from..to)
|
||||
}
|
||||
|
||||
/// Main virtual memory allocator
|
||||
#[derive(Clone)]
|
||||
pub struct VirtualMemoryAllocator<D: RangeData> {
|
||||
map: DiscreteRangeMap<PfnIndex, InclusiveInterval<PfnIndex>, D>,
|
||||
outer_range: InclusiveInterval<PfnIndex>,
|
||||
@ -41,6 +42,14 @@ impl<D: RangeData> VirtualMemoryAllocator<D> {
|
||||
}
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn regions(&self) -> impl Iterator<Item = (Range<usize>, &D)> {
|
||||
self.map.iter().map(|(range, data)| {
|
||||
let range = range.start() as usize..range.end() as usize + 1;
|
||||
(range, data)
|
||||
})
|
||||
}
|
||||
|
||||
/// Allocates a contiguous range of virtual address space and associates metadata with it
|
||||
pub fn allocate(&mut self, page_count: usize, data: D) -> Result<usize, Error> {
|
||||
let start_pfn = self
|
||||
@ -80,10 +89,7 @@ impl<D: RangeData> VirtualMemoryAllocator<D> {
|
||||
start_pfn: usize,
|
||||
page_count: usize,
|
||||
mut release: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
D: Clone,
|
||||
{
|
||||
) -> Result<(), Error> {
|
||||
let end_pfn = (start_pfn + page_count) as PfnIndex;
|
||||
let start_pfn = start_pfn as PfnIndex;
|
||||
|
||||
@ -94,4 +100,15 @@ impl<D: RangeData> VirtualMemoryAllocator<D> {
|
||||
release(origin.start() as _, range, data)
|
||||
})
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn clear<F: FnMut(Range<usize>, D) -> Result<(), Error>>(
|
||||
&mut self,
|
||||
mut release: F,
|
||||
) -> Result<(), Error> {
|
||||
self.map.drain().try_for_each(|(range, data)| {
|
||||
let range = range.start() as usize..range.end() as usize + 1;
|
||||
release(range, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -54,11 +54,29 @@
|
||||
|
||||
.global __x86_64_task_enter_user
|
||||
.global __x86_64_task_enter_kernel
|
||||
.global __x86_64_task_enter_from_fork
|
||||
.global __x86_64_enter_task
|
||||
.global __x86_64_switch_task
|
||||
|
||||
.section .text
|
||||
|
||||
__x86_64_task_enter_from_fork:
|
||||
xorq %rax, %rax
|
||||
|
||||
xorq %rcx, %rcx
|
||||
xorq %r11, %r11
|
||||
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %rdx
|
||||
popq %r10
|
||||
popq %r8
|
||||
popq %r9
|
||||
|
||||
swapgs
|
||||
|
||||
iretq
|
||||
|
||||
__x86_64_task_enter_user:
|
||||
// User stack pointer
|
||||
popq %rcx
|
||||
|
@ -2,9 +2,16 @@
|
||||
use core::{arch::global_asm, cell::UnsafeCell};
|
||||
|
||||
use abi::error::Error;
|
||||
use kernel_util::mem::address::{AsPhysicalAddress, IntoRaw};
|
||||
use kernel_util::mem::address::{AsPhysicalAddress, IntoRaw, PhysicalAddress};
|
||||
use tock_registers::interfaces::Readable;
|
||||
|
||||
use crate::{arch::x86_64::mem::KERNEL_TABLES, mem::phys, task::context::TaskContextImpl};
|
||||
use crate::{
|
||||
arch::x86_64::{mem::KERNEL_TABLES, registers::CR3},
|
||||
mem::phys,
|
||||
task::context::TaskContextImpl,
|
||||
};
|
||||
|
||||
use super::syscall::SyscallFrame;
|
||||
|
||||
struct StackBuilder {
|
||||
base: usize,
|
||||
@ -77,6 +84,54 @@ impl StackBuilder {
|
||||
|
||||
unsafe impl Sync for TaskContext {}
|
||||
|
||||
impl TaskContext {
|
||||
/// XXX
|
||||
pub(super) unsafe fn from_syscall_frame(frame: &SyscallFrame, cr3: u64) -> Result<Self, Error> {
|
||||
const USER_TASK_PAGES: usize = 8;
|
||||
|
||||
let stack_base = phys::alloc_pages_contiguous(USER_TASK_PAGES)?.virtualize_raw();
|
||||
|
||||
let mut stack = StackBuilder::new(stack_base, USER_TASK_PAGES * 0x1000);
|
||||
|
||||
// iretq frame
|
||||
stack.push(0x1B);
|
||||
stack.push(frame.user_sp as _);
|
||||
stack.push(0x200);
|
||||
stack.push(0x23);
|
||||
stack.push(frame.user_ip as _);
|
||||
|
||||
stack.push(frame.args[5] as _); // r9
|
||||
stack.push(frame.args[4] as _); // r8
|
||||
stack.push(frame.args[3] as _); // r10
|
||||
stack.push(frame.args[2] as _); // rdx
|
||||
stack.push(frame.args[1] as _); // rsi
|
||||
stack.push(frame.args[0] as _); // rdi
|
||||
|
||||
// callee-saved registers
|
||||
stack.push(__x86_64_task_enter_from_fork as _);
|
||||
|
||||
stack.push(cr3 as _);
|
||||
|
||||
stack.push(frame.rbp as _);
|
||||
stack.push(0x12345678); // XXX TODO: fs_base from SyscallFrame
|
||||
stack.push(frame.r15 as _);
|
||||
stack.push(frame.r14 as _);
|
||||
stack.push(frame.r13 as _);
|
||||
stack.push(frame.r12 as _);
|
||||
stack.push(frame.rbx as _);
|
||||
|
||||
let sp = stack.build();
|
||||
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
|
||||
debugln!("Fork TSS.RSP0 = {:#x}, cr3 = {:#x}", rsp0, cr3);
|
||||
|
||||
Ok(Self {
|
||||
inner: UnsafeCell::new(Inner { sp, tss_rsp0: rsp0 }),
|
||||
stack_base,
|
||||
stack_size: USER_TASK_PAGES * 0x1000,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskContextImpl for TaskContext {
|
||||
const SIGNAL_STACK_EXTRA_ALIGN: usize = 8;
|
||||
const USER_STACK_EXTRA_ALIGN: usize = 8;
|
||||
@ -157,6 +212,7 @@ impl TaskContextImpl for TaskContext {
|
||||
extern "C" {
|
||||
fn __x86_64_task_enter_kernel();
|
||||
fn __x86_64_task_enter_user();
|
||||
fn __x86_64_task_enter_from_fork();
|
||||
fn __x86_64_enter_task(to: *mut Inner) -> !;
|
||||
fn __x86_64_switch_task(to: *mut Inner, from: *mut Inner);
|
||||
}
|
||||
|
@ -2,9 +2,13 @@
|
||||
use core::{arch::global_asm, mem::size_of_val};
|
||||
|
||||
use abi::{arch::SavedFrame, primitive_enum, process::Signal};
|
||||
use tock_registers::interfaces::Readable;
|
||||
|
||||
use crate::{
|
||||
arch::{x86_64::apic, CpuAccess},
|
||||
arch::{
|
||||
x86_64::{apic, registers::CR3},
|
||||
CpuAccess,
|
||||
},
|
||||
task::{context::TaskFrame, thread::Thread, Cpu},
|
||||
};
|
||||
|
||||
@ -285,10 +289,12 @@ static mut IDT: [Entry; SIZE] = [Entry::NULL; SIZE];
|
||||
|
||||
fn user_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) {
|
||||
let thread = Thread::current();
|
||||
let cr3 = CR3.get();
|
||||
|
||||
warnln!("{:?} in {} {:?}", kind, thread.id, thread.name);
|
||||
warnln!("CS:RIP = {:#x}:{:#x}", frame.cs, frame.rip);
|
||||
warnln!("SS:RSP = {:#x}:{:#x}", frame.ss, frame.rsp);
|
||||
warnln!("CR3 = {:#x}", cr3);
|
||||
|
||||
match kind {
|
||||
ExceptionKind::PageFault => {
|
||||
|
@ -2,35 +2,51 @@
|
||||
|
||||
use core::arch::global_asm;
|
||||
|
||||
use abi::{arch::SavedFrame, process::SignalEntryData, syscall::SyscallFunction};
|
||||
use abi::{arch::SavedFrame, error::Error, process::SignalEntryData, syscall::SyscallFunction};
|
||||
use kernel_util::mem::address::PhysicalAddress;
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
|
||||
use crate::{
|
||||
arch::x86_64::registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR},
|
||||
syscall::raw_syscall_handler,
|
||||
task::{context::TaskFrame, thread::Thread},
|
||||
task::{
|
||||
context::{ForkFrame, TaskFrame},
|
||||
process::Process,
|
||||
thread::Thread,
|
||||
TaskContext,
|
||||
},
|
||||
};
|
||||
|
||||
/// Set of registers saved when taking a syscall instruction
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SyscallFrame {
|
||||
rax: u64,
|
||||
args: [u64; 6],
|
||||
pub(super) struct SyscallFrame {
|
||||
pub rax: u64,
|
||||
pub args: [u64; 6],
|
||||
|
||||
rcx: u64,
|
||||
r11: u64,
|
||||
pub rcx: u64,
|
||||
pub r11: u64,
|
||||
|
||||
user_ip: u64,
|
||||
user_sp: u64,
|
||||
user_flags: u64,
|
||||
pub user_ip: u64,
|
||||
pub user_sp: u64,
|
||||
pub user_flags: u64,
|
||||
|
||||
rbx: u64,
|
||||
rbp: u64,
|
||||
r12: u64,
|
||||
r13: u64,
|
||||
r14: u64,
|
||||
r15: u64,
|
||||
pub rbx: u64,
|
||||
pub rbp: u64,
|
||||
pub r12: u64,
|
||||
pub r13: u64,
|
||||
pub r14: u64,
|
||||
pub r15: u64,
|
||||
}
|
||||
|
||||
impl ForkFrame for SyscallFrame {
|
||||
unsafe fn fork(&self, address_space: u64) -> Result<TaskContext, Error> {
|
||||
TaskContext::from_syscall_frame(self, address_space)
|
||||
}
|
||||
|
||||
fn set_return_value(&mut self, value: u64) {
|
||||
self.rax = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskFrame for SyscallFrame {
|
||||
@ -117,6 +133,12 @@ fn syscall_inner(frame: &mut SyscallFrame) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if frame.rax == usize::from(SyscallFunction::Fork) as u64 {
|
||||
unsafe {
|
||||
Process::raw_fork(frame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let result = raw_syscall_handler(frame.rax, &frame.args);
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
||||
exact_size_is_empty,
|
||||
inline_const,
|
||||
maybe_uninit_uninit_array,
|
||||
const_maybe_uninit_uninit_array
|
||||
const_maybe_uninit_uninit_array,
|
||||
never_type
|
||||
)]
|
||||
#![allow(
|
||||
clippy::new_without_default,
|
||||
|
@ -1,15 +1,21 @@
|
||||
//! Process address space structures and management functions
|
||||
|
||||
use core::ops::Range;
|
||||
|
||||
use abi::error::Error;
|
||||
use cfg_if::cfg_if;
|
||||
use kernel_util::{
|
||||
mem::{table::EntryLevelExt, PageProvider},
|
||||
mem::{
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
table::EntryLevelExt,
|
||||
PageProvider,
|
||||
},
|
||||
sync::IrqSafeSpinlock,
|
||||
};
|
||||
use vfs::FileRef;
|
||||
use vmalloc::{RangeData, VirtualMemoryAllocator};
|
||||
|
||||
use crate::{arch::L3, mem::phys};
|
||||
use crate::{arch::L3, debug, mem::phys};
|
||||
|
||||
use super::{table::MapAttributes, PhysicalAddress};
|
||||
|
||||
@ -252,6 +258,70 @@ impl Inner {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn clear(&mut self) -> Result<(), Error> {
|
||||
self.allocator.clear(|pfn_range, backing| {
|
||||
let origin_pfn = pfn_range.start;
|
||||
for pfn in pfn_range {
|
||||
let offset = ((pfn - origin_pfn) * ProcessAddressSpaceImpl::PAGE_SIZE) as u64;
|
||||
|
||||
let virt = pfn * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
let phys = unsafe { self.table.unmap_page(virt)? };
|
||||
|
||||
backing.release_page(offset, phys)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn clone_range(
|
||||
&mut self,
|
||||
source: &Self,
|
||||
pfn_range: Range<usize>,
|
||||
backing: &VirtualRangeBacking,
|
||||
) -> Result<(), Error> {
|
||||
self.allocator
|
||||
.insert(pfn_range.start, pfn_range.len(), backing.clone())
|
||||
.unwrap();
|
||||
|
||||
match backing {
|
||||
VirtualRangeBacking::Anonymous => {
|
||||
let start = pfn_range.start * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
let end = pfn_range.end * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
debugln!("fork: clone_range({:#x?})", start..end);
|
||||
// Clone the data
|
||||
for i in pfn_range {
|
||||
let address = i * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
let (src_page, attrs) = source.table.translate(address).unwrap();
|
||||
let dst_page = clone_page(address, src_page)?;
|
||||
unsafe {
|
||||
self.table
|
||||
.map_page(
|
||||
address,
|
||||
dst_page,
|
||||
MapAttributes::USER_READ
|
||||
| MapAttributes::USER_WRITE
|
||||
| MapAttributes::NON_GLOBAL,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
VirtualRangeBacking::File(f) => {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_page(src_virt: usize, src_phys: PhysicalAddress) -> Result<PhysicalAddress, Error> {
|
||||
let dst_page = phys::alloc_page()?;
|
||||
let src_map = unsafe { PhysicalRef::<[u8; 4096]>::map(src_phys) };
|
||||
let mut dst_map = unsafe { PhysicalRefMut::<[u8; 4096]>::map(dst_page) };
|
||||
dst_map.copy_from_slice(src_map.as_ref());
|
||||
Ok(dst_page)
|
||||
}
|
||||
|
||||
impl ProcessAddressSpace {
|
||||
@ -267,6 +337,37 @@ impl ProcessAddressSpace {
|
||||
})
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn fork(&self) -> Result<Self, Error> {
|
||||
let src_inner = self.inner.lock();
|
||||
let new_table = ProcessAddressSpaceImpl::new()?;
|
||||
let mut new_inner = Inner {
|
||||
allocator: VirtualMemoryAllocator::new(
|
||||
ProcessAddressSpaceImpl::LOWER_LIMIT_PFN,
|
||||
ProcessAddressSpaceImpl::UPPER_LIMIT_PFN,
|
||||
),
|
||||
table: new_table,
|
||||
};
|
||||
|
||||
debugln!("fork address space!");
|
||||
|
||||
for (range, backing) in src_inner.allocator.regions() {
|
||||
// If they are present in existing allocator, there should be no
|
||||
// problem adding them to a new one
|
||||
new_inner.clone_range(&src_inner, range, backing)?;
|
||||
}
|
||||
|
||||
for (range, _) in new_inner.allocator.regions() {
|
||||
let start = range.start * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
let end = range.end * ProcessAddressSpaceImpl::PAGE_SIZE;
|
||||
debugln!("forked region: {:#x?}", start..end);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
inner: IrqSafeSpinlock::new(new_inner),
|
||||
})
|
||||
}
|
||||
|
||||
/// Allocates a region of virtual memory within the address space and maps the pages to the
|
||||
/// ones returned from `get_page` function
|
||||
pub fn allocate(
|
||||
@ -350,4 +451,10 @@ impl ProcessAddressSpace {
|
||||
pub fn as_address_with_asid(&self) -> u64 {
|
||||
self.inner.lock().table.as_address_with_asid()
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn clear(&self) -> Result<(), Error> {
|
||||
let mut inner = self.inner.lock();
|
||||
unsafe { inner.clear() }
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use abi::{
|
||||
path::Path,
|
||||
process::ProgramArgumentInner,
|
||||
};
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
use alloc::{borrow::ToOwned, string::String, sync::Arc, vec::Vec};
|
||||
use kernel_util::mem::pointer::PhysicalRefMut;
|
||||
use vfs::{FileRef, IoContext, Read, Seek};
|
||||
|
||||
@ -86,8 +86,8 @@ unsafe impl<'a> Placer for BufferPlacer<'a> {
|
||||
fn setup_program_env(
|
||||
space: &ProcessAddressSpace,
|
||||
virt: usize,
|
||||
args: &[&str],
|
||||
env: &[&str],
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO growing buffer
|
||||
let phys_page = space.map_single(
|
||||
@ -98,19 +98,24 @@ fn setup_program_env(
|
||||
let mut buffer = unsafe { PhysicalRefMut::map_slice(phys_page, 4096) };
|
||||
let mut placer = BufferPlacer::new(virt, &mut buffer);
|
||||
|
||||
let in_kernel = ProgramArgumentInner { args, env };
|
||||
let args = args.iter().map(String::as_ref).collect::<Vec<_>>();
|
||||
let envs = envs.iter().map(String::as_ref).collect::<Vec<_>>();
|
||||
|
||||
let in_kernel = ProgramArgumentInner {
|
||||
args: &args,
|
||||
env: &envs,
|
||||
};
|
||||
let in_user = in_kernel.place_ref(&mut placer)?;
|
||||
|
||||
Ok(in_user as *const _ as usize)
|
||||
}
|
||||
|
||||
fn setup_binary<S: Into<String>>(
|
||||
name: S,
|
||||
space: ProcessAddressSpace,
|
||||
image: ProcessImage,
|
||||
args: &[&str],
|
||||
envs: &[&str],
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
fn setup_context(
|
||||
space: &ProcessAddressSpace,
|
||||
image: &ProcessImage,
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
) -> Result<TaskContext, Error> {
|
||||
const USER_STACK_PAGES: usize = 16;
|
||||
|
||||
let virt_stack_base = 0x3000000;
|
||||
@ -148,18 +153,25 @@ fn setup_binary<S: Into<String>>(
|
||||
|
||||
let tls_address = proc::elf::clone_tls(&space, &image)?;
|
||||
|
||||
let context = TaskContext::user(
|
||||
TaskContext::user(
|
||||
image.entry,
|
||||
arg,
|
||||
space.as_address_with_asid(),
|
||||
user_sp,
|
||||
tls_address,
|
||||
)?;
|
||||
)
|
||||
}
|
||||
|
||||
fn setup_binary<S: Into<String>>(
|
||||
name: S,
|
||||
space: ProcessAddressSpace,
|
||||
image: ProcessImage,
|
||||
args: &Vec<String>,
|
||||
envs: &Vec<String>,
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
let context = setup_context(&space, &image, args, envs)?;
|
||||
let (process, main) = Process::new_with_main(name, Arc::new(space), context, Some(image));
|
||||
|
||||
infoln!("exec::setup_binary -> {:?}", process.id());
|
||||
|
||||
Ok((process, main))
|
||||
}
|
||||
|
||||
@ -175,13 +187,13 @@ fn load_binary(
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads a program from given `path`
|
||||
pub fn load<P: AsRef<Path>>(
|
||||
fn xxx_load_program<P: AsRef<Path>>(
|
||||
space: &ProcessAddressSpace,
|
||||
ioctx: &mut IoContext,
|
||||
path: P,
|
||||
args: &[&str],
|
||||
envs: &[&str],
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
args: Vec<String>,
|
||||
envs: Vec<String>,
|
||||
) -> Result<(ProcessImage, Vec<String>, Vec<String>), Error> {
|
||||
let mut head = [0; 256];
|
||||
let path = path.as_ref();
|
||||
let file = ioctx.open_exec(None, path)?;
|
||||
@ -196,19 +208,52 @@ pub fn load<P: AsRef<Path>>(
|
||||
&& let Some((shebang, _)) = shebang.split_once(|&ch| ch == b'\n')
|
||||
{
|
||||
let shebang = core::str::from_utf8(shebang).map_err(|_| Error::InvalidFile)?;
|
||||
let mut shebang_args = shebang.split(' ').collect::<Vec<_>>();
|
||||
let mut shebang_args = shebang.split(' ').map(|s| s.to_owned()).collect::<Vec<_>>();
|
||||
if shebang_args.is_empty() || shebang_args.len() >= 8 {
|
||||
return Err(Error::UnrecognizedExecutable);
|
||||
}
|
||||
shebang_args.extend_from_slice(args);
|
||||
shebang_args.extend_from_slice(&args);
|
||||
|
||||
return load(ioctx, shebang_args[0], &shebang_args, envs);
|
||||
return xxx_load_program(space, ioctx, shebang_args[0].clone(), shebang_args, envs);
|
||||
}
|
||||
|
||||
file.seek(SeekFrom::Start(0))?;
|
||||
|
||||
let space = ProcessAddressSpace::new()?;
|
||||
let image = load_binary(head, file, &space)?;
|
||||
|
||||
setup_binary(path.display(), space, image, args, envs)
|
||||
Ok((image, args, envs))
|
||||
}
|
||||
|
||||
/// Loads a program from given `path`
|
||||
pub fn load<P: AsRef<Path>>(
|
||||
ioctx: &mut IoContext,
|
||||
path: P,
|
||||
args: &[&str],
|
||||
envs: &[&str],
|
||||
) -> Result<(Arc<Process>, Arc<Thread>), Error> {
|
||||
let path = path.as_ref();
|
||||
let args = args.into_iter().map(|&s| s.to_owned()).collect();
|
||||
let envs = envs.into_iter().map(|&s| s.to_owned()).collect();
|
||||
|
||||
let space = ProcessAddressSpace::new()?;
|
||||
let (image, args, envs) = xxx_load_program(&space, ioctx, path, args, envs)?;
|
||||
setup_binary(path.display(), space, image, &args, &envs)
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn load_into<P: AsRef<Path>>(
|
||||
process: &Process,
|
||||
path: P,
|
||||
args: Vec<String>,
|
||||
envs: Vec<String>,
|
||||
) -> Result<(TaskContext, ProcessImage), Error> {
|
||||
let mut io = process.io.lock();
|
||||
// Have to make the Path owned, going to drop the address space from which it came
|
||||
let path = path.as_ref().to_owned();
|
||||
let space = process.space();
|
||||
space.clear()?;
|
||||
let (image, args, envs) = xxx_load_program(&space, io.ioctx(), &path, args, envs)?;
|
||||
let context = setup_context(&space, &image, &args, &envs)?;
|
||||
|
||||
Ok((context, image))
|
||||
}
|
||||
|
@ -9,10 +9,13 @@ use abi::{
|
||||
TerminalSize,
|
||||
},
|
||||
mem::MappingSource,
|
||||
process::{ExitCode, MutexOperation, Signal, SpawnOption, SpawnOptions, ThreadSpawnOptions},
|
||||
process::{
|
||||
ExecveOptions, ExitCode, MutexOperation, Signal, SpawnOption, SpawnOptions,
|
||||
ThreadSpawnOptions,
|
||||
},
|
||||
syscall::SyscallFunction,
|
||||
};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec::Vec};
|
||||
use kernel_util::{block, mem::table::EntryLevelExt, runtime, sync::IrqSafeSpinlockGuard};
|
||||
use vfs::{File, IoContext, MessagePayload, NodeRef, Read, Seek, Write};
|
||||
use yggdrasil_abi::{error::SyscallResult, io::MountOptions};
|
||||
@ -25,7 +28,7 @@ use crate::{
|
||||
proc::{self, io::ProcessIo, random},
|
||||
task::{
|
||||
process::{Process, ProcessId},
|
||||
thread::Thread,
|
||||
thread::{CurrentThread, Thread},
|
||||
},
|
||||
};
|
||||
|
||||
@ -57,6 +60,23 @@ fn run_with_io_at<
|
||||
f(at, io)
|
||||
}
|
||||
|
||||
fn sys_execve(thread: CurrentThread, options: &ExecveOptions) -> Result<!, Error> {
|
||||
let process = thread.process();
|
||||
|
||||
// Clone the options into the kernel
|
||||
let mut argv = Vec::new();
|
||||
let mut envp = Vec::new();
|
||||
|
||||
for &arg in options.arguments {
|
||||
argv.push(arg.to_owned());
|
||||
}
|
||||
for &env in options.environment {
|
||||
envp.push(env.to_owned());
|
||||
}
|
||||
|
||||
process.exec(options.program, argv, envp)
|
||||
}
|
||||
|
||||
fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error> {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
@ -448,6 +468,23 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
Ok(0)
|
||||
})
|
||||
}
|
||||
SyscallFunction::CloneFd => {
|
||||
let source_fd = RawFd::from(args[0] as u32);
|
||||
let target_fd = RawFd::from(args[1] as u32);
|
||||
|
||||
run_with_io(process, |mut io| {
|
||||
let file = io.files.file(source_fd)?.clone();
|
||||
|
||||
let fd = if target_fd != RawFd::NONE {
|
||||
io.files.set_file(target_fd, file)?;
|
||||
target_fd
|
||||
} else {
|
||||
io.files.place_file(file, true)?
|
||||
};
|
||||
|
||||
Ok(fd.0 as usize)
|
||||
})
|
||||
}
|
||||
// Process management
|
||||
SyscallFunction::SpawnProcess => {
|
||||
let options = arg_user_ref::<SpawnOptions>(args[0] as usize)?;
|
||||
@ -507,6 +544,10 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
Ok(pid as _)
|
||||
})
|
||||
}
|
||||
SyscallFunction::Exec => {
|
||||
let options = arg_user_ref::<ExecveOptions>(args[0] as usize)?;
|
||||
sys_execve(thread, options)?;
|
||||
}
|
||||
SyscallFunction::SpawnThread => {
|
||||
let options = arg_user_ref::<ThreadSpawnOptions>(args[0] as usize)?;
|
||||
let id = process.spawn_thread(options)?;
|
||||
@ -602,6 +643,8 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,5 +662,11 @@ pub fn raw_syscall_handler(func: u64, args: &[u64]) -> u64 {
|
||||
// func,
|
||||
// args
|
||||
// );
|
||||
syscall_handler(func, args).into_syscall_result() as u64
|
||||
let result = syscall_handler(func, args);
|
||||
|
||||
if let &Err(error) = &result {
|
||||
warnln!("{:?}: {:?}", func, error);
|
||||
}
|
||||
|
||||
result.into_syscall_result() as u64
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
use abi::{arch::SavedFrame, error::Error};
|
||||
use alloc::boxed::Box;
|
||||
use cfg_if::cfg_if;
|
||||
use kernel_util::thread::Termination;
|
||||
use kernel_util::{mem::address::PhysicalAddress, thread::Termination};
|
||||
|
||||
use crate::task::thread::Thread;
|
||||
|
||||
@ -47,6 +47,15 @@ pub trait TaskFrame {
|
||||
fn user_ip(&self) -> usize;
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub trait ForkFrame: Sized {
|
||||
/// XXX
|
||||
unsafe fn fork(&self, address_space: u64) -> Result<TaskContext, Error>;
|
||||
|
||||
/// XXX
|
||||
fn set_return_value(&mut self, value: u64);
|
||||
}
|
||||
|
||||
/// Platform-specific task context implementation
|
||||
pub trait TaskContextImpl: Sized {
|
||||
/// Number of bytes to offset the signal stack pointer by
|
||||
|
@ -9,21 +9,25 @@ use core::{
|
||||
};
|
||||
|
||||
use abi::{
|
||||
error::Error,
|
||||
error::{Error, SyscallResult},
|
||||
process::{ExitCode, Signal, ThreadSpawnOptions},
|
||||
};
|
||||
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
|
||||
use futures_util::Future;
|
||||
use kernel_util::{runtime::QueueWaker, sync::IrqSafeSpinlock};
|
||||
use vfs::NodeRef;
|
||||
use kernel_util::{
|
||||
runtime::QueueWaker,
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
|
||||
};
|
||||
use vfs::{IoContext, NodeRef};
|
||||
|
||||
use crate::{
|
||||
mem::process::ProcessAddressSpace,
|
||||
proc::{self, io::ProcessIo},
|
||||
task::context::TaskContextImpl,
|
||||
task::{context::TaskContextImpl, sched::CpuQueue},
|
||||
};
|
||||
|
||||
use super::{
|
||||
context::ForkFrame,
|
||||
sync::UserspaceMutex,
|
||||
thread::{Thread, ThreadId},
|
||||
TaskContext,
|
||||
@ -52,7 +56,7 @@ pub struct ProcessId(u64);
|
||||
// | ??? | Data .....|
|
||||
|
||||
/// Describes Thread-Local Storage of a process
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProcessTlsInfo {
|
||||
/// Location of the TLS master copy within the process's memory
|
||||
pub master_copy_base: usize,
|
||||
@ -61,7 +65,7 @@ pub struct ProcessTlsInfo {
|
||||
}
|
||||
|
||||
/// Describes TLS layout for a program image
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProcessTlsLayout {
|
||||
/// Data offset from the TLS base
|
||||
pub data_offset: usize,
|
||||
@ -126,6 +130,7 @@ impl ProcessTlsLayout {
|
||||
}
|
||||
|
||||
/// Describes information about a program's image in memory
|
||||
#[derive(Clone)]
|
||||
pub struct ProcessImage {
|
||||
/// Entry point address
|
||||
pub entry: usize,
|
||||
@ -142,6 +147,9 @@ struct ProcessInner {
|
||||
session_terminal: Option<NodeRef>,
|
||||
threads: Vec<Arc<Thread>>,
|
||||
mutexes: BTreeMap<usize, Arc<UserspaceMutex>>,
|
||||
|
||||
space: Arc<ProcessAddressSpace>,
|
||||
image: Option<ProcessImage>,
|
||||
}
|
||||
|
||||
/// Describes a process within the system
|
||||
@ -149,9 +157,7 @@ pub struct Process {
|
||||
name: String,
|
||||
id: ProcessId,
|
||||
|
||||
space: Arc<ProcessAddressSpace>,
|
||||
inner: IrqSafeSpinlock<ProcessInner>,
|
||||
image: Option<ProcessImage>,
|
||||
inner: IrqSafeRwLock<ProcessInner>,
|
||||
|
||||
exit_waker: QueueWaker,
|
||||
/// Process I/O information
|
||||
@ -176,16 +182,16 @@ impl Process {
|
||||
name,
|
||||
id,
|
||||
|
||||
image,
|
||||
|
||||
space: space.clone(),
|
||||
inner: IrqSafeSpinlock::new(ProcessInner {
|
||||
inner: IrqSafeRwLock::new(ProcessInner {
|
||||
state: ProcessState::Running,
|
||||
session_id: id,
|
||||
group_id: id,
|
||||
session_terminal: None,
|
||||
threads: Vec::new(),
|
||||
mutexes: BTreeMap::new(),
|
||||
|
||||
image,
|
||||
space: space.clone(),
|
||||
}),
|
||||
|
||||
exit_waker: QueueWaker::new(),
|
||||
@ -194,7 +200,7 @@ impl Process {
|
||||
|
||||
// Create "main" thread
|
||||
let thread = Thread::new_uthread(process.clone(), space, context);
|
||||
process.inner.lock().threads.push(thread.clone());
|
||||
process.inner.write().threads.push(thread.clone());
|
||||
|
||||
PROCESSES.lock().insert(id, process.clone());
|
||||
|
||||
@ -208,14 +214,15 @@ impl Process {
|
||||
self.id(),
|
||||
options
|
||||
);
|
||||
let mut inner = self.inner.write();
|
||||
|
||||
let tls_address = if let Some(image) = self.image.as_ref() {
|
||||
proc::elf::clone_tls(&self.space, image)?
|
||||
let tls_address = if let Some(image) = inner.image.as_ref() {
|
||||
proc::elf::clone_tls(&inner.space, image)?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let space = self.space.clone();
|
||||
let space = inner.space.clone();
|
||||
let context = TaskContext::user(
|
||||
options.entry as _,
|
||||
options.argument as _,
|
||||
@ -226,13 +233,81 @@ impl Process {
|
||||
let thread = Thread::new_uthread(self.clone(), space, context);
|
||||
let id = thread.id;
|
||||
|
||||
self.inner.lock().threads.push(thread.clone());
|
||||
inner.threads.push(thread.clone());
|
||||
|
||||
thread.enqueue();
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
unsafe fn fork_inner<F: ForkFrame>(&self, frame: &F) -> Result<ProcessId, Error> {
|
||||
let src_inner = self.inner.read();
|
||||
let new_space = src_inner.space.fork()?;
|
||||
let new_context = frame.fork(new_space.as_address_with_asid())?;
|
||||
|
||||
let (new_process, new_main) =
|
||||
Self::new_with_main(self.name(), Arc::new(new_space), new_context, None);
|
||||
|
||||
{
|
||||
let mut src_io = self.io.lock();
|
||||
|
||||
let new_ioctx = IoContext::inherit(src_io.ioctx());
|
||||
let mut new_io = new_process.io.lock();
|
||||
new_io.set_ioctx(new_ioctx);
|
||||
|
||||
for (old_fd, old_file) in src_io.files.iter() {
|
||||
let new_file = old_file.send()?;
|
||||
new_io.files.set_file(*old_fd, new_file)?;
|
||||
}
|
||||
}
|
||||
|
||||
new_process.inherit(self)?;
|
||||
|
||||
infoln!("Process::fork -> {:?}", new_process.id());
|
||||
new_main.enqueue_to(CpuQueue::for_cpu(1));
|
||||
|
||||
Ok(new_process.id())
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub unsafe fn raw_fork<F: ForkFrame>(frame: &mut F) {
|
||||
let src_thread = Thread::current();
|
||||
let src_process = src_thread.process();
|
||||
|
||||
let rax = src_process
|
||||
.fork_inner(frame)
|
||||
.map(|ProcessId(p)| p as u32)
|
||||
.into_syscall_result();
|
||||
|
||||
frame.set_return_value(rax as _);
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn exec(&self, program: &str, argv: Vec<String>, envp: Vec<String>) -> Result<!, Error> {
|
||||
if self.inner.read().threads.len() != 1 {
|
||||
todo!();
|
||||
}
|
||||
|
||||
let (context, image) = proc::exec::load_into(self, program, argv, envp)?;
|
||||
let mut inner = self.inner.write();
|
||||
let main = &inner.threads[0];
|
||||
|
||||
let old_context = unsafe { main.replace_context(context) };
|
||||
let new_context = main.context.as_ptr();
|
||||
inner.image = Some(image);
|
||||
|
||||
drop(inner);
|
||||
|
||||
// TODO old context is leaked
|
||||
unsafe { (&*new_context).switch(&old_context) }
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// XXX
|
||||
pub fn space(&self) -> Arc<ProcessAddressSpace> {
|
||||
self.inner.read().space.clone()
|
||||
}
|
||||
|
||||
/// Returns the [ProcessId] of this process
|
||||
pub fn id(&self) -> ProcessId {
|
||||
self.id
|
||||
@ -240,12 +315,12 @@ impl Process {
|
||||
|
||||
/// Returns the process group ID of the process
|
||||
pub fn group_id(&self) -> ProcessId {
|
||||
self.inner.lock().group_id
|
||||
self.inner.read().group_id
|
||||
}
|
||||
|
||||
/// Returns the process session ID of the process
|
||||
pub fn session_id(&self) -> ProcessId {
|
||||
self.inner.lock().session_id
|
||||
self.inner.read().session_id
|
||||
}
|
||||
|
||||
/// Returns the process name
|
||||
@ -255,35 +330,35 @@ impl Process {
|
||||
|
||||
/// Changes the process's group ID
|
||||
pub fn set_group_id(&self, id: ProcessId) {
|
||||
self.inner.lock().group_id = id;
|
||||
self.inner.write().group_id = id;
|
||||
}
|
||||
|
||||
/// Changes the process's session ID
|
||||
pub fn set_session_id(&self, id: ProcessId) {
|
||||
self.inner.lock().session_id = id;
|
||||
self.inner.write().session_id = id;
|
||||
}
|
||||
|
||||
// Resources
|
||||
|
||||
/// Returns the current session terminal of the process, if set
|
||||
pub fn session_terminal(&self) -> Option<NodeRef> {
|
||||
self.inner.lock().session_terminal.clone()
|
||||
self.inner.read().session_terminal.clone()
|
||||
}
|
||||
|
||||
/// Changes the current session terminal of the process
|
||||
pub fn set_session_terminal(&self, node: NodeRef) {
|
||||
self.inner.lock().session_terminal.replace(node);
|
||||
self.inner.write().session_terminal.replace(node);
|
||||
}
|
||||
|
||||
/// Resets the current session terminal of the process
|
||||
pub fn clear_session_terminal(&self) -> Option<NodeRef> {
|
||||
self.inner.lock().session_terminal.take()
|
||||
self.inner.write().session_terminal.take()
|
||||
}
|
||||
|
||||
/// Inherits the process information from the `parent`
|
||||
pub fn inherit(&self, parent: &Process) -> Result<(), Error> {
|
||||
let mut our_inner = self.inner.lock();
|
||||
let their_inner = parent.inner.lock();
|
||||
let mut our_inner = self.inner.write();
|
||||
let their_inner = parent.inner.read();
|
||||
|
||||
our_inner.session_id = their_inner.session_id;
|
||||
our_inner.group_id = their_inner.group_id;
|
||||
@ -296,7 +371,7 @@ impl Process {
|
||||
|
||||
/// Returns the [ExitCode] of the process, if it has exited
|
||||
pub fn get_exit_status(&self) -> Option<ExitCode> {
|
||||
match self.inner.lock().state {
|
||||
match self.inner.read().state {
|
||||
ProcessState::Running => None,
|
||||
ProcessState::Terminated(x) => Some(x),
|
||||
}
|
||||
@ -331,7 +406,7 @@ impl Process {
|
||||
/// Handles exit of a single child thread
|
||||
pub fn handle_thread_exit(&self, thread: ThreadId, code: ExitCode) {
|
||||
debugln!("Thread {} of process {}: {:?}", thread, self.id, code);
|
||||
let mut inner = self.inner.lock();
|
||||
let mut inner = self.inner.write();
|
||||
|
||||
// TODO make this cleaner
|
||||
let old_len = inner.threads.len();
|
||||
@ -356,7 +431,7 @@ impl Process {
|
||||
|
||||
/// Raises a signal for the specified process
|
||||
pub fn raise_signal(self: &Arc<Self>, signal: Signal) {
|
||||
let thread = self.inner.lock().threads[0].clone();
|
||||
let thread = self.inner.read().threads[0].clone();
|
||||
thread.raise_signal(signal);
|
||||
}
|
||||
|
||||
@ -364,7 +439,7 @@ impl Process {
|
||||
pub fn signal_group(group_id: ProcessId, signal: Signal) {
|
||||
let processes = PROCESSES.lock();
|
||||
for (_, proc) in processes.iter() {
|
||||
let inner = proc.inner.lock();
|
||||
let inner = proc.inner.read();
|
||||
if !matches!(inner.state, ProcessState::Terminated(_)) && inner.group_id == group_id {
|
||||
debugln!("Deliver group signal to {}: {:?}", proc.id(), signal);
|
||||
drop(inner);
|
||||
@ -376,7 +451,7 @@ impl Process {
|
||||
/// Returns a [UserspaceMutex] associated with the `address`. If one does not exist, will
|
||||
/// create it.
|
||||
pub fn get_or_insert_mutex(&self, address: usize) -> Arc<UserspaceMutex> {
|
||||
let mut inner = self.inner.lock();
|
||||
let mut inner = self.inner.write();
|
||||
inner
|
||||
.mutexes
|
||||
.entry(address)
|
||||
@ -393,7 +468,7 @@ impl Process {
|
||||
|
||||
/// Terminates all children of the process, `except` one
|
||||
pub async fn terminate_others(&self, except: ThreadId) {
|
||||
let mut inner = self.inner.lock();
|
||||
let mut inner = self.inner.write();
|
||||
|
||||
for thread in inner.threads.iter() {
|
||||
if thread.id == except {
|
||||
|
@ -1,5 +1,7 @@
|
||||
//! Per-CPU queue implementation
|
||||
|
||||
use core::cell::Cell;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use cfg_if::cfg_if;
|
||||
use crossbeam_queue::SegQueue;
|
||||
@ -20,7 +22,7 @@ use super::{
|
||||
pub struct CpuQueue {
|
||||
queue: SegQueue<ThreadId>,
|
||||
index: usize,
|
||||
idle: TaskContext,
|
||||
idle: Cell<TaskContext>,
|
||||
}
|
||||
|
||||
impl CpuQueue {
|
||||
@ -32,7 +34,7 @@ impl CpuQueue {
|
||||
Self {
|
||||
queue: SegQueue::new(),
|
||||
index,
|
||||
idle,
|
||||
idle: Cell::new(idle),
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +52,7 @@ impl CpuQueue {
|
||||
pub unsafe fn enter(&self) -> ! {
|
||||
let _guard = IrqGuard::acquire();
|
||||
|
||||
self.idle.enter()
|
||||
(&*self.idle.as_ptr()).enter()
|
||||
}
|
||||
|
||||
/// "Pushes" a thread to the queue for execution
|
||||
@ -151,9 +153,12 @@ impl CpuQueue {
|
||||
|
||||
cpu.set_current_thread_id(next_id);
|
||||
|
||||
let current_ctx = current_ctx.as_ptr();
|
||||
let next_ctx = next_ctx.as_ptr();
|
||||
|
||||
if !core::ptr::eq(current_ctx, next_ctx) {
|
||||
// Perform the switch
|
||||
next_ctx.switch(current_ctx);
|
||||
(&*next_ctx).switch(&*current_ctx);
|
||||
|
||||
true
|
||||
} else {
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! Thread data structures and management
|
||||
|
||||
use core::{
|
||||
cell::Cell,
|
||||
fmt,
|
||||
mem::size_of,
|
||||
ops::Deref,
|
||||
@ -91,7 +92,7 @@ pub struct Thread {
|
||||
pub id: ThreadId,
|
||||
pub name: Option<String>,
|
||||
pub sched: IrqSafeSpinlock<ThreadSchedulingInfo>,
|
||||
pub context: TaskContext,
|
||||
pub context: Cell<TaskContext>,
|
||||
|
||||
process: Option<Arc<Process>>,
|
||||
space: Option<Arc<ProcessAddressSpace>>,
|
||||
@ -103,6 +104,8 @@ pub struct Thread {
|
||||
pub affinity: ThreadAffinity,
|
||||
}
|
||||
|
||||
unsafe impl Sync for Thread {}
|
||||
|
||||
impl GlobalThreadList {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
@ -161,7 +164,7 @@ impl Thread {
|
||||
in_queue: false,
|
||||
queue: None,
|
||||
}),
|
||||
context,
|
||||
context: Cell::new(context),
|
||||
process,
|
||||
space,
|
||||
|
||||
@ -203,6 +206,10 @@ impl Thread {
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn replace_context(&self, context: TaskContext) -> TaskContext {
|
||||
self.context.replace(context)
|
||||
}
|
||||
|
||||
// Get/Set
|
||||
|
||||
/// Updates the thread affinity to run on a specific set of CPUs
|
||||
@ -432,7 +439,8 @@ impl CurrentThread {
|
||||
let inner = self.inner.lock();
|
||||
|
||||
let Some(entry) = inner.signal_entry.as_ref() else {
|
||||
todo!();
|
||||
drop(inner);
|
||||
self.exit_process(ExitCode::BySignal(signal));
|
||||
};
|
||||
|
||||
// TODO check if really in a syscall, lol
|
||||
|
Loading…
x
Reference in New Issue
Block a user