Skip to content

Commit dabe416

Browse files
authored
Fix: enclose mutex to avoid deadlock in futex (#49)
* fix(futex): remove clone * refactor(futex): enclose mutex to avoid misuse
1 parent 7a964c9 commit dabe416

File tree

4 files changed

+18
-21
lines changed

4 files changed

+18
-21
lines changed

api/src/imp/futex.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub fn sys_futex(
2727
if unsafe { uaddr.get()?.read() } != value {
2828
return Err(LinuxError::EAGAIN);
2929
}
30-
let wq = futex_table.lock().get_or_insert(addr);
30+
let wq = futex_table.get_or_insert(addr);
3131

3232
if let Some(timeout) = timeout.nullable(UserConstPtr::get)? {
3333
wq.wait_timeout(unsafe { *timeout }.into());
@@ -38,7 +38,7 @@ pub fn sys_futex(
3838
Ok(0)
3939
}
4040
FUTEX_WAKE => {
41-
let wq = futex_table.lock().get(addr);
41+
let wq = futex_table.get(addr);
4242
let mut count = 0;
4343
if let Some(wq) = wq {
4444
for _ in 0..value {
@@ -57,12 +57,8 @@ pub fn sys_futex(
5757
}
5858
let value2 = timeout.address().as_usize() as u32;
5959

60-
let mut futex_table = futex_table.lock();
6160
let wq = futex_table.get(addr);
62-
let wq2 = futex_table
63-
.get_or_insert(uaddr2.address().as_usize())
64-
.clone();
65-
drop(futex_table);
61+
let wq2 = futex_table.get_or_insert(uaddr2.address().as_usize());
6662

6763
let mut count = 0;
6864
if let Some(wq) = wq {

api/src/imp/task/exit.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,9 @@ pub fn do_exit(exit_code: i32, group_exit: bool) -> ! {
2020
if let Ok(clear_tid) = clear_child_tid.get() {
2121
unsafe { clear_tid.write(0) };
2222

23-
// Since `guard` (WaitQueueGuard) acquires lock to the futex table on
24-
// drop, we need to ensure that the temporary lock's lifetime is
25-
// encapsulated within `guard`'s scope.
2623
let guard = curr_ext
2724
.process_data()
2825
.futex_table
29-
.lock()
3026
.get(clear_tid as *const _ as usize);
3127
if let Some(futex) = guard {
3228
futex.notify_one(false);

core/src/futex.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@
33
use core::ops::Deref;
44

55
use alloc::{collections::btree_map::BTreeMap, sync::Arc};
6+
use axsync::Mutex;
67
use axtask::{TaskExtRef, WaitQueue, current};
78

89
/// A table mapping memory addresses to futex wait queues.
9-
#[derive(Default)]
10-
pub struct FutexTable(BTreeMap<usize, Arc<WaitQueue>>);
10+
pub struct FutexTable(Mutex<BTreeMap<usize, Arc<WaitQueue>>>);
1111
impl FutexTable {
12+
/// Creates a new `FutexTable`.
13+
pub fn new() -> Self {
14+
Self(Mutex::new(BTreeMap::new()))
15+
}
16+
1217
/// Gets the wait queue associated with the given address.
1318
pub fn get(&self, addr: usize) -> Option<WaitQueueGuard> {
14-
let wq = self.0.get(&addr).cloned()?;
19+
let wq = self.0.lock().get(&addr).cloned()?;
1520
Some(WaitQueueGuard {
1621
key: addr,
1722
inner: wq,
@@ -20,9 +25,9 @@ impl FutexTable {
2025

2126
/// Gets the wait queue associated with the given address, or inserts a a
2227
/// new one if it doesn't exist.
23-
pub fn get_or_insert(&mut self, addr: usize) -> WaitQueueGuard {
24-
let wq = self
25-
.0
28+
pub fn get_or_insert(&self, addr: usize) -> WaitQueueGuard {
29+
let mut table = self.0.lock();
30+
let wq = table
2631
.entry(addr)
2732
.or_insert_with(|| Arc::new(WaitQueue::new()));
2833
WaitQueueGuard {
@@ -47,9 +52,9 @@ impl Deref for WaitQueueGuard {
4752
impl Drop for WaitQueueGuard {
4853
fn drop(&mut self) {
4954
let curr = current();
50-
let mut table = curr.task_ext().process_data().futex_table.lock();
55+
let mut table = curr.task_ext().process_data().futex_table.0.lock();
5156
if Arc::strong_count(&self.inner) == 1 && self.inner.is_empty() {
52-
table.0.remove(&self.key);
57+
table.remove(&self.key);
5358
}
5459
}
5560
}

core/src/task.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ pub struct ProcessData {
209209
pub signal: Arc<ProcessSignalManager<RawMutex, WaitQueueWrapper>>,
210210

211211
/// The futex table.
212-
pub futex_table: Mutex<FutexTable>,
212+
pub futex_table: FutexTable,
213213
}
214214

215215
impl ProcessData {
@@ -235,7 +235,7 @@ impl ProcessData {
235235
axconfig::plat::SIGNAL_TRAMPOLINE,
236236
)),
237237

238-
futex_table: Mutex::default(),
238+
futex_table: FutexTable::new(),
239239
}
240240
}
241241

0 commit comments

Comments
 (0)