[libos] Fix deadlock in signal implementions

This commit is contained in:
ClawSeven 2023-12-28 15:15:11 +08:00 committed by volcano
parent e96a1348e5
commit 5d3799fcb8
4 changed files with 16 additions and 24 deletions

@ -42,21 +42,12 @@ pub fn broadcast_interrupts() -> Result<usize> {
return true; return true;
} }
let sig_mask_guard = thread.sig_mask().read().unwrap(); let interested = !*thread.sig_mask().read().unwrap();
let interested = !*sig_mask_guard; // In the nightly-2022-10-22 Rust compiler, this expression holds two nested read locks.
drop(sig_mask_guard); // However, in the stable-2023-12-21 Rust compiler, the expression drops the temporary variables
// (including: read lock guard) after each division code completes.
let thread_pending_sig = thread.sig_queues().read().unwrap().pending() & interested; !((thread.process().sig_queues().read().unwrap().pending() & interested).empty())
if !thread_pending_sig.empty() { || !((thread.sig_queues().read().unwrap().pending() & interested).empty())
return true;
}
let process_pending_sig =
thread.process().sig_queues().read().unwrap().pending() & interested;
if !process_pending_sig.empty() {
return true;
}
false
}; };
let num_signaled_threads = crate::process::table::get_all_threads() let num_signaled_threads = crate::process::table::get_all_threads()

@ -6,9 +6,10 @@ pub fn do_sigpending() -> Result<SigSet> {
let thread = current!(); let thread = current!();
let process = thread.process(); let process = thread.process();
let blocked = *thread.sig_mask().read().unwrap();
let pending = (thread.sig_queues().read().unwrap().pending() let pending = (thread.sig_queues().read().unwrap().pending()
| process.sig_queues().read().unwrap().pending()) | process.sig_queues().read().unwrap().pending())
& *thread.sig_mask().read().unwrap(); & blocked;
Ok(pending) Ok(pending)
} }

@ -125,12 +125,12 @@ fn do_deliver_signal(thread: &ThreadRef, process: &ProcessRef, cpu_context: &mut
let sig_mask = let sig_mask =
*thread.sig_mask().read().unwrap() | *thread.sig_tmp_mask().read().unwrap(); *thread.sig_mask().read().unwrap() | *thread.sig_tmp_mask().read().unwrap();
let signal_opt = process // Don't use `Option` or_else to avoid nested write locks
.sig_queues() let mut signal_opt = process.sig_queues().write().unwrap().dequeue(&sig_mask);
.write() if signal_opt.is_none() {
.unwrap() signal_opt = thread.sig_queues().write().unwrap().dequeue(&sig_mask);
.dequeue(&sig_mask) }
.or_else(|| thread.sig_queues().write().unwrap().dequeue(&sig_mask));
if signal_opt.is_none() { if signal_opt.is_none() {
return; return;
} }

@ -163,8 +163,8 @@ impl Drop for PendingSigWaiter {
} }
fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool { fn has_interest_signal(interest: &SigSet, thread: &ThreadRef, process: &ProcessRef) -> bool {
let pending = (thread.sig_queues().read().unwrap().pending() let pending = (process.sig_queues().read().unwrap().pending()
| process.sig_queues().read().unwrap().pending()) | thread.sig_queues().read().unwrap().pending())
& *interest; & *interest;
!pending.empty() !pending.empty()