Make x86_64 work (pre-syscalls)
This commit is contained in:
@@ -34,6 +34,9 @@ _entry:
|
||||
|
||||
.code64
|
||||
_entry_upper:
|
||||
movabsq $1f, %rax
|
||||
jmp *%rax
|
||||
1:
|
||||
lea bsp_stack_top(%rip), %rax
|
||||
mov %rax, %rsp
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use crate::arch::x86_64::{self, intc, gdt, idt};
|
||||
use core::arch::{global_asm, asm};
|
||||
use crate::arch::x86_64::{self, gdt, idt, intc};
|
||||
use crate::config::{ConfigKey, CONFIG};
|
||||
use crate::debug;
|
||||
use crate::dev::{display::FramebufferInfo, pseudo, Device};
|
||||
use crate::font;
|
||||
use crate::fs::{devfs, sysfs};
|
||||
use crate::mem::{
|
||||
self, heap,
|
||||
phys::{self, MemoryRegion, PageUsage, ReservedRegion},
|
||||
virt,
|
||||
};
|
||||
use crate::debug;
|
||||
use crate::fs::{devfs, sysfs};
|
||||
use crate::dev::{pseudo, Device, display::FramebufferInfo};
|
||||
use crate::proc;
|
||||
use core::arch::{asm, global_asm};
|
||||
use core::mem::MaybeUninit;
|
||||
use crate::font;
|
||||
use multiboot2::{BootInformation, MemoryArea};
|
||||
|
||||
static mut RESERVED_REGION_MB2: MaybeUninit<ReservedRegion> = MaybeUninit::uninit();
|
||||
@@ -73,6 +75,14 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||
heap::init(heap_base_virt, 16 * 1024 * 1024);
|
||||
}
|
||||
|
||||
let initrd_info = mb_info.module_tags().next().unwrap();
|
||||
{
|
||||
let mut cfg = CONFIG.lock();
|
||||
|
||||
cfg.set_usize(ConfigKey::InitrdBase, initrd_info.start_address() as usize);
|
||||
cfg.set_usize(ConfigKey::InitrdSize, initrd_info.module_size() as usize);
|
||||
}
|
||||
|
||||
// Setup hardware
|
||||
unsafe {
|
||||
x86_64::INTC.enable().ok();
|
||||
@@ -80,12 +90,16 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||
|
||||
let fb_info = mb_info.framebuffer_tag().unwrap();
|
||||
let virt = mem::virtualize(fb_info.address as usize);
|
||||
debugln!("Framebuffer base: phys={:#x}, virt={:#x}", fb_info.address, virt);
|
||||
debugln!(
|
||||
"Framebuffer base: phys={:#x}, virt={:#x}",
|
||||
fb_info.address,
|
||||
virt
|
||||
);
|
||||
x86_64::DISPLAY.set_framebuffer(FramebufferInfo {
|
||||
width: fb_info.width as usize,
|
||||
height: fb_info.height as usize,
|
||||
phys_base: fb_info.address as usize,
|
||||
virt_base: virt
|
||||
virt_base: virt,
|
||||
});
|
||||
font::init();
|
||||
debug::set_display(&x86_64::DISPLAY);
|
||||
@@ -96,10 +110,8 @@ extern "C" fn __x86_64_bsp_main(mb_checksum: u32, mb_info_ptr: u32) -> ! {
|
||||
devfs::add_named_char_device(&pseudo::ZERO, "zero").unwrap();
|
||||
devfs::add_named_char_device(&pseudo::RANDOM, "random").unwrap();
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
asm!("sti; hlt");
|
||||
}
|
||||
unsafe {
|
||||
proc::enter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
.section .text
|
||||
.global __x86_64_ctx_switch
|
||||
.global __x86_64_ctx_switch_to
|
||||
.global __x86_64_ctx_enter_kernel
|
||||
.global __x86_64_ctx_enter_from_fork
|
||||
|
||||
__x86_64_ctx_enter_user:
|
||||
pop %rcx
|
||||
pop %rdi
|
||||
pop %rdi
|
||||
pop %rdx
|
||||
|
||||
push $0x10
|
||||
push %rcx
|
||||
|
||||
push $0 // $0x200
|
||||
|
||||
push $0x08
|
||||
push %rdx
|
||||
|
||||
iretq
|
||||
|
||||
__x86_64_ctx_enter_kernel:
|
||||
pop %rdi
|
||||
pop %rdx
|
||||
mov %rsp, %rcx
|
||||
|
||||
push $0x10
|
||||
push %rcx
|
||||
|
||||
push $0x200
|
||||
|
||||
push $0x08
|
||||
push %rdx
|
||||
|
||||
iretq
|
||||
|
||||
__x86_64_ctx_enter_from_fork:
|
||||
jmp .
|
||||
|
||||
__x86_64_ctx_switch:
|
||||
// %rsi -- src ctx ptr
|
||||
// %rdi -- dst ctx ptr
|
||||
|
||||
push %r15
|
||||
push %r14
|
||||
push %r13
|
||||
push %r12
|
||||
push %rbx
|
||||
push %rbp
|
||||
|
||||
mov %cr3, %rax
|
||||
push %rax
|
||||
// TODO save gs_base
|
||||
push %rax
|
||||
|
||||
mov %rsp, (%rsi)
|
||||
__x86_64_ctx_switch_to:
|
||||
mov (%rdi), %rsp
|
||||
|
||||
pop %rbp
|
||||
pop %rbx
|
||||
pop %r12
|
||||
pop %r13
|
||||
pop %r14
|
||||
pop %r15
|
||||
|
||||
pop %rax
|
||||
test %rax, %rax
|
||||
jz 1f
|
||||
mov %rax, %cr3
|
||||
1:
|
||||
pop %rax
|
||||
// TODO set gs_base = rax
|
||||
|
||||
ret
|
||||
@@ -0,0 +1,150 @@
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
};
|
||||
use core::mem::size_of;
|
||||
use core::arch::global_asm;
|
||||
|
||||
struct Stack {
|
||||
bp: usize,
|
||||
sp: usize,
|
||||
}
|
||||
|
||||
/// Structure representing thread context
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
/// Thread's kernel stack pointer
|
||||
pub k_sp: usize, // 0x00
|
||||
|
||||
stack_base: usize,
|
||||
stack_page_count: usize,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Constructs a new kernel-space thread context
|
||||
pub fn kernel(entry: usize, arg: usize) -> Self {
|
||||
let mut stack = Stack::new(8);
|
||||
|
||||
stack.push(entry);
|
||||
stack.push(arg);
|
||||
|
||||
stack.setup_common(__x86_64_ctx_enter_kernel as usize, 0);
|
||||
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new user-space thread context
|
||||
pub fn user(entry: usize, arg: usize, cr3: usize, ustack: usize) -> Self {
|
||||
let cr3 = cr3 & 0xFFFFFFFF;
|
||||
let mut stack = Stack::new(8);
|
||||
|
||||
stack.push(entry);
|
||||
stack.push(arg);
|
||||
stack.push(0);
|
||||
stack.push(ustack);
|
||||
|
||||
stack.setup_common(__x86_64_ctx_enter_user as usize, cr3);
|
||||
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs an uninitialized thread context
|
||||
pub fn empty() -> Self {
|
||||
let stack = Stack::new(8);
|
||||
Self {
|
||||
k_sp: stack.sp,
|
||||
stack_base: stack.bp,
|
||||
stack_page_count: 8
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up a context for signal entry
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: may clobber an already active context
|
||||
pub unsafe fn setup_signal_entry(&mut self, entry: usize, arg: usize, cr3: usize, ustack: usize) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Performs initial thread entry
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: does not check if any context has already been activated
|
||||
/// before, so must only be called once.
|
||||
pub unsafe extern "C" fn enter(&mut self) -> ! {
|
||||
__x86_64_ctx_switch_to(self);
|
||||
panic!("This code should not run");
|
||||
}
|
||||
|
||||
/// Performs context switch from `self` to `to`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Unsafe: does not check if `self` is actually an active context.
|
||||
pub unsafe extern "C" fn switch(&mut self, to: &mut Context) {
|
||||
__x86_64_ctx_switch(to, self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new(page_count: usize) -> Stack {
|
||||
let phys = phys::alloc_contiguous_pages(PageUsage::Kernel, page_count).unwrap();
|
||||
let bp = mem::virtualize(phys);
|
||||
Stack {
|
||||
bp,
|
||||
sp: bp + page_count * mem::PAGE_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_base_size(bp: usize, page_count: usize) -> Stack {
|
||||
Stack {
|
||||
bp,
|
||||
sp: bp + page_count * mem::PAGE_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_common(&mut self, entry: usize, cr3: usize) {
|
||||
self.push(entry); // return address
|
||||
self.push(0); // gs_base
|
||||
self.push(cr3);
|
||||
self.push(0); // r15
|
||||
self.push(0); // r14
|
||||
self.push(0); // r13
|
||||
self.push(0); // r12
|
||||
self.push(0); // rbx
|
||||
self.push(0); // rbp
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: usize) {
|
||||
if self.bp == self.sp {
|
||||
panic!("Stack overflow");
|
||||
}
|
||||
|
||||
self.sp -= size_of::<usize>();
|
||||
unsafe {
|
||||
*(self.sp as *mut usize) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __x86_64_ctx_enter_from_fork();
|
||||
fn __x86_64_ctx_enter_kernel();
|
||||
fn __x86_64_ctx_enter_user();
|
||||
fn __x86_64_ctx_switch(dst: *mut Context, src: *mut Context);
|
||||
fn __x86_64_ctx_switch_to(dst: *mut Context);
|
||||
}
|
||||
|
||||
global_asm!(include_str!("context.S"), options(att_syntax));
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::arch::asm;
|
||||
use crate::arch::x86_64;
|
||||
use crate::debug::Level;
|
||||
use crate::dev::irq::{IrqContext, IntController};
|
||||
use crate::dev::irq::{IntController, IrqContext};
|
||||
use core::arch::{asm, global_asm};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExceptionFrame {
|
||||
@@ -50,7 +50,12 @@ fn pfault_access_type(code: u64) -> &'static str {
|
||||
|
||||
fn pfault_dump(level: Level, frame: &ExceptionFrame, cr2: u64) {
|
||||
println!(level, "\x1B[41;1mPage fault:");
|
||||
println!(level, " Illegal {} at {:#018x}\x1B[0m", pfault_access_type(frame.err_code), cr2);
|
||||
println!(
|
||||
level,
|
||||
" Illegal {} at {:#018x}\x1B[0m",
|
||||
pfault_access_type(frame.err_code),
|
||||
cr2
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -31,19 +31,51 @@ __x86_64_irq_\no:
|
||||
|
||||
__x86_64_irq_0:
|
||||
cli
|
||||
push %rax
|
||||
push %rdx
|
||||
|
||||
mov $'T', %al
|
||||
push %rax
|
||||
push %rcx
|
||||
push %rdx
|
||||
push %rbx
|
||||
push %rbp
|
||||
push %rsi
|
||||
push %rdi
|
||||
|
||||
push %r8
|
||||
push %r9
|
||||
push %r10
|
||||
push %r11
|
||||
push %r12
|
||||
push %r13
|
||||
push %r14
|
||||
push %r15
|
||||
|
||||
mov $0x3F8, %dx
|
||||
mov $'T', %al
|
||||
outb %al, %dx
|
||||
|
||||
mov $0x20, %al
|
||||
mov $0x20, %dx
|
||||
outb %al, %dx
|
||||
|
||||
call sched_yield
|
||||
|
||||
pop %r15
|
||||
pop %r14
|
||||
pop %r13
|
||||
pop %r12
|
||||
pop %r11
|
||||
pop %r10
|
||||
pop %r9
|
||||
pop %r8
|
||||
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rbp
|
||||
pop %rbx
|
||||
pop %rdx
|
||||
pop %rcx
|
||||
pop %rax
|
||||
|
||||
iretq
|
||||
|
||||
irq_entry 1
|
||||
|
||||
@@ -12,6 +12,7 @@ pub(self) use io::PortIo;
|
||||
pub mod boot;
|
||||
pub mod virt;
|
||||
pub mod intrin;
|
||||
pub mod context;
|
||||
pub(self) mod gdt;
|
||||
pub(self) mod idt;
|
||||
pub(self) mod exception;
|
||||
|
||||
@@ -9,12 +9,26 @@ use fixed::KERNEL_FIXED;
|
||||
|
||||
bitflags! {
|
||||
pub struct RawAttributesImpl: u64 {
|
||||
const PRESENT = 1 << 0;
|
||||
const WRITE = 1 << 1;
|
||||
const USER = 1 << 2;
|
||||
const BLOCK = 1 << 7;
|
||||
const GLOBAL = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MapAttributes> for RawAttributesImpl {
|
||||
fn from(src: MapAttributes) -> Self {
|
||||
todo!()
|
||||
fn from(i: MapAttributes) -> Self {
|
||||
let mut res = RawAttributesImpl::empty();
|
||||
|
||||
if i.contains(MapAttributes::USER_READ) {
|
||||
res |= RawAttributesImpl::USER;
|
||||
}
|
||||
if i.contains(MapAttributes::USER_WRITE) || i.contains(MapAttributes::KERNEL_WRITE) {
|
||||
res |= RawAttributesImpl::WRITE;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::mem::{
|
||||
use core::ops::{Index, IndexMut};
|
||||
use libsys::{error::Errno, mem::memset};
|
||||
|
||||
use super::RawAttributesImpl;
|
||||
use super::{RawAttributesImpl, KERNEL_FIXED};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
@@ -29,17 +29,17 @@ impl Entry for EntryImpl {
|
||||
|
||||
#[inline]
|
||||
fn normal(addr: usize, attrs: MapAttributes) -> Self {
|
||||
todo!()
|
||||
Self((addr as u64) | attrs.bits() | (1 << 0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn block(addr: usize, attrs: MapAttributes) -> Self {
|
||||
todo!()
|
||||
Self((addr as u64) | attrs.bits() | (1 << 7) | (1 << 0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn address(self) -> usize {
|
||||
todo!()
|
||||
(self.0 & !0xFFF) as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -49,12 +49,12 @@ impl Entry for EntryImpl {
|
||||
|
||||
#[inline]
|
||||
fn is_present(self) -> bool {
|
||||
todo!()
|
||||
self.0 & (1 << 0) != 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_normal(self) -> bool {
|
||||
todo!()
|
||||
self.0 & (1 << 7) == 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -82,7 +82,14 @@ impl Space for SpaceImpl {
|
||||
type Entry = EntryImpl;
|
||||
|
||||
fn alloc_empty() -> Result<&'static mut Self, Errno> {
|
||||
todo!()
|
||||
let kernel_pdpt_phys = unsafe {
|
||||
&KERNEL_FIXED.pdpt as *const _ as usize - mem::KERNEL_OFFSET
|
||||
};
|
||||
let page = phys::alloc_page(PageUsage::Paging)?;
|
||||
let res = unsafe { &mut *(mem::virtualize(page) as *mut Self) };
|
||||
res.0.entries[..511].fill(EntryImpl::EMPTY);
|
||||
res.0.entries[511] = EntryImpl::normal(kernel_pdpt_phys, MapAttributes::SHARE_OUTER | MapAttributes::KERNEL_EXEC | MapAttributes::KERNEL_WRITE);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
unsafe fn release(space: &'static mut Self) {
|
||||
@@ -100,11 +107,43 @@ impl Space for SpaceImpl {
|
||||
_create_intermediate: bool, // TODO handle this properly
|
||||
overwrite: bool,
|
||||
) -> Result<(), Errno> {
|
||||
todo!()
|
||||
let l0i = virt >> 39;
|
||||
let l1i = (virt >> 30) & 0x1FF;
|
||||
let l2i = (virt >> 21) & 0x1FF;
|
||||
let l3i = (virt >> 12) & 0x1FF;
|
||||
|
||||
let l0_table = self.0.next_level_table_or_alloc(l0i)?;
|
||||
let l1_table = l0_table.next_level_table_or_alloc(l1i)?;
|
||||
let l2_table = l1_table.next_level_table_or_alloc(l2i)?;
|
||||
|
||||
if l2_table[l3i].is_present() {
|
||||
warnln!("Entry already exists for address: virt={:#x}, prev={:#x}, new={:#x}", virt, l2_table[l3i].address(), entry.address());
|
||||
Err(Errno::AlreadyExists)
|
||||
} else {
|
||||
l2_table[l3i] = entry;
|
||||
unsafe {
|
||||
core::arch::asm!("invlpg ({})", in(reg) virt, options(att_syntax));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_last_level(&self, virt: usize) -> Result<Self::Entry, Errno> {
|
||||
todo!()
|
||||
let l0i = virt >> 39;
|
||||
let l1i = (virt >> 30) & 0x1FF;
|
||||
let l2i = (virt >> 21) & 0x1FF;
|
||||
let l3i = (virt >> 12) & 0x1FF;
|
||||
|
||||
let l0_table = self.0.next_level_table(l0i).ok_or(Errno::DoesNotExist)?;
|
||||
let l1_table = l0_table.next_level_table(l1i).ok_or(Errno::DoesNotExist)?;
|
||||
let l2_table = l1_table.next_level_table(l2i).ok_or(Errno::DoesNotExist)?;
|
||||
|
||||
let entry = l2_table[l3i];
|
||||
if entry.is_present() {
|
||||
Ok(entry)
|
||||
} else {
|
||||
Err(Errno::DoesNotExist)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,20 +160,51 @@ impl TableImpl {
|
||||
/// If `index` does not map to any translation table, will try to allocate, init and
|
||||
/// map a new one, returning it after doing so.
|
||||
pub fn next_level_table_or_alloc(&mut self, index: usize) -> Result<&'static mut Self, Errno> {
|
||||
todo!()
|
||||
let entry = self[index];
|
||||
if entry.is_present() {
|
||||
if !entry.is_normal() {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
Ok(unsafe { &mut *(mem::virtualize(entry.address()) as *mut _) })
|
||||
} else {
|
||||
let phys = phys::alloc_page(PageUsage::Paging)?;
|
||||
let res = unsafe { &mut *(mem::virtualize(phys) as *mut Self) };
|
||||
self[index] = EntryImpl::normal(phys, MapAttributes::USER_WRITE | MapAttributes::USER_READ);
|
||||
res.entries.fill(EntryImpl::EMPTY);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns next-level translation table reference for `index`, if one is present.
|
||||
/// Same as [next_level_table_or_alloc], but returns `None` if no table is mapped.
|
||||
pub fn next_level_table(&self, index: usize) -> Option<&'static Self> {
|
||||
todo!()
|
||||
let entry = self[index];
|
||||
if entry.is_present() {
|
||||
if !entry.is_normal() {
|
||||
panic!("Entry is not a table: idx={}", index);
|
||||
}
|
||||
|
||||
Some(unsafe { &*(mem::virtualize(entry.address()) as *const _) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns mutable next-level translation table reference for `index`,
|
||||
/// if one is present. Same as [next_level_table_or_alloc], but returns
|
||||
/// `None` if no table is mapped.
|
||||
pub fn next_level_table_mut(&mut self, index: usize) -> Option<&'static mut Self> {
|
||||
todo!()
|
||||
let entry = self[index];
|
||||
if entry.is_present() {
|
||||
if !entry.is_normal() {
|
||||
panic!("Entry is not a table: idx={}", index);
|
||||
}
|
||||
|
||||
Some(unsafe { &mut *(mem::virtualize(entry.address()) as *mut _) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-18
@@ -36,26 +36,26 @@ pub extern "C" fn init_fn(_arg: usize) -> ! {
|
||||
|
||||
proc.io.lock().set_ioctx(ioctx);
|
||||
|
||||
// Open stdin/stdout/stderr
|
||||
{
|
||||
let devfs_root = devfs::root();
|
||||
let tty_node = if console.is_empty() {
|
||||
devfs_root.lookup("ttyS0")
|
||||
} else {
|
||||
devfs_root.lookup(console)
|
||||
}
|
||||
.expect("Failed to open stdout for init process");
|
||||
// // Open stdin/stdout/stderr
|
||||
// {
|
||||
// let devfs_root = devfs::root();
|
||||
// let tty_node = if console.is_empty() {
|
||||
// devfs_root.lookup("ttyS0")
|
||||
// } else {
|
||||
// devfs_root.lookup(console)
|
||||
// }
|
||||
// .expect("Failed to open stdout for init process");
|
||||
|
||||
let mut io = proc.io.lock();
|
||||
let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
|
||||
let stderr = stdout.clone();
|
||||
// let mut io = proc.io.lock();
|
||||
// let stdin = tty_node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
// let stdout = tty_node.open(OpenFlags::O_WRONLY).unwrap();
|
||||
// let stderr = stdout.clone();
|
||||
|
||||
io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
||||
io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
||||
io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
||||
io.set_ctty(tty_node);
|
||||
}
|
||||
// io.set_file(FileDescriptor::STDIN, stdin).unwrap();
|
||||
// io.set_file(FileDescriptor::STDOUT, stdout).unwrap();
|
||||
// io.set_file(FileDescriptor::STDERR, stderr).unwrap();
|
||||
// io.set_ctty(tty_node);
|
||||
// }
|
||||
|
||||
drop(cfg);
|
||||
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@
|
||||
const_fn_fn_ptr_basics,
|
||||
const_fn_trait_bound,
|
||||
const_trait_impl,
|
||||
const_btree_new,
|
||||
panic_info_message,
|
||||
alloc_error_handler,
|
||||
asm_const,
|
||||
@@ -31,9 +32,9 @@ pub mod config;
|
||||
pub mod dev;
|
||||
pub mod fs;
|
||||
pub mod font;
|
||||
// pub mod init;
|
||||
pub mod init;
|
||||
pub mod mem;
|
||||
// pub mod proc;
|
||||
pub mod proc;
|
||||
pub mod sync;
|
||||
// pub mod syscall;
|
||||
pub mod util;
|
||||
|
||||
@@ -103,6 +103,40 @@ pub trait Space {
|
||||
create_intermediate: bool,
|
||||
overwrite: bool,
|
||||
) -> Result<(), Errno>;
|
||||
// =======
|
||||
// bitflags! {
|
||||
// /// Attributes attached to each translation [Entry]
|
||||
// pub struct MapAttributes: u64 {
|
||||
// const USER_READ = 1 << 1;
|
||||
// const USER_WRITE = 1 << 2;
|
||||
// const USER_EXEC = 1 << 3;
|
||||
// const KERNEL_WRITE = 1 << 4;
|
||||
// const KERNEL_EXEC = 1 << 5;
|
||||
//
|
||||
// const SHARE_OUTER = 1 << 6;
|
||||
// const SHARE_INNER = 2 << 6;
|
||||
//
|
||||
// const NOT_GLOBAL = 1 << 8;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub trait Entry: Clone + Copy {
|
||||
// fn from_parts(phys: usize, attrs: MapAttributes) -> Self;
|
||||
// fn target(self) -> usize;
|
||||
// fn is_present(self) -> bool;
|
||||
// fn is_table(self) -> bool;
|
||||
// }
|
||||
//
|
||||
// pub trait AddressSpace {
|
||||
// type Entry: Entry;
|
||||
//
|
||||
// fn alloc_empty() -> Result<&'static mut Self, Errno>;
|
||||
// fn release(space: &mut Self);
|
||||
// fn address_phys(&mut self) -> usize;
|
||||
// fn read_last_level_entry(&mut self, virt: usize) -> Result<Self::Entry, Errno>;
|
||||
// fn write_last_level_entry(
|
||||
// >>>>>>> d14ca5e (Make x86_64 work (pre-syscalls))
|
||||
|
||||
/// Reads an entry corresponding to `virt` address
|
||||
fn read_last_level(&self, virt: usize) -> Result<Self::Entry, Errno>;
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ pub fn switch() {
|
||||
SCHED.switch(false);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn sched_yield() {
|
||||
SCHED.switch(false);
|
||||
}
|
||||
|
||||
pub(self) static PROCESSES: IrqSafeSpinLock<BTreeMap<Pid, ProcessRef>> =
|
||||
IrqSafeSpinLock::new(BTreeMap::new());
|
||||
|
||||
|
||||
+8
-188
@@ -1,5 +1,4 @@
|
||||
//! Process data and control
|
||||
use crate::arch::{aarch64::exception::ExceptionFrame, intrin};
|
||||
use crate::mem::{
|
||||
self,
|
||||
phys::{self, PageUsage},
|
||||
@@ -8,7 +7,8 @@ use crate::mem::{
|
||||
use crate::proc::{
|
||||
wait::Wait, Context, ProcessIo, Thread, ThreadRef, ThreadState, Tid, PROCESSES, SCHED,
|
||||
};
|
||||
use crate::sync::IrqSafeSpinLock;
|
||||
use crate::arch::intrin;
|
||||
use crate::sync::{IrqSafeSpinLock, IrqSafeSpinLockGuard};
|
||||
use alloc::{rc::Rc, vec::Vec};
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use libsys::{
|
||||
@@ -17,6 +17,7 @@ use libsys::{
|
||||
signal::Signal,
|
||||
ProgramArgs,
|
||||
};
|
||||
use core::arch::asm;
|
||||
|
||||
/// Wrapper type for a process struct reference
|
||||
pub type ProcessRef = Rc<Process>;
|
||||
@@ -154,193 +155,19 @@ impl Process {
|
||||
None
|
||||
}
|
||||
|
||||
/// Handles all pending signals (when returning from aborted syscall)
|
||||
pub fn handle_pending_signals(&self) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
drop(lock);
|
||||
|
||||
loop {
|
||||
let state = self.signal_state.load(Ordering::Acquire);
|
||||
if let Some(signal) = Self::find1(state).map(|e| Signal::try_from(e as u32).unwrap()) {
|
||||
self.signal_state
|
||||
.fetch_and(!(1 << (signal as u32)), Ordering::Release);
|
||||
main_thread.clone().enter_signal(signal, ttbr0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a pending signal for a process
|
||||
pub fn set_signal(&self, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
let main_thread = Thread::get(lock.threads[0]).unwrap();
|
||||
drop(lock);
|
||||
|
||||
// TODO check that `signal` is not a fault signal
|
||||
// it is illegal to call this function with
|
||||
// fault signals
|
||||
|
||||
match main_thread.state() {
|
||||
ThreadState::Running => {
|
||||
main_thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
ThreadState::Waiting => {
|
||||
self.signal_state
|
||||
.fetch_or(1 << (signal as u32), Ordering::Release);
|
||||
main_thread.interrupt_wait(true);
|
||||
}
|
||||
ThreadState::Ready => {
|
||||
main_thread.clone().setup_signal(signal, ttbr0);
|
||||
main_thread.interrupt_wait(false);
|
||||
}
|
||||
ThreadState::Finished => {
|
||||
// TODO report error back
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Immediately delivers a signal to requested thread
|
||||
pub fn enter_fault_signal(&self, thread: ThreadRef, signal: Signal) {
|
||||
let mut lock = self.inner.lock();
|
||||
let ttbr0 = lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48);
|
||||
drop(lock);
|
||||
thread.enter_signal(signal, ttbr0);
|
||||
}
|
||||
|
||||
/// Crates a new thread in the process
|
||||
pub fn new_user_thread(&self, entry: usize, stack: usize, arg: usize) -> Result<Tid, Errno> {
|
||||
let mut lock = self.inner.lock();
|
||||
|
||||
let space_phys = lock.space.as_mut().unwrap().address_phys();
|
||||
let ttbr0 = space_phys | ((lock.id.asid() as usize) << 48);
|
||||
|
||||
let thread = Thread::new_user(lock.id, entry, stack, arg, ttbr0)?;
|
||||
let tid = thread.id();
|
||||
lock.threads.push(tid);
|
||||
SCHED.enqueue(tid);
|
||||
|
||||
Ok(tid)
|
||||
}
|
||||
|
||||
/// Creates a "fork" of the process, cloning its address space and
|
||||
/// resources
|
||||
pub fn fork(&self, frame: &mut ExceptionFrame) -> Result<Pid, Errno> {
|
||||
let src_io = self.io.lock();
|
||||
let mut src_inner = self.inner.lock();
|
||||
|
||||
let dst_id = new_user_pid();
|
||||
let dst_space = src_inner.space.as_mut().unwrap().fork()?;
|
||||
let dst_space_phys = (dst_space as *mut _ as usize) - mem::KERNEL_OFFSET;
|
||||
let dst_ttbr0 = dst_space_phys | ((dst_id.asid() as usize) << 48);
|
||||
|
||||
let mut threads = Vec::new();
|
||||
let tid = Thread::fork(Some(dst_id), frame, dst_ttbr0)?.id();
|
||||
threads.push(tid);
|
||||
|
||||
let dst = Rc::new(Self {
|
||||
exit_wait: Wait::new("process_exit"),
|
||||
io: IrqSafeSpinLock::new(src_io.fork()?),
|
||||
signal_state: AtomicU32::new(0),
|
||||
inner: IrqSafeSpinLock::new(ProcessInner {
|
||||
threads,
|
||||
exit: None,
|
||||
space: Some(dst_space),
|
||||
state: ProcessState::Active,
|
||||
id: dst_id,
|
||||
pgid: src_inner.pgid,
|
||||
ppid: Some(src_inner.id),
|
||||
sid: src_inner.sid,
|
||||
}),
|
||||
});
|
||||
|
||||
debugln!("Process {:?} forked into {:?}", src_inner.id, dst_id);
|
||||
assert!(PROCESSES.lock().insert(dst_id, dst).is_none());
|
||||
|
||||
SCHED.enqueue(tid);
|
||||
|
||||
Ok(dst_id)
|
||||
fn space_phys(lock: &mut IrqSafeSpinLockGuard<ProcessInner>) -> usize {
|
||||
lock.space.as_mut().unwrap().address_phys() | ((lock.id.asid() as usize) << 48)
|
||||
}
|
||||
|
||||
/// Terminates a process.
|
||||
pub fn exit(self: ProcessRef, status: ExitCode) {
|
||||
let thread = Thread::current();
|
||||
let mut lock = self.inner.lock();
|
||||
let is_running = thread.owner_id().map(|e| e == lock.id).unwrap_or(false);
|
||||
|
||||
infoln!("Process {:?} is exiting: {:?}", lock.id, status);
|
||||
assert!(lock.exit.is_none());
|
||||
lock.exit = Some(status);
|
||||
lock.state = ProcessState::Finished;
|
||||
|
||||
for &tid in lock.threads.iter() {
|
||||
let thread = Thread::get(tid).unwrap();
|
||||
if thread.state() == ThreadState::Waiting {
|
||||
todo!()
|
||||
}
|
||||
thread.terminate(status);
|
||||
SCHED.dequeue(tid);
|
||||
}
|
||||
|
||||
if let Some(space) = lock.space.take() {
|
||||
unsafe {
|
||||
SpaceImpl::release(space);
|
||||
intrin::flush_tlb_asid((lock.id.asid() as usize) << 48);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO when exiting from signal handler interrupting an IO operation
|
||||
// deadlock is achieved
|
||||
self.io.lock().handle_exit();
|
||||
|
||||
drop(lock);
|
||||
|
||||
self.exit_wait.wakeup_all();
|
||||
|
||||
if is_running {
|
||||
SCHED.switch(true);
|
||||
panic!("This code should never run");
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Terminates a thread of the process. If the thread is the only
|
||||
/// one remaining, process itself is exited (see [Process::exit])
|
||||
pub fn exit_thread(thread: ThreadRef, status: ExitCode) {
|
||||
let switch = {
|
||||
let switch = thread.state() == ThreadState::Running;
|
||||
let process = thread.owner().unwrap();
|
||||
let mut lock = process.inner.lock();
|
||||
let tid = thread.id();
|
||||
|
||||
if lock.threads.len() == 1 {
|
||||
// TODO call Process::exit instead?
|
||||
drop(lock);
|
||||
process.exit(status);
|
||||
return;
|
||||
}
|
||||
|
||||
lock.threads.retain(|&e| e != tid);
|
||||
|
||||
thread.terminate(status);
|
||||
SCHED.dequeue(tid);
|
||||
debugln!("Thread {:?} terminated", tid);
|
||||
|
||||
switch
|
||||
};
|
||||
|
||||
if switch {
|
||||
// TODO retain thread ID in process "finished" list and
|
||||
// drop it when process finishes
|
||||
SCHED.switch(true);
|
||||
panic!("This code should not run");
|
||||
} else {
|
||||
// Can drop this thread: it's not running
|
||||
todo!();
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn collect(&self) -> Option<ExitCode> {
|
||||
@@ -418,13 +245,6 @@ impl Process {
|
||||
(self.id().asid() as usize) << 48
|
||||
}
|
||||
|
||||
/// Flushes TLB cache for the process address space
|
||||
pub fn invalidate_tlb(&self) {
|
||||
unsafe {
|
||||
intrin::flush_tlb_asid(self.asid());
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads a new program into current process address space
|
||||
pub fn execve<F: FnOnce(&mut SpaceImpl) -> Result<usize, Errno>>(
|
||||
loader: F,
|
||||
@@ -488,7 +308,7 @@ impl Process {
|
||||
// TODO drop old context
|
||||
let ctx = thread.ctx.get();
|
||||
let asid = (process_lock.id.asid() as usize) << 48;
|
||||
intrin::flush_tlb_asid(asid);
|
||||
// Process::invalidate_asid(asid);
|
||||
|
||||
ctx.write(Context::user(
|
||||
entry,
|
||||
|
||||
@@ -151,7 +151,7 @@ pub fn is_ready() -> bool {
|
||||
#[inline(never)]
|
||||
extern "C" fn idle_fn(_a: usize) -> ! {
|
||||
loop {
|
||||
cortex_a::asm::wfi();
|
||||
// cortex_a::asm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-28
@@ -1,6 +1,6 @@
|
||||
//! Facilities for controlling threads - smallest units of
|
||||
//! execution in the operating system
|
||||
use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
// use crate::arch::aarch64::exception::ExceptionFrame;
|
||||
use crate::proc::{
|
||||
wait::{Wait, WaitStatus},
|
||||
Process, ProcessRef, SCHED, THREADS,
|
||||
@@ -143,34 +143,34 @@ impl Thread {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Creates a fork thread cloning `frame` context
|
||||
pub fn fork(
|
||||
owner: Option<Pid>,
|
||||
frame: &ExceptionFrame,
|
||||
ttbr0: usize,
|
||||
) -> Result<ThreadRef, Errno> {
|
||||
let id = new_tid();
|
||||
// /// Creates a fork thread cloning `frame` context
|
||||
// pub fn fork(
|
||||
// owner: Option<Pid>,
|
||||
// frame: &ExceptionFrame,
|
||||
// ttbr0: usize,
|
||||
// ) -> Result<ThreadRef, Errno> {
|
||||
// let id = new_tid();
|
||||
|
||||
let res = Rc::new(Self {
|
||||
ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
||||
signal_ctx: UnsafeCell::new(Context::empty()),
|
||||
signal_pending: AtomicU32::new(0),
|
||||
exit_wait: Wait::new("thread_exit"),
|
||||
exit_status: InitOnce::new(),
|
||||
inner: IrqSafeSpinLock::new(ThreadInner {
|
||||
signal_entry: 0,
|
||||
signal_stack: 0,
|
||||
id,
|
||||
owner,
|
||||
pending_wait: None,
|
||||
wait_status: WaitStatus::Done,
|
||||
state: State::Ready,
|
||||
}),
|
||||
});
|
||||
debugln!("Forked new user thread: {:?}", id);
|
||||
assert!(THREADS.lock().insert(id, res.clone()).is_none());
|
||||
Ok(res)
|
||||
}
|
||||
// let res = Rc::new(Self {
|
||||
// ctx: UnsafeCell::new(Context::fork(frame, ttbr0)),
|
||||
// signal_ctx: UnsafeCell::new(Context::empty()),
|
||||
// signal_pending: AtomicU32::new(0),
|
||||
// exit_wait: Wait::new("thread_exit"),
|
||||
// exit_status: InitOnce::new(),
|
||||
// inner: IrqSafeSpinLock::new(ThreadInner {
|
||||
// signal_entry: 0,
|
||||
// signal_stack: 0,
|
||||
// id,
|
||||
// owner,
|
||||
// pending_wait: None,
|
||||
// wait_status: WaitStatus::Done,
|
||||
// state: State::Ready,
|
||||
// }),
|
||||
// });
|
||||
// debugln!("Forked new user thread: {:?}", id);
|
||||
// assert!(THREADS.lock().insert(id, res.clone()).is_none());
|
||||
// Ok(res)
|
||||
// }
|
||||
|
||||
/// Returns the thread ID
|
||||
#[inline]
|
||||
|
||||
+6
-166
@@ -39,35 +39,12 @@ pub static WAIT_SELECT: Wait = Wait::new("select");
|
||||
|
||||
/// Checks for any timed out wait channels and interrupts them
|
||||
pub fn tick() {
|
||||
let time = machine::local_timer().timestamp().unwrap();
|
||||
let mut list = TICK_LIST.lock();
|
||||
let mut cursor = list.cursor_front_mut();
|
||||
|
||||
while let Some(item) = cursor.current() {
|
||||
if time > item.deadline {
|
||||
let tid = item.tid;
|
||||
cursor.remove_current();
|
||||
SCHED.enqueue(tid);
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
todo!();
|
||||
}
|
||||
|
||||
/// Suspends current process for given duration
|
||||
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Errno> {
|
||||
// Dummy wait descriptor which will never receive notifications
|
||||
static SLEEP_NOTIFY: Wait = Wait::new("sleep");
|
||||
let deadline = machine::local_timer().timestamp()? + timeout;
|
||||
match SLEEP_NOTIFY.wait(Some(deadline)) {
|
||||
Err(Errno::Interrupt) => {
|
||||
*remaining = deadline - machine::local_timer().timestamp()?;
|
||||
Err(Errno::Interrupt)
|
||||
}
|
||||
Err(Errno::TimedOut) => Ok(()),
|
||||
Ok(_) => panic!("Impossible result"),
|
||||
res => res,
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Suspends current process until some file descriptor
|
||||
@@ -78,49 +55,7 @@ pub fn select(
|
||||
mut wfds: Option<&mut FdSet>,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<usize, Errno> {
|
||||
if wfds.is_none() && rfds.is_none() {
|
||||
todo!();
|
||||
}
|
||||
let read = rfds.as_deref().map(FdSet::clone);
|
||||
let write = wfds.as_deref().map(FdSet::clone);
|
||||
if let Some(rfds) = &mut rfds {
|
||||
rfds.reset();
|
||||
}
|
||||
if let Some(wfds) = &mut wfds {
|
||||
wfds.reset();
|
||||
}
|
||||
|
||||
let deadline = timeout.map(|v| v + machine::local_timer().timestamp().unwrap());
|
||||
let proc = thread.owner().unwrap();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
loop {
|
||||
if let Some(read) = &read {
|
||||
for fd in read.iter() {
|
||||
let file = io.file(fd)?;
|
||||
if file.borrow().ready(false)? {
|
||||
rfds.as_mut().unwrap().set(fd);
|
||||
return Ok(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(write) = &write {
|
||||
for fd in write.iter() {
|
||||
let file = io.file(fd)?;
|
||||
if file.borrow().ready(true)? {
|
||||
wfds.as_mut().unwrap().set(fd);
|
||||
return Ok(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Suspend
|
||||
match WAIT_SELECT.wait(deadline) {
|
||||
Err(Errno::TimedOut) => return Ok(0),
|
||||
Err(e) => return Err(e),
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
todo!();
|
||||
}
|
||||
|
||||
impl Wait {
|
||||
@@ -134,61 +69,11 @@ impl Wait {
|
||||
|
||||
/// Interrupt wait pending on the channel
|
||||
pub fn abort(&self, tid: Tid, enqueue: bool) {
|
||||
let mut queue = self.queue.lock();
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == item.tid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
|
||||
let mut cursor = queue.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == *item {
|
||||
cursor.remove_current();
|
||||
let thread = Thread::get(tid).unwrap();
|
||||
thread.set_wait_status(WaitStatus::Interrupted);
|
||||
if enqueue {
|
||||
SCHED.enqueue(tid);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn wakeup_some(&self, mut limit: usize) -> usize {
|
||||
// No IRQs will arrive now == safe to manipulate tick list
|
||||
let mut queue = self.queue.lock();
|
||||
let mut count = 0;
|
||||
while limit != 0 && !queue.is_empty() {
|
||||
let tid = queue.pop_front();
|
||||
if let Some(tid) = tid {
|
||||
let mut tick_lock = TICK_LIST.lock();
|
||||
let mut cursor = tick_lock.cursor_front_mut();
|
||||
while let Some(item) = cursor.current() {
|
||||
if tid == item.tid {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
drop(tick_lock);
|
||||
|
||||
Thread::get(tid).unwrap().set_wait_status(WaitStatus::Done);
|
||||
SCHED.enqueue(tid);
|
||||
}
|
||||
|
||||
limit -= 1;
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
todo!();
|
||||
}
|
||||
|
||||
/// Notifies all processes waiting for this event
|
||||
@@ -204,51 +89,6 @@ impl Wait {
|
||||
/// Suspends current process until event is signalled or
|
||||
/// (optional) deadline is reached
|
||||
pub fn wait(&self, deadline: Option<Duration>) -> Result<(), Errno> {
|
||||
let thread = Thread::current();
|
||||
//let deadline = timeout.map(|t| machine::local_timer().timestamp().unwrap() + t);
|
||||
let mut queue_lock = self.queue.lock();
|
||||
|
||||
queue_lock.push_back(thread.id());
|
||||
thread.setup_wait(self);
|
||||
|
||||
if let Some(deadline) = deadline {
|
||||
TICK_LIST.lock().push_back(Timeout {
|
||||
tid: thread.id(),
|
||||
deadline,
|
||||
});
|
||||
}
|
||||
|
||||
loop {
|
||||
match thread.wait_status() {
|
||||
WaitStatus::Pending => {}
|
||||
WaitStatus::Done => {
|
||||
return Ok(());
|
||||
}
|
||||
WaitStatus::Interrupted => {
|
||||
return Err(Errno::Interrupt);
|
||||
}
|
||||
};
|
||||
|
||||
drop(queue_lock);
|
||||
thread.enter_wait();
|
||||
queue_lock = self.queue.lock();
|
||||
|
||||
if let Some(deadline) = deadline {
|
||||
if machine::local_timer().timestamp()? > deadline {
|
||||
let mut cursor = queue_lock.cursor_front_mut();
|
||||
|
||||
while let Some(&mut item) = cursor.current() {
|
||||
if thread.id() == item {
|
||||
cursor.remove_current();
|
||||
break;
|
||||
} else {
|
||||
cursor.move_next();
|
||||
}
|
||||
}
|
||||
|
||||
return Err(Errno::TimedOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user