forked from DragonOS-Community/DragonOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ida): IDA内部改为使用XArray实现 (DragonOS-Community#934)
目前可以记录哪些ID已经分配,支持了ID释放的功能. Signed-off-by: longjin <[email protected]>
- Loading branch information
1 parent
dd4ce90
commit 0eb0731
Showing
20 changed files
with
273 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# ID分配 | ||
|
||
:::{note} | ||
本文作者:龙进 <[email protected]> | ||
|
||
2024年9月25日 | ||
::: | ||
|
||
内核提供了一个名为`IdAllocator`的ID分配器,位于`kernel/crates/ida`中。 | ||
|
||
它能够分配、释放ID。默认它会自增分配,假如ID大于设定的最大值,它会从最小值开始寻找空闲ID。如果没有空闲的ID,则会分配失败。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,5 @@ | |
lib_ui/scm | ||
lib_ui/textui | ||
unified-init | ||
id-allocation | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ name = "ida" | |
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["longjin <[email protected]>"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
description = "一个基于XArray的ID分配器" | ||
|
||
[dependencies] | ||
kdepends = { path = "../kdepends" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# IDA | ||
|
||
一个基于XArray的ID分配器 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
#![no_std] | ||
#![feature(core_intrinsics)] | ||
#![allow(internal_features)] | ||
#![allow(clippy::needless_return)] | ||
|
||
#[cfg(test)] | ||
#[macro_use] | ||
extern crate std; | ||
|
||
use core::cmp::min; | ||
use core::intrinsics::unlikely; | ||
use core::marker::PhantomData; | ||
use core::ops::Deref; | ||
|
||
struct EmptyIdaItemRef<'a> { | ||
_marker: PhantomData<&'a EmptyIdaItem>, | ||
} | ||
|
||
impl<'a> Deref for EmptyIdaItemRef<'a> { | ||
type Target = EmptyIdaItem; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&EmptyIdaItem | ||
} | ||
} | ||
|
||
struct EmptyIdaItem; | ||
|
||
unsafe impl kdepends::xarray::ItemEntry for EmptyIdaItem { | ||
type Ref<'a> = EmptyIdaItemRef<'a> where Self: 'a; | ||
|
||
fn into_raw(self) -> *const () { | ||
core::ptr::null() | ||
} | ||
|
||
unsafe fn from_raw(_raw: *const ()) -> Self { | ||
EmptyIdaItem | ||
} | ||
|
||
unsafe fn raw_as_ref<'a>(_raw: *const ()) -> Self::Ref<'a> { | ||
EmptyIdaItemRef { | ||
_marker: PhantomData, | ||
} | ||
} | ||
} | ||
/// id分配器 | ||
pub struct IdAllocator { | ||
current_id: usize, | ||
min_id: usize, | ||
max_id: usize, | ||
used: usize, | ||
xarray: kdepends::xarray::XArray<EmptyIdaItem>, | ||
} | ||
|
||
impl IdAllocator { | ||
/// 创建一个新的id分配器 | ||
pub const fn new(initial_id: usize, max_id: usize) -> Option<Self> { | ||
if initial_id >= max_id { | ||
return None; | ||
} | ||
Some(Self { | ||
current_id: initial_id, | ||
min_id: initial_id, | ||
max_id, | ||
used: 0, | ||
xarray: kdepends::xarray::XArray::new(), | ||
}) | ||
} | ||
|
||
/// 可用的id数量 | ||
#[inline] | ||
pub fn available(&self) -> usize { | ||
self.max_id - self.min_id - self.used | ||
} | ||
|
||
/// 分配一个新的id | ||
/// | ||
/// ## 返回 | ||
/// | ||
/// 如果分配成功,返回Some(id),否则返回None | ||
pub fn alloc(&mut self) -> Option<usize> { | ||
if unlikely(self.available() == 0) { | ||
return None; | ||
} | ||
|
||
if let Some(try1) = self.do_find_first_free_index(self.current_id, self.max_id) { | ||
self.current_id = try1; | ||
self.xarray.store(try1 as u64, EmptyIdaItem); | ||
self.used += 1; | ||
return Some(try1); | ||
} | ||
|
||
// 从头开始找 | ||
if let Some(try2) = | ||
self.do_find_first_free_index(self.min_id, min(self.current_id, self.max_id)) | ||
{ | ||
self.current_id = try2; | ||
self.xarray.store(try2 as u64, EmptyIdaItem); | ||
self.used += 1; | ||
return Some(try2); | ||
} | ||
return None; | ||
} | ||
|
||
/// 检查id是否存在 | ||
/// | ||
/// ## 参数 | ||
/// | ||
/// - `id`:要检查的id | ||
/// | ||
/// ## 返回 | ||
/// | ||
/// 如果id存在,返回true,否则返回false | ||
pub fn exists(&self, id: usize) -> bool { | ||
if id < self.min_id || id >= self.max_id { | ||
return false; | ||
} | ||
self.xarray.load(id as u64).is_some() | ||
} | ||
|
||
fn do_find_first_free_index(&self, start_id: usize, end: usize) -> Option<usize> { | ||
(start_id..end).find(|&i| !self.exists(i)) | ||
} | ||
|
||
/// 释放一个id | ||
/// | ||
/// ## 参数 | ||
/// | ||
/// - `id`:要释放的id | ||
pub fn free(&mut self, id: usize) { | ||
if id < self.min_id || id >= self.max_id { | ||
return; | ||
} | ||
if self.xarray.remove(id as u64).is_some() { | ||
self.used -= 1; | ||
} | ||
} | ||
|
||
/// 返回已经使用的id数量 | ||
pub fn used(&self) -> usize { | ||
self.used | ||
} | ||
} | ||
|
||
impl core::fmt::Debug for IdAllocator { | ||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
f.debug_struct("IdAllocator") | ||
.field("current_id", &self.current_id) | ||
.field("min_id", &self.min_id) | ||
.field("max_id", &self.max_id) | ||
.field("used", &self.used) | ||
.field("xarray", &"xarray<()>") | ||
.finish() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
#[test] | ||
fn test_new_fail() { | ||
assert_eq!(IdAllocator::new(10, 10).is_none(), true); | ||
assert_eq!(IdAllocator::new(11, 10).is_none(), true); | ||
} | ||
#[test] | ||
fn test_new_success() { | ||
assert_eq!(IdAllocator::new(9, 10).is_some(), true); | ||
assert_eq!(IdAllocator::new(0, 10).is_some(), true); | ||
} | ||
|
||
#[test] | ||
fn test_id_allocator() { | ||
let mut ida = IdAllocator::new(0, 10).unwrap(); | ||
assert_eq!(ida.alloc(), Some(0)); | ||
assert_eq!(ida.alloc(), Some(1)); | ||
assert_eq!(ida.alloc(), Some(2)); | ||
assert_eq!(ida.alloc(), Some(3)); | ||
assert_eq!(ida.alloc(), Some(4)); | ||
assert_eq!(ida.alloc(), Some(5)); | ||
assert_eq!(ida.alloc(), Some(6)); | ||
assert_eq!(ida.alloc(), Some(7)); | ||
assert_eq!(ida.alloc(), Some(8)); | ||
assert_eq!(ida.alloc(), Some(9)); | ||
assert_eq!(ida.alloc(), None); | ||
|
||
for i in 0..10 { | ||
assert_eq!(ida.exists(i), true); | ||
} | ||
|
||
ida.free(5); | ||
|
||
for i in 0..10 { | ||
if i == 5 { | ||
assert_eq!(ida.exists(i), false); | ||
} else { | ||
assert_eq!(ida.exists(i), true); | ||
} | ||
} | ||
assert_eq!(ida.used(), 9); | ||
assert_eq!(ida.alloc(), Some(5)); | ||
assert_eq!(ida.alloc(), None); | ||
|
||
assert_eq!(ida.used(), 10); | ||
for i in 0..10 { | ||
ida.free(i); | ||
} | ||
|
||
assert_eq!(ida.used(), 0); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ pub extern crate memoffset; | |
pub extern crate ringbuffer; | ||
|
||
pub extern crate crc; | ||
pub extern crate xarray; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.