use crate::{ context::{self, ContextId}, sync::WaitCondition }; use alloc::{ collections::BTreeMap, sync::Arc }; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::data::IntRegisters; struct Handle { condition: Arc, sysemu: bool } static SYSCALL_BREAKPOINTS: Once>> = Once::new(); fn init_breakpoints() -> RwLock> { RwLock::new(BTreeMap::new()) } fn breakpoints() -> RwLockReadGuard<'static, BTreeMap> { SYSCALL_BREAKPOINTS.call_once(init_breakpoints).read() } fn breakpoints_mut() -> RwLockWriteGuard<'static, BTreeMap> { SYSCALL_BREAKPOINTS.call_once(init_breakpoints).write() } pub fn ptrace_cont(pid: ContextId) { let breakpoints = breakpoints(); if let Some(breakpoint) = breakpoints.get(&pid) { breakpoint.condition.notify(); } } pub fn ptrace_break_syscall(pid: ContextId, sysemu: bool) { // Continue execution of the tracee and therefore also release // locks on breakpoints(). This has to be done before trying a // mutable lock. ptrace_cont(pid); // TODO: reuse WaitConditions? breakpoints_mut().insert(pid, Handle { condition: Arc::new(WaitCondition::new()), sysemu }); } /// Note: Don't call while holding any locks, this will switch contexts pub fn ptrace_syscall_callback() -> Option { // Can't hold any locks when executing wait() let (condition, sysemu) = { let contexts = context::contexts(); let context = contexts.current()?; let context = context.read(); let breakpoints = breakpoints(); let breakpoint = breakpoints.get(&context.id)?; ( Arc::clone(&breakpoint.condition), breakpoint.sysemu ) }; // TODO: How should signals affect the wait? while !condition.wait() {} Some(sysemu) }