Browse Source

添加AlignBox和int_like宏 (#272)

LoGin 1 year ago
parent
commit
bb24249faa
5 changed files with 233 additions and 6 deletions
  1. 4 3
      kernel/src/lib.rs
  2. 114 0
      kernel/src/libs/align.rs
  3. 109 0
      kernel/src/libs/int_like.rs
  4. 5 2
      kernel/src/libs/mod.rs
  5. 1 1
      tools/bootstrap.sh

+ 4 - 3
kernel/src/lib.rs

@@ -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 - 0
kernel/src/libs/align.rs

@@ -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 - 0
kernel/src/libs/int_like.rs

@@ -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>());
+}

+ 5 - 2
kernel/src/libs/mod.rs

@@ -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;

+ 1 - 1
tools/bootstrap.sh

@@ -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..."