lock ordering
This commit is contained in:
Generated
+7
-17
@@ -137,7 +137,6 @@ dependencies = [
|
||||
"sbi-rt",
|
||||
"slab",
|
||||
"spin",
|
||||
"spinning_top 0.3.0",
|
||||
"toml",
|
||||
"x86",
|
||||
]
|
||||
@@ -148,7 +147,7 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "549ce1740e46b291953c4340adcd74c59bcf4308f4cac050fd33ba91b7168f4a"
|
||||
dependencies = [
|
||||
"spinning_top 0.2.5",
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -265,27 +264,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.225"
|
||||
version = "1.0.226"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d"
|
||||
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.225"
|
||||
version = "1.0.226"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383"
|
||||
checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.225"
|
||||
version = "1.0.226"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516"
|
||||
checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -331,15 +330,6 @@ dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
|
||||
@@ -20,7 +20,6 @@ redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", bran
|
||||
rmm = { path = "rmm", default-features = false }
|
||||
slab = { version = "0.4", default-features = false }
|
||||
spin = { version = "0.9.8" }
|
||||
spinning_top = { version = "0.3", features = ["arc_lock"] }
|
||||
# TODO: Remove
|
||||
indexmap = { version = "2.5.0", default-features = false }
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::{
|
||||
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
|
||||
},
|
||||
interrupt::irq::trigger,
|
||||
sync::CleanLockToken,
|
||||
time,
|
||||
};
|
||||
use fdt::Fdt;
|
||||
@@ -124,18 +125,17 @@ impl GenericTimer {
|
||||
}
|
||||
|
||||
impl InterruptHandler for GenericTimer {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
fn irq_handler(&mut self, irq: u32, token: &mut CleanLockToken) {
|
||||
self.clear_irq();
|
||||
{
|
||||
*time::OFFSET.lock() += self.clk_freq as u128;
|
||||
}
|
||||
|
||||
timeout::trigger();
|
||||
|
||||
context::switch::tick();
|
||||
timeout::trigger(token);
|
||||
context::switch::tick(token);
|
||||
|
||||
unsafe {
|
||||
trigger(irq);
|
||||
trigger(irq, token);
|
||||
}
|
||||
self.reload_count();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use super::InterruptController;
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
use crate::{
|
||||
dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
@@ -75,7 +78,7 @@ impl GenericInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptHandler for GenericInterruptController {
|
||||
fn irq_handler(&mut self, _irq: u32) {}
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {}
|
||||
}
|
||||
|
||||
impl InterruptController for GenericInterruptController {
|
||||
|
||||
@@ -3,9 +3,12 @@ use core::arch::asm;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
|
||||
use super::{gic::GicDistIf, InterruptController};
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
use crate::{
|
||||
dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
@@ -74,7 +77,7 @@ impl GicV3 {
|
||||
}
|
||||
|
||||
impl InterruptHandler for GicV3 {
|
||||
fn irq_handler(&mut self, _irq: u32) {}
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {}
|
||||
}
|
||||
|
||||
impl InterruptController for GicV3 {
|
||||
|
||||
@@ -2,9 +2,12 @@ use core::ptr::{read_volatile, write_volatile};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
|
||||
use super::InterruptController;
|
||||
use crate::dtb::{
|
||||
get_interrupt, get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc, IRQ_CHIP},
|
||||
use crate::{
|
||||
dtb::{
|
||||
get_interrupt, get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc, IRQ_CHIP},
|
||||
},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
@@ -278,14 +281,14 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Bcm2835ArmInterruptController {
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
if let Some(virq) = self.irq_to_virq(irq)
|
||||
&& virq < 1024
|
||||
{
|
||||
if let Some(handler) = &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
handler.irq_handler(virq as u32);
|
||||
handler.irq_handler(virq as u32, token);
|
||||
}
|
||||
} else {
|
||||
error!("unexpected irq num {}", irq);
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use core::{
|
||||
arch::asm,
|
||||
@@ -116,7 +117,7 @@ impl Bcm2836ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptHandler for Bcm2836ArmInterruptController {
|
||||
fn irq_handler(&mut self, _irq: u32) {}
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {}
|
||||
}
|
||||
|
||||
impl InterruptController for Bcm2836ArmInterruptController {
|
||||
|
||||
@@ -5,12 +5,15 @@ use syscall::{
|
||||
};
|
||||
|
||||
use super::InterruptController;
|
||||
use crate::dtb::irqchip::{InterruptHandler, IrqCell, IrqDesc};
|
||||
use crate::{
|
||||
dtb::irqchip::{InterruptHandler, IrqCell, IrqDesc},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
pub struct Null;
|
||||
|
||||
impl InterruptHandler for Null {
|
||||
fn irq_handler(&mut self, _irq: u32) {}
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {}
|
||||
}
|
||||
|
||||
impl InterruptController for Null {
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
|
||||
},
|
||||
interrupt::irq::trigger,
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use fdt::Fdt;
|
||||
use syscall::Mmio;
|
||||
@@ -18,10 +19,10 @@ pub static COM1: Mutex<SerialKind> = Mutex::new(SerialKind::NotPresent);
|
||||
pub struct Com1Irq {}
|
||||
|
||||
impl InterruptHandler for Com1Irq {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
COM1.lock().receive();
|
||||
fn irq_handler(&mut self, irq: u32, token: &mut CleanLockToken) {
|
||||
COM1.lock().receive(token);
|
||||
unsafe {
|
||||
trigger(irq);
|
||||
trigger(irq, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
exception_stack,
|
||||
memory::{ArchIntCtx, GenericPfFlags},
|
||||
panic::stack_trace,
|
||||
sync::CleanLockToken,
|
||||
syscall::{self, flag::*},
|
||||
};
|
||||
|
||||
@@ -189,8 +190,9 @@ exception_stack!(synchronous_exception_at_el0, |stack| {
|
||||
match exception_code(stack.iret.esr_el1) {
|
||||
0b010101 => {
|
||||
let scratch = &stack.scratch;
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let ret = syscall::syscall(
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4,
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4, &mut token,
|
||||
);
|
||||
stack.scratch.x0 = ret;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::{arch::device::ROOT_IC_IDX, dtb::irqchip::IRQ_CHIP, scheme::irq::irq_trigger};
|
||||
use crate::{
|
||||
arch::device::ROOT_IC_IDX, dtb::irqchip::IRQ_CHIP, scheme::irq::irq_trigger,
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
// use crate::percpu::PercpuBlock;
|
||||
@@ -12,34 +15,36 @@ unsafe fn irq_ack() -> (u32, Option<usize>) {
|
||||
}
|
||||
|
||||
exception_stack!(irq_at_el0, |_stack| {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let (irq, virq) = irq_ack();
|
||||
if let Some(virq) = virq
|
||||
&& virq < 1024
|
||||
{
|
||||
IRQ_CHIP.trigger_virq(virq as u32);
|
||||
IRQ_CHIP.trigger_virq(virq as u32, &mut token);
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
});
|
||||
|
||||
exception_stack!(irq_at_el1, |_stack| {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let (irq, virq) = irq_ack();
|
||||
if let Some(virq) = virq
|
||||
&& virq < 1024
|
||||
{
|
||||
IRQ_CHIP.trigger_virq(virq as u32);
|
||||
IRQ_CHIP.trigger_virq(virq as u32, &mut token);
|
||||
} else {
|
||||
println!("unexpected irq num {}", irq);
|
||||
}
|
||||
});
|
||||
|
||||
//TODO
|
||||
pub unsafe fn trigger(irq: u32) {
|
||||
pub unsafe fn trigger(irq: u32, token: &mut CleanLockToken) {
|
||||
unsafe {
|
||||
// FIXME add_irq accepts a u8 as irq number
|
||||
// PercpuBlock::current().stats.add_irq(irq);
|
||||
|
||||
irq_trigger(irq.try_into().unwrap());
|
||||
irq_trigger(irq.try_into().unwrap(), token);
|
||||
IRQ_CHIP.irq_eoi(irq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::sync::CleanLockToken;
|
||||
use core::arch::asm;
|
||||
|
||||
pub unsafe fn kreset() -> ! {
|
||||
@@ -20,7 +21,7 @@ pub unsafe fn emergency_reset() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn kstop() -> ! {
|
||||
pub unsafe fn kstop(token: &mut CleanLockToken) -> ! {
|
||||
unsafe {
|
||||
println!("kstop");
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
context,
|
||||
context::timeout,
|
||||
dtb::irqchip::{register_irq, InterruptHandler, IrqCell, IRQ_CHIP},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
@@ -34,7 +35,7 @@ struct ClintConnector {
|
||||
}
|
||||
|
||||
impl InterruptHandler for ClintConnector {
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {
|
||||
CLINT
|
||||
.lock()
|
||||
.as_mut()
|
||||
@@ -43,8 +44,8 @@ impl InterruptHandler for ClintConnector {
|
||||
if self.irq == IRQ_TIMER {
|
||||
// a bit of hack, but it is a really bad idea to call scheduler
|
||||
// from inside clint irq handler
|
||||
timeout::trigger();
|
||||
context::switch::tick();
|
||||
timeout::trigger(token);
|
||||
context::switch::tick(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use crate::dtb::irqchip::{InterruptController, InterruptHandler, IrqCell, IrqDesc, IRQ_CHIP};
|
||||
use crate::{
|
||||
dtb::irqchip::{InterruptController, InterruptHandler, IrqCell, IrqDesc, IRQ_CHIP},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use core::arch::asm;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
@@ -24,7 +27,7 @@ fn acknowledge(interrupt: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn interrupt(hart: usize, interrupt: usize) {
|
||||
pub unsafe fn interrupt(hart: usize, interrupt: usize, token: &mut CleanLockToken) {
|
||||
unsafe {
|
||||
assert!(
|
||||
hart < CPU_INTERRUPT_HANDLERS.len(),
|
||||
@@ -42,13 +45,13 @@ pub unsafe fn interrupt(hart: usize, interrupt: usize) {
|
||||
.unwrap_or_else(|| panic!("HLIC doesn't know of interrupt {}", interrupt));
|
||||
match &mut IRQ_CHIP.irq_desc[virq].handler {
|
||||
Some(handler) => {
|
||||
handler.irq_handler(virq as u32);
|
||||
handler.irq_handler(virq as u32, token);
|
||||
}
|
||||
_ => match IRQ_CHIP.irq_desc[virq].basic.child_ic_idx {
|
||||
Some(ic_idx) => {
|
||||
IRQ_CHIP.irq_chip_list.chips[ic_idx]
|
||||
.ic
|
||||
.irq_handler(virq as u32);
|
||||
.irq_handler(virq as u32, token);
|
||||
}
|
||||
_ => {
|
||||
panic!(
|
||||
@@ -83,10 +86,10 @@ impl Hlic {
|
||||
}
|
||||
}
|
||||
impl InterruptHandler for Hlic {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
fn irq_handler(&mut self, irq: u32, token: &mut CleanLockToken) {
|
||||
assert!(irq < 16, "Unsupported HLIC interrupt raised!");
|
||||
unsafe {
|
||||
IRQ_CHIP.trigger_virq(self.virq_base as u32 + irq);
|
||||
IRQ_CHIP.trigger_virq(self.virq_base as u32 + irq, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptController, InterruptHandler, IrqCell, IrqDesc, IRQ_CHIP},
|
||||
},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use core::{mem, num::NonZero, sync::atomic::Ordering};
|
||||
use fdt::Fdt;
|
||||
@@ -93,12 +94,12 @@ impl Plic {
|
||||
}
|
||||
}
|
||||
impl InterruptHandler for Plic {
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
fn irq_handler(&mut self, _irq: u32, token: &mut CleanLockToken) {
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
//println!("PLIC interrupt {}", irq);
|
||||
if let Some(virq) = self.irq_to_virq(irq) {
|
||||
IRQ_CHIP.trigger_virq(virq as u32);
|
||||
IRQ_CHIP.trigger_virq(virq as u32, token);
|
||||
} else {
|
||||
error!("unexpected irq num {}", irq);
|
||||
self.irq_eoi(irq);
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::{
|
||||
irqchip::{register_irq, InterruptHandler, IRQ_CHIP},
|
||||
},
|
||||
scheme::irq::irq_trigger,
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
pub static COM1: Mutex<SerialKind> = Mutex::new(SerialKind::NotPresent);
|
||||
@@ -17,10 +18,10 @@ pub static COM1: Mutex<SerialKind> = Mutex::new(SerialKind::NotPresent);
|
||||
pub struct Com1Irq {}
|
||||
|
||||
impl InterruptHandler for Com1Irq {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
COM1.lock().receive();
|
||||
fn irq_handler(&mut self, irq: u32, token: &mut CleanLockToken) {
|
||||
COM1.lock().receive(token);
|
||||
unsafe {
|
||||
irq_trigger(irq as u8);
|
||||
irq_trigger(irq as u8, token);
|
||||
IRQ_CHIP.irq_eoi(irq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::{
|
||||
memory::GenericPfFlags,
|
||||
panic::stack_trace,
|
||||
ptrace,
|
||||
sync::CleanLockToken,
|
||||
syscall::{self, flag::*},
|
||||
};
|
||||
|
||||
@@ -146,25 +147,28 @@ unsafe fn handle_system_exception(scause: usize, regs: &InterruptStack) {
|
||||
|
||||
unsafe fn handle_interrupt(interrupt: usize) {
|
||||
unsafe {
|
||||
let mut token = CleanLockToken::new();
|
||||
// FIXME retrieve from percpu area
|
||||
// For now all the interrupts go to boot hart so this suffices...
|
||||
let hart: usize = BOOT_HART_ID.load(Ordering::Relaxed);
|
||||
irqchip::hlic::interrupt(hart, interrupt);
|
||||
irqchip::hlic::interrupt(hart, interrupt, &mut token);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn handle_user_exception(scause: usize, regs: &mut InterruptStack) {
|
||||
unsafe {
|
||||
let mut token = CleanLockToken::new();
|
||||
|
||||
if scause == USERMODE_ECALL {
|
||||
let r = &mut regs.registers;
|
||||
regs.iret.sepc += 4; // skip ecall
|
||||
let ret = syscall::syscall(r.x17, r.x10, r.x11, r.x12, r.x13, r.x14);
|
||||
let ret = syscall::syscall(r.x17, r.x10, r.x11, r.x12, r.x13, r.x14, &mut token);
|
||||
r.x10 = ret;
|
||||
return;
|
||||
}
|
||||
|
||||
if scause == BREAKPOINT {
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_some() {
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None, &mut token).is_some() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::sync::CleanLockToken;
|
||||
|
||||
pub unsafe fn kreset() -> ! {
|
||||
println!("kreset");
|
||||
unimplemented!()
|
||||
@@ -7,7 +9,7 @@ pub unsafe fn emergency_reset() -> ! {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub unsafe fn kstop() -> ! {
|
||||
pub unsafe fn kstop(token: &mut CleanLockToken) -> ! {
|
||||
println!("kstop");
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
use crate::{
|
||||
ptrace, syscall,
|
||||
ptrace,
|
||||
sync::CleanLockToken,
|
||||
syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_POST_SYSCALL, PTRACE_STOP_PRE_SYSCALL},
|
||||
};
|
||||
|
||||
pub unsafe fn init() {}
|
||||
|
||||
macro_rules! with_interrupt_stack {
|
||||
(|$stack:ident| $code:block) => {{
|
||||
let allowed = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None)
|
||||
(|$stack:ident, $token:ident| $code:block) => {{
|
||||
let mut $token = CleanLockToken::new();
|
||||
|
||||
let allowed = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None, &mut $token)
|
||||
.and_then(|_| ptrace::next_breakpoint().map(|f| !f.contains(PTRACE_FLAG_IGNORE)));
|
||||
|
||||
if allowed.unwrap_or(true) {
|
||||
@@ -19,12 +23,12 @@ macro_rules! with_interrupt_stack {
|
||||
$code
|
||||
}
|
||||
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None, &mut $token);
|
||||
}};
|
||||
}
|
||||
|
||||
interrupt_stack!(syscall, |stack| {
|
||||
with_interrupt_stack!(|stack| {
|
||||
with_interrupt_stack!(|stack, token| {
|
||||
let scratch = &stack.scratch;
|
||||
let preserved = &stack.preserved;
|
||||
let ret = syscall::syscall(
|
||||
@@ -34,6 +38,7 @@ interrupt_stack!(syscall, |stack| {
|
||||
scratch.edx,
|
||||
preserved.esi,
|
||||
preserved.edi,
|
||||
&mut token,
|
||||
);
|
||||
stack.scratch.eax = ret;
|
||||
})
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::{
|
||||
arch::{gdt, interrupt::InterruptStack},
|
||||
ptrace, syscall,
|
||||
ptrace,
|
||||
sync::CleanLockToken,
|
||||
syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_POST_SYSCALL, PTRACE_STOP_PRE_SYSCALL},
|
||||
};
|
||||
use core::mem::offset_of;
|
||||
@@ -66,7 +68,8 @@ pub unsafe fn init() {
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack) {
|
||||
unsafe {
|
||||
let allowed = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None)
|
||||
let mut token = CleanLockToken::new();
|
||||
let allowed = ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None, &mut token)
|
||||
.and_then(|_| ptrace::next_breakpoint().map(|f| !f.contains(PTRACE_FLAG_IGNORE)));
|
||||
|
||||
if allowed.unwrap_or(true) {
|
||||
@@ -79,11 +82,12 @@ pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack)
|
||||
scratch.rdx,
|
||||
scratch.r10,
|
||||
scratch.r8,
|
||||
&mut token,
|
||||
);
|
||||
(*stack).scratch.rax = ret;
|
||||
}
|
||||
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None, &mut token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ use x86::irq::PageFaultError;
|
||||
|
||||
use crate::{
|
||||
arch::x86_shared::interrupt, context::signal::excp_handler, interrupt_error, interrupt_stack,
|
||||
memory::GenericPfFlags, paging::VirtualAddress, panic::stack_trace, ptrace, syscall::flag::*,
|
||||
memory::GenericPfFlags, paging::VirtualAddress, panic::stack_trace, ptrace,
|
||||
sync::CleanLockToken, syscall::flag::*,
|
||||
};
|
||||
|
||||
interrupt_stack!(divide_by_zero, |stack| {
|
||||
@@ -28,7 +29,8 @@ interrupt_stack!(debug, @paranoid, |stack| {
|
||||
let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8;
|
||||
stack.set_singlestep(false);
|
||||
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_SINGLESTEP, None).is_some() {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_SINGLESTEP, None, &mut token).is_some() {
|
||||
handled = true;
|
||||
} else {
|
||||
// There was no breakpoint, restore original value
|
||||
@@ -78,7 +80,8 @@ interrupt_stack!(breakpoint, |stack| {
|
||||
stack.iret.rip -= 1;
|
||||
}
|
||||
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None, &mut token).is_none() {
|
||||
println!("Breakpoint trap");
|
||||
stack.dump();
|
||||
excp_handler(Exception {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{context, device::local_apic::the_local_apic, percpu::PercpuBlock};
|
||||
use crate::{
|
||||
context, device::local_apic::the_local_apic, percpu::PercpuBlock, sync::CleanLockToken,
|
||||
};
|
||||
|
||||
interrupt!(wakeup, || {
|
||||
unsafe { the_local_apic().eoi() };
|
||||
@@ -13,12 +15,14 @@ interrupt!(tlb, || {
|
||||
interrupt!(switch, || {
|
||||
unsafe { the_local_apic().eoi() };
|
||||
|
||||
let _ = context::switch();
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let _ = context::switch(&mut token);
|
||||
});
|
||||
|
||||
interrupt!(pit, || {
|
||||
unsafe { the_local_apic().eoi() };
|
||||
|
||||
// Switch after a sufficient amount of time since the last switch.
|
||||
context::switch::tick();
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
context::switch::tick(&mut token);
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
ipi::{ipi, IpiKind, IpiTarget},
|
||||
percpu::PercpuBlock,
|
||||
scheme::{irq::irq_trigger, serio::serio_input},
|
||||
sync::CleanLockToken,
|
||||
time,
|
||||
};
|
||||
|
||||
@@ -34,7 +35,7 @@ pub fn spurious_count_irq15() -> usize {
|
||||
pub fn spurious_count() -> usize {
|
||||
spurious_count_irq7() + spurious_count_irq15()
|
||||
}
|
||||
pub fn spurious_irq_resource() -> syscall::Result<Vec<u8>> {
|
||||
pub fn spurious_irq_resource(_token: &mut CleanLockToken) -> syscall::Result<Vec<u8>> {
|
||||
match irq_method() {
|
||||
IrqMethod::Apic => Ok(Vec::from(&b"(not implemented for APIC yet)"[..])),
|
||||
IrqMethod::Pic => Ok(format!(
|
||||
@@ -75,7 +76,8 @@ unsafe fn trigger(irq: u8) {
|
||||
}
|
||||
IrqMethod::Apic => ioapic_mask(irq),
|
||||
}
|
||||
irq_trigger(irq);
|
||||
let mut token = CleanLockToken::new();
|
||||
irq_trigger(irq, &mut token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,11 +177,13 @@ interrupt_stack!(pit_stack, |_stack| {
|
||||
// Wake up other CPUs
|
||||
ipi(IpiKind::Pit, IpiTarget::Other);
|
||||
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
// Any better way of doing this?
|
||||
timeout::trigger();
|
||||
timeout::trigger(&mut token);
|
||||
|
||||
// Switch after a sufficient amount of time since the last switch.
|
||||
context::switch::tick();
|
||||
context::switch::tick(&mut token);
|
||||
});
|
||||
|
||||
interrupt!(keyboard, || {
|
||||
@@ -188,7 +192,8 @@ interrupt!(keyboard, || {
|
||||
|
||||
unsafe { eoi(1) };
|
||||
|
||||
serio_input(0, data);
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
serio_input(0, data, &mut token);
|
||||
});
|
||||
|
||||
interrupt!(cascade, || {
|
||||
@@ -197,12 +202,14 @@ interrupt!(cascade, || {
|
||||
});
|
||||
|
||||
interrupt!(com2, || {
|
||||
COM2.lock().receive();
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
COM2.lock().receive(&mut token);
|
||||
unsafe { eoi(3) };
|
||||
});
|
||||
|
||||
interrupt!(com1, || {
|
||||
COM1.lock().receive();
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
COM1.lock().receive(&mut token);
|
||||
unsafe { eoi(4) };
|
||||
});
|
||||
|
||||
@@ -266,7 +273,8 @@ interrupt!(mouse, || {
|
||||
|
||||
unsafe { eoi(12) };
|
||||
|
||||
serio_input(1, data);
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
serio_input(1, data, &mut token);
|
||||
});
|
||||
|
||||
interrupt!(fpu, || {
|
||||
@@ -326,7 +334,8 @@ macro_rules! allocatable_irq(
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub unsafe fn allocatable_irq_generic(number: u8) {
|
||||
unsafe {
|
||||
irq_trigger(number - 32);
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
irq_trigger(number - 32, &mut token);
|
||||
lapic_eoi();
|
||||
}
|
||||
}
|
||||
@@ -336,10 +345,12 @@ default_irqs!((), allocatable_irq);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
interrupt_error!(generic_irq, |_stack, code| {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
// The reason why 128 is subtracted and added from the code, is that PUSH imm8 sign-extends the
|
||||
// value, and the longer PUSH imm32 would make the generic_interrupts table twice as large
|
||||
// (containing lots of useless NOPs).
|
||||
irq_trigger((code as i32).wrapping_add(128) as u8);
|
||||
irq_trigger((code as i32).wrapping_add(128) as u8, &mut token);
|
||||
|
||||
unsafe { lapic_eoi() };
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::{context, scheme::acpi, time};
|
||||
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
use crate::{
|
||||
sync::CleanLockToken,
|
||||
syscall::io::{Io, Pio},
|
||||
};
|
||||
|
||||
pub unsafe fn kreset() -> ! {
|
||||
unsafe {
|
||||
@@ -56,11 +59,11 @@ pub unsafe fn emergency_reset() -> ! {
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
fn userspace_acpi_shutdown() {
|
||||
fn userspace_acpi_shutdown(token: &mut CleanLockToken) {
|
||||
info!("Notifying any potential ACPI driver");
|
||||
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
|
||||
// shutdown).
|
||||
if !acpi::register_kstop() {
|
||||
if !acpi::register_kstop(token) {
|
||||
// There was no context to switch to.
|
||||
info!("No ACPI driver was alive to handle shutdown.");
|
||||
return;
|
||||
@@ -76,7 +79,7 @@ fn userspace_acpi_shutdown() {
|
||||
// TODO: Switch directly to whichever process is handling the kstop pipe. We would add an
|
||||
// event flag like EVENT_DIRECT, which has already been suggested for IRQs.
|
||||
// TODO: Waitpid with timeout? Because, what if the ACPI driver would crash?
|
||||
let _ = context::switch();
|
||||
let _ = context::switch(token);
|
||||
|
||||
let current = time::monotonic();
|
||||
if current - initial > time::NANOS_PER_SEC {
|
||||
@@ -86,12 +89,12 @@ fn userspace_acpi_shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn kstop() -> ! {
|
||||
pub unsafe fn kstop(token: &mut CleanLockToken) -> ! {
|
||||
unsafe {
|
||||
info!("Running kstop()");
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
userspace_acpi_shutdown();
|
||||
userspace_acpi_shutdown(token);
|
||||
|
||||
// Magic shutdown code for bochs and qemu (older versions).
|
||||
for c in "Shutdown".bytes() {
|
||||
|
||||
+10
-7
@@ -19,6 +19,7 @@ use crate::{
|
||||
paging::{RmmA, RmmArch},
|
||||
percpu::PercpuBlock,
|
||||
scheme::{CallerCtx, FileHandle, SchemeId, SchemeNamespace},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
use crate::syscall::error::{Error, Result, EAGAIN, EBADF, EEXIST, EINVAL, EMFILE, ESRCH};
|
||||
@@ -428,11 +429,11 @@ pub struct BorrowedHtBuf {
|
||||
head_and_not_tail: bool,
|
||||
}
|
||||
impl BorrowedHtBuf {
|
||||
pub fn head() -> Result<Self> {
|
||||
pub fn head(token: &mut CleanLockToken) -> Result<Self> {
|
||||
Ok(Self {
|
||||
inner: Some(
|
||||
context::current()
|
||||
.write()
|
||||
.write(token.token())
|
||||
.syscall_head
|
||||
.take()
|
||||
.ok_or(Error::new(EAGAIN))?,
|
||||
@@ -440,11 +441,11 @@ impl BorrowedHtBuf {
|
||||
head_and_not_tail: true,
|
||||
})
|
||||
}
|
||||
pub fn tail() -> Result<Self> {
|
||||
pub fn tail(token: &mut CleanLockToken) -> Result<Self> {
|
||||
Ok(Self {
|
||||
inner: Some(
|
||||
context::current()
|
||||
.write()
|
||||
.write(token.token())
|
||||
.syscall_tail
|
||||
.take()
|
||||
.ok_or(Error::new(EAGAIN))?,
|
||||
@@ -495,7 +496,9 @@ impl Drop for BorrowedHtBuf {
|
||||
let Some(inner) = self.inner.take() else {
|
||||
return;
|
||||
};
|
||||
match context.write() {
|
||||
//TODO: do not allow drop so lock token can be passed in
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
match context.write(token.token()) {
|
||||
mut context => {
|
||||
(if self.head_and_not_tail {
|
||||
&mut context.syscall_head
|
||||
@@ -871,10 +874,10 @@ impl FdTbl {
|
||||
FileHandle::from(start | UPPER_FDTBL_TAG)
|
||||
}
|
||||
|
||||
pub fn force_close_all(&mut self) {
|
||||
pub fn force_close_all(&mut self, token: &mut CleanLockToken) {
|
||||
for file_opt in self.iter_mut() {
|
||||
if let Some(file) = file_opt.take() {
|
||||
let _ = file.close();
|
||||
let _ = file.close(token);
|
||||
}
|
||||
}
|
||||
self.active_count = 0;
|
||||
|
||||
+6
-5
@@ -3,6 +3,7 @@
|
||||
use crate::{
|
||||
event,
|
||||
scheme::{self, SchemeId},
|
||||
sync::CleanLockToken,
|
||||
syscall::error::{Error, Result, EBADF},
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
@@ -70,22 +71,22 @@ pub struct FileDescriptor {
|
||||
impl FileDescription {
|
||||
/// Try closing a file, although at this point the description will be destroyed anyway, if
|
||||
/// doing so fails.
|
||||
pub fn try_close(self) -> Result<()> {
|
||||
pub fn try_close(self, token: &mut CleanLockToken) -> Result<()> {
|
||||
event::unregister_file(self.scheme, self.number);
|
||||
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(self.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
scheme.close(self.number)
|
||||
scheme.close(self.number, token)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileDescriptor {
|
||||
pub fn close(self) -> Result<()> {
|
||||
pub fn close(self, token: &mut CleanLockToken) -> Result<()> {
|
||||
if let Ok(file) = Arc::try_unwrap(self.description).map(RwLock::into_inner) {
|
||||
file.try_close()?;
|
||||
file.try_close(token)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+36
-19
@@ -21,6 +21,7 @@ use crate::{
|
||||
paging::{Page, PageFlags, PageMapper, RmmA, TableKind, VirtualAddress},
|
||||
percpu::PercpuBlock,
|
||||
scheme::{self, KernelSchemes},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
use super::{context::HardBlockedReason, file::FileDescription};
|
||||
@@ -51,7 +52,7 @@ pub struct UnmapResult {
|
||||
pub flags: MunmapFlags,
|
||||
}
|
||||
impl UnmapResult {
|
||||
pub fn unmap(mut self) -> Result<()> {
|
||||
pub fn unmap(mut self, token: &mut CleanLockToken) -> Result<()> {
|
||||
let Some(GrantFileRef {
|
||||
base_offset,
|
||||
description,
|
||||
@@ -64,14 +65,13 @@ impl UnmapResult {
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
};
|
||||
|
||||
let funmap_result = scheme::schemes()
|
||||
.get(scheme_id)
|
||||
.cloned()
|
||||
let scheme_opt = scheme::schemes(token.token()).get(scheme_id).cloned();
|
||||
let funmap_result = scheme_opt
|
||||
.ok_or(Error::new(ENODEV))
|
||||
.and_then(|scheme| scheme.kfunmap(number, base_offset, self.size, self.flags));
|
||||
.and_then(|scheme| scheme.kfunmap(number, base_offset, self.size, self.flags, token));
|
||||
|
||||
if let Ok(fd) = Arc::try_unwrap(description) {
|
||||
fd.into_inner().try_close()?;
|
||||
fd.into_inner().try_close(token)?;
|
||||
}
|
||||
funmap_result?;
|
||||
|
||||
@@ -502,7 +502,11 @@ impl AddrSpaceWrapper {
|
||||
}
|
||||
/// Borrows a page from user memory, requiring that the frame be Allocated and read/write. This
|
||||
/// is intended to be used for user-kernel shared memory.
|
||||
pub fn borrow_frame_enforce_rw_allocated(self: &Arc<Self>, page: Page) -> Result<RaiiFrame> {
|
||||
pub fn borrow_frame_enforce_rw_allocated(
|
||||
self: &Arc<Self>,
|
||||
page: Page,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<RaiiFrame> {
|
||||
let mut guard = self.acquire_write();
|
||||
|
||||
let (_start_page, info) = guard.grants.contains(page).ok_or(Error::new(EINVAL))?;
|
||||
@@ -519,8 +523,9 @@ impl AddrSpaceWrapper {
|
||||
{
|
||||
Frame::containing(f)
|
||||
} else {
|
||||
let (frame, flush, new_guard) = correct_inner(self, guard, page, AccessMode::Write, 0)
|
||||
.map_err(|_| Error::new(ENOMEM))?;
|
||||
let (frame, flush, new_guard) =
|
||||
correct_inner(self, guard, page, AccessMode::Write, 0, token)
|
||||
.map_err(|_| Error::new(ENOMEM))?;
|
||||
flush.flush();
|
||||
guard = new_guard;
|
||||
|
||||
@@ -1333,6 +1338,7 @@ impl Grant {
|
||||
lock: &AddrSpaceWrapper,
|
||||
mapper: &mut PageMapper,
|
||||
flusher: &mut Flusher,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<Self> {
|
||||
if let Some(src) = src {
|
||||
let mut guard = src.addr_space_guard;
|
||||
@@ -1359,6 +1365,7 @@ impl Grant {
|
||||
src_page,
|
||||
AccessMode::Read,
|
||||
0,
|
||||
token,
|
||||
)
|
||||
.map_err(|_| Error::new(EIO))?;
|
||||
guard = new_guard;
|
||||
@@ -1383,6 +1390,7 @@ impl Grant {
|
||||
src_page,
|
||||
AccessMode::Read,
|
||||
0,
|
||||
token,
|
||||
)
|
||||
.map_err(|_| Error::new(EIO))?;
|
||||
guard = new_guard;
|
||||
@@ -2232,6 +2240,9 @@ pub struct Table {
|
||||
|
||||
impl Drop for AddrSpace {
|
||||
fn drop(&mut self) {
|
||||
//TODO: DANGER: unmap requires a CleanLockToken, this cheats!
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
for mut grant in core::mem::take(&mut self.grants).into_iter() {
|
||||
// Unpinning the grant is allowed, because pinning only occurs in UserScheme calls to
|
||||
// prevent unmapping the mapped range twice (which would corrupt only the scheme
|
||||
@@ -2245,7 +2256,7 @@ impl Drop for AddrSpace {
|
||||
// the underlying pages (and send some funmaps).
|
||||
let res = grant.unmap(&mut self.table.utable, &mut NopFlusher);
|
||||
|
||||
let _ = res.unmap();
|
||||
let _ = res.unmap(&mut token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2372,14 +2383,18 @@ pub unsafe fn copy_frame_to_frame_directly(dst: Frame, src: Frame) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_correcting_page_tables(faulting_page: Page, access: AccessMode) -> Result<(), PfError> {
|
||||
pub fn try_correcting_page_tables(
|
||||
faulting_page: Page,
|
||||
access: AccessMode,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<(), PfError> {
|
||||
let Ok(addr_space_lock) = AddrSpace::current() else {
|
||||
debug!("User page fault without address space being set.");
|
||||
return Err(PfError::Segv);
|
||||
};
|
||||
|
||||
let lock = &addr_space_lock;
|
||||
let (_, flush, _) = correct_inner(lock, lock.acquire_write(), faulting_page, access, 0)?;
|
||||
let (_, flush, _) = correct_inner(lock, lock.acquire_write(), faulting_page, access, 0, token)?;
|
||||
|
||||
flush.flush();
|
||||
|
||||
@@ -2391,6 +2406,7 @@ fn correct_inner<'l>(
|
||||
faulting_page: Page,
|
||||
access: AccessMode,
|
||||
recursion_level: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<(Frame, PageFlush<RmmA>, RwLockWriteGuard<'l, AddrSpace>), PfError> {
|
||||
let mut addr_space = &mut *addr_space_guard;
|
||||
let mut flusher = Flusher::with_cpu_set(&mut addr_space.used_by, &addr_space_lock.tlb_ack);
|
||||
@@ -2533,6 +2549,7 @@ fn correct_inner<'l>(
|
||||
src_page,
|
||||
AccessMode::Read,
|
||||
new_recursion_level,
|
||||
token,
|
||||
)?
|
||||
};
|
||||
|
||||
@@ -2610,7 +2627,7 @@ fn correct_inner<'l>(
|
||||
let (scheme_id, scheme_number) = match file_ref.description.read() {
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
};
|
||||
let user_inner = scheme::schemes()
|
||||
let user_inner = scheme::schemes(token.token())
|
||||
.get(scheme_id)
|
||||
.and_then(|s| {
|
||||
if let KernelSchemes::User(user) = s {
|
||||
@@ -2623,18 +2640,18 @@ fn correct_inner<'l>(
|
||||
|
||||
let offset = file_ref.base_offset as u64 + (pages_from_grant_start * PAGE_SIZE) as u64;
|
||||
user_inner
|
||||
.request_fmap(scheme_number, offset, 1, flags)
|
||||
.request_fmap(scheme_number, offset, 1, flags, token)
|
||||
.unwrap();
|
||||
|
||||
let context_lock = crate::context::current();
|
||||
context_lock
|
||||
.write()
|
||||
.write(token.token())
|
||||
.hard_block(HardBlockedReason::AwaitingMmap { file_ref });
|
||||
|
||||
super::switch();
|
||||
super::switch(token);
|
||||
|
||||
let frame = context_lock
|
||||
.write()
|
||||
.write(token.token())
|
||||
.fmap_ret
|
||||
.take()
|
||||
.ok_or(PfError::NonfatalInternalError)?;
|
||||
@@ -2678,9 +2695,9 @@ pub struct BorrowedFmapSource<'a> {
|
||||
pub addr_space_guard: RwLockWriteGuard<'a, AddrSpace>,
|
||||
}
|
||||
|
||||
pub fn handle_notify_files(notify_files: Vec<UnmapResult>) {
|
||||
pub fn handle_notify_files(notify_files: Vec<UnmapResult>, token: &mut CleanLockToken) {
|
||||
for file in notify_files {
|
||||
let _ = file.unmap();
|
||||
let _ = file.unmap(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+34
-32
@@ -2,12 +2,8 @@
|
||||
//!
|
||||
//! For resources on contexts, please consult [wikipedia](https://en.wikipedia.org/wiki/Context_switch) and [osdev](https://wiki.osdev.org/Context_Switching)
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
use alloc::{collections::BTreeSet, sync::Arc};
|
||||
|
||||
use spin::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use spinning_top::RwSpinlock;
|
||||
use core::num::NonZeroUsize;
|
||||
use syscall::ENOMEM;
|
||||
|
||||
use crate::{
|
||||
@@ -15,6 +11,10 @@ use crate::{
|
||||
cpu_set::LogicalCpuSet,
|
||||
paging::{RmmA, RmmArch, TableKind},
|
||||
percpu::PercpuBlock,
|
||||
sync::{
|
||||
ArcRwLockWriteGuard, CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard,
|
||||
L0, L1, L2,
|
||||
},
|
||||
syscall::error::{Error, Result},
|
||||
};
|
||||
|
||||
@@ -24,6 +24,9 @@ pub use self::{
|
||||
switch::switch,
|
||||
};
|
||||
|
||||
pub type ContextLock = RwLock<L2, Context>;
|
||||
pub type ArcContextLockWriteGuard = ArcRwLockWriteGuard<L2, Context>;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[path = "arch/aarch64.rs"]
|
||||
mod arch;
|
||||
@@ -67,9 +70,21 @@ pub use self::arch::empty_cr3;
|
||||
|
||||
// Set of weak references to all contexts available for scheduling. The only strong references are
|
||||
// the context file descriptors.
|
||||
static CONTEXTS: RwLock<BTreeSet<ContextRef>> = RwLock::new(BTreeSet::new());
|
||||
static CONTEXTS: RwLock<L1, BTreeSet<ContextRef>> = RwLock::new(BTreeSet::new());
|
||||
|
||||
pub fn init() {
|
||||
/// Get the global schemes list, const
|
||||
pub fn contexts<'a>(token: LockToken<'a, L0>) -> RwLockReadGuard<'a, L1, BTreeSet<ContextRef>> {
|
||||
CONTEXTS.read(token)
|
||||
}
|
||||
|
||||
/// Get the global schemes list, mutable
|
||||
pub fn contexts_mut<'a>(
|
||||
token: LockToken<'a, L0>,
|
||||
) -> RwLockWriteGuard<'a, L1, BTreeSet<ContextRef>> {
|
||||
CONTEXTS.write(token)
|
||||
}
|
||||
|
||||
pub fn init(token: &mut CleanLockToken) {
|
||||
let owner = None; // kmain not owned by any fd
|
||||
let mut context = Context::new(owner).expect("failed to create kmain context");
|
||||
context.sched_affinity = LogicalCpuSet::empty();
|
||||
@@ -84,11 +99,9 @@ pub fn init() {
|
||||
context.running = true;
|
||||
context.cpu_id = Some(crate::cpu_id());
|
||||
|
||||
let context_lock = Arc::new(RwSpinlock::new(context));
|
||||
let context_lock = Arc::new(ContextLock::new(context));
|
||||
|
||||
CONTEXTS
|
||||
.write()
|
||||
.insert(ContextRef(Arc::clone(&context_lock)));
|
||||
contexts_mut(token.token()).insert(ContextRef(Arc::clone(&context_lock)));
|
||||
|
||||
unsafe {
|
||||
let percpu = PercpuBlock::current();
|
||||
@@ -99,35 +112,25 @@ pub fn init() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the global schemes list, const
|
||||
pub fn contexts() -> RwLockReadGuard<'static, BTreeSet<ContextRef>> {
|
||||
CONTEXTS.read()
|
||||
}
|
||||
|
||||
/// Get the global schemes list, mutable
|
||||
pub fn contexts_mut() -> RwLockWriteGuard<'static, BTreeSet<ContextRef>> {
|
||||
CONTEXTS.write()
|
||||
}
|
||||
|
||||
pub fn current() -> Arc<RwSpinlock<Context>> {
|
||||
pub fn current() -> Arc<ContextLock> {
|
||||
PercpuBlock::current()
|
||||
.switch_internals
|
||||
.with_context(|context| Arc::clone(context))
|
||||
}
|
||||
pub fn try_current() -> Option<Arc<RwSpinlock<Context>>> {
|
||||
pub fn try_current() -> Option<Arc<ContextLock>> {
|
||||
PercpuBlock::current()
|
||||
.switch_internals
|
||||
.try_with_context(|context| context.map(Arc::clone))
|
||||
}
|
||||
pub fn is_current(context: &Arc<RwSpinlock<Context>>) -> bool {
|
||||
pub fn is_current(context: &Arc<ContextLock>) -> bool {
|
||||
PercpuBlock::current()
|
||||
.switch_internals
|
||||
.with_context(|current| Arc::ptr_eq(context, current))
|
||||
}
|
||||
|
||||
pub struct ContextRef(pub Arc<RwSpinlock<Context>>);
|
||||
pub struct ContextRef(pub Arc<ContextLock>);
|
||||
impl ContextRef {
|
||||
pub fn upgrade(&self) -> Option<Arc<RwSpinlock<Context>>> {
|
||||
pub fn upgrade(&self) -> Option<Arc<ContextLock>> {
|
||||
Some(Arc::clone(&self.0))
|
||||
}
|
||||
}
|
||||
@@ -154,18 +157,17 @@ pub fn spawn(
|
||||
userspace_allowed: bool,
|
||||
owner_proc_id: Option<NonZeroUsize>,
|
||||
func: extern "C" fn(),
|
||||
) -> Result<Arc<RwSpinlock<Context>>> {
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<Arc<ContextLock>> {
|
||||
let stack = Kstack::new()?;
|
||||
|
||||
let context_lock = Arc::try_new(RwSpinlock::new(Context::new(owner_proc_id)?))
|
||||
let context_lock = Arc::try_new(ContextLock::new(Context::new(owner_proc_id)?))
|
||||
.map_err(|_| Error::new(ENOMEM))?;
|
||||
|
||||
CONTEXTS
|
||||
.write()
|
||||
.insert(ContextRef(Arc::clone(&context_lock)));
|
||||
contexts_mut(token.token()).insert(ContextRef(Arc::clone(&context_lock)));
|
||||
|
||||
{
|
||||
let mut context = context_lock.write();
|
||||
let mut context = context_lock.write(token.token());
|
||||
let _ = context.set_addr_space(Some(AddrSpaceWrapper::new()?));
|
||||
context
|
||||
.arch
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use crate::{context, syscall::flag::SigcontrolFlags};
|
||||
use crate::{context, sync::CleanLockToken, syscall::flag::SigcontrolFlags};
|
||||
|
||||
pub fn signal_handler() {
|
||||
pub fn signal_handler(token: &mut CleanLockToken) {
|
||||
let context_lock = context::current();
|
||||
let mut context_guard = context_lock.write();
|
||||
let mut context_guard = context_lock.write(token.token());
|
||||
let context = &mut *context_guard;
|
||||
|
||||
let being_sigkilled = context.being_sigkilled;
|
||||
@@ -12,7 +12,7 @@ pub fn signal_handler() {
|
||||
if being_sigkilled {
|
||||
drop(context_guard);
|
||||
drop(context_lock);
|
||||
crate::syscall::process::exit_this_context(None);
|
||||
crate::syscall::process::exit_this_context(None, token);
|
||||
}
|
||||
|
||||
/*let thumbs_down = ptrace::breakpoint_callback(
|
||||
@@ -72,9 +72,11 @@ pub fn signal_handler() {
|
||||
);
|
||||
}
|
||||
pub fn excp_handler(excp: syscall::Exception) {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
let current = context::current();
|
||||
|
||||
let mut context = current.write();
|
||||
let context = current.write(token.token());
|
||||
|
||||
let Some(eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else {
|
||||
// TODO: Let procmgr print this?
|
||||
@@ -87,7 +89,7 @@ pub fn excp_handler(excp: syscall::Exception) {
|
||||
drop(context);
|
||||
// TODO: Allow exceptions to be caught by tracer etc, without necessarily exiting the
|
||||
// context (closing files, dropping AddrSpace, etc)
|
||||
crate::syscall::process::exit_this_context(Some(excp));
|
||||
crate::syscall::process::exit_this_context(Some(excp), &mut token);
|
||||
};
|
||||
// TODO
|
||||
/*
|
||||
|
||||
+23
-20
@@ -9,15 +9,16 @@ use core::{
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use spinning_top::{guard::ArcRwSpinlockWriteGuard, RwSpinlock};
|
||||
use syscall::PtraceFlags;
|
||||
|
||||
use crate::{
|
||||
context::{arch, contexts, Context},
|
||||
context::{arch, contexts, ArcContextLockWriteGuard, Context, ContextLock},
|
||||
cpu_set::LogicalCpuId,
|
||||
cpu_stats,
|
||||
percpu::PercpuBlock,
|
||||
ptrace, time,
|
||||
ptrace,
|
||||
sync::CleanLockToken,
|
||||
time,
|
||||
};
|
||||
|
||||
use super::ContextRef;
|
||||
@@ -71,8 +72,8 @@ unsafe fn update_runnable(context: &mut Context, cpu_id: LogicalCpuId) -> Update
|
||||
}
|
||||
|
||||
struct SwitchResultInner {
|
||||
_prev_guard: ArcRwSpinlockWriteGuard<Context>,
|
||||
_next_guard: ArcRwSpinlockWriteGuard<Context>,
|
||||
_prev_guard: ArcContextLockWriteGuard,
|
||||
_next_guard: ArcContextLockWriteGuard,
|
||||
}
|
||||
|
||||
/// Tick function to update PIT ticks and trigger a context switch if necessary.
|
||||
@@ -81,7 +82,7 @@ struct SwitchResultInner {
|
||||
/// switch if the counter reaches a set threshold (e.g., every 3 ticks).
|
||||
///
|
||||
/// The function also calls the signal handler after switching contexts.
|
||||
pub fn tick() {
|
||||
pub fn tick(token: &mut CleanLockToken) {
|
||||
let ticks_cell = &PercpuBlock::current().switch_internals.pit_ticks;
|
||||
|
||||
let new_ticks = ticks_cell.get() + 1;
|
||||
@@ -89,8 +90,8 @@ pub fn tick() {
|
||||
|
||||
// Trigger a context switch after every 3 ticks (approx. 6.75 ms).
|
||||
if new_ticks >= 3 {
|
||||
switch();
|
||||
crate::context::signal::signal_handler();
|
||||
switch(token);
|
||||
crate::context::signal::signal_handler(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ pub enum SwitchResult {
|
||||
/// - `SwitchResult::Switched`: Indicates a successful switch to a new context.
|
||||
/// - `SwitchResult::AllContextsIdle`: Indicates all contexts are idle, and the CPU will switch
|
||||
/// to an idle context.
|
||||
pub fn switch() -> SwitchResult {
|
||||
pub fn switch(token: &mut CleanLockToken) -> SwitchResult {
|
||||
let percpu = PercpuBlock::current();
|
||||
cpu_stats::add_context_switch();
|
||||
percpu
|
||||
@@ -161,11 +162,12 @@ pub fn switch() -> SwitchResult {
|
||||
|
||||
let mut switch_context_opt = None;
|
||||
{
|
||||
let contexts = contexts();
|
||||
let contexts = contexts(token.token());
|
||||
|
||||
// Lock the previous context.
|
||||
let prev_context_lock = crate::context::current();
|
||||
let prev_context_guard = prev_context_lock.write_arc();
|
||||
// We are careful not to lock this context twice
|
||||
let prev_context_guard = unsafe { prev_context_lock.write_arc() };
|
||||
|
||||
let idle_context = percpu.switch_internals.idle_context();
|
||||
|
||||
@@ -201,7 +203,8 @@ pub fn switch() -> SwitchResult {
|
||||
|
||||
{
|
||||
// Lock next context
|
||||
let mut next_context_guard = next_context_lock.write_arc();
|
||||
// We are careful not to lock this context twice
|
||||
let mut next_context_guard = unsafe { next_context_lock.write_arc() };
|
||||
|
||||
// Check if the context is runnable and can be switched to.
|
||||
if let UpdateResult::CanSwitch =
|
||||
@@ -234,7 +237,7 @@ pub fn switch() -> SwitchResult {
|
||||
let percpu = PercpuBlock::current();
|
||||
unsafe {
|
||||
percpu.switch_internals.set_current_context(Arc::clone(
|
||||
ArcRwSpinlockWriteGuard::rwlock(&next_context_guard),
|
||||
ArcContextLockWriteGuard::rwlock(&next_context_guard),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -319,10 +322,10 @@ pub struct ContextSwitchPercpu {
|
||||
switch_result: Cell<Option<SwitchResultInner>>,
|
||||
pit_ticks: Cell<usize>,
|
||||
|
||||
current_ctxt: RefCell<Option<Arc<RwSpinlock<Context>>>>,
|
||||
current_ctxt: RefCell<Option<Arc<ContextLock>>>,
|
||||
|
||||
/// The idle process.
|
||||
idle_ctxt: RefCell<Option<Arc<RwSpinlock<Context>>>>,
|
||||
idle_ctxt: RefCell<Option<Arc<ContextLock>>>,
|
||||
|
||||
pub(crate) being_sigkilled: Cell<bool>,
|
||||
}
|
||||
@@ -345,7 +348,7 @@ impl ContextSwitchPercpu {
|
||||
///
|
||||
/// # Returns
|
||||
/// The result of applying `f` to the current context.
|
||||
pub fn with_context<T>(&self, f: impl FnOnce(&Arc<RwSpinlock<Context>>) -> T) -> T {
|
||||
pub fn with_context<T>(&self, f: impl FnOnce(&Arc<ContextLock>) -> T) -> T {
|
||||
f(self
|
||||
.current_ctxt
|
||||
.borrow()
|
||||
@@ -360,7 +363,7 @@ impl ContextSwitchPercpu {
|
||||
///
|
||||
/// # Returns
|
||||
/// The result of applying `f` to the current context if any.
|
||||
pub fn try_with_context<T>(&self, f: impl FnOnce(Option<&Arc<RwSpinlock<Context>>>) -> T) -> T {
|
||||
pub fn try_with_context<T>(&self, f: impl FnOnce(Option<&Arc<ContextLock>>) -> T) -> T {
|
||||
f(self.current_ctxt.borrow().as_ref())
|
||||
}
|
||||
|
||||
@@ -371,7 +374,7 @@ impl ContextSwitchPercpu {
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `new`: The new context to be set as the current context.
|
||||
pub unsafe fn set_current_context(&self, new: Arc<RwSpinlock<Context>>) {
|
||||
pub unsafe fn set_current_context(&self, new: Arc<ContextLock>) {
|
||||
*self.current_ctxt.borrow_mut() = Some(new);
|
||||
}
|
||||
|
||||
@@ -382,7 +385,7 @@ impl ContextSwitchPercpu {
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `new`: The new context to be set as the idle context.
|
||||
pub unsafe fn set_idle_context(&self, new: Arc<RwSpinlock<Context>>) {
|
||||
pub unsafe fn set_idle_context(&self, new: Arc<ContextLock>) {
|
||||
*self.idle_ctxt.borrow_mut() = Some(new);
|
||||
}
|
||||
|
||||
@@ -390,7 +393,7 @@ impl ContextSwitchPercpu {
|
||||
///
|
||||
/// # Returns
|
||||
/// A reference to the idle context.
|
||||
pub fn idle_context(&self) -> Arc<RwSpinlock<Context>> {
|
||||
pub fn idle_context(&self) -> Arc<ContextLock> {
|
||||
Arc::clone(
|
||||
self.idle_ctxt
|
||||
.borrow()
|
||||
|
||||
+41
-30
@@ -1,9 +1,10 @@
|
||||
use alloc::collections::VecDeque;
|
||||
use spin::{Mutex, MutexGuard, Once};
|
||||
use spin::Once;
|
||||
|
||||
use crate::{
|
||||
event,
|
||||
scheme::SchemeId,
|
||||
sync::{CleanLockToken, LockToken, Mutex, MutexGuard, L0, L1},
|
||||
syscall::{
|
||||
data::TimeSpec,
|
||||
flag::{CLOCK_MONOTONIC, CLOCK_REALTIME, EVENT_READ},
|
||||
@@ -21,20 +22,26 @@ struct Timeout {
|
||||
|
||||
type Registry = VecDeque<Timeout>;
|
||||
|
||||
static REGISTRY: Once<Mutex<Registry>> = Once::new();
|
||||
static REGISTRY: Once<Mutex<L1, Registry>> = Once::new();
|
||||
|
||||
/// Initialize registry, called if needed
|
||||
fn init_registry() -> Mutex<Registry> {
|
||||
fn init_registry() -> Mutex<L1, Registry> {
|
||||
Mutex::new(Registry::new())
|
||||
}
|
||||
|
||||
/// Get the global timeouts list
|
||||
fn registry() -> MutexGuard<'static, Registry> {
|
||||
REGISTRY.call_once(init_registry).lock()
|
||||
fn registry<'a>(token: LockToken<'a, L0>) -> MutexGuard<'a, L1, Registry> {
|
||||
REGISTRY.call_once(init_registry).lock(token)
|
||||
}
|
||||
|
||||
pub fn register(scheme_id: SchemeId, event_id: usize, clock: usize, time: TimeSpec) {
|
||||
let mut registry = registry();
|
||||
pub fn register(
|
||||
scheme_id: SchemeId,
|
||||
event_id: usize,
|
||||
clock: usize,
|
||||
time: TimeSpec,
|
||||
token: &mut CleanLockToken,
|
||||
) {
|
||||
let mut registry = registry(token.token());
|
||||
registry.push_back(Timeout {
|
||||
scheme_id,
|
||||
event_id,
|
||||
@@ -43,34 +50,38 @@ pub fn register(scheme_id: SchemeId, event_id: usize, clock: usize, time: TimeSp
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trigger() {
|
||||
let mut registry = registry();
|
||||
|
||||
pub fn trigger(token: &mut CleanLockToken) {
|
||||
let mono = time::monotonic();
|
||||
let real = time::realtime();
|
||||
|
||||
let mut i = 0;
|
||||
while i < registry.len() {
|
||||
let trigger = match registry[i].clock {
|
||||
CLOCK_MONOTONIC => {
|
||||
let time = registry[i].time;
|
||||
mono >= time
|
||||
}
|
||||
CLOCK_REALTIME => {
|
||||
let time = registry[i].time;
|
||||
real >= time
|
||||
}
|
||||
clock => {
|
||||
println!("timeout::trigger: unknown clock {}", clock);
|
||||
true
|
||||
}
|
||||
};
|
||||
loop {
|
||||
let mut registry = registry(token.token());
|
||||
let timeout = if i < registry.len() {
|
||||
let trigger = match registry[i].clock {
|
||||
CLOCK_MONOTONIC => {
|
||||
let time = registry[i].time;
|
||||
mono >= time
|
||||
}
|
||||
CLOCK_REALTIME => {
|
||||
let time = registry[i].time;
|
||||
real >= time
|
||||
}
|
||||
clock => {
|
||||
println!("timeout::trigger: unknown clock {}", clock);
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
if trigger {
|
||||
let timeout = registry.remove(i).unwrap();
|
||||
event::trigger(timeout.scheme_id, timeout.event_id, EVENT_READ);
|
||||
if trigger {
|
||||
registry.remove(i).unwrap()
|
||||
} else {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
break;
|
||||
};
|
||||
event::trigger(timeout.scheme_id, timeout.event_id, EVENT_READ);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,14 +1,14 @@
|
||||
use crate::{
|
||||
context::Context,
|
||||
context::{Context, ContextLock},
|
||||
memory::{get_page_info, the_zeroed_frame, Frame, RefCount},
|
||||
paging::{RmmA, RmmArch, TableKind, PAGE_SIZE},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use spinning_top::RwSpinlock;
|
||||
|
||||
/// Super unsafe due to page table switching and raw pointers!
|
||||
pub unsafe fn debugger(target_id: Option<*const RwSpinlock<Context>>) {
|
||||
pub unsafe fn debugger(target_id: Option<*const ContextLock>, token: &mut CleanLockToken) {
|
||||
println!("DEBUGGER START");
|
||||
println!();
|
||||
|
||||
@@ -21,7 +21,7 @@ pub unsafe fn debugger(target_id: Option<*const RwSpinlock<Context>>) {
|
||||
|
||||
let old_table = unsafe { RmmA::table(TableKind::User) };
|
||||
|
||||
for context_lock in crate::context::contexts().iter() {
|
||||
for context_lock in crate::context::contexts(token.token()).iter() {
|
||||
if target_id.map_or(false, |target_id| Arc::as_ptr(&context_lock.0) != target_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use syscall::Pio;
|
||||
use crate::{
|
||||
devices::{uart_16550, uart_pl011},
|
||||
scheme::debug::{debug_input, debug_notify},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -31,30 +32,30 @@ impl SerialKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(&mut self) {
|
||||
pub fn receive(&mut self, token: &mut CleanLockToken) {
|
||||
//TODO: make PL011 receive work the same way as NS16550
|
||||
match self {
|
||||
Self::NotPresent => {}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Self::Ns16550Pio(inner) => {
|
||||
while let Some(c) = inner.receive() {
|
||||
debug_input(c);
|
||||
debug_input(c, token);
|
||||
}
|
||||
debug_notify();
|
||||
debug_notify(token);
|
||||
}
|
||||
Self::Ns16550u8(inner) => {
|
||||
while let Some(c) = inner.receive() {
|
||||
debug_input(c);
|
||||
debug_input(c, token);
|
||||
}
|
||||
debug_notify();
|
||||
debug_notify(token);
|
||||
}
|
||||
Self::Ns16550u32(inner) => {
|
||||
while let Some(c) = inner.receive() {
|
||||
debug_input(c);
|
||||
debug_input(c, token);
|
||||
}
|
||||
debug_notify();
|
||||
debug_notify(token);
|
||||
}
|
||||
Self::Pl011(inner) => inner.receive(),
|
||||
Self::Pl011(inner) => inner.receive(token),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
use core::ptr;
|
||||
|
||||
use crate::scheme::debug::{debug_input, debug_notify};
|
||||
use crate::{
|
||||
scheme::debug::{debug_input, debug_notify},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
/// UARTFR
|
||||
@@ -184,7 +187,7 @@ impl SerialPort {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(&mut self) {
|
||||
pub fn receive(&mut self, token: &mut CleanLockToken) {
|
||||
let mut flags = self.intr_stats();
|
||||
let chk_flags = UartRisFlags::RTIS | UartRisFlags::RXIS;
|
||||
while (flags & chk_flags).bits() != 0 {
|
||||
@@ -203,13 +206,13 @@ impl SerialPort {
|
||||
}
|
||||
let c = self.read_reg(self.data_reg) as u8;
|
||||
if c != 0 {
|
||||
debug_input(c);
|
||||
debug_input(c, token);
|
||||
}
|
||||
}
|
||||
|
||||
flags = self.intr_stats();
|
||||
}
|
||||
debug_notify();
|
||||
debug_notify(token);
|
||||
}
|
||||
|
||||
pub fn send(&mut self, data: u8) {
|
||||
|
||||
+9
-6
@@ -1,12 +1,15 @@
|
||||
use super::travel_interrupt_ctrl;
|
||||
use crate::{arch::device::irqchip::new_irqchip, cpu_set::LogicalCpuId, scheme::irq::irq_trigger};
|
||||
use crate::{
|
||||
arch::device::irqchip::new_irqchip, cpu_set::LogicalCpuId, scheme::irq::irq_trigger,
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
use syscall::{Error, Result, EINVAL};
|
||||
|
||||
pub trait InterruptHandler {
|
||||
fn irq_handler(&mut self, irq: u32);
|
||||
fn irq_handler(&mut self, irq: u32, token: &mut CleanLockToken);
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -294,18 +297,18 @@ impl IrqChipCore {
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_xlate(irq_data)
|
||||
}
|
||||
|
||||
pub fn trigger_virq(&mut self, virq: u32) {
|
||||
pub fn trigger_virq(&mut self, virq: u32, token: &mut CleanLockToken) {
|
||||
if virq < 1024 {
|
||||
let desc = &mut self.irq_desc[virq as usize];
|
||||
match &mut desc.handler {
|
||||
Some(handler) => {
|
||||
handler.irq_handler(virq);
|
||||
handler.irq_handler(virq, token);
|
||||
}
|
||||
_ => {
|
||||
if let Some(ic_idx) = desc.basic.child_ic_idx {
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_handler(virq);
|
||||
self.irq_chip_list.chips[ic_idx].ic.irq_handler(virq, token);
|
||||
} else {
|
||||
irq_trigger(virq as u8);
|
||||
irq_trigger(virq as u8, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-29
@@ -1,12 +1,14 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use hashbrown::HashMap;
|
||||
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use spin::Once;
|
||||
|
||||
use crate::{
|
||||
context,
|
||||
scheme::{self, SchemeId},
|
||||
sync::WaitQueue,
|
||||
sync::{
|
||||
CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, WaitQueue, L0, L1,
|
||||
},
|
||||
syscall::{
|
||||
data::Event,
|
||||
error::{Error, Result, EBADF},
|
||||
@@ -30,15 +32,16 @@ impl EventQueue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: UserSliceWo, block: bool) -> Result<usize> {
|
||||
self.queue.receive_into_user(buf, block, "EventQueue::read")
|
||||
pub fn read(&self, buf: UserSliceWo, block: bool, token: &mut CleanLockToken) -> Result<usize> {
|
||||
self.queue
|
||||
.receive_into_user(buf, block, "EventQueue::read", token)
|
||||
}
|
||||
|
||||
pub fn write(&self, events: &[Event]) -> Result<usize> {
|
||||
pub fn write(&self, events: &[Event], token: &mut CleanLockToken) -> Result<usize> {
|
||||
for event in events {
|
||||
let file = {
|
||||
let context_ref = context::current();
|
||||
let context = context_ref.read();
|
||||
let context = context_ref.read(token.token());
|
||||
|
||||
let files = context.files.read();
|
||||
match files.get(event.id).ok_or(Error::new(EBADF))? {
|
||||
@@ -62,7 +65,7 @@ impl EventQueue {
|
||||
event.flags,
|
||||
);
|
||||
|
||||
let flags = sync(RegKey { scheme, number })?;
|
||||
let flags = sync(RegKey { scheme, number }, token)?;
|
||||
if !flags.is_empty() {
|
||||
trigger(scheme, number, flags);
|
||||
}
|
||||
@@ -83,21 +86,21 @@ pub fn next_queue_id() -> EventQueueId {
|
||||
}
|
||||
|
||||
// Current event queues
|
||||
static QUEUES: Once<RwLock<EventQueueList>> = Once::new();
|
||||
static QUEUES: Once<RwLock<L1, EventQueueList>> = Once::new();
|
||||
|
||||
/// Initialize queues, called if needed
|
||||
fn init_queues() -> RwLock<EventQueueList> {
|
||||
fn init_queues() -> RwLock<L1, EventQueueList> {
|
||||
RwLock::new(HashMap::new())
|
||||
}
|
||||
|
||||
/// Get the event queues list, const
|
||||
pub fn queues() -> RwLockReadGuard<'static, EventQueueList> {
|
||||
QUEUES.call_once(init_queues).read()
|
||||
pub fn queues<'a>(token: LockToken<'a, L0>) -> RwLockReadGuard<'a, L1, EventQueueList> {
|
||||
QUEUES.call_once(init_queues).read(token)
|
||||
}
|
||||
|
||||
/// Get the event queues list, mutable
|
||||
pub fn queues_mut() -> RwLockWriteGuard<'static, EventQueueList> {
|
||||
QUEUES.call_once(init_queues).write()
|
||||
pub fn queues_mut<'a>(token: LockToken<'a, L0>) -> RwLockWriteGuard<'a, L1, EventQueueList> {
|
||||
QUEUES.call_once(init_queues).write(token)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
@@ -115,20 +118,20 @@ pub struct QueueKey {
|
||||
|
||||
type Registry = HashMap<RegKey, HashMap<QueueKey, EventFlags>>;
|
||||
|
||||
static REGISTRY: Once<RwLock<Registry>> = Once::new();
|
||||
static REGISTRY: Once<spin::RwLock<Registry>> = Once::new();
|
||||
|
||||
/// Initialize registry, called if needed
|
||||
fn init_registry() -> RwLock<Registry> {
|
||||
RwLock::new(Registry::new())
|
||||
fn init_registry() -> spin::RwLock<Registry> {
|
||||
spin::RwLock::new(Registry::new())
|
||||
}
|
||||
|
||||
/// Get the global schemes list, const
|
||||
fn registry() -> RwLockReadGuard<'static, Registry> {
|
||||
fn registry() -> spin::RwLockReadGuard<'static, Registry> {
|
||||
REGISTRY.call_once(init_registry).read()
|
||||
}
|
||||
|
||||
/// Get the global schemes list, mutable
|
||||
pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> {
|
||||
pub fn registry_mut() -> spin::RwLockWriteGuard<'static, Registry> {
|
||||
REGISTRY.call_once(init_registry).write()
|
||||
}
|
||||
|
||||
@@ -144,7 +147,7 @@ pub fn register(reg_key: RegKey, queue_key: QueueKey, flags: EventFlags) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync(reg_key: RegKey) -> Result<EventFlags> {
|
||||
pub fn sync(reg_key: RegKey, token: &mut CleanLockToken) -> Result<EventFlags> {
|
||||
let mut flags = EventFlags::empty();
|
||||
|
||||
{
|
||||
@@ -157,12 +160,12 @@ pub fn sync(reg_key: RegKey) -> Result<EventFlags> {
|
||||
}
|
||||
}
|
||||
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(reg_key.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
scheme.fevent(reg_key.number, flags)
|
||||
scheme.fevent(reg_key.number, flags, token)
|
||||
}
|
||||
|
||||
pub fn unregister_file(scheme: SchemeId, number: usize) {
|
||||
@@ -177,19 +180,27 @@ pub fn unregister_file(scheme: SchemeId, number: usize) {
|
||||
// }
|
||||
|
||||
pub fn trigger(scheme: SchemeId, number: usize, flags: EventFlags) {
|
||||
let registry = registry();
|
||||
//TODO: propogate this lock token
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
let registry = registry();
|
||||
if let Some(queue_list) = registry.get(&RegKey { scheme, number }) {
|
||||
for (queue_key, &queue_flags) in queue_list.iter() {
|
||||
let common_flags = flags & queue_flags;
|
||||
if !common_flags.is_empty() {
|
||||
let queues = queues();
|
||||
if let Some(queue) = queues.get(&queue_key.queue) {
|
||||
queue.queue.send(Event {
|
||||
id: queue_key.id,
|
||||
flags: common_flags,
|
||||
data: queue_key.data,
|
||||
});
|
||||
let queue_opt = {
|
||||
let queues = queues(token.token());
|
||||
queues.get(&queue_key.queue).cloned()
|
||||
};
|
||||
if let Some(queue) = queue_opt {
|
||||
queue.queue.send(
|
||||
Event {
|
||||
id: queue_key.id,
|
||||
flags: common_flags,
|
||||
data: queue_key.data,
|
||||
},
|
||||
&mut token,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-9
@@ -137,6 +137,7 @@ mod scheme;
|
||||
mod startup;
|
||||
|
||||
/// Synchronization primitives
|
||||
use sync::CleanLockToken;
|
||||
mod sync;
|
||||
|
||||
/// Syscall handlers
|
||||
@@ -168,8 +169,9 @@ fn init_env() -> &'static [u8] {
|
||||
}
|
||||
|
||||
extern "C" fn userspace_init() {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let bootstrap = crate::BOOTSTRAP.get().expect("BOOTSTRAP was not set");
|
||||
unsafe { crate::syscall::process::usermode_bootstrap(bootstrap) }
|
||||
unsafe { crate::syscall::process::usermode_bootstrap(bootstrap, &mut token) }
|
||||
}
|
||||
|
||||
struct Bootstrap {
|
||||
@@ -181,8 +183,10 @@ static BOOTSTRAP: spin::Once<Bootstrap> = spin::Once::new();
|
||||
|
||||
/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
|
||||
fn kmain(bootstrap: Bootstrap) -> ! {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
//Initialize the first context, stored in kernel/src/context/mod.rs
|
||||
context::init();
|
||||
context::init(&mut token);
|
||||
|
||||
//Initialize global schemes, such as `acpi:`.
|
||||
scheme::init_globals();
|
||||
@@ -196,9 +200,9 @@ fn kmain(bootstrap: Bootstrap) -> ! {
|
||||
profiling::ready_for_profiling();
|
||||
|
||||
let owner = None; // kmain not owned by any fd
|
||||
match context::spawn(true, owner, userspace_init) {
|
||||
match context::spawn(true, owner, userspace_init, &mut token) {
|
||||
Ok(context_lock) => {
|
||||
let mut context = context_lock.write();
|
||||
let mut context = context_lock.write(token.token());
|
||||
context.status = context::Status::Runnable;
|
||||
context.name.clear();
|
||||
context.name.push_str("[bootstrap]");
|
||||
@@ -213,12 +217,14 @@ fn kmain(bootstrap: Bootstrap) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
run_userspace()
|
||||
run_userspace(&mut token)
|
||||
}
|
||||
|
||||
/// This is the main kernel entry point for secondary CPUs
|
||||
#[allow(unreachable_code, unused_variables, dead_code)]
|
||||
fn kmain_ap(cpu_id: crate::cpu_set::LogicalCpuId) -> ! {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
|
||||
#[cfg(feature = "profiling")]
|
||||
profiling::maybe_run_profiling_helper_forever(cpu_id);
|
||||
|
||||
@@ -232,20 +238,21 @@ fn kmain_ap(cpu_id: crate::cpu_set::LogicalCpuId) -> ! {
|
||||
}
|
||||
}
|
||||
}
|
||||
context::init();
|
||||
|
||||
context::init(&mut token);
|
||||
|
||||
info!("AP {}", cpu_id);
|
||||
|
||||
#[cfg(feature = "profiling")]
|
||||
profiling::ready_for_profiling();
|
||||
|
||||
run_userspace();
|
||||
run_userspace(&mut token);
|
||||
}
|
||||
fn run_userspace() -> ! {
|
||||
fn run_userspace(token: &mut CleanLockToken) -> ! {
|
||||
loop {
|
||||
unsafe {
|
||||
interrupt::disable();
|
||||
match context::switch() {
|
||||
match context::switch(token) {
|
||||
SwitchResult::Switched => {
|
||||
interrupt::enable_and_nop();
|
||||
}
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ use crate::{
|
||||
},
|
||||
kernel_executable_offsets::{__usercopy_end, __usercopy_start},
|
||||
paging::{entry::EntryFlags, Page, PageFlags},
|
||||
sync::CleanLockToken,
|
||||
syscall::error::{Error, ENOMEM},
|
||||
};
|
||||
use rmm::{BumpAllocator, FrameAllocator, FrameCount, FrameUsage, TableKind, VirtualAddress};
|
||||
@@ -1014,7 +1015,8 @@ pub fn page_fault_handler(
|
||||
}
|
||||
|
||||
if address_is_user && (caused_by_user || is_usercopy) {
|
||||
match context::memory::try_correcting_page_tables(faulting_page, mode) {
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
match context::memory::try_correcting_page_tables(faulting_page, mode, &mut token) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(PfError::Oom) => todo!("oom"),
|
||||
Err(PfError::Segv | PfError::RecursionLimitExceeded) => (),
|
||||
|
||||
+4
-2
@@ -18,6 +18,7 @@ use crate::{
|
||||
arch::{consts::USER_END_OFFSET, interrupt::trace::StackTrace},
|
||||
context, cpu_id, interrupt,
|
||||
memory::KernelMapper,
|
||||
sync::CleanLockToken,
|
||||
syscall,
|
||||
};
|
||||
|
||||
@@ -44,9 +45,10 @@ fn rust_begin_unwind(info: &PanicInfo) -> ! {
|
||||
|
||||
println!("CPU {}, CID {:p}", cpu_id(), context_lock);
|
||||
|
||||
// This could deadlock, but at this point we are going to halt anyways
|
||||
{
|
||||
let context = context_lock.read();
|
||||
// This could deadlock, but at this point we are going to halt anyways
|
||||
let mut token = unsafe { CleanLockToken::new() };
|
||||
let context = context_lock.read(token.token());
|
||||
println!("NAME: {}, DEBUG ID: {}", context.name, context.debug_id);
|
||||
|
||||
if let Some([a, b, c, d, e, f]) = context.current_syscall() {
|
||||
|
||||
+16
-12
@@ -6,7 +6,7 @@ use crate::{
|
||||
event,
|
||||
percpu::PercpuBlock,
|
||||
scheme::GlobalSchemes,
|
||||
sync::WaitCondition,
|
||||
sync::{CleanLockToken, WaitCondition},
|
||||
syscall::{data::PtraceEvent, error::*, flag::*, ptrace_event},
|
||||
};
|
||||
|
||||
@@ -104,9 +104,9 @@ impl Session {
|
||||
/// Remove the session from the list of open sessions and notify any
|
||||
/// waiting processes
|
||||
// TODO
|
||||
pub fn close_session(session: &Session) {
|
||||
session.tracer.notify();
|
||||
session.tracee.notify();
|
||||
pub fn close_session(session: &Session, token: &mut CleanLockToken) {
|
||||
session.tracer.notify(token);
|
||||
session.tracee.notify(token);
|
||||
}
|
||||
|
||||
/// Wake up the tracer to make sure it catches on that the tracee is dead. This
|
||||
@@ -115,8 +115,8 @@ pub fn close_session(session: &Session) {
|
||||
/// session will *actually* be closed. This is partly to ensure ENOSRCH is
|
||||
/// returned rather than ENODEV (which occurs when there's no session - should
|
||||
/// never really happen).
|
||||
pub fn close_tracee(session: &Session) {
|
||||
session.tracer.notify();
|
||||
pub fn close_tracee(session: &Session, token: &mut CleanLockToken) {
|
||||
session.tracer.notify(token);
|
||||
|
||||
let data = session.data.lock();
|
||||
proc_trigger_event(data.file_id, EVENT_READ);
|
||||
@@ -130,7 +130,7 @@ fn proc_trigger_event(file_id: usize, flags: EventFlags) {
|
||||
/// Dispatch an event to any tracer tracing `self`. This will cause
|
||||
/// the tracer to wake up and poll for events. Returns Some(()) if an
|
||||
/// event was sent.
|
||||
pub fn send_event(event: PtraceEvent) -> Option<()> {
|
||||
pub fn send_event(event: PtraceEvent, token: &mut CleanLockToken) -> Option<()> {
|
||||
let session = Session::current()?;
|
||||
let mut data = session.data.lock();
|
||||
let breakpoint = data.breakpoint.as_ref()?;
|
||||
@@ -142,7 +142,7 @@ pub fn send_event(event: PtraceEvent) -> Option<()> {
|
||||
// Add event to queue
|
||||
data.add_event(event);
|
||||
// Notify tracer
|
||||
session.tracer.notify();
|
||||
session.tracer.notify(token);
|
||||
|
||||
Some(())
|
||||
}
|
||||
@@ -165,7 +165,7 @@ pub(crate) struct Breakpoint {
|
||||
///
|
||||
/// Note: Don't call while holding any locks or allocated data, this will
|
||||
/// switch contexts and may in fact just never terminate.
|
||||
pub fn wait(session: Arc<Session>) -> Result<()> {
|
||||
pub fn wait(session: Arc<Session>, token: &mut CleanLockToken) -> Result<()> {
|
||||
loop {
|
||||
// Lock the data, to make sure we're reading the final value before going
|
||||
// to sleep.
|
||||
@@ -178,7 +178,7 @@ pub fn wait(session: Arc<Session>) -> Result<()> {
|
||||
|
||||
// Go to sleep, and drop the lock on our data, which will allow other the
|
||||
// tracer to wake us up.
|
||||
if session.tracer.wait(data, "ptrace::wait") {
|
||||
if session.tracer.wait(data, "ptrace::wait", token) {
|
||||
// We successfully waited, wake up!
|
||||
break;
|
||||
}
|
||||
@@ -196,6 +196,7 @@ pub fn wait(session: Arc<Session>) -> Result<()> {
|
||||
pub fn breakpoint_callback(
|
||||
match_flags: PtraceFlags,
|
||||
event: Option<PtraceEvent>,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Option<PtraceFlags> {
|
||||
loop {
|
||||
let percpu = PercpuBlock::current();
|
||||
@@ -221,9 +222,12 @@ pub fn breakpoint_callback(
|
||||
data.add_event(event.unwrap_or(ptrace_event!(match_flags)));
|
||||
|
||||
// Wake up sleeping tracer
|
||||
session.tracer.notify();
|
||||
session.tracer.notify(token);
|
||||
|
||||
if session.tracee.wait(data, "ptrace::breakpoint_callback") {
|
||||
if session
|
||||
.tracee
|
||||
.wait(data, "ptrace::breakpoint_callback", token)
|
||||
{
|
||||
// We successfully waited, wake up!
|
||||
break Some(breakpoint.flags);
|
||||
}
|
||||
|
||||
+37
-21
@@ -7,7 +7,7 @@ use core::{
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::{Mutex, Once, RwLock};
|
||||
use spin::{Mutex, Once};
|
||||
use syscall::{
|
||||
dirent::{DirEntry, DirentBuf, DirentKind},
|
||||
EIO,
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
acpi::{RxsdtEnum, RXSDT_ENUM},
|
||||
context::file::InternalFlags,
|
||||
event,
|
||||
sync::WaitCondition,
|
||||
sync::{CleanLockToken, RwLock, WaitCondition, L1},
|
||||
};
|
||||
|
||||
use crate::syscall::{
|
||||
@@ -35,18 +35,19 @@ use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult};
|
||||
/// A scheme used to access the RSDT or XSDT, which is needed for e.g. `acpid` to function.
|
||||
pub struct AcpiScheme;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Handle {
|
||||
kind: HandleKind,
|
||||
stat: bool,
|
||||
}
|
||||
#[derive(Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
enum HandleKind {
|
||||
TopLevel,
|
||||
Rxsdt,
|
||||
ShutdownPipe,
|
||||
}
|
||||
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
static NEXT_FD: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
@@ -55,11 +56,11 @@ static DATA: Once<Box<[u8]>> = Once::new();
|
||||
static KSTOP_WAITCOND: WaitCondition = WaitCondition::new();
|
||||
static KSTOP_FLAG: Mutex<bool> = Mutex::new(false);
|
||||
|
||||
pub fn register_kstop() -> bool {
|
||||
pub fn register_kstop(token: &mut CleanLockToken) -> bool {
|
||||
*KSTOP_FLAG.lock() = true;
|
||||
let mut waiters_awoken = KSTOP_WAITCOND.notify();
|
||||
let mut waiters_awoken = KSTOP_WAITCOND.notify(token);
|
||||
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
|
||||
for (&fd, _) in handles
|
||||
.iter()
|
||||
@@ -109,7 +110,13 @@ impl AcpiScheme {
|
||||
}
|
||||
|
||||
impl KernelScheme for AcpiScheme {
|
||||
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let path = path.trim_start_matches('/');
|
||||
|
||||
if ctx.uid != 0 {
|
||||
@@ -148,7 +155,7 @@ impl KernelScheme for AcpiScheme {
|
||||
};
|
||||
|
||||
let fd = NEXT_FD.fetch_add(1, atomic::Ordering::Relaxed);
|
||||
let mut handles_guard = HANDLES.write();
|
||||
let mut handles_guard = HANDLES.write(token.token());
|
||||
|
||||
let _ = handles_guard.insert(
|
||||
fd,
|
||||
@@ -161,8 +168,8 @@ impl KernelScheme for AcpiScheme {
|
||||
|
||||
Ok(OpenResult::SchemeLocal(fd, int_flags))
|
||||
}
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
let mut handles = HANDLES.write();
|
||||
fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if handle.stat {
|
||||
@@ -176,8 +183,13 @@ impl KernelScheme for AcpiScheme {
|
||||
})
|
||||
}
|
||||
// TODO
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
let handles = HANDLES.read();
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
_flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if handle.stat {
|
||||
@@ -186,8 +198,8 @@ impl KernelScheme for AcpiScheme {
|
||||
|
||||
Ok(EventFlags::empty())
|
||||
}
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
if HANDLES.write().remove(&id).is_none() {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
if HANDLES.write(token.token()).remove(&id).is_none() {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
Ok(())
|
||||
@@ -199,13 +211,16 @@ impl KernelScheme for AcpiScheme {
|
||||
offset: u64,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Ok(offset) = usize::try_from(offset) else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
let mut handles = HANDLES.write();
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = {
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
if handle.stat {
|
||||
return Err(Error::new(EBADF));
|
||||
@@ -222,7 +237,7 @@ impl KernelScheme for AcpiScheme {
|
||||
|
||||
if *flag_guard {
|
||||
break;
|
||||
} else if !KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop") {
|
||||
} else if !KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop", token) {
|
||||
return Err(Error::new(EINTR));
|
||||
}
|
||||
}
|
||||
@@ -246,11 +261,12 @@ impl KernelScheme for AcpiScheme {
|
||||
buf: UserSliceWo,
|
||||
header_size: u16,
|
||||
opaque: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Some(Handle {
|
||||
kind: HandleKind::TopLevel,
|
||||
..
|
||||
}) = HANDLES.read().get(&id)
|
||||
}) = HANDLES.read(token.token()).get(&id)
|
||||
else {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
};
|
||||
@@ -274,8 +290,8 @@ impl KernelScheme for AcpiScheme {
|
||||
}
|
||||
Ok(buf.finalize())
|
||||
}
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
let handles = HANDLES.read();
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
buf.copy_exactly(&match handle.kind {
|
||||
|
||||
+44
-21
@@ -1,12 +1,11 @@
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use spin::RwLock;
|
||||
|
||||
use crate::{
|
||||
devices::graphical_debug,
|
||||
event,
|
||||
log::Writer,
|
||||
scheme::*,
|
||||
sync::WaitQueue,
|
||||
sync::{CleanLockToken, RwLock, WaitQueue, L1},
|
||||
syscall::{
|
||||
flag::{EventFlags, EVENT_READ, O_NONBLOCK},
|
||||
usercopy::{UserSliceRo, UserSliceWo},
|
||||
@@ -23,17 +22,17 @@ struct Handle {
|
||||
num: usize,
|
||||
}
|
||||
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
/// Add to the input queue
|
||||
pub fn debug_input(data: u8) {
|
||||
INPUT.send(data);
|
||||
pub fn debug_input(data: u8, token: &mut CleanLockToken) {
|
||||
INPUT.send(data, token);
|
||||
}
|
||||
|
||||
// Notify readers of input updates
|
||||
pub fn debug_notify() {
|
||||
for (id, _handle) in HANDLES.read().iter() {
|
||||
pub fn debug_notify(token: &mut CleanLockToken) {
|
||||
for (id, _handle) in HANDLES.read(token.token()).iter() {
|
||||
event::trigger(GlobalSchemes::Debug.scheme_id(), *id, EVENT_READ);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +50,13 @@ enum SpecialFds {
|
||||
}
|
||||
|
||||
impl KernelScheme for DebugScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
@@ -75,40 +80,52 @@ impl KernelScheme for DebugScheme {
|
||||
};
|
||||
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
HANDLES.write().insert(id, Handle { num });
|
||||
HANDLES.write(token.token()).insert(id, Handle { num });
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
_flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let _handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
Ok(EventFlags::empty())
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<()> {
|
||||
fn fsync(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let _handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let _handle = {
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
handles.remove(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceWo,
|
||||
flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
@@ -129,7 +146,12 @@ impl KernelScheme for DebugScheme {
|
||||
);
|
||||
}
|
||||
|
||||
INPUT.receive_into_user(buf, flags & O_NONBLOCK as u32 == 0, "DebugScheme::read")
|
||||
INPUT.receive_into_user(
|
||||
buf,
|
||||
flags & O_NONBLOCK as u32 == 0,
|
||||
"DebugScheme::read",
|
||||
token,
|
||||
)
|
||||
}
|
||||
|
||||
fn kwrite(
|
||||
@@ -138,9 +160,10 @@ impl KernelScheme for DebugScheme {
|
||||
buf: UserSliceRo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
@@ -186,9 +209,9 @@ impl KernelScheme for DebugScheme {
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
if handle.num != SpecialFds::Default as usize
|
||||
|
||||
+19
-11
@@ -2,12 +2,13 @@ use core::sync::atomic::{self, AtomicUsize};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::{Once, RwLock};
|
||||
use spin::Once;
|
||||
|
||||
use super::{CallerCtx, KernelScheme, OpenResult};
|
||||
use crate::{
|
||||
dtb::DTB_BINARY,
|
||||
scheme::InternalFlags,
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::Stat,
|
||||
error::*,
|
||||
@@ -28,7 +29,7 @@ struct Handle {
|
||||
stat: bool,
|
||||
}
|
||||
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
static NEXT_FD: AtomicUsize = AtomicUsize::new(0);
|
||||
static DATA: Once<Box<[u8]>> = Once::new();
|
||||
@@ -50,13 +51,19 @@ impl DtbScheme {
|
||||
}
|
||||
|
||||
impl KernelScheme for DtbScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let path = path.trim_matches('/');
|
||||
|
||||
if path.is_empty() {
|
||||
let id = NEXT_FD.fetch_add(1, atomic::Ordering::Relaxed);
|
||||
|
||||
let mut handles_guard = HANDLES.write();
|
||||
let mut handles_guard = HANDLES.write(token.token());
|
||||
|
||||
let _ = handles_guard.insert(
|
||||
id,
|
||||
@@ -71,8 +78,8 @@ impl KernelScheme for DtbScheme {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
let mut handles = HANDLES.write();
|
||||
fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if handle.stat {
|
||||
@@ -86,8 +93,8 @@ impl KernelScheme for DtbScheme {
|
||||
Ok(file_len as u64)
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
if HANDLES.write().remove(&id).is_none() {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
if HANDLES.write(token.token()).remove(&id).is_none() {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
Ok(())
|
||||
@@ -100,8 +107,9 @@ impl KernelScheme for DtbScheme {
|
||||
offset: u64,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if handle.stat {
|
||||
@@ -120,8 +128,8 @@ impl KernelScheme for DtbScheme {
|
||||
dst_buf.copy_common_bytes_from_slice(src_buf)
|
||||
}
|
||||
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
let handles = HANDLES.read();
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
buf.copy_exactly(&match handle.kind {
|
||||
HandleKind::RawData => {
|
||||
|
||||
+25
-10
@@ -5,6 +5,7 @@ use syscall::O_NONBLOCK;
|
||||
use crate::{
|
||||
context::file::InternalFlags,
|
||||
event::{next_queue_id, queues, queues_mut, EventQueue, EventQueueId},
|
||||
sync::CleanLockToken,
|
||||
syscall::{
|
||||
data::Event,
|
||||
error::*,
|
||||
@@ -17,30 +18,43 @@ use super::{CallerCtx, KernelScheme, OpenResult};
|
||||
pub struct EventScheme;
|
||||
|
||||
impl KernelScheme for EventScheme {
|
||||
fn kopen(&self, _path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
_path: &str,
|
||||
_flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let id = next_queue_id();
|
||||
queues_mut().insert(id, Arc::new(EventQueue::new(id)));
|
||||
queues_mut(token.token()).insert(id, Arc::new(EventQueue::new(id)));
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id.get(), InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let id = EventQueueId::from(id);
|
||||
queues_mut()
|
||||
queues_mut(token.token())
|
||||
.remove(&id)
|
||||
.ok_or(Error::new(EBADF))
|
||||
.and(Ok(()))
|
||||
}
|
||||
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceWo,
|
||||
flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let id = EventQueueId::from(id);
|
||||
|
||||
let queue = {
|
||||
let handles = queues();
|
||||
let handles = queues(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
queue.read(buf, flags & O_NONBLOCK as u32 == 0)
|
||||
queue.read(buf, flags & O_NONBLOCK as u32 == 0, token)
|
||||
}
|
||||
|
||||
fn kwrite(
|
||||
@@ -49,11 +63,12 @@ impl KernelScheme for EventScheme {
|
||||
buf: UserSliceRo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let id = EventQueueId::from(id);
|
||||
|
||||
let queue = {
|
||||
let handles = queues();
|
||||
let handles = queues(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -61,7 +76,7 @@ impl KernelScheme for EventScheme {
|
||||
|
||||
for chunk in buf.in_exact_chunks(mem::size_of::<Event>()) {
|
||||
let event = unsafe { chunk.read_exact::<Event>()? };
|
||||
if queue.write(&[event])? == 0 {
|
||||
if queue.write(&[event], token)? == 0 {
|
||||
break;
|
||||
}
|
||||
events_written += 1;
|
||||
@@ -70,7 +85,7 @@ impl KernelScheme for EventScheme {
|
||||
Ok(events_written * mem::size_of::<Event>())
|
||||
}
|
||||
|
||||
fn kfpath(&self, _id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(&self, _id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result<usize> {
|
||||
buf.copy_common_bytes_from_slice(b"event:")
|
||||
}
|
||||
}
|
||||
|
||||
+43
-18
@@ -10,7 +10,7 @@ use core::{
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::{Mutex, Once, RwLock};
|
||||
use spin::{Mutex, Once};
|
||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
|
||||
use crate::context::file::InternalFlags;
|
||||
@@ -23,6 +23,7 @@ use crate::dtb::irqchip::{acknowledge, available_irqs_iter, is_reserved, set_res
|
||||
use crate::{
|
||||
cpu_set::LogicalCpuId,
|
||||
event,
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::Stat,
|
||||
error::*,
|
||||
@@ -34,7 +35,7 @@ use crate::{
|
||||
///
|
||||
/// IRQ queues
|
||||
pub(super) static COUNTS: Mutex<[usize; 224]> = Mutex::new([0; 224]);
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
/// These are IRQs 0..=15 (corresponding to interrupt vectors 32..=47). They are opened without the
|
||||
@@ -55,11 +56,11 @@ const INO_BSP: u64 = 0x8001_0000_0000_0000;
|
||||
const INO_PHANDLE: u64 = 0x8003_0000_0000_0000;
|
||||
|
||||
/// Add to the input queue
|
||||
pub fn irq_trigger(irq: u8) {
|
||||
pub fn irq_trigger(irq: u8, token: &mut CleanLockToken) {
|
||||
COUNTS.lock()[irq as usize] += 1;
|
||||
|
||||
for (fd, _) in HANDLES
|
||||
.read()
|
||||
.read(token.token())
|
||||
.iter()
|
||||
.filter_map(|(fd, handle)| Some((fd, handle.as_irq_handle()?)))
|
||||
.filter(|&(_, (_, handle_irq))| handle_irq == irq)
|
||||
@@ -207,7 +208,13 @@ const fn vector_to_irq(vector: u8) -> u8 {
|
||||
}
|
||||
|
||||
impl crate::scheme::KernelScheme for IrqScheme {
|
||||
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
@@ -297,7 +304,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
}
|
||||
};
|
||||
let fd = NEXT_FD.fetch_add(1, Ordering::Relaxed);
|
||||
HANDLES.write().insert(fd, handle);
|
||||
HANDLES.write(token.token()).insert(fd, handle);
|
||||
Ok(OpenResult::SchemeLocal(fd, int_flags))
|
||||
}
|
||||
fn getdents(
|
||||
@@ -306,6 +313,7 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
buf: UserSliceWo,
|
||||
header_size: u16,
|
||||
opaque_id_start: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Ok(opaque) = usize::try_from(opaque_id_start) else {
|
||||
return Ok(0);
|
||||
@@ -316,7 +324,11 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?;
|
||||
let mut intermediate = String::new();
|
||||
|
||||
match *HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
match *HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::TopLevel => {
|
||||
let cpus = CPUS.get().expect("IRQ scheme not initialized");
|
||||
|
||||
@@ -362,20 +374,31 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
Ok(buf.finalize())
|
||||
}
|
||||
|
||||
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
|
||||
fn fcntl(
|
||||
&self,
|
||||
_id: usize,
|
||||
_cmd: usize,
|
||||
_arg: usize,
|
||||
_token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fevent(&self, _id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
_id: usize,
|
||||
_flags: EventFlags,
|
||||
_token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
Ok(EventFlags::empty())
|
||||
}
|
||||
|
||||
fn fsync(&self, _file: usize) -> Result<()> {
|
||||
fn fsync(&self, _file: usize, _token: &mut CleanLockToken) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
let handles_guard = HANDLES.read();
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handles_guard = HANDLES.read(token.token());
|
||||
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if let &Handle::Irq {
|
||||
@@ -394,8 +417,9 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
buffer: UserSliceRo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handles_guard = HANDLES.read();
|
||||
let handles_guard = HANDLES.read(token.token());
|
||||
let handle = handles_guard.get(&file).ok_or(Error::new(EBADF))?;
|
||||
|
||||
match handle {
|
||||
@@ -422,8 +446,8 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
let handles_guard = HANDLES.read();
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handles_guard = HANDLES.read(token.token());
|
||||
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
buf.copy_exactly(&match *handle {
|
||||
@@ -472,8 +496,8 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
let handles_guard = HANDLES.read();
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let handles_guard = HANDLES.read(token.token());
|
||||
let handle = handles_guard.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let scheme_path = match handle {
|
||||
@@ -494,8 +518,9 @@ impl crate::scheme::KernelScheme for IrqScheme {
|
||||
_offset: u64,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handles_guard = HANDLES.read();
|
||||
let handles_guard = HANDLES.read(token.token());
|
||||
let handle = handles_guard.get(&file).ok_or(Error::new(EBADF))?;
|
||||
|
||||
match *handle {
|
||||
|
||||
+14
-3
@@ -10,6 +10,7 @@ use crate::{
|
||||
},
|
||||
memory::{free_frames, used_frames, Frame, PAGE_SIZE},
|
||||
paging::VirtualAddress,
|
||||
sync::CleanLockToken,
|
||||
syscall::usercopy::UserSliceRw,
|
||||
};
|
||||
|
||||
@@ -76,6 +77,7 @@ impl MemoryScheme {
|
||||
addr_space: &Arc<AddrSpaceWrapper>,
|
||||
map: &Map,
|
||||
is_phys_contiguous: bool,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let span = PageSpan::validate_nonempty(VirtualAddress::new(map.address), map.size)
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
@@ -110,7 +112,7 @@ impl MemoryScheme {
|
||||
},
|
||||
)?;
|
||||
|
||||
handle_notify_files(notify_files);
|
||||
handle_notify_files(notify_files, token);
|
||||
|
||||
Ok(page.start_address().data())
|
||||
}
|
||||
@@ -179,7 +181,13 @@ impl MemoryScheme {
|
||||
}
|
||||
}
|
||||
impl KernelScheme for MemoryScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
ctx: CallerCtx,
|
||||
_token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if path.len() > 64 {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
@@ -237,6 +245,7 @@ impl KernelScheme for MemoryScheme {
|
||||
payload: UserSliceRw,
|
||||
_flags: syscall::CallFlags,
|
||||
_metadata: &[u64],
|
||||
_token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let (handle_ty, _, _) = u32::try_from(id)
|
||||
.ok()
|
||||
@@ -268,6 +277,7 @@ impl KernelScheme for MemoryScheme {
|
||||
addr_space: &Arc<AddrSpaceWrapper>,
|
||||
map: &Map,
|
||||
_consume: bool,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let (handle_ty, mem_ty, flags) = u32::try_from(id)
|
||||
.ok()
|
||||
@@ -279,12 +289,13 @@ impl KernelScheme for MemoryScheme {
|
||||
addr_space,
|
||||
map,
|
||||
flags.contains(HandleFlags::PHYS_CONTIGUOUS),
|
||||
token,
|
||||
),
|
||||
HandleTy::PhysBorrow => Self::physmap(map.offset, map.size, map.flags, mem_ty),
|
||||
HandleTy::Translation => Err(Error::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
fn kfstatvfs(&self, _file: usize, dst: UserSliceWo) -> Result<()> {
|
||||
fn kfstatvfs(&self, _file: usize, dst: UserSliceWo, _token: &mut CleanLockToken) -> Result<()> {
|
||||
let used = used_frames() as u64;
|
||||
let free = free_frames() as u64;
|
||||
|
||||
|
||||
+110
-33
@@ -12,7 +12,7 @@ use alloc::{boxed::Box, string::ToString, sync::Arc, vec::Vec};
|
||||
use core::{hash::BuildHasherDefault, sync::atomic::AtomicUsize};
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use indexmap::IndexMap;
|
||||
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use spin::Once;
|
||||
use syscall::{CallFlags, EventFlags, MunmapFlags};
|
||||
|
||||
use crate::{
|
||||
@@ -20,6 +20,7 @@ use crate::{
|
||||
file::{FileDescription, InternalFlags},
|
||||
memory::AddrSpaceWrapper,
|
||||
},
|
||||
sync::{CleanLockToken, LockToken, RwLock, RwLockReadGuard, RwLockWriteGuard, L0, L1},
|
||||
syscall::{
|
||||
error::*,
|
||||
usercopy::{UserSliceRo, UserSliceRw, UserSliceWo},
|
||||
@@ -361,26 +362,32 @@ impl SchemeList {
|
||||
}
|
||||
|
||||
/// Schemes list
|
||||
static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
|
||||
static SCHEMES: Once<RwLock<L1, SchemeList>> = Once::new();
|
||||
|
||||
/// Initialize schemes, called if needed
|
||||
fn init_schemes() -> RwLock<SchemeList> {
|
||||
fn init_schemes() -> RwLock<L1, SchemeList> {
|
||||
RwLock::new(SchemeList::new())
|
||||
}
|
||||
|
||||
/// Get the global schemes list, const
|
||||
pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
|
||||
SCHEMES.call_once(init_schemes).read()
|
||||
pub fn schemes<'a>(token: LockToken<'a, L0>) -> RwLockReadGuard<'a, L1, SchemeList> {
|
||||
SCHEMES.call_once(init_schemes).read(token)
|
||||
}
|
||||
|
||||
/// Get the global schemes list, mutable
|
||||
pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
|
||||
SCHEMES.call_once(init_schemes).write()
|
||||
pub fn schemes_mut<'a>(token: LockToken<'a, L0>) -> RwLockWriteGuard<'a, L1, SchemeList> {
|
||||
SCHEMES.call_once(init_schemes).write(token)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait KernelScheme: Send + Sync + 'static {
|
||||
fn kopen(&self, path: &str, flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
|
||||
@@ -391,6 +398,7 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
@@ -401,14 +409,28 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
addr_space: &Arc<AddrSpaceWrapper>,
|
||||
map: &crate::syscall::data::Map,
|
||||
consume: bool,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
fn kfunmap(&self, number: usize, offset: usize, size: usize, flags: MunmapFlags) -> Result<()> {
|
||||
fn kfunmap(
|
||||
&self,
|
||||
number: usize,
|
||||
offset: usize,
|
||||
size: usize,
|
||||
flags: MunmapFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
|
||||
fn kdup(&self, old_id: usize, buf: UserSliceRo, _caller: CallerCtx) -> Result<OpenResult> {
|
||||
fn kdup(
|
||||
&self,
|
||||
old_id: usize,
|
||||
buf: UserSliceRo,
|
||||
_caller: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
fn kwriteoff(
|
||||
@@ -418,11 +440,12 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
offset: u64,
|
||||
flags: u32,
|
||||
stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
if offset != u64::MAX {
|
||||
return Err(Error::new(ESPIPE));
|
||||
}
|
||||
self.kwrite(id, buf, flags, stored_flags)
|
||||
self.kwrite(id, buf, flags, stored_flags, token)
|
||||
}
|
||||
fn kreadoff(
|
||||
&self,
|
||||
@@ -431,28 +454,43 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
offset: u64,
|
||||
flags: u32,
|
||||
stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
if offset != u64::MAX {
|
||||
return Err(Error::new(ESPIPE));
|
||||
}
|
||||
self.kread(id, buf, flags, stored_flags)
|
||||
self.kread(id, buf, flags, stored_flags, token)
|
||||
}
|
||||
fn kwrite(&self, id: usize, buf: UserSliceRo, flags: u32, stored_flags: u32) -> Result<usize> {
|
||||
fn kwrite(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceRo,
|
||||
flags: u32,
|
||||
stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, stored_flags: u32) -> Result<usize> {
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceWo,
|
||||
flags: u32,
|
||||
stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn kfutimens(&self, id: usize, buf: UserSliceRo) -> Result<usize> {
|
||||
fn kfutimens(&self, id: usize, buf: UserSliceRo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn kfstatvfs(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
fn kfstatvfs(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
||||
@@ -462,47 +500,83 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
buf: UserSliceWo,
|
||||
header_size: u16,
|
||||
opaque_id_first: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<()> {
|
||||
fn fsync(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn ftruncate(&self, id: usize, len: usize) -> Result<()> {
|
||||
fn ftruncate(&self, id: usize, len: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
Err(Error::new(ESPIPE))
|
||||
}
|
||||
fn legacy_seek(&self, id: usize, pos: isize, whence: usize) -> Option<Result<usize>> {
|
||||
fn legacy_seek(
|
||||
&self,
|
||||
id: usize,
|
||||
pos: isize,
|
||||
whence: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Option<Result<usize>> {
|
||||
None
|
||||
}
|
||||
fn fchmod(&self, id: usize, new_mode: u16) -> Result<()> {
|
||||
fn fchmod(&self, id: usize, new_mode: u16, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn fchown(&self, id: usize, new_uid: u32, new_gid: u32) -> Result<()> {
|
||||
fn fchown(
|
||||
&self,
|
||||
id: usize,
|
||||
new_uid: u32,
|
||||
new_gid: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
Ok(EventFlags::empty())
|
||||
}
|
||||
fn flink(&self, id: usize, new_path: &str, caller_ctx: CallerCtx) -> Result<()> {
|
||||
fn flink(
|
||||
&self,
|
||||
id: usize,
|
||||
new_path: &str,
|
||||
caller_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn frename(&self, id: usize, new_path: &str, caller_ctx: CallerCtx) -> Result<()> {
|
||||
fn frename(
|
||||
&self,
|
||||
id: usize,
|
||||
new_path: &str,
|
||||
caller_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
|
||||
fn fcntl(
|
||||
&self,
|
||||
id: usize,
|
||||
cmd: usize,
|
||||
arg: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
fn rmdir(&self, path: &str, ctx: CallerCtx) -> Result<()> {
|
||||
fn rmdir(&self, path: &str, ctx: CallerCtx, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
fn unlink(&self, path: &str, ctx: CallerCtx) -> Result<()> {
|
||||
fn unlink(&self, path: &str, ctx: CallerCtx, token: &mut CleanLockToken) -> Result<()> {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn kcall(
|
||||
@@ -511,16 +585,18 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
fn kfdwrite(
|
||||
&self,
|
||||
id: usize,
|
||||
descs: Vec<Arc<RwLock<FileDescription>>>,
|
||||
descs: Vec<Arc<spin::RwLock<FileDescription>>>,
|
||||
flags: CallFlags,
|
||||
args: u64,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
@@ -530,6 +606,7 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Err(Error::new(EOPNOTSUPP))
|
||||
}
|
||||
@@ -538,7 +615,7 @@ pub trait KernelScheme: Send + Sync + 'static {
|
||||
#[derive(Debug)]
|
||||
pub enum OpenResult {
|
||||
SchemeLocal(usize, InternalFlags),
|
||||
External(Arc<RwLock<FileDescription>>),
|
||||
External(Arc<spin::RwLock<FileDescription>>),
|
||||
}
|
||||
pub struct CallerCtx {
|
||||
pub pid: usize,
|
||||
|
||||
+75
-27
@@ -1,14 +1,12 @@
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::{Mutex, RwLock};
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::{
|
||||
context::file::InternalFlags,
|
||||
event,
|
||||
sync::WaitCondition,
|
||||
sync::{CleanLockToken, RwLock, WaitCondition, L1},
|
||||
syscall::{
|
||||
data::Stat,
|
||||
error::{Error, Result, EAGAIN, EBADF, EINTR, EINVAL, ENOENT, EPIPE},
|
||||
@@ -24,7 +22,7 @@ use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult, StrOrBytes};
|
||||
static PIPE_NEXT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
|
||||
// TODO: SLOB?
|
||||
static PIPES: RwLock<HashMap<usize, Arc<Pipe>>> =
|
||||
static PIPES: RwLock<L1, HashMap<usize, Arc<Pipe>>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
const MAX_QUEUE_SIZE: usize = 65536;
|
||||
@@ -37,10 +35,10 @@ fn from_raw_id(id: usize) -> (bool, usize) {
|
||||
(id & WRITE_NOT_READ_BIT != 0, id & !WRITE_NOT_READ_BIT)
|
||||
}
|
||||
|
||||
pub fn pipe() -> Result<(usize, usize)> {
|
||||
pub fn pipe(token: &mut CleanLockToken) -> Result<(usize, usize)> {
|
||||
let id = PIPE_NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
PIPES.write().insert(
|
||||
PIPES.write(token.token()).insert(
|
||||
id,
|
||||
Arc::new(Pipe {
|
||||
queue: Mutex::new(VecDeque::new()),
|
||||
@@ -58,9 +56,19 @@ pub fn pipe() -> Result<(usize, usize)> {
|
||||
pub struct PipeScheme;
|
||||
|
||||
impl KernelScheme for PipeScheme {
|
||||
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let (is_writer_not_reader, key) = from_raw_id(id);
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
|
||||
let mut ready = EventFlags::empty();
|
||||
|
||||
@@ -81,36 +89,47 @@ impl KernelScheme for PipeScheme {
|
||||
Ok(ready)
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let (is_write_not_read, key) = from_raw_id(id);
|
||||
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
let scheme_id = GlobalSchemes::Pipe.scheme_id();
|
||||
|
||||
let can_remove = if is_write_not_read {
|
||||
event::trigger(scheme_id, key, EVENT_READ);
|
||||
|
||||
pipe.read_condition.notify();
|
||||
pipe.read_condition.notify(token);
|
||||
pipe.writer_is_alive.store(false, Ordering::SeqCst);
|
||||
|
||||
!pipe.reader_is_alive.load(Ordering::SeqCst)
|
||||
} else {
|
||||
event::trigger(scheme_id, key | WRITE_NOT_READ_BIT, EVENT_WRITE);
|
||||
|
||||
pipe.write_condition.notify();
|
||||
pipe.write_condition.notify(token);
|
||||
pipe.reader_is_alive.store(false, Ordering::SeqCst);
|
||||
|
||||
!pipe.writer_is_alive.load(Ordering::SeqCst)
|
||||
};
|
||||
|
||||
if can_remove {
|
||||
let _ = PIPES.write().remove(&key);
|
||||
let _ = PIPES.write(token.token()).remove(&key);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn kdup(&self, old_id: usize, user_buf: UserSliceRo, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kdup(
|
||||
&self,
|
||||
old_id: usize,
|
||||
user_buf: UserSliceRo,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let (is_writer_not_reader, key) = from_raw_id(old_id);
|
||||
|
||||
if is_writer_not_reader {
|
||||
@@ -123,7 +142,12 @@ impl KernelScheme for PipeScheme {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
|
||||
if pipe.has_run_dup.swap(true, Ordering::SeqCst) {
|
||||
return Err(Error::new(EBADF));
|
||||
@@ -134,12 +158,18 @@ impl KernelScheme for PipeScheme {
|
||||
InternalFlags::empty(),
|
||||
))
|
||||
}
|
||||
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if !path.trim_start_matches('/').is_empty() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
let (read_id, _) = pipe()?;
|
||||
let (read_id, _) = pipe(token)?;
|
||||
|
||||
Ok(OpenResult::SchemeLocal(read_id, InternalFlags::empty()))
|
||||
}
|
||||
@@ -151,6 +181,7 @@ impl KernelScheme for PipeScheme {
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let (_, key) = from_raw_id(id);
|
||||
|
||||
@@ -159,7 +190,12 @@ impl KernelScheme for PipeScheme {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
|
||||
if pipe.has_run_dup.swap(true, Ordering::SeqCst) {
|
||||
return Err(Error::new(EBADF));
|
||||
@@ -177,13 +213,19 @@ impl KernelScheme for PipeScheme {
|
||||
user_buf: UserSliceWo,
|
||||
fcntl_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let (is_write_not_read, key) = from_raw_id(id);
|
||||
|
||||
if is_write_not_read {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
|
||||
loop {
|
||||
let mut vec = pipe.queue.lock();
|
||||
@@ -211,7 +253,7 @@ impl KernelScheme for PipeScheme {
|
||||
key | WRITE_NOT_READ_BIT,
|
||||
EVENT_WRITE,
|
||||
);
|
||||
pipe.write_condition.notify();
|
||||
pipe.write_condition.notify(token);
|
||||
|
||||
return Ok(bytes_read);
|
||||
} else if user_buf.is_empty() {
|
||||
@@ -222,7 +264,7 @@ impl KernelScheme for PipeScheme {
|
||||
return Ok(0);
|
||||
} else if fcntl_flags & O_NONBLOCK as u32 != 0 {
|
||||
return Err(Error::new(EAGAIN));
|
||||
} else if !pipe.read_condition.wait(vec, "PipeRead::read") {
|
||||
} else if !pipe.read_condition.wait(vec, "PipeRead::read", token) {
|
||||
return Err(Error::new(EINTR));
|
||||
}
|
||||
}
|
||||
@@ -233,13 +275,19 @@ impl KernelScheme for PipeScheme {
|
||||
user_buf: UserSliceRo,
|
||||
fcntl_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let (is_write_not_read, key) = from_raw_id(id);
|
||||
|
||||
if !is_write_not_read {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
let pipe = Arc::clone(PIPES.read().get(&key).ok_or(Error::new(EBADF))?);
|
||||
let pipe = Arc::clone(
|
||||
PIPES
|
||||
.read(token.token())
|
||||
.get(&key)
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
);
|
||||
|
||||
loop {
|
||||
let mut vec = pipe.queue.lock();
|
||||
@@ -272,7 +320,7 @@ impl KernelScheme for PipeScheme {
|
||||
|
||||
if bytes_written > 0 {
|
||||
event::trigger(GlobalSchemes::Pipe.scheme_id(), key, EVENT_READ);
|
||||
pipe.read_condition.notify();
|
||||
pipe.read_condition.notify(token);
|
||||
|
||||
return Ok(bytes_written);
|
||||
} else if user_buf.is_empty() {
|
||||
@@ -281,12 +329,12 @@ impl KernelScheme for PipeScheme {
|
||||
|
||||
if fcntl_flags & O_NONBLOCK as u32 != 0 {
|
||||
return Err(Error::new(EAGAIN));
|
||||
} else if !pipe.write_condition.wait(vec, "PipeWrite::write") {
|
||||
} else if !pipe.write_condition.wait(vec, "PipeWrite::write", token) {
|
||||
return Err(Error::new(EINTR));
|
||||
}
|
||||
}
|
||||
}
|
||||
fn kfstat(&self, _id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
fn kfstat(&self, _id: usize, buf: UserSliceWo, _token: &mut CleanLockToken) -> Result<()> {
|
||||
buf.copy_exactly(&Stat {
|
||||
st_mode: MODE_FIFO | 0o666,
|
||||
..Default::default()
|
||||
|
||||
+279
-213
@@ -5,11 +5,12 @@ use crate::{
|
||||
context::{HardBlockedReason, SignalState},
|
||||
file::InternalFlags,
|
||||
memory::{handle_notify_files, AddrSpace, AddrSpaceWrapper, Grant, PageSpan},
|
||||
Context, Status,
|
||||
Context, ContextLock, Status,
|
||||
},
|
||||
memory::{get_page_info, AddRefError, RefKind, PAGE_SIZE},
|
||||
ptrace,
|
||||
scheme::{self, FileHandle, KernelScheme},
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::{GrantDesc, Map, SetSighandlerData, Stat},
|
||||
error::*,
|
||||
@@ -39,8 +40,6 @@ use hashbrown::{
|
||||
hash_map::{DefaultHashBuilder, Entry},
|
||||
HashMap,
|
||||
};
|
||||
use spin::RwLock;
|
||||
use spinning_top::RwSpinlock;
|
||||
|
||||
fn read_from(dst: UserSliceWo, src: &[u8], offset: u64) -> Result<usize> {
|
||||
let avail_src = usize::try_from(offset)
|
||||
@@ -51,15 +50,16 @@ fn read_from(dst: UserSliceWo, src: &[u8], offset: u64) -> Result<usize> {
|
||||
}
|
||||
|
||||
fn try_stop_context<T>(
|
||||
context_ref: Arc<RwSpinlock<Context>>,
|
||||
context_ref: Arc<ContextLock>,
|
||||
token: &mut CleanLockToken,
|
||||
callback: impl FnOnce(&mut Context) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
if context::is_current(&context_ref) {
|
||||
return callback(&mut *context_ref.write());
|
||||
return callback(&mut *context_ref.write(token.token()));
|
||||
}
|
||||
// Stop process
|
||||
let (prev_status, mut running) = {
|
||||
let mut context = context_ref.write();
|
||||
let mut context = context_ref.write(token.token());
|
||||
|
||||
(
|
||||
core::mem::replace(
|
||||
@@ -74,12 +74,12 @@ fn try_stop_context<T>(
|
||||
|
||||
// Wait until stopped
|
||||
while running {
|
||||
context::switch();
|
||||
context::switch(token);
|
||||
|
||||
running = context_ref.read().running;
|
||||
running = context_ref.read(token.token()).running;
|
||||
}
|
||||
|
||||
let mut context = context_ref.write();
|
||||
let mut context = context_ref.write(token.token());
|
||||
assert!(
|
||||
!context.running,
|
||||
"process can't have been restarted, we stopped it!"
|
||||
@@ -113,11 +113,11 @@ enum ContextHandle {
|
||||
Sighandler,
|
||||
Start,
|
||||
NewFiletable {
|
||||
filetable: Arc<RwLock<FdTbl>>,
|
||||
filetable: Arc<spin::RwLock<FdTbl>>,
|
||||
data: Box<[u8]>,
|
||||
},
|
||||
Filetable {
|
||||
filetable: Weak<RwLock<FdTbl>>,
|
||||
filetable: Weak<spin::RwLock<FdTbl>>,
|
||||
data: Box<[u8]>,
|
||||
},
|
||||
AddrSpace {
|
||||
@@ -134,7 +134,7 @@ enum ContextHandle {
|
||||
CurrentFiletable,
|
||||
|
||||
AwaitingFiletableChange {
|
||||
new_ft: Arc<RwLock<FdTbl>>,
|
||||
new_ft: Arc<spin::RwLock<FdTbl>>,
|
||||
},
|
||||
|
||||
// TODO: Remove this once openat is implemented, or allow openat-via-dup via e.g. the top-level
|
||||
@@ -146,19 +146,19 @@ enum ContextHandle {
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct Handle {
|
||||
context: Arc<RwSpinlock<Context>>,
|
||||
context: Arc<ContextLock>,
|
||||
kind: ContextHandle,
|
||||
}
|
||||
pub struct ProcScheme;
|
||||
|
||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
#[cfg(feature = "debugger")]
|
||||
#[allow(dead_code)]
|
||||
pub fn foreach_addrsp(mut f: impl FnMut(&Arc<AddrSpaceWrapper>)) {
|
||||
for (_, handle) in HANDLES.read().iter() {
|
||||
pub fn foreach_addrsp(token: &mut CleanLockToken, mut f: impl FnMut(&Arc<AddrSpaceWrapper>)) {
|
||||
for (_, handle) in HANDLES.read(token.token()).iter() {
|
||||
let Handle {
|
||||
kind: ContextHandle::AddrSpace { addrspace, .. },
|
||||
..
|
||||
@@ -170,14 +170,17 @@ pub fn foreach_addrsp(mut f: impl FnMut(&Arc<AddrSpaceWrapper>)) {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_handle((handle, fl): (Handle, InternalFlags)) -> Result<(usize, InternalFlags)> {
|
||||
fn new_handle(
|
||||
(handle, fl): (Handle, InternalFlags),
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<(usize, InternalFlags)> {
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
let _ = HANDLES.write().insert(id, handle);
|
||||
let _ = HANDLES.write(token.token()).insert(id, handle);
|
||||
Ok((id, fl))
|
||||
}
|
||||
|
||||
enum OpenTy {
|
||||
Ctxt(Arc<RwSpinlock<Context>>),
|
||||
Ctxt(Arc<ContextLock>),
|
||||
Auth,
|
||||
}
|
||||
|
||||
@@ -185,14 +188,15 @@ impl ProcScheme {
|
||||
fn openat_context(
|
||||
&self,
|
||||
path: &str,
|
||||
context: Arc<RwSpinlock<Context>>,
|
||||
context: Arc<ContextLock>,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<Option<(ContextHandle, bool)>> {
|
||||
Ok(Some(match path {
|
||||
"addrspace" => (
|
||||
ContextHandle::AddrSpace {
|
||||
addrspace: Arc::clone(
|
||||
context
|
||||
.read()
|
||||
.read(token.token())
|
||||
.addr_space()
|
||||
.map_err(|_| Error::new(ENOENT))?,
|
||||
),
|
||||
@@ -201,7 +205,7 @@ impl ProcScheme {
|
||||
),
|
||||
"filetable" => (
|
||||
ContextHandle::Filetable {
|
||||
filetable: Arc::downgrade(&context.read().files),
|
||||
filetable: Arc::downgrade(&context.read(token.token()).files),
|
||||
data: Box::new([]),
|
||||
},
|
||||
true,
|
||||
@@ -217,7 +221,7 @@ impl ProcScheme {
|
||||
"mmap-min-addr" => (
|
||||
ContextHandle::MmapMinAddr(Arc::clone(
|
||||
context
|
||||
.read()
|
||||
.read(token.token())
|
||||
.addr_space()
|
||||
.map_err(|_| Error::new(ENOENT))?,
|
||||
)),
|
||||
@@ -239,10 +243,14 @@ impl ProcScheme {
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
};
|
||||
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(auth_fd)?;
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(auth_fd, token)?;
|
||||
verify_scheme(hopefully_this_scheme)?;
|
||||
if !matches!(
|
||||
HANDLES.read().get(&number).ok_or(Error::new(ENOENT))?.kind,
|
||||
HANDLES
|
||||
.read(token.token())
|
||||
.get(&number)
|
||||
.ok_or(Error::new(ENOENT))?
|
||||
.kind,
|
||||
ContextHandle::Authority
|
||||
) {
|
||||
return Err(Error::new(ENOENT));
|
||||
@@ -258,11 +266,12 @@ impl ProcScheme {
|
||||
ty: OpenTy,
|
||||
operation_str: Option<&str>,
|
||||
_flags: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<(usize, InternalFlags)> {
|
||||
let operation_name = operation_str.ok_or(Error::new(EINVAL))?;
|
||||
let (mut handle, positioned) = match ty {
|
||||
OpenTy::Ctxt(context) => {
|
||||
match self.openat_context(operation_name, Arc::clone(&context))? {
|
||||
match self.openat_context(operation_name, Arc::clone(&context), token)? {
|
||||
Some((kind, positioned)) => (Handle { context, kind }, positioned),
|
||||
_ => {
|
||||
return Err(Error::new(EINVAL));
|
||||
@@ -275,8 +284,8 @@ impl ProcScheme {
|
||||
"new-context" => {
|
||||
let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed))
|
||||
.ok_or(Error::new(EMFILE))?;
|
||||
let context = context::spawn(true, Some(id), ret)?;
|
||||
HANDLES.write().insert(
|
||||
let context = context::spawn(true, Some(id), ret, token)?;
|
||||
HANDLES.write(token.token()).insert(
|
||||
id.get(),
|
||||
Handle {
|
||||
context,
|
||||
@@ -339,21 +348,30 @@ impl ProcScheme {
|
||||
}
|
||||
};
|
||||
|
||||
let (id, int_fl) = new_handle((
|
||||
handle.clone(),
|
||||
if positioned {
|
||||
InternalFlags::POSITIONED
|
||||
} else {
|
||||
InternalFlags::empty()
|
||||
},
|
||||
))?;
|
||||
let (id, int_fl) = new_handle(
|
||||
(
|
||||
handle.clone(),
|
||||
if positioned {
|
||||
InternalFlags::POSITIONED
|
||||
} else {
|
||||
InternalFlags::empty()
|
||||
},
|
||||
),
|
||||
token,
|
||||
)?;
|
||||
|
||||
Ok((id, int_fl))
|
||||
}
|
||||
}
|
||||
|
||||
impl KernelScheme for ProcScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if path != "authority" {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
@@ -362,7 +380,7 @@ impl KernelScheme for ProcScheme {
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
HANDLES.write().insert(
|
||||
HANDLES.write(token.token()).insert(
|
||||
id,
|
||||
Handle {
|
||||
// TODO: placeholder
|
||||
@@ -373,8 +391,13 @@ impl KernelScheme for ProcScheme {
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
let handles = HANDLES.read();
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
_flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
match handle {
|
||||
@@ -382,8 +405,11 @@ impl KernelScheme for ProcScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
let handle = HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?;
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handle = HANDLES
|
||||
.write(token.token())
|
||||
.remove(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
match handle {
|
||||
Handle {
|
||||
@@ -395,17 +421,17 @@ impl KernelScheme for ProcScheme {
|
||||
new_ip,
|
||||
},
|
||||
} => {
|
||||
let _ = try_stop_context(context, |context: &mut Context| {
|
||||
let _ = try_stop_context(context, token, |context: &mut Context| {
|
||||
let regs = context.regs_mut().ok_or(Error::new(EBADFD))?;
|
||||
regs.set_instr_pointer(new_ip);
|
||||
regs.set_stack_pointer(new_sp);
|
||||
|
||||
Ok(context.set_addr_space(Some(new)))
|
||||
})?;
|
||||
let _ = ptrace::send_event(crate::syscall::ptrace_event!(
|
||||
PTRACE_EVENT_ADDRSPACE_SWITCH,
|
||||
0
|
||||
));
|
||||
let _ = ptrace::send_event(
|
||||
crate::syscall::ptrace_event!(PTRACE_EVENT_ADDRSPACE_SWITCH, 0),
|
||||
token,
|
||||
);
|
||||
}
|
||||
Handle {
|
||||
kind: ContextHandle::AddrSpace { addrspace } | ContextHandle::MmapMinAddr(addrspace),
|
||||
@@ -416,7 +442,7 @@ impl KernelScheme for ProcScheme {
|
||||
kind: ContextHandle::AwaitingFiletableChange { new_ft },
|
||||
context,
|
||||
} => {
|
||||
context.write().files = new_ft;
|
||||
context.write(token.token()).files = new_ft;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -428,8 +454,13 @@ impl KernelScheme for ProcScheme {
|
||||
dst_addr_space: &Arc<AddrSpaceWrapper>,
|
||||
map: &crate::syscall::data::Map,
|
||||
consume: bool,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = HANDLES.read().get(&id).ok_or(Error::new(EBADF))?.clone();
|
||||
let handle = HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
let Handle { kind, ref context } = handle;
|
||||
|
||||
match kind {
|
||||
@@ -490,12 +521,12 @@ impl KernelScheme for ProcScheme {
|
||||
)?
|
||||
};
|
||||
|
||||
handle_notify_files(notify_files);
|
||||
handle_notify_files(notify_files, token);
|
||||
|
||||
Ok(result_base.start_address().data())
|
||||
}
|
||||
ContextHandle::Sighandler => {
|
||||
let context = context.read();
|
||||
let context = context.read(token.token());
|
||||
let sig = context.sig.as_ref().ok_or(Error::new(EBADF))?;
|
||||
let frame = match map.offset {
|
||||
// tctl
|
||||
@@ -542,15 +573,16 @@ impl KernelScheme for ProcScheme {
|
||||
offset: u64,
|
||||
_read_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
// Don't hold a global lock during the context switch later on
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
handles.get(&id).ok_or(Error::new(EBADF))?.clone()
|
||||
};
|
||||
|
||||
match handle {
|
||||
Handle { context, kind } => kind.kreadoff(id, context, buf, offset),
|
||||
Handle { context, kind } => kind.kreadoff(id, context, buf, offset, token),
|
||||
}
|
||||
}
|
||||
fn kcall(
|
||||
@@ -559,10 +591,11 @@ impl KernelScheme for ProcScheme {
|
||||
_payload: UserSliceRw,
|
||||
_flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
// TODO: simplify
|
||||
let handle = {
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -577,7 +610,9 @@ impl KernelScheme for ProcScheme {
|
||||
let verb = ProcSchemeVerb::try_from_raw(verb).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
match verb {
|
||||
ProcSchemeVerb::Iopl => context::current().write().set_userspace_io_allowed(true),
|
||||
ProcSchemeVerb::Iopl => context::current()
|
||||
.write(token.token())
|
||||
.set_userspace_io_allowed(true),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
@@ -588,22 +623,23 @@ impl KernelScheme for ProcScheme {
|
||||
_offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
// TODO: offset
|
||||
|
||||
// Don't hold a global lock during the context switch later on
|
||||
let handle = {
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
match handle {
|
||||
Handle { context, kind } => kind.kwriteoff(id, context, buf),
|
||||
Handle { context, kind } => kind.kwriteoff(id, context, buf, token),
|
||||
}
|
||||
}
|
||||
fn kfstat(&self, id: usize, buffer: UserSliceWo) -> Result<()> {
|
||||
let handles = HANDLES.read();
|
||||
fn kfstat(&self, id: usize, buffer: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
buffer.copy_exactly(&Stat {
|
||||
@@ -616,17 +652,23 @@ impl KernelScheme for ProcScheme {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
let mut handles = HANDLES.write();
|
||||
fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
handle.fsize()
|
||||
}
|
||||
|
||||
/// Dup is currently used to implement clone() and execve().
|
||||
fn kdup(&self, old_id: usize, raw_buf: UserSliceRo, _: CallerCtx) -> Result<OpenResult> {
|
||||
fn kdup(
|
||||
&self,
|
||||
old_id: usize,
|
||||
raw_buf: UserSliceRo,
|
||||
_: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let info = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
let handle = handles.get(&old_id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
handle.clone()
|
||||
@@ -649,121 +691,126 @@ impl KernelScheme for ProcScheme {
|
||||
raw_buf.copy_to_slice(&mut array[..raw_buf.len()])?;
|
||||
let buf = &array[..raw_buf.len()];
|
||||
|
||||
new_handle(match info {
|
||||
Handle {
|
||||
kind: ContextHandle::Authority,
|
||||
..
|
||||
} => {
|
||||
return self
|
||||
.open_inner(
|
||||
OpenTy::Auth,
|
||||
Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?)
|
||||
.filter(|s| !s.is_empty()),
|
||||
O_RDWR | O_CLOEXEC,
|
||||
)
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
|
||||
}
|
||||
Handle {
|
||||
kind: ContextHandle::OpenViaDup,
|
||||
context,
|
||||
} => {
|
||||
return self
|
||||
.open_inner(
|
||||
OpenTy::Ctxt(context),
|
||||
Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?)
|
||||
.filter(|s| !s.is_empty()),
|
||||
O_RDWR | O_CLOEXEC,
|
||||
)
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl));
|
||||
}
|
||||
|
||||
Handle {
|
||||
kind:
|
||||
ContextHandle::Filetable {
|
||||
ref filetable,
|
||||
ref data,
|
||||
},
|
||||
context,
|
||||
} => {
|
||||
// TODO: Maybe allow userspace to either copy or transfer recently dupped file
|
||||
// descriptors between file tables.
|
||||
if buf != b"copy" {
|
||||
return Err(Error::new(EINVAL));
|
||||
new_handle(
|
||||
match info {
|
||||
Handle {
|
||||
kind: ContextHandle::Authority,
|
||||
..
|
||||
} => {
|
||||
return self
|
||||
.open_inner(
|
||||
OpenTy::Auth,
|
||||
Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?)
|
||||
.filter(|s| !s.is_empty()),
|
||||
O_RDWR | O_CLOEXEC,
|
||||
token,
|
||||
)
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
|
||||
}
|
||||
Handle {
|
||||
kind: ContextHandle::OpenViaDup,
|
||||
context,
|
||||
} => {
|
||||
return self
|
||||
.open_inner(
|
||||
OpenTy::Ctxt(context),
|
||||
Some(core::str::from_utf8(buf).map_err(|_| Error::new(EINVAL))?)
|
||||
.filter(|s| !s.is_empty()),
|
||||
O_RDWR | O_CLOEXEC,
|
||||
token,
|
||||
)
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl));
|
||||
}
|
||||
let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
|
||||
|
||||
let new_filetable = Arc::try_new(RwLock::new(filetable.read().clone()))
|
||||
.map_err(|_| Error::new(ENOMEM))?;
|
||||
|
||||
handle(
|
||||
Handle {
|
||||
kind: ContextHandle::NewFiletable {
|
||||
filetable: new_filetable,
|
||||
data: data.clone(),
|
||||
Handle {
|
||||
kind:
|
||||
ContextHandle::Filetable {
|
||||
ref filetable,
|
||||
ref data,
|
||||
},
|
||||
context,
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
Handle {
|
||||
kind: ContextHandle::AddrSpace { ref addrspace },
|
||||
context,
|
||||
} => {
|
||||
const GRANT_FD_PREFIX: &[u8] = b"grant-fd-";
|
||||
context,
|
||||
} => {
|
||||
// TODO: Maybe allow userspace to either copy or transfer recently dupped file
|
||||
// descriptors between file tables.
|
||||
if buf != b"copy" {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let filetable = filetable.upgrade().ok_or(Error::new(EOWNERDEAD))?;
|
||||
|
||||
let kind = match buf {
|
||||
// TODO: Better way to obtain new empty address spaces, perhaps using SYS_OPEN. But
|
||||
// in that case, what scheme?
|
||||
b"empty" => ContextHandle::AddrSpace {
|
||||
addrspace: AddrSpaceWrapper::new()?,
|
||||
},
|
||||
b"exclusive" => ContextHandle::AddrSpace {
|
||||
addrspace: addrspace.try_clone()?,
|
||||
},
|
||||
b"mmap-min-addr" => ContextHandle::MmapMinAddr(Arc::clone(addrspace)),
|
||||
let new_filetable = Arc::try_new(spin::RwLock::new(filetable.read().clone()))
|
||||
.map_err(|_| Error::new(ENOMEM))?;
|
||||
|
||||
_ if buf.starts_with(GRANT_FD_PREFIX) => {
|
||||
let string = core::str::from_utf8(&buf[GRANT_FD_PREFIX.len()..])
|
||||
.map_err(|_| Error::new(EINVAL))?;
|
||||
let page_addr =
|
||||
usize::from_str_radix(string, 16).map_err(|_| Error::new(EINVAL))?;
|
||||
handle(
|
||||
Handle {
|
||||
kind: ContextHandle::NewFiletable {
|
||||
filetable: new_filetable,
|
||||
data: data.clone(),
|
||||
},
|
||||
context,
|
||||
},
|
||||
true,
|
||||
)
|
||||
}
|
||||
Handle {
|
||||
kind: ContextHandle::AddrSpace { ref addrspace },
|
||||
context,
|
||||
} => {
|
||||
const GRANT_FD_PREFIX: &[u8] = b"grant-fd-";
|
||||
|
||||
if page_addr % PAGE_SIZE != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let kind = match buf {
|
||||
// TODO: Better way to obtain new empty address spaces, perhaps using SYS_OPEN. But
|
||||
// in that case, what scheme?
|
||||
b"empty" => ContextHandle::AddrSpace {
|
||||
addrspace: AddrSpaceWrapper::new()?,
|
||||
},
|
||||
b"exclusive" => ContextHandle::AddrSpace {
|
||||
addrspace: addrspace.try_clone()?,
|
||||
},
|
||||
b"mmap-min-addr" => ContextHandle::MmapMinAddr(Arc::clone(addrspace)),
|
||||
|
||||
let page = Page::containing_address(VirtualAddress::new(page_addr));
|
||||
_ if buf.starts_with(GRANT_FD_PREFIX) => {
|
||||
let string = core::str::from_utf8(&buf[GRANT_FD_PREFIX.len()..])
|
||||
.map_err(|_| Error::new(EINVAL))?;
|
||||
let page_addr = usize::from_str_radix(string, 16)
|
||||
.map_err(|_| Error::new(EINVAL))?;
|
||||
|
||||
match addrspace
|
||||
.acquire_read()
|
||||
.grants
|
||||
.contains(page)
|
||||
.ok_or(Error::new(EINVAL))?
|
||||
{
|
||||
(_, info) => {
|
||||
return Ok(OpenResult::External(
|
||||
info.file_ref()
|
||||
.map(|r| Arc::clone(&r.description))
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
))
|
||||
if page_addr % PAGE_SIZE != 0 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
let page = Page::containing_address(VirtualAddress::new(page_addr));
|
||||
|
||||
match addrspace
|
||||
.acquire_read()
|
||||
.grants
|
||||
.contains(page)
|
||||
.ok_or(Error::new(EINVAL))?
|
||||
{
|
||||
(_, info) => {
|
||||
return Ok(OpenResult::External(
|
||||
info.file_ref()
|
||||
.map(|r| Arc::clone(&r.description))
|
||||
.ok_or(Error::new(EBADF))?,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
};
|
||||
|
||||
handle(Handle { context, kind }, true)
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
})
|
||||
handle(Handle { context, kind }, true)
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
},
|
||||
token,
|
||||
)
|
||||
.map(|(r, fl)| OpenResult::SchemeLocal(r, fl))
|
||||
}
|
||||
}
|
||||
fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> {
|
||||
fn extract_scheme_number(fd: usize, token: &mut CleanLockToken) -> Result<(KernelSchemes, usize)> {
|
||||
let (scheme_id, number) = match &*context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(FileHandle::from(fd))
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.description
|
||||
@@ -771,7 +818,7 @@ fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> {
|
||||
{
|
||||
desc => (desc.scheme, desc.number),
|
||||
};
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(scheme_id)
|
||||
.ok_or(Error::new(ENODEV))?
|
||||
.clone();
|
||||
@@ -797,8 +844,9 @@ impl ContextHandle {
|
||||
fn kwriteoff(
|
||||
self,
|
||||
id: usize,
|
||||
context: Arc<RwSpinlock<Context>>,
|
||||
context: Arc<ContextLock>,
|
||||
buf: UserSliceRo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
match self {
|
||||
Self::AddrSpace { addrspace } => {
|
||||
@@ -820,7 +868,7 @@ impl ContextHandle {
|
||||
return Err(Error::new(EOPNOTSUPP));
|
||||
}
|
||||
|
||||
let (scheme, number) = extract_scheme_number(fd)?;
|
||||
let (scheme, number) = extract_scheme_number(fd, token)?;
|
||||
|
||||
scheme.kfmap(
|
||||
number,
|
||||
@@ -832,6 +880,7 @@ impl ContextHandle {
|
||||
flags,
|
||||
},
|
||||
op == ADDRSPACE_OP_TRANSFER,
|
||||
token,
|
||||
)?;
|
||||
}
|
||||
ADDRSPACE_OP_MUNMAP => {
|
||||
@@ -854,7 +903,7 @@ impl ContextHandle {
|
||||
RegsKind::Float => {
|
||||
let regs = unsafe { buf.read_exact::<FloatRegisters>()? };
|
||||
|
||||
try_stop_context(context, |context| {
|
||||
try_stop_context(context, token, |context| {
|
||||
// NOTE: The kernel will never touch floats
|
||||
|
||||
// Ignore the rare case of floating point
|
||||
@@ -867,7 +916,7 @@ impl ContextHandle {
|
||||
RegsKind::Int => {
|
||||
let regs = unsafe { buf.read_exact::<IntRegisters>()? };
|
||||
|
||||
try_stop_context(context, |context| match context.regs_mut() {
|
||||
try_stop_context(context, token, |context| match context.regs_mut() {
|
||||
None => {
|
||||
println!(
|
||||
"{}:{}: Couldn't read registers from stopped process",
|
||||
@@ -885,7 +934,7 @@ impl ContextHandle {
|
||||
}
|
||||
RegsKind::Env => {
|
||||
let regs = unsafe { buf.read_exact::<EnvRegisters>()? };
|
||||
write_env_regs(context, regs)?;
|
||||
write_env_regs(context, regs, token)?;
|
||||
Ok(mem::size_of::<EnvRegisters>())
|
||||
}
|
||||
},
|
||||
@@ -913,7 +962,7 @@ impl ContextHandle {
|
||||
}
|
||||
};
|
||||
|
||||
let addrsp = Arc::clone(context.read().addr_space()?);
|
||||
let addrsp = Arc::clone(context.read(token.token()).addr_space()?);
|
||||
|
||||
Some(SignalState {
|
||||
threadctl_off: validate_off(
|
||||
@@ -929,20 +978,22 @@ impl ContextHandle {
|
||||
excp_handler: NonZeroUsize::new(data.excp_handler),
|
||||
thread_control: addrsp.borrow_frame_enforce_rw_allocated(
|
||||
Page::containing_address(VirtualAddress::new(data.thread_control_addr)),
|
||||
token,
|
||||
)?,
|
||||
proc_control: addrsp.borrow_frame_enforce_rw_allocated(
|
||||
Page::containing_address(VirtualAddress::new(data.proc_control_addr)),
|
||||
token,
|
||||
)?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
context.write().sig = state;
|
||||
context.write(token.token()).sig = state;
|
||||
|
||||
Ok(mem::size_of::<SetSighandlerData>())
|
||||
}
|
||||
ContextHandle::Start => match context.write().status {
|
||||
ContextHandle::Start => match context.write(token.token()).status {
|
||||
ref mut status @ Status::HardBlocked {
|
||||
reason: HardBlockedReason::NotYetStarted,
|
||||
} => {
|
||||
@@ -957,10 +1008,10 @@ impl ContextHandle {
|
||||
|
||||
ContextHandle::CurrentFiletable => {
|
||||
let filetable_fd = buf.read_usize()?;
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(filetable_fd)?;
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(filetable_fd, token)?;
|
||||
verify_scheme(hopefully_this_scheme)?;
|
||||
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let Entry::Occupied(mut entry) = handles.entry(number) else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
@@ -1004,10 +1055,10 @@ impl ContextHandle {
|
||||
let sp = iter.next().ok_or(Error::new(EINVAL))??;
|
||||
let ip = iter.next().ok_or(Error::new(EINVAL))??;
|
||||
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(addrspace_fd)?;
|
||||
let (hopefully_this_scheme, number) = extract_scheme_number(addrspace_fd, token)?;
|
||||
verify_scheme(hopefully_this_scheme)?;
|
||||
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
let &Handle {
|
||||
kind: ContextHandle::AddrSpace { ref addrspace },
|
||||
..
|
||||
@@ -1038,7 +1089,10 @@ impl ContextHandle {
|
||||
Self::SchedAffinity => {
|
||||
let mask = unsafe { buf.read_exact::<crate::cpu_set::RawMask>()? };
|
||||
|
||||
context.write().sched_affinity.override_from(&mask);
|
||||
context
|
||||
.write(token.token())
|
||||
.sched_affinity
|
||||
.override_from(&mask);
|
||||
|
||||
Ok(mem::size_of_val(&mask))
|
||||
}
|
||||
@@ -1056,7 +1110,7 @@ impl ContextHandle {
|
||||
return Err(Error::new(EPERM))
|
||||
}
|
||||
ContextVerb::Stop => {
|
||||
let mut guard = context.write();
|
||||
let mut guard = context.write(token.token());
|
||||
|
||||
match guard.status {
|
||||
Status::Dead { .. } => return Err(Error::new(EOWNERDEAD)),
|
||||
@@ -1072,7 +1126,7 @@ impl ContextHandle {
|
||||
Ok(size_of::<usize>())
|
||||
}
|
||||
ContextVerb::Unstop => {
|
||||
let mut guard = context.write();
|
||||
let mut guard = context.write(token.token());
|
||||
|
||||
if let Status::HardBlocked {
|
||||
reason: HardBlockedReason::Stopped,
|
||||
@@ -1083,7 +1137,7 @@ impl ContextHandle {
|
||||
Ok(size_of::<usize>())
|
||||
}
|
||||
ContextVerb::Interrupt => {
|
||||
let mut guard = context.write();
|
||||
let mut guard = context.write(token.token());
|
||||
guard.unblock();
|
||||
Ok(size_of::<usize>())
|
||||
}
|
||||
@@ -1098,7 +1152,8 @@ impl ContextHandle {
|
||||
let size = args.next().ok_or(Error::new(EINVAL))??;
|
||||
|
||||
if size > 0 {
|
||||
let addrsp = Arc::clone(context.read().addr_space()?);
|
||||
let addrsp =
|
||||
Arc::clone(context.read(token.token()).addr_space()?);
|
||||
let res = addrsp.munmap(
|
||||
PageSpan::validate_nonempty(
|
||||
VirtualAddress::new(base),
|
||||
@@ -1108,13 +1163,13 @@ impl ContextHandle {
|
||||
false,
|
||||
)?;
|
||||
for r in res {
|
||||
let _ = r.unmap();
|
||||
let _ = r.unmap(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::syscall::exit_this_context(None);
|
||||
crate::syscall::exit_this_context(None, token);
|
||||
} else {
|
||||
let mut ctxt = context.write();
|
||||
let mut ctxt = context.write(token.token());
|
||||
//trace!("FORCEKILL NONSELF={} {}, SELF={}", ctxt.debug_id, ctxt.pid, context::current().read().debug_id);
|
||||
ctxt.status = context::Status::Runnable;
|
||||
ctxt.being_sigkilled = true;
|
||||
@@ -1125,7 +1180,7 @@ impl ContextHandle {
|
||||
}
|
||||
ContextHandle::Attr => {
|
||||
let info = unsafe { buf.read_exact::<ProcSchemeAttrs>()? };
|
||||
let mut guard = context.write();
|
||||
let mut guard = context.write(token.token());
|
||||
|
||||
let len = info
|
||||
.debug_name
|
||||
@@ -1150,9 +1205,10 @@ impl ContextHandle {
|
||||
fn kreadoff(
|
||||
&self,
|
||||
_id: usize,
|
||||
context: Arc<RwSpinlock<Context>>,
|
||||
context: Arc<ContextLock>,
|
||||
buf: UserSliceWo,
|
||||
offset: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
match self {
|
||||
ContextHandle::Regs(kind) => {
|
||||
@@ -1164,7 +1220,7 @@ impl ContextHandle {
|
||||
|
||||
let (output, size) = match kind {
|
||||
RegsKind::Float => {
|
||||
let context = context.read();
|
||||
let context = context.read(token.token());
|
||||
// NOTE: The kernel will never touch floats
|
||||
|
||||
(
|
||||
@@ -1174,25 +1230,27 @@ impl ContextHandle {
|
||||
mem::size_of::<FloatRegisters>(),
|
||||
)
|
||||
}
|
||||
RegsKind::Int => try_stop_context(context, |context| match context.regs() {
|
||||
None => {
|
||||
assert!(!context.running, "try_stop_context is broken, clearly");
|
||||
println!(
|
||||
"{}:{}: Couldn't read registers from stopped process",
|
||||
file!(),
|
||||
line!()
|
||||
);
|
||||
Err(Error::new(ENOTRECOVERABLE))
|
||||
}
|
||||
Some(stack) => {
|
||||
let mut regs = IntRegisters::default();
|
||||
stack.save(&mut regs);
|
||||
Ok((Output { int: regs }, mem::size_of::<IntRegisters>()))
|
||||
}
|
||||
})?,
|
||||
RegsKind::Int => {
|
||||
try_stop_context(context, token, |context| match context.regs() {
|
||||
None => {
|
||||
assert!(!context.running, "try_stop_context is broken, clearly");
|
||||
println!(
|
||||
"{}:{}: Couldn't read registers from stopped process",
|
||||
file!(),
|
||||
line!()
|
||||
);
|
||||
Err(Error::new(ENOTRECOVERABLE))
|
||||
}
|
||||
Some(stack) => {
|
||||
let mut regs = IntRegisters::default();
|
||||
stack.save(&mut regs);
|
||||
Ok((Output { int: regs }, mem::size_of::<IntRegisters>()))
|
||||
}
|
||||
})?
|
||||
}
|
||||
RegsKind::Env => (
|
||||
Output {
|
||||
env: read_env_regs(context)?,
|
||||
env: read_env_regs(context, token)?,
|
||||
},
|
||||
mem::size_of::<EnvRegisters>(),
|
||||
),
|
||||
@@ -1246,14 +1304,14 @@ impl ContextHandle {
|
||||
Ok(mem::size_of::<usize>())
|
||||
}
|
||||
ContextHandle::SchedAffinity => {
|
||||
let mask = context.read().sched_affinity.to_raw();
|
||||
let mask = context.read(token.token()).sched_affinity.to_raw();
|
||||
|
||||
buf.copy_exactly(crate::cpu_set::mask_as_bytes(&mask))?;
|
||||
Ok(mem::size_of_val(&mask))
|
||||
} // TODO: Replace write() with SYS_SENDFD?
|
||||
ContextHandle::Status { .. } => {
|
||||
let status = {
|
||||
let context = context.read();
|
||||
let context = context.read(token.token());
|
||||
match context.status {
|
||||
Status::Runnable | Status::Dead { excp: None }
|
||||
if context.being_sigkilled =>
|
||||
@@ -1285,7 +1343,7 @@ impl ContextHandle {
|
||||
}
|
||||
ContextHandle::Attr => {
|
||||
let mut debug_name = [0; 32];
|
||||
let (euid, egid, ens, pid, name) = match context.read() {
|
||||
let (euid, egid, ens, pid, name) = match context.read(token.token()) {
|
||||
ref c => (c.euid, c.egid, c.ens.get() as u32, c.pid as u32, c.name),
|
||||
};
|
||||
let min = name.len().min(debug_name.len());
|
||||
@@ -1299,7 +1357,7 @@ impl ContextHandle {
|
||||
})
|
||||
}
|
||||
ContextHandle::Sighandler => {
|
||||
let data = match context.read().sig {
|
||||
let data = match context.read(token.token()).sig {
|
||||
Some(ref sig) => SetSighandlerData {
|
||||
excp_handler: sig.excp_handler.map_or(0, NonZeroUsize::get),
|
||||
user_handler: sig.user_handler.get(),
|
||||
@@ -1319,18 +1377,26 @@ impl ContextHandle {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_env_regs(context: Arc<RwSpinlock<Context>>, regs: EnvRegisters) -> Result<()> {
|
||||
fn write_env_regs(
|
||||
context: Arc<ContextLock>,
|
||||
regs: EnvRegisters,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
if context::is_current(&context) {
|
||||
context::current().write().write_current_env_regs(regs)
|
||||
context::current()
|
||||
.write(token.token())
|
||||
.write_current_env_regs(regs)
|
||||
} else {
|
||||
try_stop_context(context, |context| context.write_env_regs(regs))
|
||||
try_stop_context(context, token, |context| context.write_env_regs(regs))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_env_regs(context: Arc<RwSpinlock<Context>>) -> Result<EnvRegisters> {
|
||||
fn read_env_regs(context: Arc<ContextLock>, token: &mut CleanLockToken) -> Result<EnvRegisters> {
|
||||
if context::is_current(&context) {
|
||||
context::current().read().read_current_env_regs()
|
||||
context::current()
|
||||
.read(token.token())
|
||||
.read_current_env_regs()
|
||||
} else {
|
||||
try_stop_context(context, |context| context.read_env_regs())
|
||||
try_stop_context(context, token, |context| context.read_env_regs())
|
||||
}
|
||||
}
|
||||
|
||||
+66
-34
@@ -4,7 +4,6 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use spin::RwLock;
|
||||
use syscall::{
|
||||
dirent::{DirEntry, DirentBuf, DirentKind},
|
||||
O_EXLOCK, O_FSYNC,
|
||||
@@ -17,6 +16,7 @@ use crate::{
|
||||
user::{UserInner, UserScheme},
|
||||
FileDescription, SchemeId, SchemeNamespace,
|
||||
},
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::Stat,
|
||||
error::*,
|
||||
@@ -38,7 +38,7 @@ pub struct RootScheme {
|
||||
scheme_ns: SchemeNamespace,
|
||||
scheme_id: SchemeId,
|
||||
next_id: AtomicUsize,
|
||||
handles: RwLock<HashMap<usize, Handle>>,
|
||||
handles: RwLock<L1, HashMap<usize, Handle>>,
|
||||
}
|
||||
|
||||
impl RootScheme {
|
||||
@@ -53,7 +53,13 @@ impl RootScheme {
|
||||
}
|
||||
|
||||
impl KernelScheme for RootScheme {
|
||||
fn kopen(&self, path: &str, flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let path = path.trim_start_matches('/');
|
||||
|
||||
//TODO: Make this follow standards for flags and errors
|
||||
@@ -72,7 +78,7 @@ impl KernelScheme for RootScheme {
|
||||
|
||||
let inner = {
|
||||
let path_box = path.to_string().into_boxed_str();
|
||||
let mut schemes = scheme::schemes_mut();
|
||||
let mut schemes = scheme::schemes_mut(token.token());
|
||||
|
||||
let v2 = flags & O_FSYNC == O_FSYNC;
|
||||
let new_close = flags & O_EXLOCK == O_EXLOCK;
|
||||
@@ -110,32 +116,38 @@ impl KernelScheme for RootScheme {
|
||||
inner
|
||||
};
|
||||
|
||||
self.handles.write().insert(id, Handle::Scheme(inner));
|
||||
self.handles
|
||||
.write(token.token())
|
||||
.insert(id, Handle::Scheme(inner));
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
|
||||
} else if path.is_empty() {
|
||||
let ens = context::current().read().ens;
|
||||
let ens = context::current().read(token.token()).ens;
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||
self.handles.write().insert(id, Handle::List { ens });
|
||||
self.handles
|
||||
.write(token.token())
|
||||
.insert(id, Handle::List { ens });
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
|
||||
} else {
|
||||
let inner = Arc::new(path.as_bytes().to_vec().into_boxed_slice());
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::Relaxed);
|
||||
self.handles.write().insert(id, Handle::File(inner));
|
||||
self.handles
|
||||
.write(token.token())
|
||||
.insert(id, Handle::File(inner));
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
|
||||
}
|
||||
}
|
||||
|
||||
fn unlink(&self, path: &str, ctx: CallerCtx) -> Result<()> {
|
||||
fn unlink(&self, path: &str, ctx: CallerCtx, token: &mut CleanLockToken) -> Result<()> {
|
||||
let path = path.trim_matches('/');
|
||||
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
let inner = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
handles
|
||||
.iter()
|
||||
.find_map(|(_id, handle)| {
|
||||
@@ -152,12 +164,12 @@ impl KernelScheme for RootScheme {
|
||||
.ok_or(Error::new(ENOENT))?
|
||||
};
|
||||
|
||||
inner.unmount()
|
||||
inner.unmount(token)
|
||||
}
|
||||
|
||||
fn fsize(&self, file: usize) -> Result<u64> {
|
||||
fn fsize(&self, file: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -169,9 +181,14 @@ impl KernelScheme for RootScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn fevent(&self, file: usize, flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
file: usize,
|
||||
flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -183,9 +200,14 @@ impl KernelScheme for RootScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn kfpath(&self, file: usize, mut buf: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(
|
||||
&self,
|
||||
file: usize,
|
||||
mut buf: UserSliceWo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -206,9 +228,9 @@ impl KernelScheme for RootScheme {
|
||||
Ok(bytes_copied)
|
||||
}
|
||||
|
||||
fn fsync(&self, file: usize) -> Result<()> {
|
||||
fn fsync(&self, file: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -220,15 +242,15 @@ impl KernelScheme for RootScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self, file: usize) -> Result<()> {
|
||||
fn close(&self, file: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handle = self
|
||||
.handles
|
||||
.write()
|
||||
.write(token.token())
|
||||
.remove(&file)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
match handle {
|
||||
Handle::Scheme(inner) => {
|
||||
scheme::schemes_mut().remove(inner.scheme_id);
|
||||
scheme::schemes_mut(token.token()).remove(inner.scheme_id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -241,15 +263,16 @@ impl KernelScheme for RootScheme {
|
||||
_offset: u64,
|
||||
flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
match handle {
|
||||
Handle::Scheme(inner) => inner.read(buf, flags),
|
||||
Handle::Scheme(inner) => inner.read(buf, flags, token),
|
||||
Handle::File(_) => Err(Error::new(EBADF)),
|
||||
Handle::List { .. } => Err(Error::new(EISDIR)),
|
||||
}
|
||||
@@ -260,14 +283,20 @@ impl KernelScheme for RootScheme {
|
||||
buf: UserSliceWo,
|
||||
header_size: u16,
|
||||
opaque: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Handle::List { ens } = *self.handles.read().get(&id).ok_or(Error::new(EBADF))? else {
|
||||
let Handle::List { ens } = *self
|
||||
.handles
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
else {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
};
|
||||
|
||||
let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?;
|
||||
{
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
for (i, (name, _)) in schemes
|
||||
.iter_name(ens)
|
||||
.enumerate()
|
||||
@@ -292,23 +321,24 @@ impl KernelScheme for RootScheme {
|
||||
buf: UserSliceRo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
match handle {
|
||||
Handle::Scheme(inner) => inner.write(buf),
|
||||
Handle::Scheme(inner) => inner.write(buf, token),
|
||||
Handle::File(_) => Err(Error::new(EBADF)),
|
||||
Handle::List { .. } => Err(Error::new(EISDIR)),
|
||||
}
|
||||
}
|
||||
|
||||
fn kfstat(&self, file: usize, buf: UserSliceWo) -> Result<()> {
|
||||
fn kfstat(&self, file: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&file).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -334,13 +364,14 @@ impl KernelScheme for RootScheme {
|
||||
fn kfdwrite(
|
||||
&self,
|
||||
id: usize,
|
||||
descs: Vec<Arc<RwLock<FileDescription>>>,
|
||||
descs: Vec<Arc<spin::RwLock<FileDescription>>>,
|
||||
flags: CallFlags,
|
||||
arg: u64,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
@@ -358,15 +389,16 @@ impl KernelScheme for RootScheme {
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = self.handles.read();
|
||||
let handles = self.handles.read(token.token());
|
||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
handle.clone()
|
||||
};
|
||||
|
||||
match handle {
|
||||
Handle::Scheme(inner) => inner.call_fdread(payload, flags, metadata),
|
||||
Handle::Scheme(inner) => inner.call_fdread(payload, flags, metadata, token),
|
||||
Handle::File(_) => Err(Error::new(EBADF)),
|
||||
Handle::List { .. } => Err(Error::new(EISDIR)),
|
||||
}
|
||||
|
||||
+36
-19
@@ -5,12 +5,10 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use spin::RwLock;
|
||||
|
||||
use crate::{
|
||||
event,
|
||||
scheme::*,
|
||||
sync::WaitQueue,
|
||||
sync::{CleanLockToken, RwLock, WaitQueue, L1},
|
||||
syscall::{
|
||||
flag::{EventFlags, EVENT_READ, O_NONBLOCK},
|
||||
usercopy::UserSliceWo,
|
||||
@@ -27,17 +25,17 @@ struct Handle {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
/// Add to the input queue
|
||||
pub fn serio_input(index: usize, data: u8) {
|
||||
pub fn serio_input(index: usize, data: u8, token: &mut CleanLockToken) {
|
||||
#[cfg(feature = "profiling")]
|
||||
crate::profiling::serio_command(index, data);
|
||||
|
||||
INPUT[index].send(data);
|
||||
INPUT[index].send(data, token);
|
||||
|
||||
for (id, _handle) in HANDLES.read().iter() {
|
||||
for (id, _handle) in HANDLES.read(token.token()).iter() {
|
||||
event::trigger(GlobalSchemes::Serio.scheme_id(), *id, EVENT_READ);
|
||||
}
|
||||
}
|
||||
@@ -45,7 +43,13 @@ pub fn serio_input(index: usize, data: u8) {
|
||||
pub struct SerioScheme;
|
||||
|
||||
impl KernelScheme for SerioScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
@@ -56,23 +60,28 @@ impl KernelScheme for SerioScheme {
|
||||
}
|
||||
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
HANDLES.write().insert(id, Handle { index });
|
||||
HANDLES.write(token.token()).insert(id, Handle { index });
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
_flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
let _handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
Ok(EventFlags::empty())
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<()> {
|
||||
fn fsync(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let _handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
@@ -80,17 +89,24 @@ impl KernelScheme for SerioScheme {
|
||||
}
|
||||
|
||||
/// Close the file `number`
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
let _handle = {
|
||||
let mut handles = HANDLES.write();
|
||||
let mut handles = HANDLES.write(token.token());
|
||||
handles.remove(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn kread(&self, id: usize, buf: UserSliceWo, flags: u32, _stored_flags: u32) -> Result<usize> {
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceWo,
|
||||
flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
@@ -98,12 +114,13 @@ impl KernelScheme for SerioScheme {
|
||||
buf,
|
||||
flags & O_NONBLOCK as u32 == 0,
|
||||
"SerioScheme::read",
|
||||
token,
|
||||
)
|
||||
}
|
||||
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let handle = {
|
||||
let handles = HANDLES.read();
|
||||
let handles = HANDLES.read(token.token());
|
||||
*handles.get(&id).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
let path = format!("serio:{}", handle.index).into_bytes();
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::fmt::Write;
|
||||
|
||||
use crate::{context, syscall::error::Result};
|
||||
use crate::{context, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = String::new();
|
||||
|
||||
{
|
||||
let mut rows = Vec::new();
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
let mut contexts = context::contexts(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
for context_lock in contexts.iter().filter_map(|r| r.upgrade()) {
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
rows.push((context.pid, context.name.clone(), context.status_reason));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ use alloc::{
|
||||
};
|
||||
use core::fmt::Write;
|
||||
|
||||
use crate::{context, paging::PAGE_SIZE, syscall::error::Result};
|
||||
use crate::{context, paging::PAGE_SIZE, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = format!(
|
||||
"{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<11}{:<12}{:<8}{}\n",
|
||||
"PID", "EUID", "EGID", "ENS", "STAT", "CPU", "AFFINITY", "TIME", "MEM", "NAME"
|
||||
@@ -14,9 +14,10 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
|
||||
let mut rows = Vec::new();
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
let mut contexts = context::contexts(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
for context_ref in contexts.iter().filter_map(|r| r.upgrade()) {
|
||||
let context = context_ref.read();
|
||||
let context = context_ref.read(token.token());
|
||||
|
||||
let mut stat_string = String::new();
|
||||
// TODO: All user programs must have some grant in order for executable memory to even
|
||||
|
||||
@@ -2,10 +2,11 @@ use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
device::cpu::cpu_info,
|
||||
sync::CleanLockToken,
|
||||
syscall::error::{Error, Result, EIO},
|
||||
};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = format!("CPUs: {}\n", crate::cpu_count());
|
||||
|
||||
match cpu_info(&mut string) {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{context, syscall::error::Result};
|
||||
use crate::{context, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
Ok(context::current().read().name.as_bytes().to_vec())
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
Ok(context::current()
|
||||
.read(token.token())
|
||||
.name
|
||||
.as_bytes()
|
||||
.to_vec())
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
context,
|
||||
context::{file::FileDescription, memory::AddrSpaceWrapper},
|
||||
scheme,
|
||||
sync::CleanLockToken,
|
||||
syscall::error::Result,
|
||||
};
|
||||
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
|
||||
@@ -9,7 +10,7 @@ use core::{fmt::Write, hash::Hash};
|
||||
use hashbrown::HashMap;
|
||||
use spin::RwLock;
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
#[derive(Debug)]
|
||||
struct Ref<T>(Arc<T>);
|
||||
impl<T> Hash for Ref<T> {
|
||||
@@ -31,7 +32,10 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
let mut map = HashMap::<Ref<RwLock<FileDescription>>, Descr>::new();
|
||||
|
||||
let mut report = String::new();
|
||||
'contexts: for context in context::contexts().iter().filter_map(|c| c.upgrade()) {
|
||||
'contexts: for context in context::contexts(token.token())
|
||||
.iter()
|
||||
.filter_map(|c| c.upgrade())
|
||||
{
|
||||
let context = context.read();
|
||||
let files = context.files.read();
|
||||
writeln!(report, "'{}' {{", context.name).unwrap();
|
||||
@@ -51,7 +55,7 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
let descr = map.entry(fr).or_default();
|
||||
|
||||
let scheme_id = file.description.read().scheme;
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.names
|
||||
.iter()
|
||||
.flat_map(|(_, v)| v.iter())
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::{
|
||||
},
|
||||
paging::PAGE_SIZE,
|
||||
scheme,
|
||||
sync::CleanLockToken,
|
||||
syscall::{
|
||||
error::Result,
|
||||
flag::MapFlags,
|
||||
@@ -14,16 +15,17 @@ use crate::{
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
use core::{fmt::Write, num::NonZeroUsize, str};
|
||||
|
||||
fn inner(fpath_user: UserSliceRw) -> Result<Vec<u8>> {
|
||||
fn inner(fpath_user: UserSliceRw, token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = String::new();
|
||||
let mut fpath_kernel = [0; PAGE_SIZE];
|
||||
|
||||
{
|
||||
let mut rows = Vec::new();
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
let mut contexts = context::contexts(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
for context_ref in contexts.iter().filter_map(|r| r.upgrade()) {
|
||||
let context = context_ref.read();
|
||||
let context = context_ref.read(token.token());
|
||||
rows.push((
|
||||
context.pid,
|
||||
context.name.clone(),
|
||||
@@ -54,7 +56,7 @@ fn inner(fpath_user: UserSliceRw) -> Result<Vec<u8>> {
|
||||
);
|
||||
|
||||
let scheme = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
match schemes.get(description.scheme) {
|
||||
Some(scheme) => scheme.clone(),
|
||||
None => {
|
||||
@@ -64,7 +66,11 @@ fn inner(fpath_user: UserSliceRw) -> Result<Vec<u8>> {
|
||||
}
|
||||
};
|
||||
|
||||
match scheme.kfpath(description.number, fpath_user.reinterpret_unchecked()) {
|
||||
match scheme.kfpath(
|
||||
description.number,
|
||||
fpath_user.reinterpret_unchecked(),
|
||||
token,
|
||||
) {
|
||||
Ok(path_len) => {
|
||||
fpath_user.copy_to_slice(&mut fpath_kernel)?;
|
||||
let fname = str::from_utf8(&fpath_kernel[..path_len]).unwrap_or("?");
|
||||
@@ -81,10 +87,10 @@ fn inner(fpath_user: UserSliceRw) -> Result<Vec<u8>> {
|
||||
Ok(string.into_bytes())
|
||||
}
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let page_count = NonZeroUsize::new(1).unwrap();
|
||||
let fpath_page = {
|
||||
let addr_space = Arc::clone(context::current().read().addr_space()?);
|
||||
let addr_space = Arc::clone(context::current().read(token.token()).addr_space()?);
|
||||
addr_space.acquire_write().mmap(
|
||||
&addr_space,
|
||||
None,
|
||||
@@ -104,10 +110,11 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
)?
|
||||
};
|
||||
|
||||
let res = UserSlice::rw(fpath_page.start_address().data(), PAGE_SIZE).and_then(inner);
|
||||
let res = UserSlice::rw(fpath_page.start_address().data(), PAGE_SIZE)
|
||||
.and_then(|fpath_user| inner(fpath_user, token));
|
||||
|
||||
{
|
||||
let addr_space = Arc::clone(context::current().read().addr_space()?);
|
||||
let addr_space = Arc::clone(context::current().read(token.token()).addr_space()?);
|
||||
addr_space.munmap(PageSpan::new(fpath_page, page_count.get()), false)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::fmt::Write;
|
||||
|
||||
use crate::syscall::error::Result;
|
||||
use crate::{sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = String::new();
|
||||
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{log::LOG, syscall::error::Result};
|
||||
use crate::{log::LOG, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut vec = Vec::new();
|
||||
|
||||
if let Some(ref log) = *LOG.lock() {
|
||||
|
||||
+57
-24
@@ -13,12 +13,12 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::RwLock;
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
use crate::arch::interrupt;
|
||||
use crate::{
|
||||
context::file::InternalFlags,
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::Stat,
|
||||
error::{Error, Result, EBADF, ENOENT},
|
||||
@@ -57,15 +57,15 @@ enum Handle {
|
||||
}
|
||||
|
||||
enum Kind {
|
||||
Rd(fn() -> Result<Vec<u8>>),
|
||||
Wr(fn(&[u8]) -> Result<usize>),
|
||||
Rd(fn(&mut CleanLockToken) -> Result<Vec<u8>>),
|
||||
Wr(fn(&[u8], &mut CleanLockToken) -> Result<usize>),
|
||||
}
|
||||
use Kind::*;
|
||||
|
||||
/// System information scheme
|
||||
pub struct SysScheme;
|
||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
static HANDLES: RwLock<HashMap<usize, Handle>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, Handle>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
const FILES: &[(&'static str, Kind)] = &[
|
||||
@@ -82,7 +82,7 @@ const FILES: &[(&'static str, Kind)] = &[
|
||||
("scheme_num", Rd(scheme_num::resource)),
|
||||
("syscall", Rd(syscall::resource)),
|
||||
("uname", Rd(uname::resource)),
|
||||
("env", Rd(|| Ok(Vec::from(crate::init_env())))),
|
||||
("env", Rd(|_| Ok(Vec::from(crate::init_env())))),
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
("spurious_irq", Rd(interrupt::irq::spurious_irq_resource)),
|
||||
#[cfg(feature = "sys_stat")]
|
||||
@@ -100,9 +100,9 @@ const FILES: &[(&'static str, Kind)] = &[
|
||||
),
|
||||
(
|
||||
"kstop",
|
||||
Wr(|arg| unsafe {
|
||||
Wr(|arg, token| unsafe {
|
||||
match arg.trim_ascii() {
|
||||
b"shutdown" => crate::stop::kstop(),
|
||||
b"shutdown" => crate::stop::kstop(token),
|
||||
b"reset" => crate::stop::kreset(),
|
||||
b"emergency_reset" => crate::stop::emergency_reset(),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
@@ -112,13 +112,19 @@ const FILES: &[(&'static str, Kind)] = &[
|
||||
];
|
||||
|
||||
impl KernelScheme for SysScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let path = path.trim_matches('/');
|
||||
|
||||
if path.is_empty() {
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
HANDLES.write().insert(id, Handle::TopLevel);
|
||||
HANDLES.write(token.token()).insert(id, Handle::TopLevel);
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED))
|
||||
} else {
|
||||
@@ -134,10 +140,10 @@ impl KernelScheme for SysScheme {
|
||||
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
let data = match entry.1 {
|
||||
Rd(r) => Some(r()?),
|
||||
Rd(r) => Some(r(token)?),
|
||||
Wr(_) => None,
|
||||
};
|
||||
HANDLES.write().insert(
|
||||
HANDLES.write(token.token()).insert(
|
||||
id,
|
||||
Handle::Resource {
|
||||
path: entry.0,
|
||||
@@ -148,19 +154,26 @@ impl KernelScheme for SysScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn fsize(&self, id: usize) -> Result<u64> {
|
||||
match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
fn fsize(&self, id: usize, token: &mut CleanLockToken) -> Result<u64> {
|
||||
match HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::TopLevel => Ok(0),
|
||||
Handle::Resource { data, .. } => Ok(data.as_ref().map_or(0, |d| d.len() as u64)),
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
HANDLES.write().remove(&id).ok_or(Error::new(EBADF))?;
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
HANDLES
|
||||
.write(token.token())
|
||||
.remove(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
Ok(())
|
||||
}
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
let handles = HANDLES.read();
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let handles = HANDLES.read(token.token());
|
||||
let path = match handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::TopLevel => "",
|
||||
Handle::Resource { path, .. } => path,
|
||||
@@ -182,12 +195,17 @@ impl KernelScheme for SysScheme {
|
||||
pos: u64,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Ok(pos) = usize::try_from(pos) else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
match HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::TopLevel | Handle::Resource { data: None, .. } => {
|
||||
return Err(Error::new(EISDIR))
|
||||
}
|
||||
@@ -208,8 +226,13 @@ impl KernelScheme for SysScheme {
|
||||
_pos: u64,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
let (handler, intermediate, len) = match HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::TopLevel | Handle::Resource { data: Some(_), .. } => {
|
||||
return Err(Error::new(EISDIR))
|
||||
}
|
||||
@@ -223,9 +246,10 @@ impl KernelScheme for SysScheme {
|
||||
else {
|
||||
return Err(Error::new(EBADFD))?;
|
||||
};
|
||||
handler(&intermediate[..len])
|
||||
(handler, intermediate, len)
|
||||
}
|
||||
}
|
||||
};
|
||||
handler(&intermediate[..len], token)
|
||||
}
|
||||
fn getdents(
|
||||
&self,
|
||||
@@ -233,11 +257,16 @@ impl KernelScheme for SysScheme {
|
||||
buf: UserSliceWo,
|
||||
header_size: u16,
|
||||
first_index: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let Ok(first_index) = usize::try_from(first_index) else {
|
||||
return Ok(0);
|
||||
};
|
||||
match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
match HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::Resource { .. } => return Err(Error::new(ENOTDIR)),
|
||||
Handle::TopLevel => {
|
||||
let mut buf = DirentBuf::new(buf, header_size).ok_or(Error::new(EIO))?;
|
||||
@@ -254,8 +283,12 @@ impl KernelScheme for SysScheme {
|
||||
}
|
||||
}
|
||||
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo) -> Result<()> {
|
||||
let stat = match HANDLES.read().get(&id).ok_or(Error::new(EBADF))? {
|
||||
fn kfstat(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let stat = match HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
{
|
||||
Handle::Resource { data, .. } => Stat {
|
||||
st_mode: 0o666 | MODE_FILE,
|
||||
st_uid: 0,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{context, scheme, syscall::error::Result};
|
||||
use crate::{context, scheme, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
let scheme_ns = context::current().read().ens;
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let scheme_ns = context::current().read(token.token()).ens;
|
||||
|
||||
let mut data = Vec::new();
|
||||
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
for (name, _scheme_id) in schemes.iter_name(scheme_ns) {
|
||||
data.extend_from_slice(name.as_bytes());
|
||||
data.push(b'\n');
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{context, scheme, syscall::error::Result};
|
||||
use crate::{context, scheme, sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
let scheme_ns = context::current().read().ens;
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let scheme_ns = context::current().read(token.token()).ens;
|
||||
|
||||
let mut data = Vec::new();
|
||||
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
for (name, &scheme_id) in schemes.iter_name(scheme_ns) {
|
||||
data.extend_from_slice(format!("{:>4}: ", scheme_id.get()).as_bytes());
|
||||
data.extend_from_slice(name.as_bytes());
|
||||
|
||||
@@ -2,16 +2,17 @@ use crate::{
|
||||
context::{contexts, ContextRef, Status},
|
||||
cpu_stats::{get_context_switch_count, get_contexts_count, irq_counts},
|
||||
percpu::get_all_stats,
|
||||
sync::CleanLockToken,
|
||||
syscall::error::Result,
|
||||
time::START,
|
||||
};
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
/// Get the sys:stat data as displayed to the user.
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let start_time_sec = *START.lock() / 1_000_000_000;
|
||||
|
||||
let (contexts_running, contexts_blocked) = get_contexts_stats();
|
||||
let (contexts_running, contexts_blocked) = get_contexts_stats(token);
|
||||
let res = format!(
|
||||
"{}{}\n\
|
||||
boot_time: {start_time_sec}\n\
|
||||
@@ -68,11 +69,11 @@ fn get_irq_stats() -> String {
|
||||
}
|
||||
|
||||
/// Format contexts stats.
|
||||
fn get_contexts_stats() -> (u64, u64) {
|
||||
fn get_contexts_stats(token: &mut CleanLockToken) -> (u64, u64) {
|
||||
let mut running = 0;
|
||||
let mut blocked = 0;
|
||||
|
||||
let statuses = contexts()
|
||||
let statuses = contexts(token.token())
|
||||
.iter()
|
||||
.filter_map(ContextRef::upgrade)
|
||||
.map(|context| context.read_arc().status.clone())
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::fmt::Write;
|
||||
|
||||
use crate::{context, syscall, syscall::error::Result};
|
||||
use crate::{context, sync::CleanLockToken, syscall, syscall::error::Result};
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
let mut string = String::new();
|
||||
|
||||
{
|
||||
let mut rows = Vec::new();
|
||||
{
|
||||
let contexts = context::contexts();
|
||||
let mut contexts = context::contexts(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
for context_ref in contexts.iter().filter_map(|r| r.upgrade()) {
|
||||
let context = context_ref.read();
|
||||
let context = context_ref.read(token.token());
|
||||
rows.push((context.pid, context.name.clone(), context.current_syscall()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::syscall::error::Result;
|
||||
use crate::{sync::CleanLockToken, syscall::error::Result};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub fn resource() -> Result<Vec<u8>> {
|
||||
pub fn resource(_token: &mut CleanLockToken) -> Result<Vec<u8>> {
|
||||
Ok(format!(
|
||||
"Redox\n\n{}\n\n{}\n",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
|
||||
+54
-17
@@ -3,10 +3,10 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
use hashbrown::{hash_map::DefaultHashBuilder, HashMap};
|
||||
use spin::RwLock;
|
||||
|
||||
use crate::{
|
||||
context::{file::InternalFlags, timeout},
|
||||
sync::{CleanLockToken, RwLock, L1},
|
||||
syscall::{
|
||||
data::TimeSpec,
|
||||
error::*,
|
||||
@@ -19,13 +19,19 @@ use crate::{
|
||||
use super::{CallerCtx, GlobalSchemes, KernelScheme, OpenResult};
|
||||
|
||||
static NEXT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
static HANDLES: RwLock<HashMap<usize, usize>> =
|
||||
static HANDLES: RwLock<L1, HashMap<usize, usize>> =
|
||||
RwLock::new(HashMap::with_hasher(DefaultHashBuilder::new()));
|
||||
|
||||
pub struct TimeScheme;
|
||||
|
||||
impl KernelScheme for TimeScheme {
|
||||
fn kopen(&self, path: &str, _flags: usize, _ctx: CallerCtx) -> Result<OpenResult> {
|
||||
fn kopen(
|
||||
&self,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_ctx: CallerCtx,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<OpenResult> {
|
||||
let clock = path.parse::<usize>().map_err(|_| Error::new(ENOENT))?;
|
||||
|
||||
match clock {
|
||||
@@ -35,37 +41,61 @@ impl KernelScheme for TimeScheme {
|
||||
}
|
||||
|
||||
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
||||
HANDLES.write().insert(id, clock);
|
||||
HANDLES.write(token.token()).insert(id, clock);
|
||||
|
||||
Ok(OpenResult::SchemeLocal(id, InternalFlags::empty()))
|
||||
}
|
||||
|
||||
fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
|
||||
fn fcntl(
|
||||
&self,
|
||||
_id: usize,
|
||||
_cmd: usize,
|
||||
_arg: usize,
|
||||
_token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
|
||||
fn fevent(
|
||||
&self,
|
||||
id: usize,
|
||||
_flags: EventFlags,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<EventFlags> {
|
||||
HANDLES
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))
|
||||
.and(Ok(EventFlags::empty()))
|
||||
}
|
||||
|
||||
fn fsync(&self, id: usize) -> Result<()> {
|
||||
HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
|
||||
fn fsync(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, id: usize) -> Result<()> {
|
||||
fn close(&self, id: usize, token: &mut CleanLockToken) -> Result<()> {
|
||||
HANDLES
|
||||
.write()
|
||||
.write(token.token())
|
||||
.remove(&id)
|
||||
.ok_or(Error::new(EBADF))
|
||||
.and(Ok(()))
|
||||
}
|
||||
fn kread(&self, id: usize, buf: UserSliceWo, _flags: u32, _stored_flags: u32) -> Result<usize> {
|
||||
let clock = *HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
|
||||
fn kread(
|
||||
&self,
|
||||
id: usize,
|
||||
buf: UserSliceWo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let clock = *HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let mut bytes_read = 0;
|
||||
|
||||
@@ -93,23 +123,30 @@ impl KernelScheme for TimeScheme {
|
||||
buf: UserSliceRo,
|
||||
_flags: u32,
|
||||
_stored_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let clock = *HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
|
||||
let clock = *HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let mut bytes_written = 0;
|
||||
|
||||
for current_chunk in buf.in_exact_chunks(mem::size_of::<TimeSpec>()) {
|
||||
let time = unsafe { current_chunk.read_exact::<TimeSpec>()? };
|
||||
|
||||
timeout::register(GlobalSchemes::Time.scheme_id(), id, clock, time);
|
||||
timeout::register(GlobalSchemes::Time.scheme_id(), id, clock, time, token);
|
||||
|
||||
bytes_written += mem::size_of::<TimeSpec>();
|
||||
}
|
||||
|
||||
Ok(bytes_written)
|
||||
}
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo) -> Result<usize> {
|
||||
let clock = *HANDLES.read().get(&id).ok_or(Error::new(EBADF))?;
|
||||
fn kfpath(&self, id: usize, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let clock = *HANDLES
|
||||
.read(token.token())
|
||||
.get(&id)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let scheme_path = format!("time:{}", clock).into_bytes();
|
||||
buf.copy_common_bytes_from_slice(&scheme_path)
|
||||
|
||||
+267
-138
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -1,4 +1,5 @@
|
||||
pub use self::{wait_condition::WaitCondition, wait_queue::WaitQueue};
|
||||
pub use self::{ordered::*, wait_condition::WaitCondition, wait_queue::WaitQueue};
|
||||
|
||||
pub mod ordered;
|
||||
pub mod wait_condition;
|
||||
pub mod wait_queue;
|
||||
|
||||
@@ -0,0 +1,440 @@
|
||||
// This code was adapted from MIT licensed https://github.com/antialize/ordered-locks
|
||||
// We cannot use that library directly as it is wrapping std::sync types
|
||||
|
||||
//! This create implement compiletime ordering of locks into levels, [`L1`], [`L2`], [`L3`], [`L4`] and [`L5`].
|
||||
//! In order to acquire a lock at level `i` only locks at level `i-1` or below may be held.
|
||||
//!
|
||||
//! If locks are alwayes acquired in level order on all threads, then one cannot have a deadlock
|
||||
//! involving only acquireng locks.
|
||||
//!
|
||||
//! In the following example we create two [muteces](Mutex) at level [`L1`] and [`L2`] and lock them
|
||||
//! in the propper order.
|
||||
//! ```
|
||||
//! use ordered_locks::{L1, L2, Mutex, CleanLockToken};
|
||||
//! // Create value at lock level 0, this lock cannot be acquired while a level1 lock is heldt
|
||||
//! let v1 = Mutex::<L1, _>::new(42);
|
||||
//! // Create value at lock level 1
|
||||
//! let v2 = Mutex::<L2, _>::new(43);
|
||||
//! // Construct a token indicating that this thread does not hold any locks
|
||||
//! let mut token = unsafe {CleanLockToken::new()};
|
||||
//!
|
||||
//! {
|
||||
//! // We can aquire the locks for v1 and v2 at the same time
|
||||
//! let mut g1 = v1.lock(token.token());
|
||||
//! let (g1, token) = g1.token_split();
|
||||
//! let mut g2 = v2.lock(token);
|
||||
//! *g2 = 11;
|
||||
//! *g1 = 12;
|
||||
//! }
|
||||
//! // Once the guards are dropped we can acquire other things
|
||||
//! *v2.lock(token.token()) = 13;
|
||||
//! ```
|
||||
//!
|
||||
//! In the following example we create two [muteces](Mutex) at level [`L1`] and [`L2`] and try to lock
|
||||
//! the mutex at [`L1`] while already holding a [`Mutex`] at [`L2`] which failes to compile.
|
||||
//! ```compile_fail
|
||||
//! use ordered_locks::{L1, L2, Mutex, CleanLockToken};
|
||||
//! // Create value at lock level 0, this lock cannot be acquired while a level1 lock is heldt
|
||||
//! let v1 = Mutex::<L1, _>::new(42);
|
||||
//! // Create value at lock level 1
|
||||
//! let v2 = Mutex::<L2, _>::new(43);
|
||||
//! // Construct a token indicating that this thread does not hold any locks
|
||||
//! let mut clean_token = unsafe {CleanLockToken::new()};
|
||||
//! let token = clean_token.token();
|
||||
//!
|
||||
//! // Try to aquire locks in the wrong order
|
||||
//! let mut g2 = v2.lock(token);
|
||||
//! let (g2, token) = g2.token_split();
|
||||
//! let mut g1 = v1.lock(token); // shouldn't compile!
|
||||
//! *g2 = 11;
|
||||
//! *g1 = 12;
|
||||
//! ```
|
||||
use alloc::sync::Arc;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Lock level of a mutex
|
||||
///
|
||||
/// While a mutex of L1 is locked on a thread, only mutexes of L2 or higher may be locked.
|
||||
/// This lock hierarchy prevents deadlocks from occurring. For a dead lock to occour
|
||||
/// We need some thread TA to hold a resource RA, and request a resource RB, while
|
||||
/// another thread TB holds RB, and requests RA. This is not possible with a lock
|
||||
/// hierarchy either RA or RB must be on a level that the other.
|
||||
///
|
||||
/// At some point in time we would want Level to be replaced by usize, however
|
||||
/// with current cont generics (rust 1.55), we cannot compare const generic arguments
|
||||
/// so we are left with this mess.
|
||||
pub trait Level {}
|
||||
|
||||
/// Indicate that the implementor is lower that the level O
|
||||
pub trait Lower<O: Level>: Level {}
|
||||
|
||||
/// Lowest locking level, no locks can be on this level
|
||||
#[derive(Debug)]
|
||||
pub struct L0 {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct L1 {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct L2 {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct L3 {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct L4 {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct L5 {}
|
||||
|
||||
impl Level for L0 {}
|
||||
impl Level for L1 {}
|
||||
impl Level for L2 {}
|
||||
impl Level for L3 {}
|
||||
impl Level for L4 {}
|
||||
impl Level for L5 {}
|
||||
|
||||
impl Lower<L1> for L0 {}
|
||||
impl Lower<L2> for L0 {}
|
||||
impl Lower<L3> for L0 {}
|
||||
impl Lower<L4> for L0 {}
|
||||
impl Lower<L5> for L0 {}
|
||||
|
||||
impl Lower<L2> for L1 {}
|
||||
impl Lower<L3> for L1 {}
|
||||
impl Lower<L4> for L1 {}
|
||||
impl Lower<L5> for L1 {}
|
||||
|
||||
impl Lower<L3> for L2 {}
|
||||
impl Lower<L4> for L2 {}
|
||||
impl Lower<L5> for L2 {}
|
||||
|
||||
impl Lower<L4> for L3 {}
|
||||
impl Lower<L5> for L3 {}
|
||||
|
||||
impl Lower<L5> for L4 {}
|
||||
|
||||
/// Indicate that the implementor is higher that the level O
|
||||
pub trait Higher<O: Level>: Level {}
|
||||
impl<L1: Level, L2: Level> Higher<L2> for L1 where L2: Lower<L1> {}
|
||||
|
||||
/// While this exists only locks with a level higher than L, may be locked.
|
||||
/// These tokens are carried around the call stack to indicate tho current locking level.
|
||||
/// They have no size and should disappear at runtime.
|
||||
pub struct LockToken<'a, L: Level>(PhantomData<&'a mut L>);
|
||||
|
||||
impl<'a, L: Level> LockToken<'a, L> {
|
||||
/// Create a borrowed copy of self
|
||||
pub fn token(&mut self) -> LockToken<'_, L> {
|
||||
LockToken(Default::default())
|
||||
}
|
||||
|
||||
/// Create a borrowed copy of self, on a higher level
|
||||
pub fn downgrade<LC: Higher<L>>(&mut self) -> LockToken<'_, LC> {
|
||||
LockToken(Default::default())
|
||||
}
|
||||
|
||||
pub fn downgraded<LP: Lower<L>>(_: LockToken<'a, LP>) -> Self {
|
||||
LockToken(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Token indicating that there are no acquired locks while not borrowed.
|
||||
pub struct CleanLockToken(());
|
||||
|
||||
impl CleanLockToken {
|
||||
/// Create a borrowed copy of self
|
||||
pub fn token(&mut self) -> LockToken<'_, L0> {
|
||||
LockToken(Default::default())
|
||||
}
|
||||
|
||||
/// Create a borrowed copy of self, on a higher level
|
||||
pub fn downgrade<L: Level>(&mut self) -> LockToken<'_, L> {
|
||||
LockToken(Default::default())
|
||||
}
|
||||
|
||||
/// Create a new instance
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is safe to call as long as there are no currently acquired locks
|
||||
/// in the thread/task, and as long as there are no other CleanLockToken
|
||||
/// in the thread/task.
|
||||
///
|
||||
/// A CleanLockToken
|
||||
pub unsafe fn new() -> Self {
|
||||
CleanLockToken(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutual exclusion primitive useful for protecting shared data
|
||||
///
|
||||
/// This mutex will block threads waiting for the lock to become available. The
|
||||
/// mutex can also be statically initialized or created via a `new`
|
||||
/// constructor. Each mutex has a type parameter which represents the data that
|
||||
/// it is protecting. The data can only be accessed through the RAII guards
|
||||
/// returned from `lock` and `try_lock`, which guarantees that the data is only
|
||||
/// ever accessed when the mutex is locked.
|
||||
#[derive(Debug)]
|
||||
pub struct Mutex<L: Level, T> {
|
||||
inner: spin::Mutex<T>,
|
||||
_phantom: PhantomData<L>,
|
||||
}
|
||||
|
||||
impl<L: Level, T: Default> Default for Mutex<L, T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Level, T> Mutex<L, T> {
|
||||
/// Creates a new mutex in an unlocked state ready for use
|
||||
pub const fn new(val: T) -> Self {
|
||||
Self {
|
||||
inner: spin::Mutex::new(val),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Acquires a mutex, blocking the current thread until it is able to do so.
|
||||
///
|
||||
/// This function will block the local thread until it is available to acquire the mutex.
|
||||
/// Upon returning, the thread is the only thread with the mutex held.
|
||||
/// An RAII guard is returned to allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be unlocked.
|
||||
pub fn lock<'a, LP: Lower<L> + 'a>(
|
||||
&'a self,
|
||||
lock_token: LockToken<'a, LP>,
|
||||
) -> MutexGuard<'a, L, T> {
|
||||
MutexGuard {
|
||||
inner: self.inner.lock(),
|
||||
lock_token: LockToken::downgraded(lock_token),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to acquire this lock.
|
||||
///
|
||||
/// If the lock could not be acquired at this time, then `None` is returned.
|
||||
/// Otherwise, an RAII guard is returned. The lock will be unlocked when the
|
||||
/// guard is dropped.
|
||||
///
|
||||
/// This function does not block.
|
||||
pub fn try_lock<'a, LP: Lower<L> + 'a>(
|
||||
&'a self,
|
||||
lock_token: LockToken<'a, LP>,
|
||||
) -> Option<MutexGuard<'a, L, T>> {
|
||||
match self.inner.try_lock() {
|
||||
Some(inner) => Some(MutexGuard {
|
||||
inner,
|
||||
lock_token: LockToken::downgraded(lock_token),
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes this Mutex, returning the underlying data.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
|
||||
/// dropped (falls out of scope), the lock will be unlocked.
|
||||
///
|
||||
/// The data protected by the mutex can be accessed through this guard via its
|
||||
/// `Deref` and `DerefMut` implementations.
|
||||
pub struct MutexGuard<'a, L: Level, T: ?Sized + 'a> {
|
||||
inner: spin::MutexGuard<'a, T>,
|
||||
lock_token: LockToken<'a, L>,
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T: ?Sized + 'a> MutexGuard<'a, L, T> {
|
||||
/// Split the guard into two parts, the first a mutable reference to the held content
|
||||
/// the second a [`LockToken`] that can be used for further locking
|
||||
pub fn token_split(&mut self) -> (&mut T, LockToken<'_, L>) {
|
||||
(&mut self.inner, self.lock_token.token())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T: ?Sized + 'a> core::ops::Deref for MutexGuard<'a, L, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
impl<'a, L: Level, T: ?Sized + 'a> core::ops::DerefMut for MutexGuard<'a, L, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RwLock<L: Level, T> {
|
||||
inner: spin::RwLock<T>,
|
||||
_phantom: PhantomData<L>,
|
||||
}
|
||||
|
||||
impl<L: Level, T: Default> Default for RwLock<L, T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A reader-writer lock
|
||||
///
|
||||
/// This type of lock allows a number of readers or at most one writer at any point in time.
|
||||
/// The write portion of this lock typically allows modification of the underlying data (exclusive access)
|
||||
/// and the read portion of this lock typically allows for read-only access (shared access).
|
||||
///
|
||||
/// The type parameter T represents the data that this lock protects. It is required that T satisfies
|
||||
/// Send to be shared across threads and Sync to allow concurrent access through readers.
|
||||
/// The RAII guards returned from the locking methods implement Deref (and DerefMut for the write methods)
|
||||
/// to allow access to the contained of the lock.
|
||||
impl<L: Level, T> RwLock<L, T> {
|
||||
/// Creates a new instance of an RwLock<T> which is unlocked.
|
||||
pub const fn new(val: T) -> Self {
|
||||
Self {
|
||||
inner: spin::RwLock::new(val),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes this RwLock, returning the underlying data.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner.into_inner()
|
||||
}
|
||||
|
||||
/// Locks this RwLock with exclusive write access, blocking the current thread until it can be acquired.
|
||||
/// This function will not return while other writers or other readers currently have access to the lock.
|
||||
/// Returns an RAII guard which will drop the write access of this RwLock when dropped.
|
||||
pub fn write<'a, LP: Lower<L> + 'a>(
|
||||
&'a self,
|
||||
lock_token: LockToken<'a, LP>,
|
||||
) -> RwLockWriteGuard<'a, L, T> {
|
||||
RwLockWriteGuard {
|
||||
inner: self.inner.write(),
|
||||
lock_token: LockToken::downgraded(lock_token),
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks this RwLock with shared read access, blocking the current thread until it can be acquired.
|
||||
///
|
||||
/// The calling thread will be blocked until there are no more writers which hold the lock.
|
||||
/// There may be other readers currently inside the lock when this method returns.
|
||||
///
|
||||
/// Note that attempts to recursively acquire a read lock on a RwLock when the current thread
|
||||
/// already holds one may result in a deadlock.
|
||||
///
|
||||
/// Returns an RAII guard which will release this thread’s shared access once it is dropped.
|
||||
pub fn read<'a, LP: Lower<L> + 'a>(
|
||||
&'a self,
|
||||
lock_token: LockToken<'a, LP>,
|
||||
) -> RwLockReadGuard<'a, L, T> {
|
||||
RwLockReadGuard {
|
||||
inner: self.inner.read(),
|
||||
lock_token: LockToken::downgraded(lock_token),
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe due to not using token, currently required by context::switch
|
||||
pub unsafe fn write_arc(self: &Arc<Self>) -> ArcRwLockWriteGuard<L, T> {
|
||||
core::mem::forget(self.inner.write());
|
||||
ArcRwLockWriteGuard {
|
||||
rwlock: self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// RAII structure used to release the exclusive write access of a lock when dropped
|
||||
pub struct RwLockWriteGuard<'a, L: Level, T> {
|
||||
inner: spin::RwLockWriteGuard<'a, T>,
|
||||
lock_token: LockToken<'a, L>,
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T> RwLockWriteGuard<'a, L, T> {
|
||||
/// Split the guard into two parts, the first a mutable reference to the held content
|
||||
/// the second a [`LockToken`] that can be used for further locking
|
||||
pub fn token_split(&mut self) -> (&mut T, LockToken<'_, L>) {
|
||||
(&mut self.inner, self.lock_token.token())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T> core::ops::Deref for RwLockWriteGuard<'a, L, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T> core::ops::DerefMut for RwLockWriteGuard<'a, L, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// RAII structure used to release the shared read access of a lock when dropped.
|
||||
pub struct RwLockReadGuard<'a, L: Level, T> {
|
||||
inner: spin::RwLockReadGuard<'a, T>,
|
||||
lock_token: LockToken<'a, L>,
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T> RwLockReadGuard<'a, L, T> {
|
||||
/// Split the guard into two parts, the first a reference to the held content
|
||||
/// the second a [`LockToken`] that can be used for further locking
|
||||
pub fn token_split(&mut self) -> (&T, LockToken<'_, L>) {
|
||||
(&self.inner, self.lock_token.token())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, L: Level, T> core::ops::Deref for RwLockReadGuard<'a, L, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ArcRwLockWriteGuard<L: Level + 'static, T> {
|
||||
rwlock: Arc<RwLock<L, T>>,
|
||||
}
|
||||
|
||||
impl<L: Level, T> ArcRwLockWriteGuard<L, T> {
|
||||
pub fn rwlock(s: &Self) -> &Arc<RwLock<L, T>> {
|
||||
&s.rwlock
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Level, T> core::ops::Deref for ArcRwLockWriteGuard<L, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*self.rwlock.inner.as_mut_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Level, T> core::ops::DerefMut for ArcRwLockWriteGuard<L, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { &mut *self.rwlock.inner.as_mut_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Level, T> Drop for ArcRwLockWriteGuard<L, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.rwlock.inner.force_write_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function can only be called if no lock is held by the calling thread/task
|
||||
#[inline]
|
||||
pub fn check_no_locks(_: LockToken<'_, L0>) {}
|
||||
+23
-16
@@ -2,14 +2,15 @@ use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use spin::Mutex;
|
||||
use spinning_top::RwSpinlock;
|
||||
|
||||
use crate::context::{self, Context};
|
||||
use crate::{
|
||||
context::{self, ContextLock},
|
||||
sync::{CleanLockToken, Mutex, L1},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WaitCondition {
|
||||
contexts: Mutex<Vec<Weak<RwSpinlock<Context>>>>,
|
||||
contexts: Mutex<L1, Vec<Weak<ContextLock>>>,
|
||||
}
|
||||
|
||||
impl WaitCondition {
|
||||
@@ -20,35 +21,37 @@ impl WaitCondition {
|
||||
}
|
||||
|
||||
// Notify all waiters
|
||||
pub fn notify(&self) -> usize {
|
||||
let mut contexts = self.contexts.lock();
|
||||
pub fn notify(&self, token: &mut CleanLockToken) -> usize {
|
||||
let mut contexts = self.contexts.lock(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
let len = contexts.len();
|
||||
while let Some(context_weak) = contexts.pop() {
|
||||
if let Some(context_ref) = context_weak.upgrade() {
|
||||
context_ref.write().unblock();
|
||||
context_ref.write(token.token()).unblock();
|
||||
}
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
// Notify as though a signal woke the waiters
|
||||
pub unsafe fn notify_signal(&self) -> usize {
|
||||
let contexts = self.contexts.lock();
|
||||
pub unsafe fn notify_signal(&self, token: &mut CleanLockToken) -> usize {
|
||||
let mut contexts = self.contexts.lock(token.token());
|
||||
let (contexts, mut token) = contexts.token_split();
|
||||
let len = contexts.len();
|
||||
for context_weak in contexts.iter() {
|
||||
if let Some(context_ref) = context_weak.upgrade() {
|
||||
context_ref.write().unblock();
|
||||
context_ref.write(token.token()).unblock();
|
||||
}
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
// Wait until notified. Unlocks guard when blocking is ready. Returns false if resumed by a signal or the notify_signal function
|
||||
pub fn wait<T>(&self, guard: T, reason: &'static str) -> bool {
|
||||
pub fn wait<T>(&self, guard: T, reason: &'static str, token: &mut CleanLockToken) -> bool {
|
||||
let current_context_ref = context::current();
|
||||
{
|
||||
{
|
||||
let mut context = current_context_ref.write();
|
||||
let mut context = current_context_ref.write(token.token());
|
||||
if let Some((control, pctl, _)) = context.sigcontrol()
|
||||
&& control.currently_pending_unblocked(pctl) != 0
|
||||
{
|
||||
@@ -58,18 +61,18 @@ impl WaitCondition {
|
||||
}
|
||||
|
||||
self.contexts
|
||||
.lock()
|
||||
.lock(token.token())
|
||||
.push(Arc::downgrade(¤t_context_ref));
|
||||
|
||||
drop(guard);
|
||||
}
|
||||
|
||||
context::switch();
|
||||
context::switch(token);
|
||||
|
||||
let mut waited = true;
|
||||
|
||||
{
|
||||
let mut contexts = self.contexts.lock();
|
||||
let mut contexts = self.contexts.lock(token.token());
|
||||
|
||||
// TODO: retain
|
||||
let mut i = 0;
|
||||
@@ -90,6 +93,10 @@ impl WaitCondition {
|
||||
|
||||
impl Drop for WaitCondition {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.notify_signal() };
|
||||
//TODO: drop violates lock tokens
|
||||
unsafe {
|
||||
let mut token = CleanLockToken::new();
|
||||
self.notify_signal(&mut token);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+12
-6
@@ -3,7 +3,7 @@ use spin::Mutex;
|
||||
use syscall::{EAGAIN, EINTR};
|
||||
|
||||
use crate::{
|
||||
sync::WaitCondition,
|
||||
sync::{CleanLockToken, WaitCondition},
|
||||
syscall::{
|
||||
error::{Error, Result, EINVAL},
|
||||
usercopy::UserSliceWo,
|
||||
@@ -27,7 +27,12 @@ impl<T> WaitQueue<T> {
|
||||
self.inner.lock().is_empty()
|
||||
}
|
||||
|
||||
pub fn receive(&self, block: bool, reason: &'static str) -> Result<T> {
|
||||
pub fn receive(
|
||||
&self,
|
||||
block: bool,
|
||||
reason: &'static str,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<T> {
|
||||
loop {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
@@ -37,7 +42,7 @@ impl<T> WaitQueue<T> {
|
||||
}
|
||||
_ => {
|
||||
if block {
|
||||
if !self.condition.wait(inner, reason) {
|
||||
if !self.condition.wait(inner, reason, token) {
|
||||
return Err(Error::new(EINTR));
|
||||
}
|
||||
continue;
|
||||
@@ -54,13 +59,14 @@ impl<T> WaitQueue<T> {
|
||||
buf: UserSliceWo,
|
||||
block: bool,
|
||||
reason: &'static str,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
loop {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
if inner.is_empty() {
|
||||
if block {
|
||||
if !self.condition.wait(inner, reason) {
|
||||
if !self.condition.wait(inner, reason, token) {
|
||||
return Err(Error::new(EINTR));
|
||||
}
|
||||
continue;
|
||||
@@ -100,13 +106,13 @@ impl<T> WaitQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, value: T) -> usize {
|
||||
pub fn send(&self, value: T, token: &mut CleanLockToken) -> usize {
|
||||
let len = {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.push_back(value);
|
||||
inner.len()
|
||||
};
|
||||
self.condition.notify();
|
||||
self.condition.notify(token);
|
||||
len
|
||||
}
|
||||
}
|
||||
|
||||
+15
-6
@@ -9,7 +9,7 @@ use super::{
|
||||
usercopy::UserSlice,
|
||||
};
|
||||
|
||||
use crate::syscall::error::Result;
|
||||
use crate::{sync::CleanLockToken, syscall::error::Result};
|
||||
|
||||
struct ByteStr<'a>(&'a [u8]);
|
||||
|
||||
@@ -217,12 +217,17 @@ impl SyscallDebugInfo {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "syscall_debug", inline)]
|
||||
pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) {
|
||||
pub fn debug_start([a, b, c, d, e, f]: [usize; 6], token: &mut CleanLockToken) {
|
||||
if cfg!(not(feature = "syscall_debug")) {
|
||||
return;
|
||||
}
|
||||
|
||||
let do_debug = if false && crate::context::current().read().name.contains("init") {
|
||||
let do_debug = if false
|
||||
&& crate::context::current()
|
||||
.read(token.token())
|
||||
.name
|
||||
.contains("init")
|
||||
{
|
||||
if a == SYS_CLOCK_GETTIME || a == SYS_YIELD || a == SYS_FUTEX {
|
||||
false
|
||||
} else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
|
||||
@@ -237,7 +242,7 @@ pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) {
|
||||
let debug_start = if do_debug {
|
||||
let context_lock = crate::context::current();
|
||||
{
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
print!("{} (*{}*): ", context.name, context.pid,);
|
||||
}
|
||||
|
||||
@@ -261,7 +266,11 @@ pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "syscall_debug", inline)]
|
||||
pub fn debug_end([a, b, c, d, e, f]: [usize; 6], result: Result<usize>) {
|
||||
pub fn debug_end(
|
||||
[a, b, c, d, e, f]: [usize; 6],
|
||||
result: Result<usize>,
|
||||
token: &mut CleanLockToken,
|
||||
) {
|
||||
if cfg!(not(feature = "syscall_debug")) {
|
||||
return;
|
||||
}
|
||||
@@ -278,7 +287,7 @@ pub fn debug_end([a, b, c, d, e, f]: [usize; 6], result: Result<usize>) {
|
||||
|
||||
let context_lock = crate::context::current();
|
||||
{
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
print!("{} (*{}*): ", context.name, context.pid,);
|
||||
}
|
||||
|
||||
|
||||
+167
-125
@@ -13,6 +13,7 @@ use crate::{
|
||||
},
|
||||
paging::{Page, VirtualAddress, PAGE_SIZE},
|
||||
scheme::{self, CallerCtx, FileHandle, KernelScheme, OpenResult, StrOrBytes},
|
||||
sync::CleanLockToken,
|
||||
syscall::{data::Stat, error::*, flag::*},
|
||||
};
|
||||
|
||||
@@ -20,29 +21,36 @@ use super::usercopy::{UserSlice, UserSliceRo, UserSliceRw, UserSliceWo};
|
||||
|
||||
pub fn file_op_generic<T>(
|
||||
fd: FileHandle,
|
||||
op: impl FnOnce(&dyn KernelScheme, usize) -> Result<T>,
|
||||
token: &mut CleanLockToken,
|
||||
op: impl FnOnce(&dyn KernelScheme, usize, &mut CleanLockToken) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
file_op_generic_ext(fd, |s, _, desc| op(s, desc.number))
|
||||
file_op_generic_ext(fd, token, |s, _, desc, token| op(s, desc.number, token))
|
||||
}
|
||||
pub fn file_op_generic_ext<T>(
|
||||
fd: FileHandle,
|
||||
op: impl FnOnce(&dyn KernelScheme, Arc<RwLock<FileDescription>>, FileDescription) -> Result<T>,
|
||||
token: &mut CleanLockToken,
|
||||
op: impl FnOnce(
|
||||
&dyn KernelScheme,
|
||||
Arc<RwLock<FileDescription>>,
|
||||
FileDescription,
|
||||
&mut CleanLockToken,
|
||||
) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
let (file, desc) = {
|
||||
let file = context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
let desc = *file.description.read();
|
||||
(file, desc)
|
||||
};
|
||||
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(desc.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
op(&*scheme, file.description, desc)
|
||||
op(&*scheme, file.description, desc, token)
|
||||
}
|
||||
pub fn copy_path_to_buf(raw_path: UserSliceRo, max_len: usize) -> Result<String> {
|
||||
let mut path_buf = vec![0_u8; max_len];
|
||||
@@ -67,8 +75,8 @@ fn is_legacy(path_buf: &String) -> bool {
|
||||
}
|
||||
|
||||
/// Open syscall
|
||||
pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
let (pid, uid, gid, scheme_ns) = match context::current().read() {
|
||||
pub fn open(raw_path: UserSliceRo, flags: usize, token: &mut CleanLockToken) -> Result<FileHandle> {
|
||||
let (pid, uid, gid, scheme_ns) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.pid.into(), cx.euid, cx.egid, cx.ens),
|
||||
};
|
||||
|
||||
@@ -83,7 +91,7 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
// Display a deprecation warning for any usage of the legacy scheme syntax (scheme:/path)
|
||||
// FIXME remove entries from this list as the respective programs get updated
|
||||
if path_buf.contains(':') && !is_legacy(&path_buf) {
|
||||
let name = context::current().read().name.clone();
|
||||
let name = context::current().read(token.token()).name.clone();
|
||||
if name.contains("cosmic") && (path_buf == "event:" || path_buf.starts_with("time:")) {
|
||||
// FIXME cosmic apps likely need crate updates
|
||||
} else {
|
||||
@@ -95,14 +103,19 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
|
||||
let description = {
|
||||
let (scheme_id, scheme) = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
let (scheme_id, scheme) = schemes
|
||||
.get_name(scheme_ns, scheme_name.as_ref())
|
||||
.ok_or(Error::new(ENODEV))?;
|
||||
(scheme_id, scheme.clone())
|
||||
};
|
||||
|
||||
match scheme.kopen(reference.as_ref(), flags, CallerCtx { uid, gid, pid })? {
|
||||
match scheme.kopen(
|
||||
reference.as_ref(),
|
||||
flags,
|
||||
CallerCtx { uid, gid, pid },
|
||||
token,
|
||||
)? {
|
||||
OpenResult::SchemeLocal(number, internal_flags) => {
|
||||
Arc::new(RwLock::new(FileDescription {
|
||||
scheme: scheme_id,
|
||||
@@ -117,7 +130,7 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result<FileHandle> {
|
||||
};
|
||||
//drop(path_buf);
|
||||
context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.add_file(FileDescriptor {
|
||||
description,
|
||||
cloexec: flags & O_CLOEXEC == O_CLOEXEC,
|
||||
@@ -130,6 +143,7 @@ pub fn openat(
|
||||
raw_path: UserSliceRo,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<FileHandle> {
|
||||
let path_buf = copy_path_to_buf(raw_path, PATH_MAX)?;
|
||||
|
||||
@@ -139,16 +153,16 @@ pub fn openat(
|
||||
}
|
||||
|
||||
let pipe = context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(fh)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let description = pipe.description.read();
|
||||
|
||||
let caller_ctx = context::current().read().caller_ctx();
|
||||
let caller_ctx = context::current().read(token.token()).caller_ctx();
|
||||
|
||||
let new_description = {
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(description.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
@@ -159,6 +173,7 @@ pub fn openat(
|
||||
flags,
|
||||
fcntl_flags,
|
||||
caller_ctx,
|
||||
token,
|
||||
);
|
||||
|
||||
match res? {
|
||||
@@ -176,7 +191,7 @@ pub fn openat(
|
||||
};
|
||||
|
||||
context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.add_file(FileDescriptor {
|
||||
description: new_description,
|
||||
cloexec: false,
|
||||
@@ -184,8 +199,8 @@ pub fn openat(
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
/// rmdir syscall
|
||||
pub fn rmdir(raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_ns, caller_ctx) = match context::current().read() {
|
||||
pub fn rmdir(raw_path: UserSliceRo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let (scheme_ns, caller_ctx) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.ens, cx.caller_ctx()),
|
||||
};
|
||||
|
||||
@@ -198,18 +213,18 @@ pub fn rmdir(raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_name, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let scheme = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
let (_scheme_id, scheme) = schemes
|
||||
.get_name(scheme_ns, scheme_name.as_ref())
|
||||
.ok_or(Error::new(ENODEV))?;
|
||||
scheme.clone()
|
||||
};
|
||||
scheme.rmdir(reference.as_ref(), caller_ctx)
|
||||
scheme.rmdir(reference.as_ref(), caller_ctx, token)
|
||||
}
|
||||
|
||||
/// Unlink syscall
|
||||
pub fn unlink(raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_ns, caller_ctx) = match context::current().read() {
|
||||
pub fn unlink(raw_path: UserSliceRo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let (scheme_ns, caller_ctx) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.ens, cx.caller_ctx()),
|
||||
};
|
||||
/*
|
||||
@@ -221,30 +236,34 @@ pub fn unlink(raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_name, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let scheme = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
let (_scheme_id, scheme) = schemes
|
||||
.get_name(scheme_ns, scheme_name.as_ref())
|
||||
.ok_or(Error::new(ENODEV))?;
|
||||
scheme.clone()
|
||||
};
|
||||
scheme.unlink(reference.as_ref(), caller_ctx)
|
||||
scheme.unlink(reference.as_ref(), caller_ctx, token)
|
||||
}
|
||||
|
||||
/// Close syscall
|
||||
pub fn close(fd: FileHandle) -> Result<()> {
|
||||
pub fn close(fd: FileHandle, token: &mut CleanLockToken) -> Result<()> {
|
||||
let file = {
|
||||
let context_lock = context::current();
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
context.remove_file(fd).ok_or(Error::new(EBADF))?
|
||||
};
|
||||
|
||||
file.close()
|
||||
file.close(token)
|
||||
}
|
||||
|
||||
fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescriptor> {
|
||||
fn duplicate_file(
|
||||
fd: FileHandle,
|
||||
user_buf: UserSliceRo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<FileDescriptor> {
|
||||
let (caller_ctx, file) = {
|
||||
let context_lock = context::current();
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
(
|
||||
context.caller_ctx(),
|
||||
context.get_file(fd).ok_or(Error::new(EBADF))?,
|
||||
@@ -260,12 +279,12 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescripto
|
||||
let description = { *file.description.read() };
|
||||
|
||||
let new_description = {
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(description.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
match scheme.kdup(description.number, user_buf, caller_ctx)? {
|
||||
match scheme.kdup(description.number, user_buf, caller_ctx, token)? {
|
||||
OpenResult::SchemeLocal(number, internal_flags) => {
|
||||
Arc::new(RwLock::new(FileDescription {
|
||||
offset: 0,
|
||||
@@ -287,25 +306,30 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result<FileDescripto
|
||||
}
|
||||
|
||||
/// Duplicate file descriptor
|
||||
pub fn dup(fd: FileHandle, buf: UserSliceRo) -> Result<FileHandle> {
|
||||
let new_file = duplicate_file(fd, buf)?;
|
||||
pub fn dup(fd: FileHandle, buf: UserSliceRo, token: &mut CleanLockToken) -> Result<FileHandle> {
|
||||
let new_file = duplicate_file(fd, buf, token)?;
|
||||
|
||||
context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.add_file(new_file)
|
||||
.ok_or(Error::new(EMFILE))
|
||||
}
|
||||
|
||||
/// Duplicate file descriptor, replacing another
|
||||
pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: UserSliceRo) -> Result<FileHandle> {
|
||||
pub fn dup2(
|
||||
fd: FileHandle,
|
||||
new_fd: FileHandle,
|
||||
buf: UserSliceRo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<FileHandle> {
|
||||
if fd == new_fd {
|
||||
Ok(new_fd)
|
||||
} else {
|
||||
let _ = close(new_fd);
|
||||
let new_file = duplicate_file(fd, buf)?;
|
||||
let _ = close(new_fd, token);
|
||||
let new_file = duplicate_file(fd, buf, token)?;
|
||||
|
||||
let context_ref = context::current();
|
||||
let context = context_ref.read();
|
||||
let context = context_ref.read(token.token());
|
||||
|
||||
context
|
||||
.insert_file(new_fd, new_file)
|
||||
@@ -317,6 +341,7 @@ pub fn call(
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: UserSliceRo,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let mut meta = [0_u64; 3];
|
||||
|
||||
@@ -327,12 +352,12 @@ pub fn call(
|
||||
|
||||
match flags {
|
||||
f if f.contains(CallFlags::WRITE | CallFlags::FD) => {
|
||||
call_fdwrite(fd, payload, flags, &meta[..copied / 8])
|
||||
call_fdwrite(fd, payload, flags, &meta[..copied / 8], token)
|
||||
}
|
||||
f if f.contains(CallFlags::READ | CallFlags::FD) => {
|
||||
call_fdread(fd, payload, flags, &meta[..copied / 8])
|
||||
call_fdread(fd, payload, flags, &meta[..copied / 8], token)
|
||||
}
|
||||
_ => call_normal(fd, payload, flags, &meta[..copied / 8]),
|
||||
_ => call_normal(fd, payload, flags, &meta[..copied / 8], token),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,9 +366,10 @@ fn call_normal(
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let file = (match (
|
||||
context::current().read(),
|
||||
context::current().read(token.token()),
|
||||
flags.contains(CallFlags::CONSUME),
|
||||
) {
|
||||
(ctxt, true) => ctxt.remove_file(fd),
|
||||
@@ -355,12 +381,12 @@ fn call_normal(
|
||||
let desc = file.description.read();
|
||||
(desc.scheme, desc.number)
|
||||
};
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(scheme_id)
|
||||
.ok_or(Error::new(EBADFD))?
|
||||
.clone();
|
||||
|
||||
scheme.kcall(number, payload, flags, metadata)
|
||||
scheme.kcall(number, payload, flags, metadata, token)
|
||||
}
|
||||
|
||||
fn call_fdwrite(
|
||||
@@ -368,6 +394,7 @@ fn call_fdwrite(
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let payload_chunks = payload.in_exact_chunks(size_of::<usize>());
|
||||
let fds = payload_chunks
|
||||
@@ -379,7 +406,7 @@ fn call_fdwrite(
|
||||
|
||||
let len = fds.len();
|
||||
|
||||
fdwrite_inner(fd, fds, flags, 0, metadata)?;
|
||||
fdwrite_inner(fd, fds, flags, 0, metadata, token)?;
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
@@ -390,25 +417,29 @@ fn fdwrite_inner(
|
||||
flags: CallFlags,
|
||||
arg: u64,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
// TODO: Ensure deadlocks can't happen
|
||||
let (scheme, number, descs_to_send) = {
|
||||
let current_lock = context::current();
|
||||
let current = current_lock.read();
|
||||
|
||||
let (scheme, number) = match current
|
||||
.get_file(socket)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.description
|
||||
.read()
|
||||
{
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
let (scheme, number) = {
|
||||
let current_lock = context::current();
|
||||
let current = current_lock.read(token.token());
|
||||
match current
|
||||
.get_file(socket)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.description
|
||||
.read()
|
||||
{
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
}
|
||||
};
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(scheme)
|
||||
.ok_or(Error::new(ENODEV))?
|
||||
.clone();
|
||||
|
||||
let current_lock = context::current();
|
||||
let current = current_lock.read(token.token());
|
||||
(
|
||||
scheme,
|
||||
number,
|
||||
@@ -438,7 +469,7 @@ fn fdwrite_inner(
|
||||
CallFlags::empty()
|
||||
};
|
||||
|
||||
scheme.kfdwrite(number, descs_to_send, flags_to_scheme, arg, metadata)
|
||||
scheme.kfdwrite(number, descs_to_send, flags_to_scheme, arg, metadata, token)
|
||||
}
|
||||
|
||||
fn call_fdread(
|
||||
@@ -446,20 +477,22 @@ fn call_fdread(
|
||||
payload: UserSliceRw,
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let (scheme, number) = {
|
||||
let current_lock = context::current();
|
||||
let current = current_lock.read();
|
||||
|
||||
let (scheme, number) = match current
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.description
|
||||
.read()
|
||||
{
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
let (scheme, number) = {
|
||||
let current_lock = context::current();
|
||||
let current = current_lock.read(token.token());
|
||||
match current
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.description
|
||||
.read()
|
||||
{
|
||||
ref desc => (desc.scheme, desc.number),
|
||||
}
|
||||
};
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(scheme)
|
||||
.ok_or(Error::new(ENODEV))?
|
||||
.clone();
|
||||
@@ -467,10 +500,16 @@ fn call_fdread(
|
||||
(scheme, number)
|
||||
};
|
||||
|
||||
scheme.kfdread(number, payload, flags, metadata)
|
||||
scheme.kfdread(number, payload, flags, metadata, token)
|
||||
}
|
||||
|
||||
pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) -> Result<usize> {
|
||||
pub fn sendfd(
|
||||
socket: FileHandle,
|
||||
fd: FileHandle,
|
||||
flags_raw: usize,
|
||||
arg: u64,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let sendfd_flags = SendFdFlags::from_bits(flags_raw).ok_or(Error::new(EINVAL))?;
|
||||
let mut call_flags = CallFlags::FD | CallFlags::WRITE;
|
||||
if sendfd_flags.contains(SendFdFlags::CLONE) {
|
||||
@@ -479,13 +518,13 @@ pub fn sendfd(socket: FileHandle, fd: FileHandle, flags_raw: usize, arg: u64) ->
|
||||
if sendfd_flags.contains(SendFdFlags::EXCLUSIVE) {
|
||||
call_flags |= CallFlags::FD_EXCLUSIVE;
|
||||
}
|
||||
fdwrite_inner(socket, Vec::from([fd]), call_flags, arg, &[])
|
||||
fdwrite_inner(socket, Vec::from([fd]), call_flags, arg, &[], token)
|
||||
}
|
||||
|
||||
/// File descriptor controls
|
||||
pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
|
||||
pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let file = context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
@@ -493,10 +532,10 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
|
||||
|
||||
if cmd == F_DUPFD {
|
||||
// Not in match because 'files' cannot be locked
|
||||
let new_file = duplicate_file(fd, UserSlice::empty())?;
|
||||
let new_file = duplicate_file(fd, UserSlice::empty(), token)?;
|
||||
|
||||
let context_lock = context::current();
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
|
||||
return context
|
||||
.add_file_min(new_file, arg)
|
||||
@@ -506,18 +545,18 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
|
||||
|
||||
// Communicate fcntl with scheme
|
||||
if cmd != F_GETFD && cmd != F_SETFD {
|
||||
let scheme = scheme::schemes()
|
||||
let scheme = scheme::schemes(token.token())
|
||||
.get(description.scheme)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.clone();
|
||||
|
||||
scheme.fcntl(description.number, cmd, arg)?;
|
||||
scheme.fcntl(description.number, cmd, arg, token)?;
|
||||
};
|
||||
|
||||
// Perform kernel operation if scheme agrees
|
||||
{
|
||||
let context_lock = context::current();
|
||||
let context = context_lock.read();
|
||||
let context = context_lock.read(token.token());
|
||||
|
||||
let mut files = context.files.write();
|
||||
match *files.get_mut(fd.get()).ok_or(Error::new(EBADF))? {
|
||||
@@ -548,12 +587,12 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flink(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
let (caller_ctx, scheme_ns) = match context::current().read() {
|
||||
pub fn flink(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let (caller_ctx, scheme_ns) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.caller_ctx(), cx.ens),
|
||||
};
|
||||
let file = context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
@@ -566,7 +605,7 @@ pub fn flink(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_name, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let (scheme_id, scheme) = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
let (scheme_id, scheme) = schemes
|
||||
.get_name(scheme_ns, scheme_name.as_ref())
|
||||
.ok_or(Error::new(ENODEV))?;
|
||||
@@ -579,15 +618,15 @@ pub fn flink(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
return Err(Error::new(EXDEV));
|
||||
}
|
||||
|
||||
scheme.flink(description.number, reference.as_ref(), caller_ctx)
|
||||
scheme.flink(description.number, reference.as_ref(), caller_ctx, token)
|
||||
}
|
||||
|
||||
pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
let (caller_ctx, scheme_ns) = match context::current().read() {
|
||||
pub fn frename(fd: FileHandle, raw_path: UserSliceRo, token: &mut CleanLockToken) -> Result<()> {
|
||||
let (caller_ctx, scheme_ns) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.caller_ctx(), cx.ens),
|
||||
};
|
||||
let file = context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.get_file(fd)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
@@ -600,7 +639,7 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
let (scheme_name, reference) = path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let (scheme_id, scheme) = {
|
||||
let schemes = scheme::schemes();
|
||||
let schemes = scheme::schemes(token.token());
|
||||
let (scheme_id, scheme) = schemes
|
||||
.get_name(scheme_ns, scheme_name.as_ref())
|
||||
.ok_or(Error::new(ENODEV))?;
|
||||
@@ -613,13 +652,13 @@ pub fn frename(fd: FileHandle, raw_path: UserSliceRo) -> Result<()> {
|
||||
return Err(Error::new(EXDEV));
|
||||
}
|
||||
|
||||
scheme.frename(description.number, reference.as_ref(), caller_ctx)
|
||||
scheme.frename(description.number, reference.as_ref(), caller_ctx, token)
|
||||
}
|
||||
|
||||
/// File status
|
||||
pub fn fstat(fd: FileHandle, user_buf: UserSliceWo) -> Result<()> {
|
||||
file_op_generic_ext(fd, |scheme, _, desc| {
|
||||
scheme.kfstat(desc.number, user_buf)?;
|
||||
pub fn fstat(fd: FileHandle, user_buf: UserSliceWo, token: &mut CleanLockToken) -> Result<()> {
|
||||
file_op_generic_ext(fd, token, |scheme, _, desc, token| {
|
||||
scheme.kfstat(desc.number, user_buf, token)?;
|
||||
|
||||
// TODO: Ensure only the kernel can access the stat when st_dev is set, or use another API
|
||||
// for retrieving the scheme ID from a file descriptor.
|
||||
@@ -639,7 +678,7 @@ pub fn fstat(fd: FileHandle, user_buf: UserSliceWo) -> Result<()> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
|
||||
pub fn funmap(virtual_address: usize, length: usize, token: &mut CleanLockToken) -> Result<usize> {
|
||||
// Partial lengths in funmap are allowed according to POSIX, but not particularly meaningful;
|
||||
// since the memory needs to SIGSEGV if later read, the entire page needs to disappear.
|
||||
//
|
||||
@@ -654,14 +693,14 @@ pub fn funmap(virtual_address: usize, length: usize) -> Result<usize> {
|
||||
);
|
||||
}
|
||||
|
||||
let addr_space = Arc::clone(context::current().read().addr_space()?);
|
||||
let addr_space = Arc::clone(context::current().read(token.token()).addr_space()?);
|
||||
let span = PageSpan::validate_nonempty(VirtualAddress::new(virtual_address), length_aligned)
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
let unpin = false;
|
||||
let notify = addr_space.munmap(span, unpin)?;
|
||||
|
||||
for map in notify {
|
||||
let _ = map.unmap();
|
||||
let _ = map.unmap(token);
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
@@ -673,6 +712,7 @@ pub fn mremap(
|
||||
new_address: usize,
|
||||
new_size: usize,
|
||||
flags: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
if old_address % PAGE_SIZE != 0
|
||||
|| old_size % PAGE_SIZE != 0
|
||||
@@ -712,7 +752,7 @@ pub fn mremap(
|
||||
return Err(Error::new(EOPNOTSUPP));
|
||||
}
|
||||
|
||||
let raii_frame = addr_space.borrow_frame_enforce_rw_allocated(src_span.base)?;
|
||||
let raii_frame = addr_space.borrow_frame_enforce_rw_allocated(src_span.base, token)?;
|
||||
|
||||
let base = addr_space.acquire_write().mmap(
|
||||
&addr_space,
|
||||
@@ -752,17 +792,17 @@ pub fn mremap(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lseek(fd: FileHandle, pos: i64, whence: usize) -> Result<usize> {
|
||||
pub fn lseek(fd: FileHandle, pos: i64, whence: usize, token: &mut CleanLockToken) -> Result<usize> {
|
||||
enum Ret {
|
||||
Legacy(usize),
|
||||
Fsize((Option<u64>, Arc<RwLock<FileDescription>>)),
|
||||
}
|
||||
let fsize_or_legacy = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
|
||||
let fsize_or_legacy = file_op_generic_ext(fd, token, |scheme, desc_arc, desc, token| {
|
||||
Ok(
|
||||
if let Some(new_off) = scheme.legacy_seek(desc.number, pos as isize, whence) {
|
||||
if let Some(new_off) = scheme.legacy_seek(desc.number, pos as isize, whence, token) {
|
||||
Ret::Legacy(new_off?)
|
||||
} else if whence == SEEK_END {
|
||||
Ret::Fsize((Some(scheme.fsize(desc.number)?), desc_arc))
|
||||
Ret::Fsize((Some(scheme.fsize(desc.number, token)?), desc_arc))
|
||||
} else {
|
||||
Ret::Fsize((None, desc_arc))
|
||||
},
|
||||
@@ -789,19 +829,20 @@ pub fn lseek(fd: FileHandle, pos: i64, whence: usize) -> Result<usize> {
|
||||
|
||||
Ok(guard.offset as usize)
|
||||
}
|
||||
pub fn sys_read(fd: FileHandle, buf: UserSliceWo) -> Result<usize> {
|
||||
let (bytes_read, desc_arc, desc) = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
|
||||
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
desc.offset
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
Ok((
|
||||
scheme.kreadoff(desc.number, buf, offset, desc.flags, desc.flags)?,
|
||||
desc_arc,
|
||||
desc,
|
||||
))
|
||||
})?;
|
||||
pub fn sys_read(fd: FileHandle, buf: UserSliceWo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let (bytes_read, desc_arc, desc) =
|
||||
file_op_generic_ext(fd, token, |scheme, desc_arc, desc, token| {
|
||||
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
desc.offset
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
Ok((
|
||||
scheme.kreadoff(desc.number, buf, offset, desc.flags, desc.flags, token)?,
|
||||
desc_arc,
|
||||
desc,
|
||||
))
|
||||
})?;
|
||||
if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
match desc_arc.write().offset {
|
||||
ref mut offset => *offset = offset.saturating_add(bytes_read as u64),
|
||||
@@ -809,19 +850,20 @@ pub fn sys_read(fd: FileHandle, buf: UserSliceWo) -> Result<usize> {
|
||||
}
|
||||
Ok(bytes_read)
|
||||
}
|
||||
pub fn sys_write(fd: FileHandle, buf: UserSliceRo) -> Result<usize> {
|
||||
let (bytes_written, desc_arc, desc) = file_op_generic_ext(fd, |scheme, desc_arc, desc| {
|
||||
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
desc.offset
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
Ok((
|
||||
scheme.kwriteoff(desc.number, buf, offset, desc.flags, desc.flags)?,
|
||||
desc_arc,
|
||||
desc,
|
||||
))
|
||||
})?;
|
||||
pub fn sys_write(fd: FileHandle, buf: UserSliceRo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let (bytes_written, desc_arc, desc) =
|
||||
file_op_generic_ext(fd, token, |scheme, desc_arc, desc, token| {
|
||||
let offset = if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
desc.offset
|
||||
} else {
|
||||
u64::MAX
|
||||
};
|
||||
Ok((
|
||||
scheme.kwriteoff(desc.number, buf, offset, desc.flags, desc.flags, token)?,
|
||||
desc_arc,
|
||||
desc,
|
||||
))
|
||||
})?;
|
||||
if desc.internal_flags.contains(InternalFlags::POSITIONED) {
|
||||
match desc_arc.write().offset {
|
||||
ref mut offset => *offset = offset.saturating_add(bytes_written as u64),
|
||||
|
||||
+20
-12
@@ -8,18 +8,17 @@ use alloc::{
|
||||
};
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use rmm::Arch;
|
||||
use spin::RwLock;
|
||||
use spinning_top::RwSpinlock;
|
||||
use syscall::EINTR;
|
||||
|
||||
use crate::{
|
||||
context::{
|
||||
self,
|
||||
memory::{AddrSpace, AddrSpaceWrapper},
|
||||
Context,
|
||||
ContextLock,
|
||||
},
|
||||
memory::PhysicalAddress,
|
||||
paging::{Page, VirtualAddress},
|
||||
sync::{CleanLockToken, Mutex, L1},
|
||||
time,
|
||||
};
|
||||
|
||||
@@ -42,7 +41,7 @@ pub struct FutexEntry {
|
||||
// TODO: FUTEX_REQUEUE
|
||||
target_virtaddr: VirtualAddress,
|
||||
// Context to wake up, and compare address spaces.
|
||||
context_lock: Arc<RwSpinlock<Context>>,
|
||||
context_lock: Arc<ContextLock>,
|
||||
// address space to check against if virt matches but not phys
|
||||
addr_space: Weak<AddrSpaceWrapper>,
|
||||
}
|
||||
@@ -53,7 +52,7 @@ pub struct FutexEntry {
|
||||
// lwp_park/lwp_unpark from NetBSD) could be a simpler replacement.
|
||||
//
|
||||
// TODO: Use an actual hash table.
|
||||
static FUTEXES: RwLock<FutexList> = RwLock::new(FutexList::new());
|
||||
static FUTEXES: Mutex<L1, FutexList> = Mutex::new(FutexList::new());
|
||||
|
||||
fn validate_and_translate_virt(space: &AddrSpace, addr: VirtualAddress) -> Option<PhysicalAddress> {
|
||||
// TODO: Move this elsewhere!
|
||||
@@ -69,7 +68,14 @@ fn validate_and_translate_virt(space: &AddrSpace, addr: VirtualAddress) -> Optio
|
||||
Some(frame.add(off))
|
||||
}
|
||||
|
||||
pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) -> Result<usize> {
|
||||
pub fn futex(
|
||||
addr: usize,
|
||||
op: usize,
|
||||
val: usize,
|
||||
val2: usize,
|
||||
_addr2: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let current_addrsp = AddrSpace::current()?;
|
||||
|
||||
// Keep the address space locked so we can safely read from the physical address. Unlock it
|
||||
@@ -89,7 +95,8 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) ->
|
||||
.transpose()?;
|
||||
|
||||
{
|
||||
let mut futexes = FUTEXES.write();
|
||||
let mut futexes = FUTEXES.lock(token.token());
|
||||
let (futexes, mut token) = futexes.token_split();
|
||||
|
||||
let context_lock = context::current();
|
||||
|
||||
@@ -137,7 +144,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) ->
|
||||
}
|
||||
|
||||
{
|
||||
let mut context = context_lock.write();
|
||||
let mut context = context_lock.write(token.token());
|
||||
|
||||
context.wake = timeout_opt.map(|TimeSpec { tv_sec, tv_nsec }| {
|
||||
tv_sec as u128 * time::NANOS_PER_SEC + tv_nsec as u128
|
||||
@@ -161,10 +168,10 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) ->
|
||||
|
||||
drop(addr_space_guard);
|
||||
|
||||
context::switch();
|
||||
context::switch(token);
|
||||
|
||||
if timeout_opt.is_some() {
|
||||
context::current().write().wake = None;
|
||||
context::current().write(token.token()).wake = None;
|
||||
Err(Error::new(ETIMEDOUT))
|
||||
} else {
|
||||
Ok(0)
|
||||
@@ -174,7 +181,8 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) ->
|
||||
let mut woken = 0;
|
||||
|
||||
{
|
||||
let mut futexes = FUTEXES.write();
|
||||
let mut futexes = FUTEXES.lock(token.token());
|
||||
let (futexes, mut token) = futexes.token_split();
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
@@ -187,7 +195,7 @@ pub fn futex(addr: usize, op: usize, val: usize, val2: usize, _addr2: usize) ->
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
futexes[i].context_lock.write().unblock();
|
||||
futexes[i].context_lock.write(token.token()).unblock();
|
||||
futexes.swap_remove_back(i);
|
||||
woken += 1;
|
||||
}
|
||||
|
||||
+102
-67
@@ -23,11 +23,11 @@ use self::{
|
||||
usercopy::UserSlice,
|
||||
};
|
||||
|
||||
use crate::percpu::PercpuBlock;
|
||||
|
||||
use crate::{
|
||||
context::memory::AddrSpace,
|
||||
percpu::PercpuBlock,
|
||||
scheme::{memory::MemoryScheme, FileHandle},
|
||||
sync::CleanLockToken,
|
||||
};
|
||||
|
||||
/// Debug
|
||||
@@ -54,13 +54,29 @@ pub mod usercopy;
|
||||
/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
|
||||
/// function calls [`Error::mux`] on it.
|
||||
#[must_use]
|
||||
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> usize {
|
||||
pub fn syscall(
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> usize {
|
||||
#[inline(always)]
|
||||
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> Result<usize> {
|
||||
fn inner(
|
||||
a: usize,
|
||||
b: usize,
|
||||
c: usize,
|
||||
d: usize,
|
||||
e: usize,
|
||||
f: usize,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<usize> {
|
||||
let fd = FileHandle::from(b);
|
||||
//SYS_* is declared in kernel/syscall/src/number.rs
|
||||
match a {
|
||||
SYS_WRITE2 => file_op_generic_ext(fd, |scheme, _, desc| {
|
||||
SYS_WRITE2 => file_op_generic_ext(fd, token, |scheme, _, desc, token| {
|
||||
let flags = if f == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
@@ -77,17 +93,18 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
e as u64,
|
||||
flags.map_or(desc.flags, |f| desc.rw_flags(f)),
|
||||
desc.flags,
|
||||
token,
|
||||
)
|
||||
}),
|
||||
SYS_WRITE => sys_write(fd, UserSlice::ro(c, d)?),
|
||||
SYS_WRITE => sys_write(fd, UserSlice::ro(c, d)?, token),
|
||||
SYS_FMAP => {
|
||||
let addrspace = AddrSpace::current()?;
|
||||
let map = unsafe { UserSlice::ro(c, d)?.read_exact::<Map>()? };
|
||||
if b == !0 {
|
||||
MemoryScheme::fmap_anonymous(&addrspace, &map, false)
|
||||
MemoryScheme::fmap_anonymous(&addrspace, &map, false, token)
|
||||
} else {
|
||||
file_op_generic(fd, |scheme, number| {
|
||||
scheme.kfmap(number, &addrspace, &map, false)
|
||||
file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.kfmap(number, &addrspace, &map, false, token)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -99,15 +116,15 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
|
||||
file_op_generic(fd, |scheme, number| {
|
||||
scheme.getdents(number, UserSlice::wo(c, d)?, header_size, f as u64)
|
||||
file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.getdents(number, UserSlice::wo(c, d)?, header_size, f as u64, token)
|
||||
})
|
||||
}
|
||||
SYS_FUTIMENS => file_op_generic(fd, |scheme, number| {
|
||||
scheme.kfutimens(number, UserSlice::ro(c, d)?)
|
||||
SYS_FUTIMENS => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.kfutimens(number, UserSlice::ro(c, d)?, token)
|
||||
}),
|
||||
|
||||
SYS_READ2 => file_op_generic_ext(fd, |scheme, _, desc| {
|
||||
SYS_READ2 => file_op_generic_ext(fd, token, |scheme, _, desc, token| {
|
||||
let flags = if f == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
@@ -124,79 +141,97 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
e as u64,
|
||||
flags.map_or(desc.flags, |f| desc.rw_flags(f)),
|
||||
desc.flags,
|
||||
token,
|
||||
)
|
||||
}),
|
||||
SYS_READ => sys_read(fd, UserSlice::wo(c, d)?),
|
||||
SYS_FPATH => file_op_generic(fd, |scheme, number| {
|
||||
scheme.kfpath(number, UserSlice::wo(c, d)?)
|
||||
SYS_READ => sys_read(fd, UserSlice::wo(c, d)?, token),
|
||||
SYS_FPATH => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.kfpath(number, UserSlice::wo(c, d)?, token)
|
||||
}),
|
||||
SYS_FSTAT => fstat(fd, UserSlice::wo(c, d)?).map(|()| 0),
|
||||
SYS_FSTATVFS => file_op_generic(fd, |scheme, number| {
|
||||
scheme.kfstatvfs(number, UserSlice::wo(c, d)?).map(|()| 0)
|
||||
SYS_FSTAT => fstat(fd, UserSlice::wo(c, d)?, token).map(|()| 0),
|
||||
SYS_FSTATVFS => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme
|
||||
.kfstatvfs(number, UserSlice::wo(c, d)?, token)
|
||||
.map(|()| 0)
|
||||
}),
|
||||
|
||||
SYS_DUP => dup(fd, UserSlice::ro(c, d)?).map(FileHandle::into),
|
||||
SYS_DUP2 => dup2(fd, FileHandle::from(c), UserSlice::ro(d, e)?).map(FileHandle::into),
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
SYS_SENDFD => sendfd(fd, FileHandle::from(c), d, e as u64 | ((f as u64) << 32)),
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
SYS_SENDFD => sendfd(fd, FileHandle::from(c), d, e as u64),
|
||||
|
||||
SYS_LSEEK => lseek(fd, c as i64, d),
|
||||
SYS_FCHMOD => file_op_generic(fd, |scheme, number| {
|
||||
scheme.fchmod(number, c as u16).map(|()| 0)
|
||||
}),
|
||||
SYS_FCHOWN => file_op_generic(fd, |scheme, number| {
|
||||
scheme.fchown(number, c as u32, d as u32).map(|()| 0)
|
||||
}),
|
||||
SYS_FCNTL => fcntl(fd, c, d),
|
||||
SYS_FEVENT => file_op_generic(fd, |scheme, number| {
|
||||
Ok(scheme
|
||||
.fevent(number, EventFlags::from_bits_truncate(c))?
|
||||
.bits())
|
||||
}),
|
||||
SYS_FLINK => flink(fd, UserSlice::ro(c, d)?).map(|()| 0),
|
||||
SYS_FRENAME => frename(fd, UserSlice::ro(c, d)?).map(|()| 0),
|
||||
SYS_FUNMAP => funmap(b, c),
|
||||
|
||||
SYS_FSYNC => file_op_generic(fd, |scheme, number| scheme.fsync(number).map(|()| 0)),
|
||||
// TODO: 64-bit lengths on 32-bit platforms
|
||||
SYS_FTRUNCATE => {
|
||||
file_op_generic(fd, |scheme, number| scheme.ftruncate(number, c).map(|()| 0))
|
||||
SYS_DUP => dup(fd, UserSlice::ro(c, d)?, token).map(FileHandle::into),
|
||||
SYS_DUP2 => {
|
||||
dup2(fd, FileHandle::from(c), UserSlice::ro(d, e)?, token).map(FileHandle::into)
|
||||
}
|
||||
|
||||
SYS_CLOSE => close(fd).map(|()| 0),
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
SYS_SENDFD => sendfd(
|
||||
fd,
|
||||
FileHandle::from(c),
|
||||
d,
|
||||
e as u64 | ((f as u64) << 32),
|
||||
token,
|
||||
),
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
SYS_SENDFD => sendfd(fd, FileHandle::from(c), d, e as u64, token),
|
||||
|
||||
SYS_LSEEK => lseek(fd, c as i64, d, token),
|
||||
SYS_FCHMOD => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.fchmod(number, c as u16, token).map(|()| 0)
|
||||
}),
|
||||
SYS_FCHOWN => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.fchown(number, c as u32, d as u32, token).map(|()| 0)
|
||||
}),
|
||||
SYS_FCNTL => fcntl(fd, c, d, token),
|
||||
SYS_FEVENT => file_op_generic(fd, token, |scheme, number, token| {
|
||||
Ok(scheme
|
||||
.fevent(number, EventFlags::from_bits_truncate(c), token)?
|
||||
.bits())
|
||||
}),
|
||||
SYS_FLINK => flink(fd, UserSlice::ro(c, d)?, token).map(|()| 0),
|
||||
SYS_FRENAME => frename(fd, UserSlice::ro(c, d)?, token).map(|()| 0),
|
||||
SYS_FUNMAP => funmap(b, c, token),
|
||||
|
||||
SYS_FSYNC => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.fsync(number, token).map(|()| 0)
|
||||
}),
|
||||
// TODO: 64-bit lengths on 32-bit platforms
|
||||
SYS_FTRUNCATE => file_op_generic(fd, token, |scheme, number, token| {
|
||||
scheme.ftruncate(number, c, token).map(|()| 0)
|
||||
}),
|
||||
|
||||
SYS_CLOSE => close(fd, token).map(|()| 0),
|
||||
SYS_CALL => call(
|
||||
fd,
|
||||
UserSlice::rw(c, d)?,
|
||||
CallFlags::from_bits(e & !0xff).ok_or(Error::new(EINVAL))?,
|
||||
UserSlice::ro(f, (e & 0xff) * 8)?,
|
||||
token,
|
||||
),
|
||||
|
||||
SYS_OPEN => open(UserSlice::ro(b, c)?, d).map(FileHandle::into),
|
||||
SYS_OPENAT => openat(fd, UserSlice::ro(c, d)?, e, f as _).map(FileHandle::into),
|
||||
SYS_RMDIR => rmdir(UserSlice::ro(b, c)?).map(|()| 0),
|
||||
SYS_UNLINK => unlink(UserSlice::ro(b, c)?).map(|()| 0),
|
||||
SYS_YIELD => sched_yield().map(|()| 0),
|
||||
SYS_OPEN => open(UserSlice::ro(b, c)?, d, token).map(FileHandle::into),
|
||||
SYS_OPENAT => openat(fd, UserSlice::ro(c, d)?, e, f as _, token).map(FileHandle::into),
|
||||
SYS_RMDIR => rmdir(UserSlice::ro(b, c)?, token).map(|()| 0),
|
||||
SYS_UNLINK => unlink(UserSlice::ro(b, c)?, token).map(|()| 0),
|
||||
SYS_YIELD => sched_yield(token).map(|()| 0),
|
||||
SYS_NANOSLEEP => nanosleep(
|
||||
UserSlice::ro(b, core::mem::size_of::<TimeSpec>())?,
|
||||
UserSlice::wo(c, core::mem::size_of::<TimeSpec>())?.none_if_null(),
|
||||
token,
|
||||
)
|
||||
.map(|()| 0),
|
||||
SYS_CLOCK_GETTIME => {
|
||||
clock_gettime(b, UserSlice::wo(c, core::mem::size_of::<TimeSpec>())?).map(|()| 0)
|
||||
}
|
||||
SYS_FUTEX => futex(b, c, d, e, f),
|
||||
SYS_FUTEX => futex(b, c, d, e, f, token),
|
||||
|
||||
SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)).map(|()| 0),
|
||||
SYS_MKNS => mkns(UserSlice::ro(
|
||||
b,
|
||||
c.checked_mul(core::mem::size_of::<[usize; 2]>())
|
||||
.ok_or(Error::new(EOVERFLOW))?,
|
||||
)?),
|
||||
SYS_MREMAP => mremap(b, c, d, e, f),
|
||||
SYS_MKNS => mkns(
|
||||
UserSlice::ro(
|
||||
b,
|
||||
c.checked_mul(core::mem::size_of::<[usize; 2]>())
|
||||
.ok_or(Error::new(EOVERFLOW))?,
|
||||
)?,
|
||||
token,
|
||||
),
|
||||
SYS_MREMAP => mremap(b, c, d, e, f, token),
|
||||
|
||||
_ => return Err(Error::new(ENOSYS)),
|
||||
}
|
||||
@@ -204,17 +239,17 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
|
||||
PercpuBlock::current().inside_syscall.set(true);
|
||||
|
||||
debug_start([a, b, c, d, e, f]);
|
||||
debug_start([a, b, c, d, e, f], token);
|
||||
|
||||
let result = inner(a, b, c, d, e, f);
|
||||
let result = inner(a, b, c, d, e, f, token);
|
||||
|
||||
debug_end([a, b, c, d, e, f], result);
|
||||
debug_end([a, b, c, d, e, f], result, token);
|
||||
|
||||
let percpu = PercpuBlock::current();
|
||||
percpu.inside_syscall.set(false);
|
||||
|
||||
if percpu.switch_internals.being_sigkilled.get() {
|
||||
exit_this_context(None);
|
||||
exit_this_context(None, token);
|
||||
}
|
||||
|
||||
// errormux turns Result<usize> into -errno
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{context, scheme, syscall::error::*};
|
||||
use crate::{context, scheme, sync::CleanLockToken, syscall::error::*};
|
||||
|
||||
use super::{
|
||||
copy_path_to_buf,
|
||||
usercopy::{UserSlice, UserSliceRo},
|
||||
};
|
||||
|
||||
pub fn mkns(mut user_buf: UserSliceRo) -> Result<usize> {
|
||||
let (uid, from) = match context::current().read() {
|
||||
pub fn mkns(mut user_buf: UserSliceRo, token: &mut CleanLockToken) -> Result<usize> {
|
||||
let (uid, from) = match context::current().read(token.token()) {
|
||||
ref cx => (cx.euid, cx.ens),
|
||||
};
|
||||
|
||||
@@ -36,6 +36,6 @@ pub fn mkns(mut user_buf: UserSliceRo) -> Result<usize> {
|
||||
user_buf = next_part;
|
||||
}
|
||||
|
||||
let to = scheme::schemes_mut().make_ns(from, names)?;
|
||||
let to = scheme::schemes_mut(token.token()).make_ns(from, names)?;
|
||||
Ok(to.into())
|
||||
}
|
||||
|
||||
+10
-9
@@ -11,6 +11,7 @@ use crate::{
|
||||
},
|
||||
event,
|
||||
scheme::GlobalSchemes,
|
||||
sync::CleanLockToken,
|
||||
syscall::EventFlags,
|
||||
};
|
||||
|
||||
@@ -24,13 +25,13 @@ use crate::{
|
||||
|
||||
use super::usercopy::UserSliceWo;
|
||||
|
||||
pub fn exit_this_context(excp: Option<syscall::Exception>) -> ! {
|
||||
pub fn exit_this_context(excp: Option<syscall::Exception>, token: &mut CleanLockToken) -> ! {
|
||||
let mut close_files;
|
||||
let addrspace_opt;
|
||||
|
||||
let context_lock = context::current();
|
||||
{
|
||||
let mut context = context_lock.write();
|
||||
let mut context = context_lock.write(token.token());
|
||||
close_files = Arc::try_unwrap(mem::take(&mut context.files))
|
||||
.map_or_else(|_| FdTbl::new(), RwLock::into_inner);
|
||||
addrspace_opt = context
|
||||
@@ -41,11 +42,11 @@ pub fn exit_this_context(excp: Option<syscall::Exception>) -> ! {
|
||||
}
|
||||
|
||||
// Files must be closed while context is valid so that messages can be passed
|
||||
close_files.force_close_all();
|
||||
close_files.force_close_all(token);
|
||||
drop(addrspace_opt);
|
||||
// TODO: Should status == Status::HardBlocked be handled differently?
|
||||
let owner = {
|
||||
let mut guard = context_lock.write();
|
||||
let mut guard = context_lock.write(token.token());
|
||||
guard.status = context::Status::Dead { excp };
|
||||
guard.owner_proc_id
|
||||
};
|
||||
@@ -57,9 +58,9 @@ pub fn exit_this_context(excp: Option<syscall::Exception>) -> ! {
|
||||
);
|
||||
}
|
||||
{
|
||||
let _ = context::contexts_mut().remove(&ContextRef(context_lock));
|
||||
let _ = context::contexts_mut(token.token()).remove(&ContextRef(context_lock));
|
||||
}
|
||||
context::switch();
|
||||
context::switch(token);
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
@@ -72,13 +73,13 @@ pub fn mprotect(address: usize, size: usize, flags: MapFlags) -> Result<()> {
|
||||
AddrSpace::current()?.mprotect(span, flags)
|
||||
}
|
||||
|
||||
pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) {
|
||||
pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap, token: &mut CleanLockToken) {
|
||||
assert_ne!(bootstrap.page_count, 0);
|
||||
|
||||
{
|
||||
let addr_space = Arc::clone(
|
||||
context::current()
|
||||
.read()
|
||||
.read(token.token())
|
||||
.addr_space()
|
||||
.expect("expected bootstrap context to have an address space"),
|
||||
);
|
||||
@@ -128,7 +129,7 @@ pub unsafe fn usermode_bootstrap(bootstrap: &Bootstrap) {
|
||||
// Start in a minimal environment without any stack.
|
||||
|
||||
match context::current()
|
||||
.write()
|
||||
.write(token.token())
|
||||
.regs_mut()
|
||||
.expect("bootstrap needs registers to be available")
|
||||
{
|
||||
|
||||
+12
-7
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
context,
|
||||
sync::CleanLockToken,
|
||||
syscall::{
|
||||
data::TimeSpec,
|
||||
error::*,
|
||||
@@ -24,7 +25,11 @@ pub fn clock_gettime(clock: usize, buf: UserSliceWo) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Nanosleep will sleep by switching the current context
|
||||
pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Result<()> {
|
||||
pub fn nanosleep(
|
||||
req_buf: UserSliceRo,
|
||||
rem_buf_opt: Option<UserSliceWo>,
|
||||
token: &mut CleanLockToken,
|
||||
) -> Result<()> {
|
||||
let req = unsafe { req_buf.read_exact::<TimeSpec>()? };
|
||||
|
||||
let start = time::monotonic();
|
||||
@@ -32,7 +37,7 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Resu
|
||||
|
||||
let current_context = context::current();
|
||||
{
|
||||
let mut context = current_context.write();
|
||||
let mut context = current_context.write(token.token());
|
||||
|
||||
if let Some((tctl, pctl, _)) = context.sigcontrol() {
|
||||
if tctl.currently_pending_unblocked(pctl) != 0 {
|
||||
@@ -46,9 +51,9 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Resu
|
||||
|
||||
// TODO: The previous wakeup reason was most likely signals, but is there any other possible
|
||||
// reason?
|
||||
context::switch();
|
||||
context::switch(token);
|
||||
|
||||
let was_interrupted = current_context.write().wake.take().is_some();
|
||||
let was_interrupted = current_context.write(token.token()).wake.take().is_some();
|
||||
|
||||
if let Some(rem_buf) = rem_buf_opt {
|
||||
let current = time::monotonic();
|
||||
@@ -74,9 +79,9 @@ pub fn nanosleep(req_buf: UserSliceRo, rem_buf_opt: Option<UserSliceWo>) -> Resu
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sched_yield() -> Result<()> {
|
||||
context::switch();
|
||||
pub fn sched_yield(token: &mut CleanLockToken) -> Result<()> {
|
||||
context::switch(token);
|
||||
// TODO: Do this check in userspace
|
||||
context::signal::signal_handler();
|
||||
context::signal::signal_handler(token);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,6 +1,9 @@
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::syscall::error::{Error, Result, EINVAL};
|
||||
use crate::{
|
||||
sync::CleanLockToken,
|
||||
syscall::error::{Error, Result, EINVAL},
|
||||
};
|
||||
|
||||
pub const NANOS_PER_SEC: u128 = 1_000_000_000;
|
||||
|
||||
@@ -18,7 +21,7 @@ pub fn realtime() -> u128 {
|
||||
*START.lock() + monotonic()
|
||||
}
|
||||
|
||||
pub fn sys_update_time_offset(buf: &[u8]) -> Result<usize> {
|
||||
pub fn sys_update_time_offset(buf: &[u8], _token: &mut CleanLockToken) -> Result<usize> {
|
||||
let start = <[u8; 16]>::try_from(buf).map_err(|_| Error::new(EINVAL))?;
|
||||
*START.lock() = u128::from_ne_bytes(start);
|
||||
Ok(16)
|
||||
|
||||
Reference in New Issue
Block a user