kernel: futex 64-shard hash table (Phase 0c, plan order #1)

Re-apply P6-futex-sharding.patch from local/patches/kernel/ to the local
fork. Replaces the single global Mutex<L1, FutexList> with a 64-shard
hash table to eliminate contention between futex operations on
different addresses (different cores no longer serialize on one lock).

src/syscall/futex.rs: static FUTEXES changes from a single
Mutex<L1, FutexList> to a [Mutex<L1, Shard>; 64] array indexed by
hash of the physical address.

This is the foundation patch for Phase 1 (Futex Completeness).
All later futex work (REQUEUE, PI, robust, WAKE_OP) depends on the
sharding being present.

The Cargo.lock diff is the expected dep resolution update.

Multi-threading plan Phase 0c, plan order #1 (P6-futex-sharding).
This commit is contained in:
2026-07-02 06:26:24 +03:00
parent 9bc1fbfe46
commit ed3f0e1e64
2 changed files with 14 additions and 5 deletions
Generated
+4 -1
View File
@@ -202,7 +202,6 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
[[package]]
name = "redox_syscall"
version = "0.8.1"
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#79cb6d9057642be31623677458a93aa88145864f"
dependencies = [
"bitflags 2.11.1",
]
@@ -418,3 +417,7 @@ dependencies = [
"quote",
"syn",
]
[[patch.unused]]
name = "libredox"
version = "0.1.17"
+10 -4
View File
@@ -49,8 +49,13 @@ pub struct FutexEntry {
// implement that fully in userspace. Although futex is probably the best API for process-shared
// POSIX synchronization primitives, a local hash table and wait-for-thread kernel APIs (e.g.
// lwp_park/lwp_unpark from NetBSD) could be a simpler replacement.
static FUTEXES: Mutex<L1, FutexList> =
Mutex::new(FutexList::with_hasher(DefaultHashBuilder::new()));
const FUTEX_SHARDS: usize = 64;
fn futex_shard(phys: PhysicalAddress) -> usize {
(phys.data() as usize >> 12) % FUTEX_SHARDS
}
static FUTEXES: [Mutex<L1, FutexList>; FUTEX_SHARDS] = [const { Mutex::new(FutexList::with_hasher(DefaultHashBuilder::new())) }; FUTEX_SHARDS];
fn validate_and_translate_virt(space: &AddrSpace, addr: VirtualAddress) -> Option<PhysicalAddress> {
// TODO: Move this elsewhere!
@@ -97,7 +102,7 @@ pub fn futex(
{
// TODO: Lock ordering violation
let mut token = unsafe { CleanLockToken::new() };
let mut futexes = FUTEXES.lock(token.token());
let mut futexes = FUTEXES[futex_shard(target_physaddr)].lock(token.token());
let (futexes, mut token) = futexes.token_split();
let (fetched, expected) = if op == FUTEX_WAIT {
@@ -181,10 +186,11 @@ pub fn futex(
}
FUTEX_WAKE => {
let mut woken = 0;
let shard = futex_shard(target_physaddr);
{
drop(addr_space_guard);
let mut futexes_map = FUTEXES.lock(token.token());
let mut futexes_map = FUTEXES[shard].lock(token.token());
let (futexes_map, mut token) = futexes_map.token_split();
let is_empty = if let Some(futexes) = futexes_map.get_mut(&target_physaddr) {