Fix the thread status ordering by limiting the API

This commit is contained in:
Zhang Junyang 2024-09-29 10:29:27 +08:00 committed by Tate, Hongliang Tian
parent 55bf2c847c
commit 1b23182dcc
7 changed files with 58 additions and 47 deletions

View File

@ -71,7 +71,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) ->
let thread = thread_table::get_thread(tid) let thread = thread_table::get_thread(tid)
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?; .ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?;
if thread.status().is_exited() { if thread.is_exited() {
return Ok(()); return Ok(());
} }

View File

@ -14,7 +14,7 @@ use crate::{
/// ///
/// If the thread is not a POSIX thread, this method will panic. /// If the thread is not a POSIX thread, this method will panic.
pub fn do_exit(thread: &Thread, posix_thread: &PosixThread, term_status: TermStatus) -> Result<()> { pub fn do_exit(thread: &Thread, posix_thread: &PosixThread, term_status: TermStatus) -> Result<()> {
if thread.status().is_exited() { if thread.is_exited() {
return Ok(()); return Ok(());
} }
thread.exit(); thread.exit();

View File

@ -277,7 +277,7 @@ impl PosixThread {
let tasks = process.tasks().lock(); let tasks = process.tasks().lock();
tasks tasks
.iter() .iter()
.all(|task| Thread::borrow_from_task(task).status().is_exited()) .all(|task| Thread::borrow_from_task(task).is_exited())
} }
/// Gets the read-only credentials of the thread. /// Gets the read-only credentials of the thread.

View File

@ -31,7 +31,6 @@ use crate::{
get_current_userspace, get_current_userspace,
prelude::*, prelude::*,
process::{do_exit_group, TermStatus}, process::{do_exit_group, TermStatus},
thread::status::ThreadStatus,
}; };
pub trait SignalContext { pub trait SignalContext {
@ -107,20 +106,10 @@ pub fn handle_pending_signal(user_ctx: &mut UserContext, ctx: &Context) -> Resul
} }
SigDefaultAction::Ign => {} SigDefaultAction::Ign => {}
SigDefaultAction::Stop => { SigDefaultAction::Stop => {
let _ = ctx.thread.atomic_status().compare_exchange( let _ = ctx.thread.stop();
ThreadStatus::Running,
ThreadStatus::Stopped,
Ordering::AcqRel,
Ordering::Relaxed,
);
} }
SigDefaultAction::Cont => { SigDefaultAction::Cont => {
let _ = ctx.thread.atomic_status().compare_exchange( let _ = ctx.thread.resume();
ThreadStatus::Stopped,
ThreadStatus::Running,
Ordering::AcqRel,
Ordering::Relaxed,
);
} }
} }
} }

View File

@ -32,7 +32,7 @@ impl KernelThreadExt for Thread {
fn join(&self) { fn join(&self) {
loop { loop {
if self.status().is_exited() { if self.is_exited() {
return; return;
} else { } else {
Thread::yield_now(); Thread::yield_now();

View File

@ -86,27 +86,59 @@ impl Thread {
/// Runs this thread at once. /// Runs this thread at once.
pub fn run(&self) { pub fn run(&self) {
self.set_status(ThreadStatus::Running); self.status.store(ThreadStatus::Running, Ordering::Release);
self.task.upgrade().unwrap().run(); self.task.upgrade().unwrap().run();
} }
/// Returns whether the thread is exited.
pub fn is_exited(&self) -> bool {
self.status.load(Ordering::Acquire).is_exited()
}
/// Returns whether the thread is stopped.
pub fn is_stopped(&self) -> bool {
self.status.load(Ordering::Acquire).is_stopped()
}
/// Stops the thread if it is running.
///
/// If the previous status is not [`ThreadStatus::Running`], this function
/// returns [`Err`] with the previous state. Otherwise, it sets the status
/// to [`ThreadStatus::Stopped`] and returns [`Ok`] with the previous state.
///
/// This function only sets the status to [`ThreadStatus::Stopped`],
/// without initiating a reschedule.
pub fn stop(&self) -> core::result::Result<ThreadStatus, ThreadStatus> {
self.status.compare_exchange(
ThreadStatus::Running,
ThreadStatus::Stopped,
Ordering::AcqRel,
Ordering::Acquire,
)
}
/// Resumes running the thread if it is stopped.
///
/// If the previous status is not [`ThreadStatus::Stopped`], this function
/// returns [`None`]. Otherwise, it sets the status to
/// [`ThreadStatus::Running`] and returns [`Some(())`].
///
/// This function only sets the status to [`ThreadStatus::Running`],
/// without initiating a reschedule.
pub fn resume(&self) -> Option<()> {
self.status
.compare_exchange(
ThreadStatus::Stopped,
ThreadStatus::Running,
Ordering::AcqRel,
Ordering::Acquire,
)
.ok()
.map(|_| ())
}
pub(super) fn exit(&self) { pub(super) fn exit(&self) {
self.set_status(ThreadStatus::Exited); self.status.store(ThreadStatus::Exited, Ordering::Release);
}
/// Returns the reference to the atomic status.
pub fn atomic_status(&self) -> &AtomicThreadStatus {
&self.status
}
/// Returns the current status.
pub fn status(&self) -> ThreadStatus {
self.status.load(Ordering::Acquire)
}
/// Updates the status with the new value.
pub fn set_status(&self, new_status: ThreadStatus) {
self.status.store(new_status, Ordering::Release);
} }
/// Returns the reference to the atomic priority. /// Returns the reference to the atomic priority.
@ -114,16 +146,6 @@ impl Thread {
&self.priority &self.priority
} }
/// Returns the current priority.
pub fn priority(&self) -> Priority {
self.priority.load(Ordering::Relaxed)
}
/// Updates the priority with the new value.
pub fn set_priority(&self, new_priority: Priority) {
self.priority.store(new_priority, Ordering::Relaxed)
}
/// Returns the reference to the atomic CPU affinity. /// Returns the reference to the atomic CPU affinity.
pub fn atomic_cpu_affinity(&self) -> &AtomicCpuSet { pub fn atomic_cpu_affinity(&self) -> &AtomicCpuSet {
&self.cpu_affinity &self.cpu_affinity

View File

@ -71,17 +71,17 @@ pub fn create_new_user_task(user_space: Arc<UserSpace>, thread_ref: Arc<Thread>)
ReturnReason::KernelEvent => {} ReturnReason::KernelEvent => {}
}; };
if current_thread.status().is_exited() { if current_thread.is_exited() {
break; break;
} }
handle_pending_signal(user_ctx, &ctx).unwrap(); handle_pending_signal(user_ctx, &ctx).unwrap();
// If current is suspended, wait for a signal to wake up self // If current is suspended, wait for a signal to wake up self
while current_thread.status().is_stopped() { while current_thread.is_stopped() {
Thread::yield_now(); Thread::yield_now();
debug!("{} is suspended.", current_posix_thread.tid()); debug!("{} is suspended.", current_posix_thread.tid());
handle_pending_signal(user_ctx, &ctx).unwrap(); handle_pending_signal(user_ctx, &ctx).unwrap();
} }
if current_thread.status().is_exited() { if current_thread.is_exited() {
debug!("exit due to signal"); debug!("exit due to signal");
break; break;
} }