添加AlignBox和int_like宏 (#272)

This commit is contained in:
LoGin 2023-05-28 23:00:37 +08:00 committed by GitHub
parent ab5c8ca46d
commit bb24249faa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 233 additions and 6 deletions

View File

@ -1,11 +1,12 @@
#![no_std] // <1>
#![no_main] // <1>
#![feature(alloc_error_handler)]
#![feature(const_mut_refs)]
#![feature(core_intrinsics)] // <2>
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#![feature(drain_filter)] // 允许Vec的drain_filter特性
#![feature(c_void_variant)]
#![feature(drain_filter)] // 允许Vec的drain_filter特性
#![feature(panic_info_message)]
#![feature(ptr_internals)]
#![feature(trait_upcasting)]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]

114
kernel/src/libs/align.rs Normal file
View File

@ -0,0 +1,114 @@
#![allow(dead_code)]
//! 这是一个关于对齐的库,提供了一些对齐的宏和函数、结构体
use core::{alloc::GlobalAlloc, fmt::Debug, ptr::Unique};
use crate::{syscall::SystemError, KERNEL_ALLOCATOR};
/// # AlignedBox
///
/// 一个用于分配对齐内存的结构体。分配的内存地址符合`ALIGN`的要求。
/// 如果类型T的对齐要求大于`ALIGN`则采用T的对齐要求。
///
/// ## 说明
///
/// `ALIGN`: 对齐要求必须是2的幂次方,且不为0否则编译时报错
pub struct AlignedBox<T, const ALIGN: usize> {
inner: Unique<T>,
}
impl<T, const ALIGN: usize> AlignedBox<T, ALIGN> {
const LAYOUT: core::alloc::Layout = {
const fn max(a: usize, b: usize) -> usize {
if a > b {
a
} else {
b
}
}
let layout = core::alloc::Layout::from_size_align(
core::mem::size_of::<T>(),
max(ALIGN, core::mem::align_of::<T>()),
);
if let Ok(layout) = layout {
layout
} else {
panic!("Check alignment failed at compile time.")
}
};
/// 分配一个新的内存空间并将其初始化为零。然后返回AlignedBox
///
/// # Errors
///
/// 如果分配失败,则返回`Err(SystemError::ENOMEM)`
#[inline(always)]
pub fn new_zeroed() -> Result<Self, SystemError>
where
T: SafeForZero,
{
let ptr = unsafe { KERNEL_ALLOCATOR.alloc_zeroed(Self::LAYOUT) };
if ptr.is_null() {
return Err(SystemError::ENOMEM);
} else {
return Ok(AlignedBox {
inner: unsafe { Unique::new_unchecked(ptr.cast()) },
});
}
}
}
impl<T, const ALIGN: usize> Debug for AlignedBox<T, ALIGN> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
return write!(
f,
"AlignedBox<{:?}, {:?}>, ptr: {:p}, size: {:}",
core::any::type_name::<T>(),
core::mem::align_of::<T>(),
self.inner.as_ptr(),
core::mem::size_of::<T>()
);
}
}
impl<T, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> {
fn drop(&mut self) {
unsafe {
// 释放 Unique 智能指针所拥有的内存,并调用类型的析构函数以清理资源
core::ptr::drop_in_place(self.inner.as_ptr());
// dealloc memory space
KERNEL_ALLOCATOR.dealloc(self.inner.as_ptr().cast(), Self::LAYOUT);
}
}
}
impl<T, const ALIGN: usize> core::ops::Deref for AlignedBox<T, ALIGN> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner.as_ptr() }
}
}
impl<T, const ALIGN: usize> core::ops::DerefMut for AlignedBox<T, ALIGN> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.inner.as_ptr() }
}
}
impl<T: Clone + SafeForZero, const ALIGN: usize> Clone for AlignedBox<T, ALIGN> {
fn clone(&self) -> Self {
let mut new: AlignedBox<T, ALIGN> =
Self::new_zeroed().unwrap_or_else(|_| alloc::alloc::handle_alloc_error(Self::LAYOUT));
new.clone_from(self);
return new;
}
}
/// 一个用于表明某个类型是安全的用于零初始化的 trait
///
/// 该 trait 用于表明某个类型是安全的用于零初始化的,即该类型的所有位都可以被初始化为 0 而不会出现未定义行为。
pub unsafe trait SafeForZero {}
unsafe impl<const NUM: usize> SafeForZero for [u8; NUM] {}

109
kernel/src/libs/int_like.rs Normal file
View File

@ -0,0 +1,109 @@
//! These code are bring from redox-os, and I think it's a good idea to use it in our project.
//!
//! Helpers used to define types that are backed by integers (typically `usize`),
//! without compromising safety.
//!
//! # Example
//!
//! ```
//! /// Define an opaque type `Pid` backed by a `usize`.
//! int_like!(Pid, usize);
//!
//! const ZERO: Pid = Pid::from(0);
//! ```
//!
//! # Example
//!
//! ```
//! /// Define opaque types `Pid` and `AtomicPid`, backed respectively by a `usize`
//! /// and a `AtomicUsize`.
//!
//! int_like!(Pid, AtomicPid, usize, AtomicUsize);
//!
//! const ZERO: Pid = Pid::from(0);
//! let ATOMIC_PID: AtomicPid = AtomicPid::default();
//! ```
#[macro_export]
macro_rules! int_like {
($new_type_name:ident, $backing_type: ident) => {
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub struct $new_type_name($backing_type);
impl $new_type_name {
#[allow(dead_code)]
pub const fn into(self) -> $backing_type {
self.0
}
#[allow(dead_code)]
pub const fn from(x: $backing_type) -> Self {
$new_type_name(x)
}
}
};
($new_type_name:ident, $new_atomic_type_name: ident, $backing_type:ident, $backing_atomic_type:ident) => {
int_like!($new_type_name, $backing_type);
/// A mutable holder for T that can safely be shared among threads.
/// Runtime equivalent to using `AtomicUsize`, just type-safer.
pub struct $new_atomic_type_name {
container: $backing_atomic_type,
}
impl $new_atomic_type_name {
#[allow(dead_code)]
pub const fn new(x: $new_type_name) -> Self {
$new_atomic_type_name {
container: $backing_atomic_type::new(x.into())
}
}
#[allow(dead_code)]
pub const fn default() -> Self {
Self::new($new_type_name::from(0))
}
#[allow(dead_code)]
pub fn load(&self, order: ::core::sync::atomic::Ordering) -> $new_type_name {
$new_type_name::from(self.container.load(order))
}
#[allow(dead_code)]
pub fn store(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) {
self.container.store(val.into(), order)
}
#[allow(dead_code)]
pub fn swap(&self, val: $new_type_name, order: ::core::sync::atomic::Ordering) -> $new_type_name {
$new_type_name::from(self.container.swap(val.into(), order))
}
#[allow(dead_code)]
pub fn compare_exchange(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> {
match self.container.compare_exchange(current.into(), new.into(), success, failure) {
Ok(result) => Ok($new_type_name::from(result)),
Err(result) => Err($new_type_name::from(result))
}
}
#[allow(dead_code)]
pub fn compare_exchange_weak(&self, current: $new_type_name, new: $new_type_name, success: ::core::sync::atomic::Ordering, failure: ::core::sync::atomic::Ordering) -> ::core::result::Result<$new_type_name, $new_type_name> {
match self.container.compare_exchange_weak(current.into(), new.into(), success, failure) {
Ok(result) => Ok($new_type_name::from(result)),
Err(result) => Err($new_type_name::from(result))
}
}
}
}
}
#[test]
fn test() {
use core::mem::size_of;
use ::core::sync::atomic::AtomicUsize;
// Generate type `usize_like`.
int_like!(UsizeLike, usize);
assert_eq!(size_of::<UsizeLike>(), size_of::<usize>());
// Generate types `usize_like` and `AtomicUsize`.
int_like!(UsizeLike2, AtomicUsizeLike, usize, AtomicUsize);
assert_eq!(size_of::<UsizeLike2>(), size_of::<usize>());
assert_eq!(size_of::<AtomicUsizeLike>(), size_of::<AtomicUsize>());
}

View File

@ -1,6 +1,11 @@
pub mod align;
pub mod atomic;
pub mod casting;
pub mod ffi_convert;
#[macro_use]
pub mod int_like;
pub mod keyboard_parser;
pub mod lazy_init;
pub mod list;
pub mod lockref;
pub mod mutex;
@ -14,6 +19,4 @@ pub mod spinlock;
pub mod vec_cursor;
#[macro_use]
pub mod volatile;
pub mod keyboard_parser;
pub mod lazy_init;
pub mod wait_queue;

View File

@ -43,7 +43,7 @@ install_ubuntu_debian_pkg()
gnupg \
lsb-release \
llvm-dev libclang-dev clang gcc-multilib \
gcc build-essential fdisk dosfstools dnsmasq bridge-utils iptables libssl-dev
gcc build-essential fdisk dosfstools dnsmasq bridge-utils iptables libssl-dev pkg-config
if [ -z "$(which docker)" ] && [ -n ${dockerInstall} ]; then
echo "正在安装docker..."