starry_core/
futex.rs

1//! Futex implementation.
2
3use core::ops::Deref;
4
5use alloc::{collections::btree_map::BTreeMap, sync::Arc};
6use axsync::Mutex;
7use axtask::{TaskExtRef, WaitQueue, current};
8
9/// A table mapping memory addresses to futex wait queues.
10pub struct FutexTable(Mutex<BTreeMap<usize, Arc<WaitQueue>>>);
11impl FutexTable {
12    /// Creates a new `FutexTable`.
13    pub fn new() -> Self {
14        Self(Mutex::new(BTreeMap::new()))
15    }
16
17    /// Gets the wait queue associated with the given address.
18    pub fn get(&self, addr: usize) -> Option<WaitQueueGuard> {
19        let wq = self.0.lock().get(&addr).cloned()?;
20        Some(WaitQueueGuard {
21            key: addr,
22            inner: wq,
23        })
24    }
25
26    /// Gets the wait queue associated with the given address, or inserts a a
27    /// new one if it doesn't exist.
28    pub fn get_or_insert(&self, addr: usize) -> WaitQueueGuard {
29        let mut table = self.0.lock();
30        let wq = table
31            .entry(addr)
32            .or_insert_with(|| Arc::new(WaitQueue::new()));
33        WaitQueueGuard {
34            key: addr,
35            inner: wq.clone(),
36        }
37    }
38}
39
40#[doc(hidden)]
41pub struct WaitQueueGuard {
42    key: usize,
43    inner: Arc<WaitQueue>,
44}
45impl Deref for WaitQueueGuard {
46    type Target = Arc<WaitQueue>;
47
48    fn deref(&self) -> &Self::Target {
49        &self.inner
50    }
51}
52impl Drop for WaitQueueGuard {
53    fn drop(&mut self) {
54        let curr = current();
55        let mut table = curr.task_ext().process_data().futex_table.0.lock();
56        if Arc::strong_count(&self.inner) == 1 && self.inner.is_empty() {
57            table.remove(&self.key);
58        }
59    }
60}