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",
"bitflags 2.4.2",
"bytemuck",
"cfg-if",
"crossbeam-queue",
"device-api",
"device-api-macros",

View File

@ -40,7 +40,6 @@ bitflags = "2.3.3"
spinning_top = "0.2.5"
static_assertions = "1.1.0"
tock-registers = "0.8.1"
cfg-if = "1.0.0"
git-version = "0.3.5"
log = "0.4.20"
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"
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]
default = ["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();
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);
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>(
file: Arc<F>,
) -> Result<(ElfStream<AnyEndian, FileReader<Arc<F>>>, FileReader<Arc<F>>), Error> {

View File

@ -7,10 +7,13 @@ use alloc::{
sync::{Arc, Weak},
vec::Vec,
};
use kernel_arch::KernelTableManagerImpl;
use kernel_arch::{
task::{TaskContext, UserContextInfo},
KernelTableManagerImpl,
};
use libk_mm::{phys::GlobalPhysicalAllocator, process::ProcessAddressSpace};
use libk_util::{
event::OneTimeEvent,
event::{BoolEvent, OneTimeEvent},
sync::{
spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard},
IrqSafeSpinlock,
@ -23,6 +26,7 @@ use yggdrasil_abi::{
use crate::{
task::{
binary,
futex::UserspaceMutex,
thread::Thread,
types::{AllocateProcessId, ProcessTlsInfo},
@ -62,6 +66,8 @@ pub struct ProcessInner {
mutexes: BTreeMap<usize, Arc<UserspaceMutex>>,
space: Option<Arc<ProcessAddressSpace>>,
image: Option<ProcessImage>,
thread_exits: BTreeMap<ThreadId, Arc<BoolEvent>>,
}
/// Describes a process within the system
@ -106,7 +112,7 @@ impl Process {
// Create "main" thread
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());
@ -123,33 +129,33 @@ impl Process {
/// Spawns a new child thread within the process
pub fn spawn_thread(self: &Arc<Self>, options: &ThreadSpawnOptions) -> Result<ThreadId, Error> {
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!()
// XXX
// let tls_address = if let Some(image) = inner.image.as_ref() {
// proc::elf::clone_tls(&space, image)?
// } else {
// 0
// };
let tls_address = if let Some(image) = inner.image.as_ref() {
binary::elf::clone_tls(&space, image)?
} else {
0
};
// let context = TaskContextImpl::user(
// options.entry as _,
// options.argument as _,
// space.as_address_with_asid(),
// options.stack_top,
// tls_address,
// )?;
// let thread = Thread::new_uthread(self.clone(), space.clone(), context);
// let id = thread.id;
let info = UserContextInfo {
entry: options.entry as _,
argument: options.argument as _,
address_space: space.as_address_with_asid(),
stack_pointer: options.stack_top,
single_step: false,
tls: tls_address,
};
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>>(
@ -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) {
let mut inner = self.inner.write();
@ -399,10 +419,13 @@ impl ProcessInner {
mutexes: BTreeMap::new(),
image,
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);
}

View File

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

View File

@ -25,7 +25,7 @@ pub struct ArmTimer {
}
/// ARM timer tick interval (in some time units?)
pub const TICK_INTERVAL: u64 = 1000000;
pub const TICK_INTERVAL: u64 = 250000;
impl InterruptHandler for ArmTimer {
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 {
/// Constructs an instance of ARM generic timer.
///

View File

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

View File

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

View File

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

View File

@ -219,7 +219,7 @@ impl Device for Pl011 {
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)?;
Ok(())

View File

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

View File

@ -6,12 +6,13 @@ use abi::{
mem::MappingSource,
process::{
ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnOption, SpawnOptions,
ThreadSpawnOptions,
},
};
use alloc::sync::Arc;
use libk::{
block,
task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread},
task::{debug::ThreadDebugger, process::Process, runtime, thread::Thread, ThreadId},
vfs::IoContext,
};
use libk_mm::{
@ -236,3 +237,28 @@ pub(crate) fn start_session() -> Result<(), Error> {
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::{
io::ChannelPublisherId,
process::{ExecveOptions, ProcessId},
process::{ExecveOptions, ProcessId, ThreadSpawnOptions},
SyscallFunction,
};
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 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 exit_signal(frame: &SignalEntryData) -> !;

View File

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