proc: add userspace mutex system call

This commit is contained in:
Mark Poliakov 2023-11-24 13:30:26 +02:00
parent 8bc8b30362
commit 307f14678f
5 changed files with 101 additions and 42 deletions

View File

@ -15,7 +15,7 @@ use crate::{
phys,
pointer::{PhysicalRef, PhysicalRefMut},
process::ProcessAddressSpace,
table::{EntryLevel, MapAttributes},
table::MapAttributes,
},
task::process::{ProcessImage, ProcessTlsInfo, ProcessTlsLayout},
};
@ -252,7 +252,7 @@ fn tls_segment(
source.read_exact(dst.deref_mut())
},
data_size,
);
)?;
}
if mem_size > data_size {
@ -264,7 +264,7 @@ fn tls_segment(
Ok(())
},
mem_size - data_size,
);
)?;
}
Ok(tls)
@ -294,8 +294,6 @@ pub fn load_elf_from_file(
PT_TLS => {
assert!(tls.is_none());
tls.replace(tls_segment(space, phdr, &file)?);
// tls_master_address = tls_segment(space, phdr, &file)?;
// tls_size = phdr.p_memsz as usize;
}
_ => (),
}

View File

@ -4,7 +4,7 @@ use core::{mem::MaybeUninit, time::Duration};
use abi::{
error::Error,
io::{DeviceRequest, DirectoryEntry, FileAttr, FileMode, OpenOptions, RawFd, SeekFrom},
process::{ExitCode, Signal, SpawnOption, SpawnOptions, ThreadSpawnOptions},
process::{ExitCode, MutexOperation, Signal, SpawnOption, SpawnOptions, ThreadSpawnOptions},
syscall::SyscallFunction,
};
use alloc::rc::Rc;
@ -365,6 +365,22 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
let id = process.spawn_thread(options)?;
Ok(id.as_user() as _)
}
SyscallFunction::Mutex => {
let address = args[0] as usize;
let op = arg_user_ref::<MutexOperation>(args[1] as usize)?;
let mutex = process.get_or_insert_mutex(address);
match op {
&MutexOperation::Wait(value, _timeout) => {
block! { mutex.wait(value).await }.unwrap()
}
MutexOperation::Wake => mutex.wake(),
MutexOperation::WakeAll => mutex.wake_all(),
}
Ok(0)
}
SyscallFunction::Exit => {
let code = ExitCode::from(args[0] as i32);
// TODO separate handlers for process exit and thread exit?

View File

@ -17,6 +17,7 @@ pub mod context;
pub mod process;
pub mod runtime;
pub mod sched;
pub mod sync;
pub mod thread;
pub use context::{Cpu, TaskContext};

View File

@ -4,7 +4,7 @@ use core::{
fmt,
mem::size_of,
pin::Pin,
sync::atomic::{AtomicU64, Ordering},
sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
task::{Context, Poll},
};
@ -36,6 +36,7 @@ use crate::{
use super::{
runtime::QueueWaker,
sync::UserspaceMutex,
thread::{Thread, ThreadId, ThreadState},
TaskContext,
};
@ -133,6 +134,7 @@ struct ProcessInner {
session_terminal: Option<VnodeRef>,
threads: Vec<Arc<Thread>>,
mutexes: BTreeMap<usize, Arc<UserspaceMutex>>,
}
pub struct Process {
@ -173,6 +175,7 @@ impl Process {
group_id: id,
session_terminal: None,
threads: Vec::new(),
mutexes: BTreeMap::new(),
}),
exit_waker: QueueWaker::new(),
@ -322,47 +325,12 @@ impl Process {
self.exit_waker.wake_all();
}
// // Scheduler still holds a lock of this process?
// // TODO cancel Wait if a process was killed while suspended?
// {
// let inner = self.inner.lock();
// let exit_status = ExitCode::from(inner.exit_status);
// debugln!(
// "Handling exit of #{} with status {:?}",
// self.id(),
// exit_status
// );
//
// // TODO cleanup address space
// // if let Some(space) = self.get_address_space() {
// // }
//
// self.io.lock().handle_exit();
// }
//
// // Notify any waiters we're done
// self.exit_waker.wake_all();
}
/// Raises a signal for the specified process
pub fn raise_signal(self: &Arc<Self>, signal: Signal) {
let thread = self.inner.lock().threads[0].clone();
thread.raise_signal(signal);
// // TODO if the process does not have any running/ready threads, pick one and wake it up
// if inner
// .threads
// .iter()
// .all(|t| t.state.load(Ordering::Acquire) == ThreadState::Suspended)
// {
// let thread = inner.threads[0].clone();
// drop(inner);
// thread.enqueue_somewhere();
// return;
// }
}
/// Raises a signal for the specified process group
@ -378,6 +346,15 @@ impl Process {
}
}
pub fn get_or_insert_mutex(&self, address: usize) -> Arc<UserspaceMutex> {
let mut inner = self.inner.lock();
inner
.mutexes
.entry(address)
.or_insert_with(|| Arc::new(UserspaceMutex::new(address)))
.clone()
}
// Process list
pub fn get(id: ProcessId) -> Option<Arc<Self>> {
PROCESSES.lock().get(&id).cloned()

67
src/task/sync.rs Normal file
View File

@ -0,0 +1,67 @@
use core::{
pin::Pin,
sync::atomic::{AtomicU32, Ordering},
task::{Context, Poll},
};
use alloc::sync::Arc;
use futures_util::Future;
use super::runtime::QueueWaker;
pub struct UserspaceMutex {
queue: QueueWaker,
address: usize,
}
impl UserspaceMutex {
pub fn new(address: usize) -> Self {
Self {
queue: QueueWaker::new(),
address,
}
}
pub fn wait(self: Arc<Self>, compare_value: u32) -> impl Future<Output = ()> {
struct WaitFuture {
mutex: Arc<UserspaceMutex>,
compare_value: u32,
}
impl WaitFuture {
fn load(&self, ordering: Ordering) -> u32 {
let value = unsafe { &*(self.mutex.address as *const AtomicU32) };
value.load(ordering)
}
}
impl Future for WaitFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.mutex.queue.register(cx.waker());
// Test the mutex
if self.load(Ordering::Acquire) != self.compare_value {
self.mutex.queue.remove(cx.waker());
Poll::Ready(())
} else {
Poll::Pending
}
}
}
WaitFuture {
mutex: self,
compare_value,
}
}
pub fn wake(&self) {
self.queue.wake_one();
}
pub fn wake_all(&self) {
self.queue.wake_all();
}
}