proc: spawn_thread/exit_thread/wait_thread

This commit is contained in:
Mark Poliakov 2024-04-25 16:02:00 +03:00
parent 58008d8704
commit 3383d0350c
16 changed files with 113 additions and 96 deletions

1
Cargo.lock generated
View File

@ -2115,7 +2115,6 @@ dependencies = [
"atomic_enum", "atomic_enum",
"bitflags 2.4.2", "bitflags 2.4.2",
"bytemuck", "bytemuck",
"cfg-if",
"crossbeam-queue", "crossbeam-queue",
"device-api", "device-api",
"device-api-macros", "device-api-macros",

View File

@ -40,7 +40,6 @@ bitflags = "2.3.3"
spinning_top = "0.2.5" spinning_top = "0.2.5"
static_assertions = "1.1.0" static_assertions = "1.1.0"
tock-registers = "0.8.1" tock-registers = "0.8.1"
cfg-if = "1.0.0"
git-version = "0.3.5" git-version = "0.3.5"
log = "0.4.20" log = "0.4.20"
futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] }
@ -70,6 +69,12 @@ kernel-arch-x86_64 = { path = "arch/x86_64" }
prettyplease = "0.2.15" prettyplease = "0.2.15"
abi-generator = { path = "../tool/abi-generator" } abi-generator = { path = "../tool/abi-generator" }
# To make rust-analyzer recognize those
[dev-dependencies]
aarch64-cpu = "9.3.1"
device-tree = { path = "lib/device-tree" }
kernel-arch-aarch64 = { path = "arch/aarch64" }
[features] [features]
default = ["fb_console"] default = ["fb_console"]
fb_console = [] fb_console = []

View File

@ -128,7 +128,7 @@ pub fn load(file: FileRef) -> Result<LoadedModule, Error> {
let name = dynstr.get(sym.st_name as _).unwrap(); let name = dynstr.get(sym.st_name as _).unwrap();
if sym.st_shndx == elf::abi::SHN_UNDEF && sym.st_bind() != elf::abi::STB_LOCAL { if sym.st_shndx == elf::abi::SHN_UNDEF && sym.st_bind() != elf::abi::STB_LOCAL {
let Some(value) = lookup_symbol(&name) else { let Some(value) = lookup_symbol(name) else {
log::warn!("Could not load module: undefined reference to {:?} (possibly compiled against a different libk?)", name); log::warn!("Could not load module: undefined reference to {:?} (possibly compiled against a different libk?)", name);
return Err(Error::InvalidArgument); return Err(Error::InvalidArgument);
}; };

View File

@ -132,6 +132,7 @@ pub fn open_elf_file<F: Read + Seek>(file: Arc<F>) -> Result<ElfKind<F>, Error>
} }
} }
#[allow(clippy::type_complexity)]
pub fn open_elf_direct<F: Read + Seek>( pub fn open_elf_direct<F: Read + Seek>(
file: Arc<F>, file: Arc<F>,
) -> Result<(ElfStream<AnyEndian, FileReader<Arc<F>>>, FileReader<Arc<F>>), Error> { ) -> Result<(ElfStream<AnyEndian, FileReader<Arc<F>>>, FileReader<Arc<F>>), Error> {

View File

@ -7,10 +7,13 @@ use alloc::{
sync::{Arc, Weak}, sync::{Arc, Weak},
vec::Vec, vec::Vec,
}; };
use kernel_arch::KernelTableManagerImpl; use kernel_arch::{
task::{TaskContext, UserContextInfo},
KernelTableManagerImpl,
};
use libk_mm::{phys::GlobalPhysicalAllocator, process::ProcessAddressSpace}; use libk_mm::{phys::GlobalPhysicalAllocator, process::ProcessAddressSpace};
use libk_util::{ use libk_util::{
event::OneTimeEvent, event::{BoolEvent, OneTimeEvent},
sync::{ sync::{
spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard}, spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard},
IrqSafeSpinlock, IrqSafeSpinlock,
@ -23,6 +26,7 @@ use yggdrasil_abi::{
use crate::{ use crate::{
task::{ task::{
binary,
futex::UserspaceMutex, futex::UserspaceMutex,
thread::Thread, thread::Thread,
types::{AllocateProcessId, ProcessTlsInfo}, types::{AllocateProcessId, ProcessTlsInfo},
@ -62,6 +66,8 @@ pub struct ProcessInner {
mutexes: BTreeMap<usize, Arc<UserspaceMutex>>, mutexes: BTreeMap<usize, Arc<UserspaceMutex>>,
space: Option<Arc<ProcessAddressSpace>>, space: Option<Arc<ProcessAddressSpace>>,
image: Option<ProcessImage>, image: Option<ProcessImage>,
thread_exits: BTreeMap<ThreadId, Arc<BoolEvent>>,
} }
/// Describes a process within the system /// Describes a process within the system
@ -106,7 +112,7 @@ impl Process {
// Create "main" thread // Create "main" thread
let thread = Thread::new_uthread(process.id, space, context); let thread = Thread::new_uthread(process.id, space, context);
process.inner.write().threads.push(thread.clone()); process.inner.write().register_thread(thread.clone());
MANAGER.register_process(process.clone()); MANAGER.register_process(process.clone());
@ -123,33 +129,33 @@ impl Process {
/// Spawns a new child thread within the process /// Spawns a new child thread within the process
pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> { pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> {
log::debug!("Spawn thread in {} with options: {:#x?}", self.id, options); log::debug!("Spawn thread in {} with options: {:#x?}", self.id, options);
// let mut inner = self.inner.write(); let mut inner = self.inner.write();
// let space = inner.space.clone().unwrap(); let space = inner.space.clone().unwrap();
todo!() let tls_address = if let Some(image) = inner.image.as_ref() {
// XXX binary::elf::clone_tls(&space, image)?
// let tls_address = if let Some(image) = inner.image.as_ref() { } else {
// proc::elf::clone_tls(&space, image)? 0
// } else { };
// 0
// };
// let context = TaskContextImpl::user( let info = UserContextInfo {
// options.entry as _, entry: options.entry as _,
// options.argument as _, argument: options.argument as _,
// space.as_address_with_asid(), address_space: space.as_address_with_asid(),
// options.stack_top, stack_pointer: options.stack_top,
// tls_address, single_step: false,
// )?; tls: tls_address,
// let thread = Thread::new_uthread(self.clone(), space.clone(), context); };
// let id = thread.id; let context = TaskContextImpl::user(info)?;
let thread = Thread::new_uthread(self.id, space.clone(), context);
let id = thread.id;
// inner.add_thread(thread.clone()); inner.register_thread(thread.clone());
// thread.enqueue(); thread.enqueue();
// Ok(id) Ok(id)
} }
unsafe fn fork_inner<F: ForkFrame<Context = TaskContextImpl>>( unsafe fn fork_inner<F: ForkFrame<Context = TaskContextImpl>>(
@ -367,6 +373,20 @@ impl Process {
} }
} }
pub async fn wait_for_thread(&self, thread: ThreadId) -> Result<(), Error> {
let exit = {
let inner = self.inner.read();
inner
.thread_exits
.get(&thread)
.cloned()
.ok_or(Error::DoesNotExist)?
};
exit.wait().await;
Ok(())
}
pub async fn terminate_others(&self, except: ThreadId) { pub async fn terminate_others(&self, except: ThreadId) {
let mut inner = self.inner.write(); let mut inner = self.inner.write();
@ -399,10 +419,13 @@ impl ProcessInner {
mutexes: BTreeMap::new(), mutexes: BTreeMap::new(),
image, image,
space: space.clone(), space: space.clone(),
thread_exits: BTreeMap::new(),
} }
} }
pub fn add_thread(&mut self, thread: Arc<Thread>) { pub fn register_thread(&mut self, thread: Arc<Thread>) {
self.thread_exits.insert(thread.id, thread.exit.clone());
self.threads.push(thread); self.threads.push(thread);
} }

View File

@ -75,7 +75,8 @@ pub struct Thread {
inner: IrqSafeSpinlock<ThreadInner>, inner: IrqSafeSpinlock<ThreadInner>,
signal_queue: SegQueue<Signal>, signal_queue: SegQueue<Signal>,
pub exit: BoolEvent, pub exit: Arc<BoolEvent>,
/// CPU scheduling affinity mask /// CPU scheduling affinity mask
pub affinity: ThreadAffinity, pub affinity: ThreadAffinity,
} }
@ -125,7 +126,7 @@ impl Thread {
inner: IrqSafeSpinlock::new(ThreadInner { signal_entry: None }), inner: IrqSafeSpinlock::new(ThreadInner { signal_entry: None }),
signal_queue: SegQueue::new(), signal_queue: SegQueue::new(),
exit: BoolEvent::new(), exit: Arc::new(BoolEvent::new()),
affinity: ThreadAffinity::any_cpu(), affinity: ThreadAffinity::any_cpu(),
}); });

View File

@ -25,7 +25,7 @@ pub struct ArmTimer {
} }
/// ARM timer tick interval (in some time units?) /// ARM timer tick interval (in some time units?)
pub const TICK_INTERVAL: u64 = 1000000; pub const TICK_INTERVAL: u64 = 250000;
impl InterruptHandler for ArmTimer { impl InterruptHandler for ArmTimer {
fn handle_irq(&self, _vector: Option<usize>) -> bool { fn handle_irq(&self, _vector: Option<usize>) -> bool {
@ -76,36 +76,6 @@ impl Device for ArmTimer {
} }
} }
// impl TimestampSource for ArmTimer {
// fn timestamp(&self) -> Result<Duration, Error> {
// }
// }
// impl InterruptSource for ArmTimer {
// fn handle_irq(&self) -> Result<bool, Error> {
// CNTP_TVAL_EL0.set(TICK_INTERVAL);
// let t = self.timestamp()?;
//
// wait::tick(t);
// tasklet::tick(t);
//
// unsafe {
// Cpu::local().queue().yield_cpu();
// }
//
// Ok(true)
// }
//
// unsafe fn init_irq(&'static self) -> Result<(), Error> {
// let intc = PLATFORM.interrupt_controller();
//
// intc.register_handler(self.irq, self)?;
// intc.enable_irq(self.irq)?;
//
// Ok(())
// }
// }
impl ArmTimer { impl ArmTimer {
/// Constructs an instance of ARM generic timer. /// Constructs an instance of ARM generic timer.
/// ///

View File

@ -2,7 +2,6 @@
use abi::error::Error; use abi::error::Error;
use cfg_if::cfg_if;
use device_api::{ use device_api::{
interrupt::{IpiDeliveryTarget, IpiMessage}, interrupt::{IpiDeliveryTarget, IpiMessage},
ResetDevice, ResetDevice,
@ -10,19 +9,18 @@ use device_api::{
use kernel_arch::{Architecture, ArchitectureImpl}; use kernel_arch::{Architecture, ArchitectureImpl};
use libk_mm::table::EntryLevel; use libk_mm::table::EntryLevel;
cfg_if! { #[cfg(any(target_arch = "aarch64", rust_analyzer))]
if #[cfg(target_arch = "aarch64")] {
pub mod aarch64; pub mod aarch64;
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub use aarch64::{AArch64 as PlatformImpl, PLATFORM}; pub use aarch64::{AArch64 as PlatformImpl, PLATFORM};
} else if #[cfg(target_arch = "x86_64")] {
pub mod x86_64;
pub use x86_64::{X86_64 as PlatformImpl, PLATFORM}; #[cfg(any(target_arch = "x86_64", rust_analyzer))]
} else { pub mod x86_64;
compile_error!("Architecture is not supported"); #[cfg(any(target_arch = "x86_64", rust_analyzer))]
} pub use x86_64::{PLATFORM, X86_64 as PlatformImpl};
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
compile_error!("Unsupported architecture");
/// Architecture-specific lowest level of page mapping /// Architecture-specific lowest level of page mapping
pub type L3 = <PlatformImpl as Platform>::L3; pub type L3 = <PlatformImpl as Platform>::L3;

View File

@ -1,10 +1,4 @@
//! Power-management related device drivers //! Power-management related device drivers
use cfg_if::cfg_if; #[cfg(any(target_arch = "aarch64", rust_analyzer))]
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod arm_psci; pub mod arm_psci;
// pub mod sunxi_rwdog;
}
}

View File

@ -1,10 +1,4 @@
//! Serial device interfaces //! Serial device interfaces
use cfg_if::cfg_if; #[cfg(any(target_arch = "aarch64", rust_analyzer))]
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod pl011; pub mod pl011;
// pub mod sunxi_uart;
}
}

View File

@ -219,7 +219,7 @@ impl Device for Pl011 {
self.inner.init(IrqSafeSpinlock::new(inner)); self.inner.init(IrqSafeSpinlock::new(inner));
debug::add_sink(self, LogLevel::Info); debug::add_sink(self, LogLevel::Debug);
devfs::add_char_device(self, CharDeviceType::TtySerial)?; devfs::add_char_device(self, CharDeviceType::TtySerial)?;
Ok(()) Ok(())

View File

@ -2,14 +2,14 @@
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
use abi::{error::Error, io::OpenOptions}; use abi::error::Error;
use alloc::{format, string::String, sync::Arc}; use alloc::{format, string::String};
use git_version::git_version; use git_version::git_version;
use libk::{ use libk::{
task::{cpu_count, process::Process, sched}, task::{cpu_count, sched},
vfs::{ vfs::{
impls::{const_value_node, mdir, read_fn_node, ReadOnlyFnValueNode}, impls::{const_value_node, mdir, read_fn_node, ReadOnlyFnValueNode},
CommonImpl, InstanceData, NodeRef, RegularImpl, NodeRef,
}, },
}; };
use libk_mm::phys; use libk_mm::phys;

View File

@ -6,12 +6,13 @@ use abi::{
mem::MappingSource, mem::MappingSource,
process::{ process::{
ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnOption, SpawnOptions, ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnOption, SpawnOptions,
ThreadSpawnOptions,
}, },
}; };
use alloc::sync::Arc; use alloc::sync::Arc;
use libk::{ use libk::{
block, block,
task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread}, task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread, ThreadId},
vfs::IoContext, vfs::IoContext,
}; };
use libk_mm::{ use libk_mm::{
@ -236,3 +237,28 @@ pub(crate) fn start_session() -> Result<(), Error> {
Ok(()) Ok(())
} }
pub(crate) fn spawn_thread(options: &ThreadSpawnOptions) -> Result<u32, Error> {
let thread = Thread::current();
let process = thread.process();
process
.spawn_thread(options)
.map(|tid| tid.as_user() as u32)
}
pub(crate) fn exit_thread() -> ! {
let thread = Thread::current();
// TODO exit codes are not supported in here
thread.exit(ExitCode::SUCCESS)
}
pub(crate) fn wait_thread(id: u32) -> Result<(), Error> {
let tid = ThreadId::User(id as u64);
let this_thread = Thread::current();
let process = this_thread.process();
block!(process.wait_for_thread(tid).await)??;
Ok(())
}

View File

@ -39,7 +39,7 @@ mod generated {
use abi::{ use abi::{
io::ChannelPublisherId, io::ChannelPublisherId,
process::{ExecveOptions, ProcessId}, process::{ExecveOptions, ProcessId, ThreadSpawnOptions},
SyscallFunction, SyscallFunction,
}; };
use abi_lib::SyscallRegister; use abi_lib::SyscallRegister;

View File

@ -63,6 +63,11 @@ syscall spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId>;
syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>; syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>;
syscall get_pid() -> ProcessId; syscall get_pid() -> ProcessId;
// TODO use ThreadId
syscall spawn_thread(options: &ThreadSpawnOptions) -> Result<u32>;
syscall exit_thread() -> !;
syscall wait_thread(tid: u32) -> Result<()>;
syscall nanosleep(dur: &Duration) -> Result<()>; syscall nanosleep(dur: &Duration) -> Result<()>;
syscall exit_signal(frame: &SignalEntryData) -> !; syscall exit_signal(frame: &SignalEntryData) -> !;

View File

@ -20,6 +20,7 @@ mod generated {
net::SocketType, net::SocketType,
process::{ process::{
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions, ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions,
ThreadSpawnOptions,
}, },
SyscallFunction, SyscallFunction,
}; };