diff --git a/src/ptrace.rs b/src/ptrace.rs index 0a62fb422c..6cf59407e3 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -170,6 +170,7 @@ pub fn wait(session: Arc, token: &mut CleanLockToken) -> Result<()> { // Lock the data, to make sure we're reading the final value before going // to sleep. let data = session.data.lock(); + let mut token = token.downgrade(); // Wake up if a breakpoint is already reached or there's an unread event if data.breakpoint.as_ref().map(|b| b.reached).unwrap_or(false) || !data.events.is_empty() { @@ -178,7 +179,7 @@ pub fn wait(session: Arc, token: &mut CleanLockToken) -> Result<()> { // Go to sleep, and drop the lock on our data, which will allow other the // tracer to wake us up. - if session.tracer.wait(data, "ptrace::wait", token) { + if session.tracer.wait(data, "ptrace::wait", &mut token) { // We successfully waited, wake up! break; } @@ -223,10 +224,11 @@ pub fn breakpoint_callback( // Wake up sleeping tracer session.tracer.notify(token); + let mut token = token.downgrade(); if session .tracee - .wait(data, "ptrace::breakpoint_callback", token) + .wait(data, "ptrace::breakpoint_callback", &mut token) { // We successfully waited, wake up! break Some(breakpoint.flags); diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index e9539112d2..29ca8a12ab 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -270,10 +270,11 @@ impl KernelScheme for AcpiScheme { loop { let flag_guard = KSTOP_FLAG.lock(); + let mut token = token.downgrade(); if *flag_guard { break; - } else if !KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop", token) { + } else if !KSTOP_WAITCOND.wait(flag_guard, "waiting for kstop", &mut token) { return Err(Error::new(EINTR)); } } diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs index 8503af2732..217ed20c00 100644 --- a/src/scheme/pipe.rs +++ b/src/scheme/pipe.rs @@ -255,7 +255,7 @@ impl KernelScheme for PipeScheme { loop { let mut vec = pipe.queue.lock(token.token()); - let (vec, mut token) = vec.token_split(); + let (mut vec, mut token) = vec.into_split(); let (s1, s2) = vec.as_slices(); let s1_count = core::cmp::min(user_buf.len(), s1.len()); @@ -279,9 +279,9 @@ impl KernelScheme for PipeScheme { GlobalSchemes::Pipe.scheme_id(), key | WRITE_NOT_READ_BIT, EVENT_WRITE, - token, + token.token(), ); - pipe.write_condition.notify_locked(token); + pipe.write_condition.notify_locked(token.token()); return Ok(bytes_read); } else if user_buf.is_empty() { @@ -292,7 +292,7 @@ impl KernelScheme for PipeScheme { return Ok(0); } else if fcntl_flags & O_NONBLOCK as u32 != 0 { return Err(Error::new(EAGAIN)); - } else if !pipe.read_condition.wait(vec, "PipeRead::read", token) { + } else if !pipe.read_condition.wait(vec, "PipeRead::read", &mut token) { return Err(Error::new(EINTR)); } } @@ -314,7 +314,7 @@ impl KernelScheme for PipeScheme { loop { let mut vec = pipe.queue.lock(token.token()); - let (vec, mut token) = vec.token_split(); + let (mut vec, mut token) = vec.into_split(); if !pipe.reader_is_alive.load(Ordering::Relaxed) { return Err(Error::new(EPIPE)); @@ -343,8 +343,13 @@ impl KernelScheme for PipeScheme { } if bytes_written > 0 { - event::trigger_locked(GlobalSchemes::Pipe.scheme_id(), key, EVENT_READ, token); - pipe.read_condition.notify_locked(token); + event::trigger_locked( + GlobalSchemes::Pipe.scheme_id(), + key, + EVENT_READ, + token.token(), + ); + pipe.read_condition.notify_locked(token.token()); return Ok(bytes_written); } else if user_buf.is_empty() { @@ -353,7 +358,10 @@ impl KernelScheme for PipeScheme { if fcntl_flags & O_NONBLOCK as u32 != 0 { return Err(Error::new(EAGAIN)); - } else if !pipe.write_condition.wait(vec, "PipeWrite::write", token) { + } else if !pipe + .write_condition + .wait(vec, "PipeWrite::write", &mut token) + { return Err(Error::new(EINTR)); } } @@ -392,8 +400,8 @@ impl KernelScheme for PipeScheme { }; loop { - let mut vec = pipe.fd_queue.lock(token.token()); - let (vec, mut token) = vec.token_split(); + let vec = pipe.fd_queue.lock(token.token()); + let (mut vec, mut token) = vec.into_split(); if !pipe.reader_is_alive.load(Ordering::Relaxed) { return Err(Error::new(EPIPE)); @@ -415,13 +423,21 @@ impl KernelScheme for PipeScheme { let fds_written = vec.len() - before_len; if fds_written > 0 { - event::trigger_locked(GlobalSchemes::Pipe.scheme_id(), key, EVENT_READ, token); - pipe.read_condition.notify_locked(token); + event::trigger_locked( + GlobalSchemes::Pipe.scheme_id(), + key, + EVENT_READ, + token.token(), + ); + pipe.read_condition.notify_locked(token.token()); return Ok(fds_written); } - if !pipe.write_condition.wait(vec, "PipeWrite::write", token) { + if !pipe + .write_condition + .wait(vec, "PipeWrite::write", &mut token) + { return Err(Error::new(EINTR)); } } @@ -451,8 +467,8 @@ impl KernelScheme for PipeScheme { } loop { - let mut vec = pipe.fd_queue.lock(token.token()); - let (vec, mut token) = vec.token_split(); + let vec = pipe.fd_queue.lock(token.token()); + let (mut vec, mut token) = vec.into_split(); let fds_available = vec.len(); let max_fds_read = payload.len() / core::mem::size_of::(); @@ -480,16 +496,16 @@ impl KernelScheme for PipeScheme { GlobalSchemes::Pipe.scheme_id(), key | WRITE_NOT_READ_BIT, EVENT_WRITE, - token, + token.token(), ); - pipe.write_condition.notify_locked(token); + pipe.write_condition.notify_locked(token.token()); return Ok(fds_to_read); } if !pipe.writer_is_alive.load(Ordering::SeqCst) { return Ok(0); - } else if !pipe.read_condition.wait(vec, "PipeRead::read", token) { + } else if !pipe.read_condition.wait(vec, "PipeRead::read", &mut token) { return Err(Error::new(EINTR)); } } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index f39d888209..fae4cdaaf9 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -259,7 +259,7 @@ impl UserInner { }; let mut states = self.states.lock(token.token()); - let (states, mut token) = states.token_split(); + let (mut states, mut token) = states.into_split(); match states.get_mut(sqe.tag as usize) { // invalid state None => return Err(Error::new(EBADFD)), diff --git a/src/sync/ordered.rs b/src/sync/ordered.rs index 2855680847..68c5277927 100644 --- a/src/sync/ordered.rs +++ b/src/sync/ordered.rs @@ -286,6 +286,12 @@ impl<'a, L: Level, T: ?Sized + 'a> MutexGuard<'a, L, T> { pub fn token_split(&mut self) -> (&mut T, LockToken<'_, L>) { (&mut self.inner, self.lock_token.token()) } + + /// Split the guard into two parts, the first is the owned content + /// the second a [`LockToken`] that can be used for further locking + pub fn into_split(self) -> (spin::MutexGuard<'a, T>, LockToken<'a, L>) { + (self.inner, self.lock_token) + } } impl<'a, L: Level, T: ?Sized + 'a> core::ops::Deref for MutexGuard<'a, L, T> { diff --git a/src/sync/wait_condition.rs b/src/sync/wait_condition.rs index 3b5abdf305..956cdcbcfd 100644 --- a/src/sync/wait_condition.rs +++ b/src/sync/wait_condition.rs @@ -6,7 +6,7 @@ use alloc::{ }; use crate::{ - context::{self, ContextLock, PreemptGuard}, + context::{self, ContextLock, PreemptGuard, PreemptGuardL1}, sync::{CleanLockToken, LockToken, Mutex, L1, L3}, }; @@ -52,15 +52,22 @@ impl WaitCondition { len } - // Wait until notified. Unlocks guard when blocking is ready. Returns false if resumed by a signal or the notify_signal function - pub fn wait(&self, guard: T, reason: &'static str, token: &mut CleanLockToken) -> bool { + /// Wait until notified. Unlocks guard when blocking is ready. Returns false if resumed by a signal or the notify_signal function. + /// SAFETY: Caller MUST ensure the given token is coming from the guard. There is no compiler check to do it. + pub fn wait<'a, T>( + &self, + guard: T, + reason: &'static str, + token: &'a mut LockToken<'a, L1>, + ) -> bool { let current_context_ref = context::current(); { // Avoid a context switch between blocking ourselves and adding // ourselves to the wait list as otherwise we might miss a wakeup. // We cannot add ourselves to the wait list first as that would lead // to deadlock if we were woken up immediately. - let mut preempt = PreemptGuard::new(¤t_context_ref, token); + let mut token = token.token(); + let mut preempt = PreemptGuardL1::new(¤t_context_ref, &mut token); let token = preempt.token(); { let mut context = current_context_ref.write(token.token()); @@ -79,7 +86,11 @@ impl WaitCondition { drop(guard); } - context::switch(token); + { + // SAFETY: Guaranteed by caller + let token = unsafe { &mut CleanLockToken::new() }; + context::switch(token); + } let mut waited = true; diff --git a/src/sync/wait_queue.rs b/src/sync/wait_queue.rs index 08fd1eae60..e7cffa8b0c 100644 --- a/src/sync/wait_queue.rs +++ b/src/sync/wait_queue.rs @@ -35,10 +35,11 @@ impl WaitQueue { ) -> Result { loop { let mut inner = self.inner.lock(); + let mut token = token.downgrade(); if inner.is_empty() { if block { - if !self.condition.wait(inner, reason, token) { + if !self.condition.wait(inner, reason, &mut token) { return Err(Error::new(EINTR)); } continue;