mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-19 12:36:46 +00:00
Avoid excessive heap allocations in sys_futex
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
5d84ac7775
commit
85d4cdbbb0
@ -11,6 +11,7 @@
|
|||||||
#![feature(btree_extract_if)]
|
#![feature(btree_extract_if)]
|
||||||
#![feature(debug_closure_helpers)]
|
#![feature(debug_closure_helpers)]
|
||||||
#![feature(extend_one)]
|
#![feature(extend_one)]
|
||||||
|
#![feature(extract_if)]
|
||||||
#![feature(fn_traits)]
|
#![feature(fn_traits)]
|
||||||
#![feature(format_args_nl)]
|
#![feature(format_args_nl)]
|
||||||
#![feature(int_roundings)]
|
#![feature(int_roundings)]
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#![expect(dead_code)]
|
|
||||||
|
|
||||||
use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListAtomicLink};
|
|
||||||
use ostd::{
|
use ostd::{
|
||||||
cpu::num_cpus,
|
cpu::num_cpus,
|
||||||
sync::{Waiter, Waker},
|
sync::{Waiter, Waker},
|
||||||
@ -12,7 +9,6 @@ use spin::Once;
|
|||||||
use crate::{prelude::*, process::Pid, time::wait::ManagedTimeout};
|
use crate::{prelude::*, process::Pid, time::wait::ManagedTimeout};
|
||||||
|
|
||||||
type FutexBitSet = u32;
|
type FutexBitSet = u32;
|
||||||
type FutexBucketRef = Arc<Mutex<FutexBucket>>;
|
|
||||||
|
|
||||||
const FUTEX_OP_MASK: u32 = 0x0000_000F;
|
const FUTEX_OP_MASK: u32 = 0x0000_000F;
|
||||||
const FUTEX_FLAGS_MASK: u32 = 0xFFFF_FFF0;
|
const FUTEX_FLAGS_MASK: u32 = 0xFFFF_FFF0;
|
||||||
@ -183,7 +179,7 @@ fn get_bucket_count() -> usize {
|
|||||||
((1 << 8) * num_cpus()).next_power_of_two()
|
((1 << 8) * num_cpus()).next_power_of_two()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_futex_bucket(key: FutexKey) -> (usize, FutexBucketRef) {
|
fn get_futex_bucket(key: FutexKey) -> (usize, &'static SpinLock<FutexBucket>) {
|
||||||
FUTEX_BUCKETS.get().unwrap().get_bucket(key)
|
FUTEX_BUCKETS.get().unwrap().get_bucket(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +189,7 @@ pub fn init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct FutexBucketVec {
|
struct FutexBucketVec {
|
||||||
vec: Vec<FutexBucketRef>,
|
vec: Vec<SpinLock<FutexBucket>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutexBucketVec {
|
impl FutexBucketVec {
|
||||||
@ -202,20 +198,20 @@ impl FutexBucketVec {
|
|||||||
vec: Vec::with_capacity(size),
|
vec: Vec::with_capacity(size),
|
||||||
};
|
};
|
||||||
for _ in 0..size {
|
for _ in 0..size {
|
||||||
let bucket = Arc::new(Mutex::new(FutexBucket::new()));
|
let bucket = SpinLock::new(FutexBucket::new());
|
||||||
buckets.vec.push(bucket);
|
buckets.vec.push(bucket);
|
||||||
}
|
}
|
||||||
buckets
|
buckets
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bucket(&self, key: FutexKey) -> (usize, FutexBucketRef) {
|
pub fn get_bucket(&self, key: FutexKey) -> (usize, &SpinLock<FutexBucket>) {
|
||||||
let index = (self.vec.len() - 1) & {
|
let index = (self.size() - 1) & {
|
||||||
// The addr is the multiples of 4, so we ignore the last 2 bits
|
// The addr is the multiples of 4, so we ignore the last 2 bits
|
||||||
let addr = key.addr() >> 2;
|
let addr = key.addr() >> 2;
|
||||||
// simple hash
|
// simple hash
|
||||||
addr / self.size()
|
addr / self.size()
|
||||||
};
|
};
|
||||||
(index, self.vec[index].clone())
|
(index, &self.vec[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
fn size(&self) -> usize {
|
||||||
@ -224,76 +220,47 @@ impl FutexBucketVec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct FutexBucket {
|
struct FutexBucket {
|
||||||
items: LinkedList<FutexItemAdapter>,
|
items: Vec<FutexItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
intrusive_adapter!(FutexItemAdapter = Box<FutexItem>: FutexItem { link: LinkedListAtomicLink });
|
|
||||||
|
|
||||||
impl FutexBucket {
|
impl FutexBucket {
|
||||||
pub fn new() -> FutexBucket {
|
pub fn new() -> FutexBucket {
|
||||||
FutexBucket {
|
FutexBucket {
|
||||||
items: LinkedList::new(FutexItemAdapter::new()),
|
items: Vec::with_capacity(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_item(&mut self, item: Box<FutexItem>) {
|
pub fn add_item(&mut self, item: FutexItem) {
|
||||||
self.items.push_back(item);
|
self.items.push(item);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_item(&mut self, item: &FutexItem) {
|
|
||||||
let mut item_cursor = self.items.front_mut();
|
|
||||||
while !item_cursor.is_null() {
|
|
||||||
// The item_cursor has been checked not null.
|
|
||||||
let futex_item = item_cursor.get().unwrap();
|
|
||||||
|
|
||||||
if !futex_item.match_up(item) {
|
|
||||||
item_cursor.move_next();
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
let _ = item_cursor.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_and_wake_items(&mut self, key: FutexKey, max_count: usize) -> usize {
|
pub fn remove_and_wake_items(&mut self, key: FutexKey, max_count: usize) -> usize {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut item_cursor = self.items.front_mut();
|
|
||||||
while !item_cursor.is_null() && count < max_count {
|
|
||||||
// The item_cursor has been checked not null.
|
|
||||||
let item = item_cursor.get().unwrap();
|
|
||||||
|
|
||||||
if !item.key.match_up(&key) {
|
self.items.retain(|item| {
|
||||||
item_cursor.move_next();
|
if item.key.match_up(&key) && count < max_count {
|
||||||
continue;
|
if item.wake() {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
});
|
||||||
let item = item_cursor.remove().unwrap();
|
|
||||||
if !item.wake() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
count
|
count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_item_keys(&mut self, key: FutexKey, new_key: FutexKey, max_count: usize) {
|
pub fn update_item_keys(&mut self, key: FutexKey, new_key: FutexKey, max_count: usize) {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut item_cursor = self.items.front_mut();
|
for item in self.items.iter_mut() {
|
||||||
while !item_cursor.is_null() && count < max_count {
|
if item.key.match_up(&key) {
|
||||||
// The item_cursor has been checked not null.
|
item.key = new_key;
|
||||||
let item = item_cursor.get().unwrap();
|
count += 1;
|
||||||
|
}
|
||||||
if !item.key.match_up(&key) {
|
if count >= max_count {
|
||||||
item_cursor.move_next();
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut item = item_cursor.remove().unwrap();
|
|
||||||
item.key = new_key;
|
|
||||||
item_cursor.insert_before(item);
|
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,38 +272,31 @@ impl FutexBucket {
|
|||||||
max_nrequeues: usize,
|
max_nrequeues: usize,
|
||||||
) {
|
) {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut item_cursor = self.items.front_mut();
|
self.items
|
||||||
while !item_cursor.is_null() && count < max_nrequeues {
|
.extract_if(.., |item| {
|
||||||
// The item_cursor has been checked not null.
|
if item.key.match_up(&key) && count < max_nrequeues {
|
||||||
let item = item_cursor.get().unwrap();
|
count += 1;
|
||||||
|
true
|
||||||
if !item.key.match_up(&key) {
|
} else {
|
||||||
item_cursor.move_next();
|
false
|
||||||
continue;
|
}
|
||||||
}
|
})
|
||||||
|
.for_each(|mut extracted| {
|
||||||
let mut item = item_cursor.remove().unwrap();
|
extracted.key = new_key;
|
||||||
item.key = new_key;
|
another.add_item(extracted);
|
||||||
another.add_item(item);
|
});
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FutexItem {
|
struct FutexItem {
|
||||||
key: FutexKey,
|
key: FutexKey,
|
||||||
waker: Arc<Waker>,
|
waker: Arc<Waker>,
|
||||||
link: LinkedListAtomicLink,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutexItem {
|
impl FutexItem {
|
||||||
pub fn create(key: FutexKey) -> (Box<Self>, Waiter) {
|
pub fn create(key: FutexKey) -> (Self, Waiter) {
|
||||||
let (waiter, waker) = Waiter::new_pair();
|
let (waiter, waker) = Waiter::new_pair();
|
||||||
let futex_item = Box::new(FutexItem {
|
let futex_item = FutexItem { key, waker };
|
||||||
key,
|
|
||||||
waker,
|
|
||||||
link: LinkedListAtomicLink::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
(futex_item, waiter)
|
(futex_item, waiter)
|
||||||
}
|
}
|
||||||
@ -345,10 +305,6 @@ impl FutexItem {
|
|||||||
pub fn wake(&self) -> bool {
|
pub fn wake(&self) -> bool {
|
||||||
self.waker.wake_up()
|
self.waker.wake_up()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_up(&self, another: &Self) -> bool {
|
|
||||||
self.key.match_up(&another.key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The addr of a futex, it should be used to mark different futex word
|
// The addr of a futex, it should be used to mark different futex word
|
||||||
@ -376,10 +332,6 @@ impl FutexKey {
|
|||||||
self.addr
|
self.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitset(&self) -> FutexBitSet {
|
|
||||||
self.bitset
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_up(&self, another: &Self) -> bool {
|
pub fn match_up(&self, another: &Self) -> bool {
|
||||||
// TODO: Use hash value to do match_up
|
// TODO: Use hash value to do match_up
|
||||||
self.addr == another.addr && (self.bitset & another.bitset) != 0 && self.pid == another.pid
|
self.addr == another.addr && (self.bitset & another.bitset) != 0 && self.pid == another.pid
|
||||||
|
Reference in New Issue
Block a user