mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 11:53:24 +00:00
Optimize the ThreadStatus
to be lock-free
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
0eaa6e637d
commit
27bcece750
@ -20,7 +20,7 @@ pub fn do_exit_group(term_status: TermStatus) {
|
|||||||
// Exit all threads
|
// Exit all threads
|
||||||
let threads = current.threads().lock().clone();
|
let threads = current.threads().lock().clone();
|
||||||
for thread in threads {
|
for thread in threads {
|
||||||
if thread.is_exited() {
|
if thread.status().is_exited() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>) -> Result<()> {
|
|||||||
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.is_exited() {
|
if thread.status().is_exited() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ impl PosixThread {
|
|||||||
let threads = process.threads().lock();
|
let threads = process.threads().lock();
|
||||||
threads
|
threads
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|thread| !thread.status().lock().is_exited())
|
.filter(|thread| !thread.status().is_exited())
|
||||||
.count()
|
.count()
|
||||||
== 0
|
== 0
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub mod sig_queues;
|
|||||||
mod sig_stack;
|
mod sig_stack;
|
||||||
pub mod signals;
|
pub mod signals;
|
||||||
|
|
||||||
use core::mem;
|
use core::{mem, sync::atomic::Ordering};
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_frame::{cpu::UserContext, task::Task};
|
use aster_frame::{cpu::UserContext, task::Task};
|
||||||
@ -30,7 +30,7 @@ use super::posix_thread::{PosixThread, PosixThreadExt};
|
|||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{do_exit_group, TermStatus},
|
process::{do_exit_group, TermStatus},
|
||||||
thread::Thread,
|
thread::{status::ThreadStatus, Thread},
|
||||||
util::{write_bytes_to_user, write_val_to_user},
|
util::{write_bytes_to_user, write_val_to_user},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,18 +91,20 @@ pub fn handle_pending_signal(
|
|||||||
}
|
}
|
||||||
SigDefaultAction::Ign => {}
|
SigDefaultAction::Ign => {}
|
||||||
SigDefaultAction::Stop => {
|
SigDefaultAction::Stop => {
|
||||||
let mut status = current_thread.status().lock();
|
let _ = current_thread.atomic_status().compare_exchange(
|
||||||
if status.is_running() {
|
ThreadStatus::Running,
|
||||||
status.set_stopped();
|
ThreadStatus::Stopped,
|
||||||
}
|
Ordering::AcqRel,
|
||||||
drop(status);
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
SigDefaultAction::Cont => {
|
SigDefaultAction::Cont => {
|
||||||
let mut status = current_thread.status().lock();
|
let _ = current_thread.atomic_status().compare_exchange(
|
||||||
if status.is_stopped() {
|
ThreadStatus::Stopped,
|
||||||
status.set_running();
|
ThreadStatus::Running,
|
||||||
}
|
Ordering::AcqRel,
|
||||||
drop(status);
|
Ordering::Relaxed,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,11 +56,9 @@ impl KernelThreadExt for Thread {
|
|||||||
|
|
||||||
fn join(&self) {
|
fn join(&self) {
|
||||||
loop {
|
loop {
|
||||||
let status = self.status.lock();
|
if self.status().is_exited() {
|
||||||
if status.is_exited() {
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
drop(status);
|
|
||||||
Thread::yield_now();
|
Thread::yield_now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicU32, Ordering};
|
|||||||
|
|
||||||
use aster_frame::task::Task;
|
use aster_frame::task::Task;
|
||||||
|
|
||||||
use self::status::ThreadStatus;
|
use self::status::{AtomicThreadStatus, ThreadStatus};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub mod exception;
|
pub mod exception;
|
||||||
@ -31,7 +31,7 @@ pub struct Thread {
|
|||||||
data: Box<dyn Send + Sync + Any>,
|
data: Box<dyn Send + Sync + Any>,
|
||||||
|
|
||||||
// mutable part
|
// mutable part
|
||||||
status: Mutex<ThreadStatus>,
|
status: AtomicThreadStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Thread {
|
impl Thread {
|
||||||
@ -46,7 +46,7 @@ impl Thread {
|
|||||||
tid,
|
tid,
|
||||||
task,
|
task,
|
||||||
data: Box::new(data),
|
data: Box::new(data),
|
||||||
status: Mutex::new(status),
|
status: AtomicThreadStatus::new(status),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,25 +67,29 @@ impl Thread {
|
|||||||
|
|
||||||
/// Run this thread at once.
|
/// Run this thread at once.
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
self.status.lock().set_running();
|
self.set_status(ThreadStatus::Running);
|
||||||
self.task.run();
|
self.task.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
let mut status = self.status.lock();
|
self.set_status(ThreadStatus::Exited);
|
||||||
if !status.is_exited() {
|
|
||||||
status.set_exited();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_exited(&self) -> bool {
|
/// Returns the reference to the atomic status.
|
||||||
self.status.lock().is_exited()
|
pub fn atomic_status(&self) -> &AtomicThreadStatus {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn status(&self) -> &Mutex<ThreadStatus> {
|
|
||||||
&self.status
|
&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);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn yield_now() {
|
pub fn yield_now() {
|
||||||
Task::yield_now()
|
Task::yield_now()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,51 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
use core::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
|
use int_to_c_enum::TryFromInt;
|
||||||
|
|
||||||
|
/// A `ThreadStatus` which can be safely shared between threads.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AtomicThreadStatus(AtomicU8);
|
||||||
|
|
||||||
|
impl AtomicThreadStatus {
|
||||||
|
/// Creates a new atomic status.
|
||||||
|
pub fn new(status: ThreadStatus) -> Self {
|
||||||
|
Self(AtomicU8::new(status as u8))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads a value from the atomic status.
|
||||||
|
pub fn load(&self, order: Ordering) -> ThreadStatus {
|
||||||
|
ThreadStatus::try_from(self.0.load(order)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a value into the atomic status.
|
||||||
|
pub fn store(&self, new_status: ThreadStatus, order: Ordering) {
|
||||||
|
self.0.store(new_status as u8, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a value into the atomic status if the current value is the same as the `current` value.
|
||||||
|
pub fn compare_exchange(
|
||||||
|
&self,
|
||||||
|
current: ThreadStatus,
|
||||||
|
new: ThreadStatus,
|
||||||
|
success: Ordering,
|
||||||
|
failure: Ordering,
|
||||||
|
) -> Result<ThreadStatus, ThreadStatus> {
|
||||||
|
self.0
|
||||||
|
.compare_exchange(current as u8, new as u8, success, failure)
|
||||||
|
.map(|val| ThreadStatus::try_from(val).unwrap())
|
||||||
|
.map_err(|val| ThreadStatus::try_from(val).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, TryFromInt)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum ThreadStatus {
|
pub enum ThreadStatus {
|
||||||
Init,
|
Init = 0,
|
||||||
Running,
|
Running = 1,
|
||||||
Exited,
|
Exited = 2,
|
||||||
Stopped,
|
Stopped = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadStatus {
|
impl ThreadStatus {
|
||||||
@ -20,18 +60,4 @@ impl ThreadStatus {
|
|||||||
pub fn is_stopped(&self) -> bool {
|
pub fn is_stopped(&self) -> bool {
|
||||||
*self == ThreadStatus::Stopped
|
*self == ThreadStatus::Stopped
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_running(&mut self) {
|
|
||||||
debug_assert!(!self.is_exited());
|
|
||||||
*self = ThreadStatus::Running;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_stopped(&mut self) {
|
|
||||||
debug_assert!(!self.is_exited());
|
|
||||||
*self = ThreadStatus::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_exited(&mut self) {
|
|
||||||
*self = ThreadStatus::Exited;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -40,16 +40,16 @@ pub fn create_new_user_task(user_space: Arc<UserSpace>, thread_ref: Weak<Thread>
|
|||||||
// handle user event:
|
// handle user event:
|
||||||
handle_user_event(user_event, context);
|
handle_user_event(user_event, context);
|
||||||
// should be do this comparison before handle signal?
|
// should be do this comparison before handle signal?
|
||||||
if current_thread.status().lock().is_exited() {
|
if current_thread.status().is_exited() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
handle_pending_signal(context, ¤t_thread).unwrap();
|
handle_pending_signal(context, ¤t_thread).unwrap();
|
||||||
if current_thread.status().lock().is_exited() {
|
if current_thread.status().is_exited() {
|
||||||
debug!("exit due to signal");
|
debug!("exit due to signal");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 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().lock().is_stopped() {
|
while current_thread.status().is_stopped() {
|
||||||
Thread::yield_now();
|
Thread::yield_now();
|
||||||
debug!("{} is suspended.", current_thread.tid());
|
debug!("{} is suspended.", current_thread.tid());
|
||||||
handle_pending_signal(context, ¤t_thread).unwrap();
|
handle_pending_signal(context, ¤t_thread).unwrap();
|
||||||
|
Reference in New Issue
Block a user