diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index 58a86ce4..03ddb7ec 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -12,14 +12,14 @@ jobs: name: Format check ${{ matrix.arch }} runs-on: ubuntu-latest continue-on-error: true - container: dragonos/dragonos-dev:v1.3 + container: dragonos/dragonos-dev:v1.4 strategy: matrix: arch: [x86_64, riscv64] steps: - - run: echo "Running in dragonos/dragonos-dev:v1.3" + - run: echo "Running in dragonos/dragonos-dev:v1.4" - uses: actions/checkout@v3 - name: Format check @@ -35,14 +35,14 @@ jobs: name: Kernel static test ${{ matrix.arch }} runs-on: ubuntu-latest continue-on-error: true - container: dragonos/dragonos-dev:v1.3 + container: dragonos/dragonos-dev:v1.4 strategy: matrix: arch: [x86_64, riscv64] steps: - - run: echo "Running in dragonos/dragonos-dev:v1.3" + - run: echo "Running in dragonos/dragonos-dev:v1.4" - uses: actions/checkout@v3 @@ -56,10 +56,10 @@ jobs: build-x86_64: runs-on: ubuntu-latest - container: dragonos/dragonos-dev:v1.3 + container: dragonos/dragonos-dev:v1.4 steps: - - run: echo "Running in dragonos/dragonos-dev:v1.3" + - run: echo "Running in dragonos/dragonos-dev:v1.4" - uses: actions/checkout@v3 - name: build the DragonOS @@ -78,10 +78,10 @@ jobs: build-riscv64: runs-on: ubuntu-latest - container: dragonos/dragonos-dev:v1.3 + container: dragonos/dragonos-dev:v1.4 steps: - - run: echo "Running in dragonos/dragonos-dev:v1.3" + - run: echo "Running in dragonos/dragonos-dev:v1.4" - uses: actions/checkout@v3 with: diff --git a/docs/kernel/boot/cmdline.md b/docs/kernel/boot/cmdline.md new file mode 100644 index 00000000..16b42614 --- /dev/null +++ b/docs/kernel/boot/cmdline.md @@ -0,0 +1,109 @@ +# 内核启动命令行参数 + +:::{note} +本文作者: +- 龙进 +::: + +## 概述 + +  DragonOS内核启动命令行参数解析模块旨在提供类似Linux的内核启动命令行参数解析支持,以便更灵活地让内核执行不同的行为。该模块允许内核在启动时接收并解析命令行参数,根据参数的不同类型执行相应的回调函数或设置环境变量。 + +:::{note} +暂时不支持设置回调函数 +::: + +## 设计方案 + + +### 参数类型 + +内核启动命令行参数分为三种类型: + +- Arg类型 +- KV类型 +- EarlyKV类型 + +#### Arg类型 + +Arg类型的参数在命令行中只有名称,没有值。分为以下两种类型: + +- ArgNormal:默认值为`false`,如果命令行中包含这个参数,则会设置为`true`。 +- ArgInv:默认值为`true`,如果命令行中包含这个参数,则会设置为`false`。 + +#### KV类型 + +KV类型的参数在命令行中表现为`name=value`,`value`按照逗号分隔。内核模块可提供参数的默认值。 + +#### EarlyKV类型 + +EarlyKV类型的参数与KV类型类似,但它们在内存管理初始化之前被解析。 + +### Module标志 + +Module标志类似于`usbprobe.xxxx`。 + +### 参数声明 +提供宏来声明内核命令行参数。 +### procfs支持 + +:::{note} +TODO: 在`/proc/cmdline`下显示当前内核的启动命令行参数。 +::: + +## 声明内核启动命令行参数的宏 + +### Arg类型参数声明 +```rust +kernel_cmdline_param_arg!(varname, name, default_bool, inv); +``` +- `varname`:参数的变量名 +- `name`:参数的名称 +- `default_bool`:默认值 +- `inv`:是否反转 + +### KV类型参数声明 + +```rust +kernel_cmdline_param_kv!(varname, name, default_str); +``` + +- `varname`:参数的变量名 +- `name`:参数的名称 +- `default_str`:默认值 + +### 内存管理初始化之前的KV类型参数声明 + +```rust +kernel_cmdline_param_early_kv!(varname, name, default_str); +``` + +- `varname`:参数的变量名 +- `name`:参数的名称 +- `default_str`:默认值 + +## 示例 + +以下示例展示了如何声明和使用KV类型参数: +```rust +kernel_cmdline_param_kv!(ROOTFS_PATH_PARAM, root, ""); +if let Some(rootfs_dev_path) = ROOTFS_PATH_PARAM.value_str() { + ....... +} else { + ....... +}; +``` + +### 使用方式 + +1. 在内核代码中,使用`kernel_cmdline_param_kv!`宏声明所需的KV类型参数。 +2. 在内核初始化过程中,通过参数的`value_str()`或者`value_bool()`方法获取参数值。 +3. 根据参数值执行相应的操作。 + +通过以上步骤,开发者可以灵活地使用内核启动命令行参数来控制内核行为。 + + +## TODO + +- 支持在`/proc/cmdline`下显示当前内核的启动命令行参数。(需要在procfs重构后) +- 支持设置回调函数,调用回调函数来设置参数值 diff --git a/docs/kernel/boot/index.rst b/docs/kernel/boot/index.rst index 006564bf..25d6b66e 100644 --- a/docs/kernel/boot/index.rst +++ b/docs/kernel/boot/index.rst @@ -1,10 +1,9 @@ 引导加载 ==================================== - - DragonOS采用GRUB2作为其引导加载程序,支持Multiboot2协议引导。目前仅支持GRUB2.06版本。 .. toctree:: :maxdepth: 1 :caption: 目录 bootloader + cmdline diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 3156e114..18781dbd 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -41,6 +41,7 @@ fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev hashbrown = "=0.13.2" ida = { path = "crates/ida" } intertrait = { path = "crates/intertrait" } +kcmdline_macros = { path = "crates/kcmdline_macros" } kdepends = { path = "crates/kdepends" } klog_types = { path = "crates/klog_types" } linkme = "=0.3.27" diff --git a/kernel/crates/kcmdline_macros/Cargo.toml b/kernel/crates/kcmdline_macros/Cargo.toml new file mode 100644 index 00000000..e39f16b6 --- /dev/null +++ b/kernel/crates/kcmdline_macros/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "kcmdline_macros" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/kernel/crates/kcmdline_macros/src/lib.rs b/kernel/crates/kcmdline_macros/src/lib.rs new file mode 100644 index 00000000..ff4fe32c --- /dev/null +++ b/kernel/crates/kcmdline_macros/src/lib.rs @@ -0,0 +1,74 @@ +#![no_std] +#![deny(clippy::all)] +#![allow(clippy::crate_in_macro_def)] + +/// 定义一个bool类型的参数 +/// +/// # 参数 +/// +/// - `$varname`: 参数的变量名 +/// - `$name`: 参数的名称 +/// - `$default_bool`: 默认值 +/// - `$inv`: 是否反转 +#[macro_export] +macro_rules! kernel_cmdline_param_arg { + ($varname:ident, $name:ident, $default_bool:expr, $inv:expr) => { + #[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_ARG)] + static $varname: crate::init::cmdline::KernelCmdlineParameter = + crate::init::cmdline::KernelCmdlineParamBuilder::new( + stringify!($name), + crate::init::cmdline::KCmdlineParamType::Arg, + ) + .default_bool($default_bool) + .inv($inv) + .build() + .unwrap(); + }; +} + +/// 定义一个key-value类型的参数 +/// +/// # 参数 +/// - `$varname`: 参数的变量名 +/// - `$name`: 参数的名称 +/// - `$default_str`: 默认值 +#[macro_export] +macro_rules! kernel_cmdline_param_kv { + ($varname:ident, $name:ident, $default_str:expr) => { + #[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_KV)] + static $varname: crate::init::cmdline::KernelCmdlineParameter = + crate::init::cmdline::KernelCmdlineParamBuilder::new( + stringify!($name), + crate::init::cmdline::KCmdlineParamType::KV, + ) + .default_str($default_str) + .build() + .unwrap(); + }; +} + +/// 定义一个内存管理初始化之前就要设置的key-value类型的参数 +/// +/// # 参数 +/// - `$varname`: 参数的变量名 +/// - `$name`: 参数的名称 +/// - `$default_str`: 默认值 +#[macro_export] +macro_rules! kernel_cmdline_param_early_kv { + ($varname:ident, $name:ident, $default_str:expr) => { + #[::linkme::distributed_slice(crate::init::cmdline::KCMDLINE_PARAM_EARLY_KV)] + static $varname: crate::init::cmdline::KernelCmdlineParameter = { + static ___KV: crate::init::cmdline::KernelCmdlineEarlyKV = { + const { assert!($default_str.len() < KernelCmdlineEarlyKV::VALUE_MAX_LEN) }; + crate::init::cmdline::KernelCmdlineParamBuilder::new( + stringify!($name), + crate::init::cmdline::KCmdlineParamType::EarlyKV, + ) + .default_str($default_str) + .build_early_kv() + .unwrap() + }; + crate::init::cmdline::KernelCmdlineParameter::EarlyKV(&___KV) + }; + }; +} diff --git a/kernel/crates/rust-slabmalloc/src/lib.rs b/kernel/crates/rust-slabmalloc/src/lib.rs index 819fc854..5b995fd9 100644 --- a/kernel/crates/rust-slabmalloc/src/lib.rs +++ b/kernel/crates/rust-slabmalloc/src/lib.rs @@ -65,7 +65,12 @@ pub enum AllocationError { /// Needs to adhere to safety requirements of a rust allocator (see GlobalAlloc et. al.). pub unsafe trait Allocator<'a> { fn allocate(&mut self, layout: Layout) -> Result, AllocationError>; - fn deallocate(&mut self, ptr: NonNull, layout: Layout) -> Result<(), AllocationError>; + unsafe fn deallocate( + &mut self, + ptr: NonNull, + layout: Layout, + slab_callback: &'static dyn CallBack, + ) -> Result<(), AllocationError>; /// Refill the allocator with a [`ObjectPage`]. /// @@ -77,3 +82,8 @@ pub unsafe trait Allocator<'a> { new_page: &'a mut ObjectPage<'a>, ) -> Result<(), AllocationError>; } + +/// 将slab_page归还Buddy的回调函数 +pub trait CallBack: Send + Sync { + unsafe fn free_slab_page(&self, _: *mut u8, _: usize) {} +} diff --git a/kernel/crates/rust-slabmalloc/src/pages.rs b/kernel/crates/rust-slabmalloc/src/pages.rs index 6d2f6516..1e92eb7e 100644 --- a/kernel/crates/rust-slabmalloc/src/pages.rs +++ b/kernel/crates/rust-slabmalloc/src/pages.rs @@ -255,6 +255,20 @@ pub trait AllocablePage { self.bitfield().clear_bit(idx); Ok(()) } + + /// 统计page中还可以分配多少个object + fn free_obj_count(&self) -> usize { + // 统计page中还可以分配多少个object + let mut free_obj_count = 0; + + // 遍历page中的bitfield(用来统计内存分配情况的u64数组) + for b in self.bitfield().iter() { + let bitval = b.load(Ordering::Relaxed); + free_obj_count += bitval.count_zeros() as usize; + } + + free_obj_count + } } /// Holds allocated data within a 4 KiB page. diff --git a/kernel/crates/rust-slabmalloc/src/sc.rs b/kernel/crates/rust-slabmalloc/src/sc.rs index fd34eada..a17f5770 100644 --- a/kernel/crates/rust-slabmalloc/src/sc.rs +++ b/kernel/crates/rust-slabmalloc/src/sc.rs @@ -59,21 +59,29 @@ pub struct SCAllocator<'a, P: AllocablePage> { pub(crate) slabs: PageList<'a, P>, /// List of full ObjectPages (everything allocated in these don't need to search them). pub(crate) full_slabs: PageList<'a, P>, + /// Free objects count + pub(crate) free_obj_count: usize, + /// Maximum free objects num for this `SCAllocator`. + pub(crate) free_limit: usize, } /// Creates an instance of a scallocator, we do this in a macro because we /// re-use the code in const and non-const functions macro_rules! new_sc_allocator { - ($size:expr) => { + ($size:expr) => {{ + let obj_per_page = cmin((P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD) / $size, 8 * 64); SCAllocator { size: $size, allocation_count: 0, - obj_per_page: cmin((P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD) / $size, 8 * 64), + obj_per_page, empty_slabs: PageList::new(), slabs: PageList::new(), full_slabs: PageList::new(), + // TODO: 优化free_limit的计算: https://bbs.dragonos.org.cn/t/topic/358 + free_limit: 2 * obj_per_page, + free_obj_count: 0, } - }; + }}; } impl<'a, P: AllocablePage> SCAllocator<'a, P> { @@ -241,6 +249,7 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> { *page.next() = Rawlink::none(); trace!("adding page to SCAllocator {:p}", page); self.insert_empty(page); + self.free_obj_count += self.obj_per_page; } /// Allocates a block of memory descriped by `layout`. @@ -294,6 +303,7 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> { self.size, ptr as usize ); + self.free_obj_count -= 1; } res @@ -304,7 +314,12 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> { /// May return an error in case an invalid `layout` is provided. /// The function may also move internal slab pages between lists partial -> empty /// or full -> partial lists. - pub fn deallocate(&self, ptr: NonNull, layout: Layout) -> Result<(), AllocationError> { + pub unsafe fn deallocate( + &mut self, + ptr: NonNull, + layout: Layout, + slab_callback: &'static dyn CallBack, + ) -> Result<(), AllocationError> { assert!(layout.size() <= self.size); assert!(self.size <= (P::SIZE - OBJECT_PAGE_METADATA_OVERHEAD)); trace!( @@ -324,6 +339,17 @@ impl<'a, P: AllocablePage> SCAllocator<'a, P> { let ret = slab_page.deallocate(ptr, new_layout); debug_assert!(ret.is_ok(), "Slab page deallocate won't fail at the moment"); + self.free_obj_count += 1; + let is_empty_after_dealloc = slab_page.is_empty(self.obj_per_page); + + // 如果slab_page是空白的,且空闲块数大于free_limit,将slab_page归还buddy + if self.free_obj_count >= self.free_limit && is_empty_after_dealloc { + self.slabs.remove_from_list(slab_page); + // 将slab_page归还buddy + slab_callback.free_slab_page(slab_page as *const P as *mut u8, P::SIZE); + } + self.check_page_assignments(); + ret } } diff --git a/kernel/crates/rust-slabmalloc/src/zone.rs b/kernel/crates/rust-slabmalloc/src/zone.rs index 118d45c0..3e6d7cad 100644 --- a/kernel/crates/rust-slabmalloc/src/zone.rs +++ b/kernel/crates/rust-slabmalloc/src/zone.rs @@ -3,7 +3,6 @@ //! The ZoneAllocator achieves this by having many `SCAllocator` use crate::*; -use core::sync::atomic::Ordering; /// Creates an instance of a zone, we do this in a macro because we /// re-use the code in const and non-const functions @@ -139,16 +138,8 @@ impl<'a> ZoneAllocator<'a> { // 遍历scallocator中的部分分配的page(partial_page) for slab_page in scallocator.slabs.iter_mut() { - // 统计page中还可以分配多少个object - let mut free_obj_count = 0; - // 遍历page中的bitfield(用来统计内存分配情况的u64数组) - for b in slab_page.bitfield().iter() { - let bitval = b.load(Ordering::Relaxed); - let free_count = bitval.count_zeros() as usize; - free_obj_count += free_count; - } // 剩余可分配object数乘上page中规定的每个object的大小,即空闲空间 - free += free_obj_count * scallocator.size(); + free += slab_page.free_obj_count() * scallocator.size(); } // 遍历scallocator中的empty_page,把空页空间也加上去 free += @@ -178,9 +169,15 @@ unsafe impl<'a> crate::Allocator<'a> for ZoneAllocator<'a> { /// # Arguments /// * `ptr` - Address of the memory location to free. /// * `layout` - Memory layout of the block pointed to by `ptr`. - fn deallocate(&mut self, ptr: NonNull, layout: Layout) -> Result<(), AllocationError> { + /// * `slab_callback` - The callback function to free slab_page in buddy. + unsafe fn deallocate( + &mut self, + ptr: NonNull, + layout: Layout, + slab_callback: &'static dyn CallBack, + ) -> Result<(), AllocationError> { match ZoneAllocator::get_slab(layout.size()) { - Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout), + Slab::Base(idx) => self.small_slabs[idx].deallocate(ptr, layout, slab_callback), Slab::Unsupported => Err(AllocationError::InvalidLayout), } } diff --git a/kernel/src/arch/x86_64/syscall/mod.rs b/kernel/src/arch/x86_64/syscall/mod.rs index e977d0b8..d9468df6 100644 --- a/kernel/src/arch/x86_64/syscall/mod.rs +++ b/kernel/src/arch/x86_64/syscall/mod.rs @@ -133,7 +133,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) { show &= false; } } - show = false; + show &= false; if show { debug!("[SYS] [Pid: {:?}] [Call: {:?}]", pid, to_print); } diff --git a/kernel/src/driver/net/mod.rs b/kernel/src/driver/net/mod.rs index a685603e..bf57a885 100644 --- a/kernel/src/driver/net/mod.rs +++ b/kernel/src/driver/net/mod.rs @@ -241,24 +241,27 @@ impl IfaceCommon { self.poll_at_ms.store(0, Ordering::Relaxed); } - if has_events { - // log::debug!("IfaceCommon::poll: has_events"); - // We never try to hold the write lock in the IRQ context, and we disable IRQ when - // holding the write lock. So we don't need to disable IRQ when holding the read lock. - self.bounds.read().iter().for_each(|bound_socket| { - bound_socket.on_iface_events(); + // if has_events { + + // log::debug!("IfaceCommon::poll: has_events"); + // We never try to hold the write lock in the IRQ context, and we disable IRQ when + // holding the write lock. So we don't need to disable IRQ when holding the read lock. + self.bounds.read().iter().for_each(|bound_socket| { + bound_socket.on_iface_events(); + if has_events { bound_socket .wait_queue() .wakeup(Some(ProcessState::Blocked(true))); - }); + } + }); - // let closed_sockets = self - // .closing_sockets - // .lock_irq_disabled() - // .extract_if(|closing_socket| closing_socket.is_closed()) - // .collect::>(); - // drop(closed_sockets); - } + // let closed_sockets = self + // .closing_sockets + // .lock_irq_disabled() + // .extract_if(|closing_socket| closing_socket.is_closed()) + // .collect::>(); + // drop(closed_sockets); + // } } pub fn update_ip_addrs(&self, ip_addrs: &[smoltcp::wire::IpCidr]) -> Result<(), SystemError> { diff --git a/kernel/src/driver/net/virtio_net.rs b/kernel/src/driver/net/virtio_net.rs index db530fd8..477dc1cf 100644 --- a/kernel/src/driver/net/virtio_net.rs +++ b/kernel/src/driver/net/virtio_net.rs @@ -257,7 +257,7 @@ impl Device for VirtIONetDevice { impl VirtIODevice for VirtIONetDevice { fn handle_irq(&self, _irq: IrqNumber) -> Result { - log::warn!("VirtioInterface: poll_ifaces_try_lock_onetime -> poll_ifaces"); + // log::warn!("VirtioInterface: poll_ifaces_try_lock_onetime -> poll_ifaces"); poll_ifaces(); return Ok(IrqReturn::Handled); } diff --git a/kernel/src/driver/serial/serial8250/serial8250_pio.rs b/kernel/src/driver/serial/serial8250/serial8250_pio.rs index 0c346369..f5cba86f 100644 --- a/kernel/src/driver/serial/serial8250/serial8250_pio.rs +++ b/kernel/src/driver/serial/serial8250/serial8250_pio.rs @@ -19,12 +19,14 @@ use crate::{ }, serial::{AtomicBaudRate, BaudRate, DivisorFraction, UartPort}, tty::{ + console::ConsoleSwitch, kthread::send_to_tty_refresh_thread, termios::WindowSize, tty_core::{TtyCore, TtyCoreData}, tty_driver::{TtyDriver, TtyDriverManager, TtyOperation}, - virtual_terminal::{vc_manager, VirtConsole}, + virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, VirtConsole}, }, + video::console::dummycon::dummy_console, }, exception::{ irqdata::IrqHandlerData, @@ -32,7 +34,7 @@ use crate::{ manage::irq_manager, IrqNumber, }, - libs::rwlock::RwLock, + libs::{rwlock::RwLock, spinlock::SpinLock}, }; use system_error::SystemError; @@ -265,9 +267,20 @@ impl UartPort for Serial8250PIOPort { } fn handle_irq(&self) -> Result<(), SystemError> { - if let Some(c) = self.read_one_byte() { - send_to_tty_refresh_thread(&[c]); + let mut buf = [0; 8]; + let mut index = 0; + + // Read up to the size of the buffer + while index < buf.len() { + if let Some(c) = self.read_one_byte() { + buf[index] = c; + index += 1; + } else { + break; // No more bytes to read + } } + + send_to_tty_refresh_thread(&buf[0..index]); Ok(()) } @@ -385,7 +398,18 @@ impl TtyOperation for Serial8250PIOTtyDriverInner { if tty.core().index() >= unsafe { PIO_PORTS.len() } { return Err(SystemError::ENODEV); } - let vc = VirtConsole::new(None); + + *tty.core().window_size_write() = WindowSize::DEFAULT; + let vc_data = Arc::new(SpinLock::new(VirtualConsoleData::new(usize::MAX))); + let mut vc_data_guard = vc_data.lock_irqsave(); + vc_data_guard.set_driver_funcs(Arc::downgrade(&dummy_console()) as Weak); + vc_data_guard.init( + Some(tty.core().window_size().row.into()), + Some(tty.core().window_size().col.into()), + true, + ); + drop(vc_data_guard); + let vc = VirtConsole::new(Some(vc_data)); let vc_index = vc_manager().alloc(vc.clone()).ok_or(SystemError::EBUSY)?; self.do_install(driver, tty, vc.clone()).inspect_err(|_| { vc_manager().free(vc_index); diff --git a/kernel/src/driver/tty/sysfs.rs b/kernel/src/driver/tty/sysfs.rs index 12d3a660..b731ab04 100644 --- a/kernel/src/driver/tty/sysfs.rs +++ b/kernel/src/driver/tty/sysfs.rs @@ -12,7 +12,6 @@ use crate::{ kobject::KObject, subsys::SubSysPrivate, }, - filesystem::sysfs::AttributeGroup, init::initcall::INITCALL_SUBSYS, }; @@ -62,7 +61,6 @@ impl Class for TtyClass { fn subsystem(&self) -> &SubSysPrivate { return &self.subsystem; } - } /// 初始化帧缓冲区子系统 diff --git a/kernel/src/driver/tty/termios.rs b/kernel/src/driver/tty/termios.rs index b219d203..0a0ca4bb 100644 --- a/kernel/src/driver/tty/termios.rs +++ b/kernel/src/driver/tty/termios.rs @@ -2,7 +2,7 @@ use super::tty_ldisc::LineDisciplineType; /// ## 窗口大小 #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct WindowSize { /// 行 pub row: u16, @@ -26,12 +26,6 @@ impl WindowSize { } } -impl Default for WindowSize { - fn default() -> Self { - Self::DEFAULT - } -} - #[derive(Debug, Clone, Copy)] pub struct Termios { pub input_mode: InputMode, diff --git a/kernel/src/driver/tty/tty_core.rs b/kernel/src/driver/tty/tty_core.rs index 376de925..93f0e9c4 100644 --- a/kernel/src/driver/tty/tty_core.rs +++ b/kernel/src/driver/tty/tty_core.rs @@ -31,7 +31,7 @@ use super::{ TtyLineDiscipline, }, tty_port::TtyPort, - virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData}, + virtual_terminal::{vc_manager, virtual_console::VirtualConsoleData, DrawRegion}, }; #[derive(Debug)] @@ -103,7 +103,7 @@ impl TtyCore { self.line_discipline.clone() } - pub fn write_without_serial(&self, buf: &[u8], nr: usize) -> Result { + pub fn write_to_core(&self, buf: &[u8], nr: usize) -> Result { self.core .driver() .driver_funcs() @@ -489,6 +489,61 @@ impl TtyCoreData { pub fn add_epitem(&self, epitem: Arc) { self.epitems.lock().push_back(epitem) } + + pub fn eptiems(&self) -> &SpinLock>> { + &self.epitems + } + + pub fn do_write(&self, buf: &[u8], mut nr: usize) -> Result { + // 关闭中断 + if let Some(vc_data) = self.vc_data() { + let mut vc_data_guard = vc_data.lock_irqsave(); + let mut offset = 0; + + // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着 + let mut rescan = false; + let mut ch: u32 = 0; + + let mut draw = DrawRegion::default(); + + // 首先隐藏光标再写 + vc_data_guard.hide_cursor(); + + while nr != 0 { + if !rescan { + ch = buf[offset] as u32; + offset += 1; + nr -= 1; + } + + let (tc, rescan_last) = vc_data_guard.translate(&mut ch); + if tc.is_none() { + // 表示未转换完成 + continue; + } + + let tc = tc.unwrap(); + rescan = rescan_last; + + if vc_data_guard.is_control(tc, ch) { + vc_data_guard.flush(&mut draw); + vc_data_guard.do_control(ch); + continue; + } + + if !vc_data_guard.console_write_normal(tc, ch, &mut draw) { + continue; + } + } + + vc_data_guard.flush(&mut draw); + + // TODO: notify update + return Ok(offset); + } else { + return Ok(0); + } + } } impl TtyOperation for TtyCore { diff --git a/kernel/src/driver/tty/tty_port.rs b/kernel/src/driver/tty/tty_port.rs index b387343f..d0488132 100644 --- a/kernel/src/driver/tty/tty_port.rs +++ b/kernel/src/driver/tty/tty_port.rs @@ -4,7 +4,10 @@ use alloc::sync::{Arc, Weak}; use kdepends::thingbuf::mpsc; use system_error::SystemError; -use crate::libs::spinlock::{SpinLock, SpinLockGuard}; +use crate::{ + libs::spinlock::{SpinLock, SpinLockGuard}, + net::event_poll::EventPoll, +}; use super::tty_core::TtyCore; @@ -85,6 +88,8 @@ pub trait TtyPort: Sync + Send + Debug { return ld.receive_buf(tty, buf, None, count); } + EventPoll::wakeup_epoll(tty.core().eptiems(), None)?; + ret } } diff --git a/kernel/src/driver/tty/virtual_terminal/mod.rs b/kernel/src/driver/tty/virtual_terminal/mod.rs index 8336591a..31abbfb6 100644 --- a/kernel/src/driver/tty/virtual_terminal/mod.rs +++ b/kernel/src/driver/tty/virtual_terminal/mod.rs @@ -300,55 +300,6 @@ impl TtyConsoleDriverInner { Ok(Self { console }) } - fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result { - // 关闭中断 - let vc_data = tty.vc_data().unwrap(); - let mut vc_data_guard = vc_data.lock_irqsave(); - - let mut offset = 0; - - // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着 - let mut rescan = false; - let mut ch: u32 = 0; - - let mut draw = DrawRegion::default(); - - // 首先隐藏光标再写 - vc_data_guard.hide_cursor(); - - while nr != 0 { - if !rescan { - ch = buf[offset] as u32; - offset += 1; - nr -= 1; - } - - let (tc, rescan_last) = vc_data_guard.translate(&mut ch); - if tc.is_none() { - // 表示未转换完成 - continue; - } - - let tc = tc.unwrap(); - rescan = rescan_last; - - if vc_data_guard.is_control(tc, ch) { - vc_data_guard.flush(&mut draw); - vc_data_guard.do_control(ch); - continue; - } - - if !vc_data_guard.console_write_normal(tc, ch, &mut draw) { - continue; - } - } - - vc_data_guard.flush(&mut draw); - - // TODO: notify update - return Ok(offset); - } - fn do_install(&self, tty: Arc, vc: &Arc) -> Result<(), SystemError> { let tty_core = tty.core(); @@ -426,7 +377,7 @@ impl TtyOperation for TtyConsoleDriverInner { // loop {} // } send_to_default_serial8250_port(buf); - let ret = self.do_write(tty, buf, nr); + let ret = tty.do_write(buf, nr); self.flush_chars(tty); ret } diff --git a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs index 3b5630ed..da7cdcd5 100644 --- a/kernel/src/driver/tty/virtual_terminal/virtual_console.rs +++ b/kernel/src/driver/tty/virtual_terminal/virtual_console.rs @@ -206,7 +206,7 @@ impl VirtualConsoleData { } } - pub(super) fn init(&mut self, rows: Option, cols: Option, clear: bool) { + pub fn init(&mut self, rows: Option, cols: Option, clear: bool) { if let Some(rows) = rows { self.rows = rows; } @@ -242,7 +242,7 @@ impl VirtualConsoleData { self.driver_funcs.as_ref().unwrap().upgrade().unwrap() } - pub(super) fn set_driver_funcs(&mut self, func: Weak) { + pub fn set_driver_funcs(&mut self, func: Weak) { self.driver_funcs = Some(func); } @@ -312,7 +312,7 @@ impl VirtualConsoleData { /// /// ### 返回值 /// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool) - pub(super) fn translate(&mut self, c: &mut u32) -> (Option, bool) { + pub fn translate(&mut self, c: &mut u32) -> (Option, bool) { if self.vc_state != VirtualConsoleState::ESnormal { // 在控制字符状态下不需要翻译 return (Some(*c), false); @@ -440,7 +440,7 @@ impl VirtualConsoleData { const CTRL_ALWAYS: u32 = 0x0800f501; /// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符 - pub(super) fn is_control(&self, tc: u32, c: u32) -> bool { + pub fn is_control(&self, tc: u32, c: u32) -> bool { // 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符 if self.vc_state != VirtualConsoleState::ESnormal { return true; @@ -1257,7 +1257,7 @@ impl VirtualConsoleData { /// ## 处理终端控制字符 #[inline(never)] - pub(super) fn do_control(&mut self, ch: u32) { + pub fn do_control(&mut self, ch: u32) { // 首先检查是否处于 ANSI 控制字符串状态 if self.vc_state.is_ansi_control_string() && (8..=13).contains(&ch) { return; @@ -1534,12 +1534,7 @@ impl VirtualConsoleData { } #[inline(never)] - pub(super) fn console_write_normal( - &mut self, - mut tc: u32, - c: u32, - draw: &mut DrawRegion, - ) -> bool { + pub fn console_write_normal(&mut self, mut tc: u32, c: u32, draw: &mut DrawRegion) -> bool { let mut attr = self.attr; let himask = self.hi_font_mask; let charmask = if himask == 0 { 0xff } else { 0x1ff }; @@ -1753,7 +1748,7 @@ impl VirtualConsoleData { return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4); } - pub(super) fn flush(&self, draw: &mut DrawRegion) { + pub fn flush(&self, draw: &mut DrawRegion) { if draw.x.is_none() { return; } diff --git a/kernel/src/filesystem/eventfd.rs b/kernel/src/filesystem/eventfd.rs index 5a90ff67..4d0d9a76 100644 --- a/kernel/src/filesystem/eventfd.rs +++ b/kernel/src/filesystem/eventfd.rs @@ -137,7 +137,7 @@ impl IndexNode for EventFdInode { let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, pollflag)?; + EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; return Ok(8); } @@ -184,7 +184,7 @@ impl IndexNode for EventFdInode { let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&self.epitems, pollflag)?; + EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; return Ok(8); } diff --git a/kernel/src/filesystem/vfs/core.rs b/kernel/src/filesystem/vfs/core.rs index 41984a71..f52470f6 100644 --- a/kernel/src/filesystem/vfs/core.rs +++ b/kernel/src/filesystem/vfs/core.rs @@ -5,7 +5,7 @@ use log::{error, info}; use system_error::SystemError; use crate::{ - driver::base::block::manager::block_dev_manager, + driver::base::block::{gendisk::GenDisk, manager::block_dev_manager}, filesystem::{ devfs::devfs_init, fat::fs::FATFileSystem, @@ -28,6 +28,7 @@ use super::{ /// 当没有指定根文件系统时,尝试的根文件系统列表 const ROOTFS_TRY_LIST: [&str; 4] = ["/dev/sda1", "/dev/sda", "/dev/vda1", "/dev/vda"]; +kernel_cmdline_param_kv!(ROOTFS_PATH_PARAM, root, ""); /// @brief 原子地生成新的Inode号。 /// 请注意,所有的inode号都需要通过该函数来生成.全局的inode号,除了以下两个特殊的以外,都是唯一的 @@ -116,20 +117,26 @@ fn migrate_virtual_filesystem(new_fs: Arc) -> Result<(), SystemE return Ok(()); } +fn try_find_gendisk_as_rootfs(path: &str) -> Option> { + if let Some(gd) = block_dev_manager().lookup_gendisk_by_path(path) { + info!("Use {} as rootfs", path); + return Some(gd); + } + return None; +} + pub fn mount_root_fs() -> Result<(), SystemError> { info!("Try to mount root fs..."); block_dev_manager().print_gendisks(); - - let gendisk = ROOTFS_TRY_LIST - .iter() - .find_map(|&path| { - if let Some(gd) = block_dev_manager().lookup_gendisk_by_path(path) { - info!("Use {} as rootfs", path); - return Some(gd); - } - return None; - }) - .ok_or(SystemError::ENODEV)?; + let gendisk = if let Some(rootfs_dev_path) = ROOTFS_PATH_PARAM.value_str() { + try_find_gendisk_as_rootfs(rootfs_dev_path) + .unwrap_or_else(|| panic!("Failed to find rootfs device {}", rootfs_dev_path)) + } else { + ROOTFS_TRY_LIST + .iter() + .find_map(|&path| try_find_gendisk_as_rootfs(path)) + .ok_or(SystemError::ENODEV)? + }; let fatfs: Result, SystemError> = FATFileSystem::new(gendisk); if fatfs.is_err() { diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index cc479883..c4ab9079 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -399,6 +399,15 @@ impl IndexNode for MountFSInode { return self.inner_inode.ioctl(cmd, data, private_data); } + #[inline] + fn kernel_ioctl( + &self, + arg: Arc, + data: &FilePrivateData, + ) -> Result { + return self.inner_inode.kernel_ioctl(arg, data); + } + #[inline] fn list(&self) -> Result, SystemError> { return self.inner_inode.list(); diff --git a/kernel/src/init/boot.rs b/kernel/src/init/boot.rs index 426ea1cc..b692e3fb 100644 --- a/kernel/src/init/boot.rs +++ b/kernel/src/init/boot.rs @@ -46,13 +46,20 @@ impl BootParams { /// 开机命令行参数字符串 pub fn boot_cmdline_str(&self) -> &str { - core::str::from_utf8(self.boot_cmdline()).unwrap() + core::str::from_utf8(&self.boot_cmdline()[..self.boot_cmdline_len()]).unwrap() } pub fn bootloader_name(&self) -> Option<&str> { self.bootloader_name.as_deref() } + pub fn boot_cmdline_len(&self) -> usize { + self.boot_command_line + .iter() + .position(|&x| x == 0) + .unwrap_or(self.boot_command_line.len()) + } + /// 追加开机命令行参数 /// /// 如果开机命令行参数已经满了,则不会追加。 @@ -149,13 +156,6 @@ pub fn boot_callbacks() -> &'static dyn BootCallbacks { } pub(super) fn boot_callback_except_early() { - boot_callbacks() - .init_kernel_cmdline() - .inspect_err(|e| { - log::error!("Failed to init kernel cmdline: {:?}", e); - }) - .ok(); - let mut boot_params = boot_params().write(); boot_params.bootloader_name = boot_callbacks() .init_bootloader_name() diff --git a/kernel/src/init/cmdline.rs b/kernel/src/init/cmdline.rs new file mode 100644 index 00000000..0d0ff040 --- /dev/null +++ b/kernel/src/init/cmdline.rs @@ -0,0 +1,476 @@ +use core::{ + str, + sync::atomic::{fence, Ordering}, +}; + +use alloc::{ffi::CString, vec::Vec}; + +use crate::libs::spinlock::SpinLock; + +use super::boot_params; + +#[::linkme::distributed_slice] +pub static KCMDLINE_PARAM_EARLY_KV: [KernelCmdlineParameter] = [..]; + +#[::linkme::distributed_slice] +pub static KCMDLINE_PARAM_KV: [KernelCmdlineParameter] = [..]; + +#[::linkme::distributed_slice] +pub static KCMDLINE_PARAM_ARG: [KernelCmdlineParameter] = [..]; + +static KERNEL_CMDLINE_PARAM_MANAGER: KernelCmdlineManager = KernelCmdlineManager::new(); + +#[inline(always)] +pub fn kenrel_cmdline_param_manager() -> &'static KernelCmdlineManager { + &KERNEL_CMDLINE_PARAM_MANAGER +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KCmdlineParamType { + /// bool类型参数 + Arg, + /// key-value类型参数 + KV, + /// 内存管理初始化之前的KV参数 + EarlyKV, +} + +pub struct KernelCmdlineParamBuilder { + name: &'static str, + ty: KCmdlineParamType, + default_str: &'static str, + default_bool: bool, + inv: bool, +} + +impl KernelCmdlineParamBuilder { + pub const fn new(name: &'static str, ty: KCmdlineParamType) -> Self { + Self { + name, + ty, + default_str: "", + default_bool: false, + inv: false, + } + } + + pub const fn default_str(mut self, default_str: &'static str) -> Self { + self.default_str = default_str; + self + } + + pub const fn default_bool(mut self, default_bool: bool) -> Self { + self.default_bool = default_bool; + self + } + + pub const fn inv(mut self, inv: bool) -> Self { + self.inv = inv; + self + } + + pub const fn build_early_kv(self) -> Option { + if matches!(self.ty, KCmdlineParamType::EarlyKV) { + Some(KernelCmdlineEarlyKV { + name: self.name, + value: [0; KernelCmdlineEarlyKV::VALUE_MAX_LEN], + index: 0, + initialized: false, + default: self.default_str, + }) + } else { + None + } + } + + pub const fn build(self) -> Option { + match self.ty { + KCmdlineParamType::Arg => Some(KernelCmdlineParameter::Arg(KernelCmdlineArg { + name: self.name, + value: self.default_bool, + initialized: false, + inv: self.inv, + default: self.default_bool, + })), + KCmdlineParamType::KV => Some(KernelCmdlineParameter::KV(KernelCmdlineKV { + name: self.name, + value: None, + initialized: false, + default: self.default_str, + })), + _ => None, + } + } +} + +#[allow(dead_code)] +pub enum KernelCmdlineParameter { + Arg(KernelCmdlineArg), + KV(KernelCmdlineKV), + EarlyKV(&'static KernelCmdlineEarlyKV), +} + +impl KernelCmdlineParameter { + pub fn name(&self) -> &str { + match self { + KernelCmdlineParameter::Arg(v) => v.name, + KernelCmdlineParameter::KV(v) => v.name, + KernelCmdlineParameter::EarlyKV(v) => v.name, + } + } + + /// 获取bool类型参数的值 + pub fn value_bool(&self) -> Option { + match self { + KernelCmdlineParameter::Arg(v) => Some(v.value()), + _ => None, + } + } + + /// 获取key-value类型参数的值 + pub fn value_str(&self) -> Option<&str> { + match self { + KernelCmdlineParameter::Arg(_) => None, + KernelCmdlineParameter::KV(v) => v + .value + .as_ref() + .and_then(|v| str::from_utf8(v.as_bytes()).ok()), + KernelCmdlineParameter::EarlyKV(v) => v.value_str(), + } + } + + pub fn is_arg(&self) -> bool { + matches!(self, KernelCmdlineParameter::Arg(_)) + } + + pub fn is_kv(&self) -> bool { + matches!(self, KernelCmdlineParameter::KV(_)) + } + + pub fn is_early_kv(&self) -> bool { + matches!(self, KernelCmdlineParameter::EarlyKV(_)) + } + + /// 强行获取可变引用 + /// + /// # Safety + /// + /// 只能在内核初始化阶段pid0使用! + #[allow(clippy::mut_from_ref)] + unsafe fn force_mut(&self) -> &mut Self { + let p = self as *const Self as *mut Self; + p.as_mut().unwrap() + } +} + +#[derive(Debug)] +pub struct KernelCmdlineArg { + name: &'static str, + value: bool, + initialized: bool, + /// 是否反转 + inv: bool, + default: bool, +} + +impl KernelCmdlineArg { + pub fn value(&self) -> bool { + volatile_read!(self.value) + } +} + +pub struct KernelCmdlineKV { + name: &'static str, + value: Option, + initialized: bool, + default: &'static str, +} + +/// 在内存管理初始化之前的KV参数 +pub struct KernelCmdlineEarlyKV { + name: &'static str, + value: [u8; Self::VALUE_MAX_LEN], + index: usize, + initialized: bool, + default: &'static str, +} + +impl KernelCmdlineEarlyKV { + pub const VALUE_MAX_LEN: usize = 256; + + pub fn value(&self) -> &[u8] { + &self.value[..self.index] + } + + pub fn value_str(&self) -> Option<&str> { + core::str::from_utf8(&self.value[..self.index]).ok() + } + + /// 强行获取可变引用 + /// + /// # Safety + /// + /// 只能在内核初始化阶段pid0使用! + #[allow(clippy::mut_from_ref)] + unsafe fn force_mut(&self) -> &mut Self { + let p = self as *const Self as *mut Self; + p.as_mut().unwrap() + } +} + +pub struct KernelCmdlineManager { + inner: SpinLock, +} + +pub(super) struct InnerKernelCmdlineManager { + /// init进程的路径 + init_path: Option, + init_args: Vec, + init_envs: Vec, +} + +impl KernelCmdlineManager { + const fn new() -> Self { + Self { + inner: SpinLock::new(InnerKernelCmdlineManager { + init_path: None, + init_args: Vec::new(), + init_envs: Vec::new(), + }), + } + } + + pub(super) fn init_proc_path(&self) -> Option { + self.inner.lock().init_path.clone() + } + + pub(super) fn init_proc_args(&self) -> Vec { + self.inner.lock().init_args.clone() + } + + pub(super) fn init_proc_envs(&self) -> Vec { + self.inner.lock().init_envs.clone() + } + + /// 在内存管理初始化之前设置部分参数 + pub fn early_init(&self) { + let boot_params = boot_params().read(); + + for argument in self.split_args(boot_params.boot_cmdline_str()) { + let (node, option, value) = match self.split_arg(argument) { + Some(v) => v, + None => continue, + }; + // 查找参数 + if let Some(param) = self.find_param(node, option, KCmdlineParamType::EarlyKV) { + let param = unsafe { param.force_mut() }; + match param { + KernelCmdlineParameter::EarlyKV(p) => { + let p = unsafe { p.force_mut() }; + if let Some(value) = value { + let value = value.as_bytes(); + let len = value.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); + p.value[..len].copy_from_slice(&value[..len]); + p.index = len; + } + p.initialized = true; + } + _ => unreachable!(), + } + fence(Ordering::SeqCst); + } + } + + // 初始化默认值 + KCMDLINE_PARAM_EARLY_KV.iter().for_each(|x| { + let x = unsafe { x.force_mut() }; + if let KernelCmdlineParameter::EarlyKV(v) = x { + if !v.initialized { + let v = unsafe { v.force_mut() }; + let len = v.default.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); + v.value[..len].copy_from_slice(v.default.as_bytes()); + v.index = len; + v.initialized = true; + } + } + }); + } + + /// 在内存管理初始化之后设置命令行参数 + pub fn init(&self) { + let mut inner = self.inner.lock(); + let boot_params = boot_params().read(); + // `--`以后的参数都是init进程的参数 + let mut kernel_cmdline_end = false; + for argument in self.split_args(boot_params.boot_cmdline_str()) { + if kernel_cmdline_end { + if inner.init_path.is_none() { + panic!("cmdline: init proc path is not set while init proc args are set"); + } + if !argument.is_empty() { + inner.init_args.push(CString::new(argument).unwrap()); + } + continue; + } + + if argument == "--" { + kernel_cmdline_end = true; + continue; + } + + let (node, option, value) = match self.split_arg(argument) { + Some(v) => v, + None => continue, + }; + if option == "init" && value.is_some() { + if inner.init_path.is_some() { + panic!("cmdline: init proc path is set twice"); + } + inner.init_path = Some(CString::new(value.unwrap()).unwrap()); + continue; + } + // log::debug!( + // "cmdline: node: {:?}, option: {:?}, value: {:?}", + // node, + // option, + // value + // ); + if let Some(param) = self.find_param(node, option, KCmdlineParamType::KV) { + let param = unsafe { param.force_mut() }; + match param { + KernelCmdlineParameter::KV(p) => { + if p.value.is_some() { + log::warn!("cmdline: parameter {} is set twice", p.name); + continue; + } + p.value = Some(CString::new(value.unwrap()).unwrap()); + p.initialized = true; + } + _ => unreachable!(), + } + fence(Ordering::SeqCst); + } else if let Some(param) = self.find_param(node, option, KCmdlineParamType::Arg) { + let param = unsafe { param.force_mut() }; + match param { + KernelCmdlineParameter::Arg(p) => { + if p.initialized { + log::warn!("cmdline: parameter {} is set twice", p.name); + continue; + } + p.value = !p.inv; + p.initialized = true; + } + _ => unreachable!(), + } + fence(Ordering::SeqCst); + } else if node.is_none() { + if let Some(val) = value { + inner + .init_envs + .push(CString::new(format!("{}={}", option, val)).unwrap()); + } else if !option.is_empty() { + inner.init_args.push(CString::new(option).unwrap()); + } + } + } + fence(Ordering::SeqCst); + // 初始化默认值 + self.default_initialize(); + fence(Ordering::SeqCst); + } + + fn default_initialize(&self) { + KCMDLINE_PARAM_ARG.iter().for_each(|x| { + let x = unsafe { x.force_mut() }; + if let KernelCmdlineParameter::Arg(v) = x { + if !v.initialized { + v.value = v.default; + v.initialized = true; + } + } + fence(Ordering::SeqCst); + }); + + KCMDLINE_PARAM_KV.iter().for_each(|x| { + let x = unsafe { x.force_mut() }; + if let KernelCmdlineParameter::KV(v) = x { + if !v.initialized { + v.value = Some(CString::new(v.default).unwrap()); + v.initialized = true; + } + } + fence(Ordering::SeqCst); + }); + } + + fn find_param( + &self, + node: Option<&str>, + option: &str, + param_typ: KCmdlineParamType, + ) -> Option<&KernelCmdlineParameter> { + let list = match param_typ { + KCmdlineParamType::Arg => &KCMDLINE_PARAM_ARG, + KCmdlineParamType::KV => &KCMDLINE_PARAM_KV, + KCmdlineParamType::EarlyKV => &KCMDLINE_PARAM_EARLY_KV, + }; + + list.iter().find(|x| { + let name = x.name(); + if let Some(node) = node { + // 加1是因为有一个点号 + name.len() == (node.len() + option.len() + 1) + && name.starts_with(node) + && name[node.len() + 1..].starts_with(option) + } else { + name == option + } + }) + } + + fn split_arg<'a>(&self, arg: &'a str) -> Option<(Option<&'a str>, &'a str, Option<&'a str>)> { + let mut iter = arg.splitn(2, '='); + let key = iter.next().unwrap(); + let value = iter.next(); + let value = value.map(|v| v.trim()); + if value.is_some() && iter.next().is_some() { + log::warn!("cmdline: invalid argument: {}", arg); + return None; + } + + let mut iter = key.splitn(2, '.'); + let v1 = iter.next().map(|v| v.trim()); + let v2 = iter.next().map(|v| v.trim()); + let v3 = iter.next().map(|v| v.trim()); + let v = [v1, v2, v3]; + + let mut key_split_len = 0; + v.iter().for_each(|x| { + if x.is_some() { + key_split_len += 1 + } + }); + + let (node, option) = match key_split_len { + 1 => (None, v[0].unwrap()), + 2 => (Some(v[0].unwrap()), v[1].unwrap()), + _ => { + log::warn!("cmdline: invalid argument: {}", arg); + return None; + } + }; + + Some((node, option, value)) + } + + fn split_args<'a>(&self, cmdline: &'a str) -> impl Iterator { + // 是否在引号内 + let mut in_quote = false; + cmdline.split(move |c: char| { + if c == '"' { + in_quote = !in_quote; + } + !in_quote && c.is_whitespace() + }) + } +} diff --git a/kernel/src/init/init.rs b/kernel/src/init/init.rs index a1d8aee8..953f0974 100644 --- a/kernel/src/init/init.rs +++ b/kernel/src/init/init.rs @@ -31,7 +31,10 @@ use crate::{ }, }; -use super::boot::boot_callback_except_early; +use super::{ + boot::{boot_callback_except_early, boot_callbacks}, + cmdline::kenrel_cmdline_param_manager, +}; /// The entry point for the kernel /// @@ -52,9 +55,7 @@ pub fn start_kernel() -> ! { #[inline(never)] fn do_start_kernel() { init_before_mem_init(); - early_init_logging(); - early_setup_arch().expect("setup_arch failed"); unsafe { mm_init() }; if scm_reinit().is_ok() { @@ -62,8 +63,10 @@ fn do_start_kernel() { warn!("Failed to init textui: {:?}", e); } } - + // 初始化内核命令行参数 + kenrel_cmdline_param_manager().init(); boot_callback_except_early(); + init_intertrait(); vfs_init().expect("vfs init failed"); @@ -99,4 +102,16 @@ fn init_before_mem_init() { serial_early_init().expect("serial early init failed"); let video_ok = unsafe { VideoRefreshManager::video_init().is_ok() }; scm_init(video_ok); + + early_init_logging(); + + early_setup_arch().expect("setup_arch failed"); + + boot_callbacks() + .init_kernel_cmdline() + .inspect_err(|e| { + log::error!("Failed to init kernel cmdline: {:?}", e); + }) + .ok(); + kenrel_cmdline_param_manager().early_init(); } diff --git a/kernel/src/init/initial_kthread.rs b/kernel/src/init/initial_kthread.rs index f5d6b028..a6670f16 100644 --- a/kernel/src/init/initial_kthread.rs +++ b/kernel/src/init/initial_kthread.rs @@ -14,12 +14,17 @@ use crate::{ }, filesystem::vfs::core::mount_root_fs, net::net_core::net_init, - process::{kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags, ProcessManager}, + process::{ + exec::ProcInitInfo, kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags, + ProcessManager, + }, smp::smp_init, syscall::Syscall, }; -use super::initcall::do_initcalls; +use super::{cmdline::kenrel_cmdline_param_manager, initcall::do_initcalls}; + +const INIT_PROC_TRYLIST: [&str; 3] = ["/bin/dragonreach", "/bin/init", "/bin/sh"]; pub fn initial_kernel_thread() -> i32 { kernel_init().unwrap_or_else(|err| { @@ -73,39 +78,79 @@ fn switch_to_user() -> ! { *current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS; drop(current_pcb); - let mut trap_frame = TrapFrame::new(); - // 逐个尝试运行init进程 - if try_to_run_init_process("/bin/dragonreach", &mut trap_frame).is_err() - && try_to_run_init_process("/bin/init", &mut trap_frame).is_err() - && try_to_run_init_process("/bin/sh", &mut trap_frame).is_err() - { - panic!("Failed to run init process: No working init found."); - } + let mut proc_init_info = ProcInitInfo::new(""); + proc_init_info.envs.push(CString::new("PATH=/").unwrap()); + proc_init_info.args = kenrel_cmdline_param_manager().init_proc_args(); + proc_init_info.envs = kenrel_cmdline_param_manager().init_proc_envs(); + let mut trap_frame = TrapFrame::new(); + + if let Some(path) = kenrel_cmdline_param_manager().init_proc_path() { + log::info!("Boot with specified init process: {:?}", path); + + try_to_run_init_process( + path.as_c_str().to_str().unwrap(), + &mut proc_init_info, + &mut trap_frame, + ) + .unwrap_or_else(|e| { + panic!( + "Failed to run specified init process: {:?}, err: {:?}", + path, e + ) + }); + } else { + let mut ok = false; + for path in INIT_PROC_TRYLIST.iter() { + if try_to_run_init_process(path, &mut proc_init_info, &mut trap_frame).is_ok() { + ok = true; + break; + } + } + if !ok { + panic!("Failed to run init process: No working init found."); + } + } + drop(proc_init_info); // 需要确保执行到这里之后,上面所有的资源都已经释放(比如arc之类的) compiler_fence(Ordering::SeqCst); unsafe { arch_switch_to_user(trap_frame) }; } -fn try_to_run_init_process(path: &str, trap_frame: &mut TrapFrame) -> Result<(), SystemError> { - if let Err(e) = run_init_process(path, trap_frame) { +fn try_to_run_init_process( + path: &str, + proc_init_info: &mut ProcInitInfo, + trap_frame: &mut TrapFrame, +) -> Result<(), SystemError> { + proc_init_info.proc_name = CString::new(path).unwrap(); + proc_init_info.args.insert(0, CString::new(path).unwrap()); + if let Err(e) = run_init_process(proc_init_info, trap_frame) { if e != SystemError::ENOENT { error!( "Failed to run init process: {path} exists but couldn't execute it (error {:?})", e ); } + + proc_init_info.args.remove(0); return Err(e); } Ok(()) } -fn run_init_process(path: &str, trap_frame: &mut TrapFrame) -> Result<(), SystemError> { - let argv = vec![CString::new(path).unwrap()]; - let envp = vec![CString::new("PATH=/").unwrap()]; - +fn run_init_process( + proc_init_info: &ProcInitInfo, + trap_frame: &mut TrapFrame, +) -> Result<(), SystemError> { compiler_fence(Ordering::SeqCst); - Syscall::do_execve(path.to_string(), argv, envp, trap_frame)?; + let path = proc_init_info.proc_name.to_str().unwrap(); + + Syscall::do_execve( + path.to_string(), + proc_init_info.args.clone(), + proc_init_info.envs.clone(), + trap_frame, + )?; Ok(()) } diff --git a/kernel/src/init/mod.rs b/kernel/src/init/mod.rs index 15e02bca..ee4f9942 100644 --- a/kernel/src/init/mod.rs +++ b/kernel/src/init/mod.rs @@ -2,6 +2,7 @@ use crate::libs::rwlock::RwLock; use self::boot::BootParams; pub mod boot; +pub mod cmdline; #[allow(clippy::module_inception)] pub mod init; pub mod initcall; diff --git a/kernel/src/ipc/pipe.rs b/kernel/src/ipc/pipe.rs index 864bc750..05b8927c 100644 --- a/kernel/src/ipc/pipe.rs +++ b/kernel/src/ipc/pipe.rs @@ -267,7 +267,7 @@ impl IndexNode for LockedPipeInode { let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&inode.epitems, pollflag)?; + EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?; //返回读取的字节数 return Ok(num); @@ -413,7 +413,7 @@ impl IndexNode for LockedPipeInode { let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32); // 唤醒epoll中等待的进程 - EventPoll::wakeup_epoll(&inode.epitems, pollflag)?; + EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?; // 返回写入的字节数 return Ok(len); diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 974f1fdb..aa67c0a7 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -81,7 +81,8 @@ extern crate smoltcp; extern crate intertrait; #[cfg(target_arch = "x86_64")] extern crate x86; - +#[macro_use] +extern crate kcmdline_macros; extern crate klog_types; extern crate uefi; extern crate uefi_raw; diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs index 75fca7ce..16e52397 100644 --- a/kernel/src/libs/lib_ui/textui.rs +++ b/kernel/src/libs/lib_ui/textui.rs @@ -1045,9 +1045,8 @@ pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) let port = current_vc.port(); let tty = port.port_data().internal_tty(); if let Some(tty) = tty { - send_to_default_serial8250_port(&[character]); return tty - .write_without_serial(buf.as_bytes(), buf.len()) + .write_to_core(buf.as_bytes(), buf.len()) .map(|_| 0) .unwrap_or_else(|e| e.to_posix_errno()); } diff --git a/kernel/src/mm/allocator/kernel_allocator.rs b/kernel/src/mm/allocator/kernel_allocator.rs index 6201fef3..9d71d907 100644 --- a/kernel/src/mm/allocator/kernel_allocator.rs +++ b/kernel/src/mm/allocator/kernel_allocator.rs @@ -51,7 +51,7 @@ impl KernelAllocator { return Ok(NonNull::from(slice)); } - unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) { + pub(super) unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) { // 由于buddy分配的页数量是2的幂,因此释放的时候也需要按照2的幂向上取整。 let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two(); let page_frame_count = PageFrameCount::new(count); diff --git a/kernel/src/mm/allocator/slab.rs b/kernel/src/mm/allocator/slab.rs index 710f9b7b..e564c325 100644 --- a/kernel/src/mm/allocator/slab.rs +++ b/kernel/src/mm/allocator/slab.rs @@ -4,12 +4,16 @@ use alloc::boxed::Box; use log::debug; use slabmalloc::*; +use crate::{arch::MMArch, mm::MemoryManagementArch, KERNEL_ALLOCATOR}; + // 全局slab分配器 pub(crate) static mut SLABALLOCATOR: Option = None; // slab初始化状态 pub(crate) static mut SLABINITSTATE: AtomicBool = AtomicBool::new(false); +static SLAB_CALLBACK: SlabCallback = SlabCallback; + /// slab分配器,实际为一堆小的allocator,可以在里面装4K的page /// 利用这些allocator可以为对象分配不同大小的空间 pub(crate) struct SlabAllocator { @@ -52,7 +56,7 @@ impl SlabAllocator { ) -> Result<(), AllocationError> { if let Some(nptr) = NonNull::new(ptr) { self.zone - .deallocate(nptr, layout) + .deallocate(nptr, layout, &SLAB_CALLBACK) .expect("Couldn't deallocate"); return Ok(()); } else { @@ -80,3 +84,13 @@ pub unsafe fn slab_usage() -> SlabUsage { SlabUsage::new(0, 0) } } + +/// 归还slab_page给buddy的回调 +pub struct SlabCallback; +impl CallBack for SlabCallback { + unsafe fn free_slab_page(&self, base_addr: *mut u8, size: usize) { + assert_eq!(base_addr as usize & (MMArch::PAGE_SIZE - 1), 0); // 确认地址4k对齐 + assert_eq!(size, MMArch::PAGE_SIZE); // 确认释放的slab_page大小 + KERNEL_ALLOCATOR.free_in_buddy(base_addr, Layout::from_size_align_unchecked(size, 1)); + } +} diff --git a/kernel/src/net/event_poll/mod.rs b/kernel/src/net/event_poll/mod.rs index af19ee1c..f6a9ad61 100644 --- a/kernel/src/net/event_poll/mod.rs +++ b/kernel/src/net/event_poll/mod.rs @@ -716,41 +716,50 @@ impl EventPoll { /// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可 pub fn wakeup_epoll( epitems: &SpinLock>>, - pollflags: EPollEventType, + pollflags: Option, ) -> Result<(), SystemError> { let mut epitems_guard = epitems.try_lock_irqsave()?; // 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓 if let Some(epitem) = epitems_guard.pop_front() { - let epoll = epitem.epoll().upgrade().unwrap(); - let mut epoll_guard = epoll.try_lock()?; - let binding = epitem.clone(); - let event_guard = binding.event().read(); - let ep_events = EPollEventType::from_bits_truncate(event_guard.events()); + let pollflags = pollflags.unwrap_or({ + if let Some(file) = epitem.file.upgrade() { + EPollEventType::from_bits_truncate(file.poll()? as u32) + } else { + EPollEventType::empty() + } + }); - // 检查事件合理性以及是否有感兴趣的事件 - if !(ep_events - .difference(EPollEventType::EP_PRIVATE_BITS) - .is_empty() - || pollflags.difference(ep_events).is_empty()) - { - // TODO: 未处理pm相关 + if let Some(epoll) = epitem.epoll().upgrade() { + let mut epoll_guard = epoll.try_lock()?; + let binding = epitem.clone(); + let event_guard = binding.event().read(); + let ep_events = EPollEventType::from_bits_truncate(event_guard.events()); - // 首先将就绪的epitem加入等待队列 - epoll_guard.ep_add_ready(epitem.clone()); + // 检查事件合理性以及是否有感兴趣的事件 + if !(ep_events + .difference(EPollEventType::EP_PRIVATE_BITS) + .is_empty() + || pollflags.difference(ep_events).is_empty()) + { + // TODO: 未处理pm相关 - if epoll_guard.ep_has_waiter() { - if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE) - && !pollflags.contains(EPollEventType::POLLFREE) - { - // 避免惊群 - epoll_guard.ep_wake_one(); - } else { - epoll_guard.ep_wake_all(); + // 首先将就绪的epitem加入等待队列 + epoll_guard.ep_add_ready(epitem.clone()); + + if epoll_guard.ep_has_waiter() { + if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE) + && !pollflags.contains(EPollEventType::POLLFREE) + { + // 避免惊群 + epoll_guard.ep_wake_one(); + } else { + epoll_guard.ep_wake_all(); + } } } - } - epitems_guard.push_back(epitem); + epitems_guard.push_back(epitem); + } } Ok(()) } diff --git a/kernel/src/net/socket/buffer.rs b/kernel/src/net/socket/buffer.rs index 49ca8acd..814314ab 100644 --- a/kernel/src/net/socket/buffer.rs +++ b/kernel/src/net/socket/buffer.rs @@ -1,7 +1,6 @@ use alloc::vec::Vec; use alloc::{string::String, sync::Arc}; -use log::debug; use system_error::SystemError; use crate::libs::spinlock::SpinLock; @@ -43,14 +42,14 @@ impl Buffer { let len = core::cmp::min(buf.len(), read_buffer.len()); buf[..len].copy_from_slice(&read_buffer[..len]); let _ = read_buffer.split_off(len); - log::debug!("recv buf {}", String::from_utf8_lossy(buf)); + // log::debug!("recv buf {}", String::from_utf8_lossy(buf)); return Ok(len); } pub fn write_read_buffer(&self, buf: &[u8]) -> Result { let mut buffer = self.read_buffer.lock_irqsave(); - log::debug!("send buf {}", String::from_utf8_lossy(buf)); + // log::debug!("send buf {}", String::from_utf8_lossy(buf)); let len = buf.len(); if self.metadata.buf_size - buffer.len() < len { return Err(SystemError::ENOBUFS); diff --git a/kernel/src/net/socket/inet/common/mod.rs b/kernel/src/net/socket/inet/common/mod.rs index 96a5c256..63c58244 100644 --- a/kernel/src/net/socket/inet/common/mod.rs +++ b/kernel/src/net/socket/inet/common/mod.rs @@ -45,7 +45,7 @@ impl BoundInner { // iface // } // 强绑VirtualIO - log::debug!("Not bind to any iface, bind to virtIO"); + // log::debug!("Not bind to any iface, bind to virtIO"); let iface = NET_DEVICES .read_irqsave() .get(&0) diff --git a/kernel/src/net/socket/inet/stream/inner.rs b/kernel/src/net/socket/inet/stream/inner.rs index 99c649a3..4d7499ae 100644 --- a/kernel/src/net/socket/inet/stream/inner.rs +++ b/kernel/src/net/socket/inet/stream/inner.rs @@ -3,6 +3,7 @@ use core::sync::atomic::{AtomicU32, AtomicUsize}; use crate::libs::rwlock::RwLock; use crate::net::socket::EPollEventType; use crate::net::socket::{self, inet::Types}; +use alloc::boxed::Box; use alloc::vec::Vec; use smoltcp; use system_error::SystemError::{self, *}; @@ -30,13 +31,13 @@ where #[derive(Debug)] pub enum Init { - Unbound(smoltcp::socket::tcp::Socket<'static>), + Unbound(Box>), Bound((socket::inet::BoundInner, smoltcp::wire::IpEndpoint)), } impl Init { pub(super) fn new() -> Self { - Init::Unbound(new_smoltcp_socket()) + Init::Unbound(Box::new(new_smoltcp_socket())) } /// 传入一个已经绑定的socket @@ -55,7 +56,7 @@ impl Init { ) -> Result { match self { Init::Unbound(socket) => { - let bound = socket::inet::BoundInner::bind(socket, &local_endpoint.addr)?; + let bound = socket::inet::BoundInner::bind(*socket, &local_endpoint.addr)?; bound .port_manager() .bind_port(Types::Tcp, local_endpoint.port)?; @@ -73,7 +74,7 @@ impl Init { match self { Init::Unbound(socket) => { let (bound, address) = - socket::inet::BoundInner::bind_ephemeral(socket, remote_endpoint.addr) + socket::inet::BoundInner::bind_ephemeral(*socket, remote_endpoint.addr) .map_err(|err| (Self::new(), err))?; let bound_port = bound .port_manager() @@ -125,7 +126,7 @@ impl Init { } else { smoltcp::wire::IpListenEndpoint::from(local) }; - log::debug!("listen at {:?}", listen_addr); + // log::debug!("listen at {:?}", listen_addr); let mut inners = Vec::new(); if let Err(err) = || -> Result<(), SystemError> { for _ in 0..(backlog - 1) { @@ -440,4 +441,13 @@ impl Inner { Inner::Established(est) => est.with_mut(|socket| socket.recv_capacity()), } } + + pub fn iface(&self) -> Option<&alloc::sync::Arc> { + match self { + Inner::Init(_) => None, + Inner::Connecting(conn) => Some(conn.inner.iface()), + Inner::Listening(listen) => Some(listen.inners[0].iface()), + Inner::Established(est) => Some(est.inner.iface()), + } + } } diff --git a/kernel/src/net/socket/inet/stream/mod.rs b/kernel/src/net/socket/inet/stream/mod.rs index e3338943..8f8cc745 100644 --- a/kernel/src/net/socket/inet/stream/mod.rs +++ b/kernel/src/net/socket/inet/stream/mod.rs @@ -185,11 +185,19 @@ impl TcpSocket { } pub fn try_recv(&self, buf: &mut [u8]) -> Result { - poll_ifaces(); - match self.inner.read().as_ref().expect("Tcp Inner is None") { - Inner::Established(inner) => inner.recv_slice(buf), - _ => Err(EINVAL), - } + self.inner + .read() + .as_ref() + .map(|inner| { + inner.iface().unwrap().poll(); + let result = match inner { + Inner::Established(inner) => inner.recv_slice(buf), + _ => Err(EINVAL), + }; + inner.iface().unwrap().poll(); + result + }) + .unwrap() } pub fn try_send(&self, buf: &[u8]) -> Result { @@ -221,6 +229,7 @@ impl TcpSocket { // should only call on accept fn is_acceptable(&self) -> bool { // (self.poll() & EP::EPOLLIN.bits() as usize) != 0 + self.inner.read().as_ref().unwrap().iface().unwrap().poll(); EP::from_bits_truncate(self.poll() as u32).contains(EP::EPOLLIN) } } @@ -233,7 +242,7 @@ impl Socket for TcpSocket { fn get_name(&self) -> Result { match self.inner.read().as_ref().expect("Tcp Inner is None") { Inner::Init(Init::Unbound(_)) => Ok(Endpoint::Ip(UNSPECIFIED_LOCAL_ENDPOINT)), - Inner::Init(Init::Bound((_, local))) => Ok(Endpoint::Ip(local.clone())), + Inner::Init(Init::Bound((_, local))) => Ok(Endpoint::Ip(*local)), Inner::Connecting(connecting) => Ok(Endpoint::Ip(connecting.get_name())), Inner::Established(established) => Ok(Endpoint::Ip(established.local_endpoint())), Inner::Listening(listening) => Ok(Endpoint::Ip(listening.get_name())), @@ -255,7 +264,7 @@ impl Socket for TcpSocket { } fn poll(&self) -> usize { - self.pollee.load(core::sync::atomic::Ordering::Relaxed) + self.pollee.load(core::sync::atomic::Ordering::SeqCst) } fn listen(&self, backlog: usize) -> Result<(), SystemError> { diff --git a/kernel/src/net/socket/inet/syscall.rs b/kernel/src/net/socket/inet/syscall.rs index 98fc2dca..3340f699 100644 --- a/kernel/src/net/socket/inet/syscall.rs +++ b/kernel/src/net/socket/inet/syscall.rs @@ -11,7 +11,7 @@ fn create_inet_socket( socket_type: Type, protocol: smoltcp::wire::IpProtocol, ) -> Result, SystemError> { - log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol); + // log::debug!("type: {:?}, protocol: {:?}", socket_type, protocol); use smoltcp::wire::IpProtocol::*; use Type::*; match socket_type { diff --git a/kernel/src/net/socket/unix/mod.rs b/kernel/src/net/socket/unix/mod.rs index 82196cc3..05986f7e 100644 --- a/kernel/src/net/socket/unix/mod.rs +++ b/kernel/src/net/socket/unix/mod.rs @@ -27,7 +27,7 @@ impl family::Family for Unix { impl Unix { pub fn new_pairs(socket_type: Type) -> Result<(Arc, Arc), SystemError> { - log::debug!("socket_type {:?}", socket_type); + // log::debug!("socket_type {:?}", socket_type); match socket_type { Type::SeqPacket => seqpacket::SeqpacketSocket::new_pairs(), Type::Stream | Type::Datagram => stream::StreamSocket::new_pairs(), diff --git a/kernel/src/net/socket/unix/seqpacket/inner.rs b/kernel/src/net/socket/unix/seqpacket/inner.rs index c43921ec..9875d18e 100644 --- a/kernel/src/net/socket/unix/seqpacket/inner.rs +++ b/kernel/src/net/socket/unix/seqpacket/inner.rs @@ -62,11 +62,7 @@ pub(super) struct Listener { impl Listener { pub(super) fn new(inode: Endpoint, backlog: usize) -> Self { log::debug!("backlog {}", backlog); - let back = if backlog > 1024 { - 1024 as usize - } else { - backlog - }; + let back = if backlog > 1024 { 1024_usize } else { backlog }; return Self { inode, backlog: AtomicUsize::new(back), @@ -82,7 +78,7 @@ impl Listener { log::debug!(" incom len {}", incoming_conns.len()); let conn = incoming_conns .pop_front() - .ok_or_else(|| SystemError::EAGAIN_OR_EWOULDBLOCK)?; + .ok_or(SystemError::EAGAIN_OR_EWOULDBLOCK)?; let socket = Arc::downcast::(conn.inner()).map_err(|_| SystemError::EINVAL)?; let peer = match &*socket.inner.read() { @@ -190,7 +186,7 @@ impl Connected { if self.can_send()? { return self.send_slice(buf); } else { - log::debug!("can not send {:?}", String::from_utf8_lossy(&buf[..])); + log::debug!("can not send {:?}", String::from_utf8_lossy(buf)); return Err(SystemError::ENOBUFS); } } diff --git a/kernel/src/net/socket/unix/seqpacket/mod.rs b/kernel/src/net/socket/unix/seqpacket/mod.rs index a1d29788..8b578d01 100644 --- a/kernel/src/net/socket/unix/seqpacket/mod.rs +++ b/kernel/src/net/socket/unix/seqpacket/mod.rs @@ -230,11 +230,7 @@ impl Socket for SeqpacketSocket { if !self.is_nonblocking() { loop { wq_wait_event_interruptible!(self.wait_queue, self.is_acceptable(), {})?; - match self - .try_accept() - .map(|(seqpacket_socket, remote_endpoint)| { - (seqpacket_socket, Endpoint::from(remote_endpoint)) - }) { + match self.try_accept() { Ok((socket, epoint)) => return Ok((socket, epoint)), Err(_) => continue, } @@ -260,7 +256,7 @@ impl Socket for SeqpacketSocket { } fn close(&self) -> Result<(), SystemError> { - log::debug!("seqpacket close"); + // log::debug!("seqpacket close"); self.shutdown.recv_shutdown(); self.shutdown.send_shutdown(); Ok(()) @@ -274,7 +270,7 @@ impl Socket for SeqpacketSocket { }; if let Some(endpoint) = endpoint { - return Ok(Endpoint::from(endpoint)); + return Ok(endpoint); } else { return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); } @@ -289,7 +285,7 @@ impl Socket for SeqpacketSocket { }; if let Some(endpoint) = endpoint { - return Ok(Endpoint::from(endpoint)); + return Ok(endpoint); } else { return Err(SystemError::EAGAIN_OR_EWOULDBLOCK); } @@ -402,7 +398,7 @@ impl Socket for SeqpacketSocket { flags: MessageFlag, _address: Option, ) -> Result<(usize, Endpoint), SystemError> { - log::debug!("recvfrom flags {:?}", flags); + // log::debug!("recvfrom flags {:?}", flags); if flags.contains(MessageFlag::OOB) { return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); } @@ -417,7 +413,7 @@ impl Socket for SeqpacketSocket { match &*self.inner.write() { Inner::Connected(connected) => match connected.recv_slice(buffer) { Ok(usize) => { - log::debug!("recvs from successfully"); + // log::debug!("recvs from successfully"); return Ok((usize, connected.peer_endpoint().unwrap().clone())); } Err(_) => continue, diff --git a/kernel/src/net/socket/unix/stream/mod.rs b/kernel/src/net/socket/unix/stream/mod.rs index 2978a0b1..0ee57d1b 100644 --- a/kernel/src/net/socket/unix/stream/mod.rs +++ b/kernel/src/net/socket/unix/stream/mod.rs @@ -231,10 +231,7 @@ impl Socket for StreamSocket { //目前只实现了阻塞式实现 loop { wq_wait_event_interruptible!(self.wait_queue, self.is_acceptable(), {})?; - match self - .try_accept() - .map(|(stream_socket, remote_endpoint)| (stream_socket, remote_endpoint)) - { + match self.try_accept() { Ok((socket, endpoint)) => { debug!("server accept!:{:?}", endpoint); return Ok((socket, endpoint)); diff --git a/kernel/src/net/syscall.rs b/kernel/src/net/syscall.rs index b59ad171..81f59576 100644 --- a/kernel/src/net/syscall.rs +++ b/kernel/src/net/syscall.rs @@ -41,18 +41,18 @@ impl Syscall { protocol: usize, ) -> Result { // 打印收到的参数 - log::debug!( - "socket: address_family={:?}, socket_type={:?}, protocol={:?}", - address_family, - socket_type, - protocol - ); + // log::debug!( + // "socket: address_family={:?}, socket_type={:?}, protocol={:?}", + // address_family, + // socket_type, + // protocol + // ); let address_family = socket::AddressFamily::try_from(address_family as u16)?; let type_arg = SysArgSocketType::from_bits_truncate(socket_type as u32); let is_nonblock = type_arg.is_nonblock(); let is_close_on_exec = type_arg.is_cloexec(); let stype = socket::Type::try_from(type_arg)?; - log::debug!("type_arg {:?} stype {:?}", type_arg, stype); + // log::debug!("type_arg {:?} stype {:?}", type_arg, stype); let inode = socket::create_socket( address_family, @@ -256,7 +256,7 @@ impl Syscall { let socket: Arc = ProcessManager::current_pcb() .get_socket(fd as i32) .ok_or(SystemError::EBADF)?; - log::debug!("bind: socket={:?}", socket); + // log::debug!("bind: socket={:?}", socket); socket.bind(endpoint)?; Ok(0) } diff --git a/kernel/src/net/syscall_util.rs b/kernel/src/net/syscall_util.rs index 90bb34d1..12c47e7a 100644 --- a/kernel/src/net/syscall_util.rs +++ b/kernel/src/net/syscall_util.rs @@ -296,7 +296,7 @@ impl From for SockAddr { } let addr_un = SockAddrUn { sun_family: AddressFamily::Unix as u16, - sun_path: sun_path, + sun_path, }; return SockAddr { addr_un }; } diff --git a/tools/BUILD_CONTAINER_VERSION b/tools/BUILD_CONTAINER_VERSION index 26e5d195..64c411b8 100644 --- a/tools/BUILD_CONTAINER_VERSION +++ b/tools/BUILD_CONTAINER_VERSION @@ -1 +1 @@ -v1.3 \ No newline at end of file +v1.4 \ No newline at end of file diff --git a/tools/bootstrap.sh b/tools/bootstrap.sh index aee206b9..ddb5a608 100644 --- a/tools/bootstrap.sh +++ b/tools/bootstrap.sh @@ -232,6 +232,7 @@ rustInstall() { echo "正在安装DragonOS所需的rust组件...首次安装需要一些时间来更新索引,请耐心等待..." cargo install cargo-binutils + cargo install bpf-linker rustup toolchain install nightly-2023-08-15-x86_64-unknown-linux-gnu rustup toolchain install $RUST_VERSION-x86_64-unknown-linux-gnu rustup component add rust-src --toolchain $RUST_VERSION-x86_64-unknown-linux-gnu diff --git a/tools/write_disk_image.sh b/tools/write_disk_image.sh index 5aa915f6..27b43110 100644 --- a/tools/write_disk_image.sh +++ b/tools/write_disk_image.sh @@ -126,9 +126,8 @@ cfg_content='set timeout=15 set default=0 insmod efi_gop menuentry "DragonOS" { - multiboot2 /boot/kernel.elf "KERNEL_ELF" + multiboot2 /boot/kernel.elf init=/bin/dragonreach }' - # 增加insmod efi_gop防止32位uefi启动报错 echo "echo '${cfg_content}' > ${boot_folder}/grub/grub.cfg" | sh fi diff --git a/user/apps/ping/src/ping.rs b/user/apps/ping/src/ping.rs index 7af719bc..a17881dc 100644 --- a/user/apps/ping/src/ping.rs +++ b/user/apps/ping/src/ping.rs @@ -101,7 +101,7 @@ impl Ping { for i in 0..this.config.count { let _this = this.clone(); - let handle = thread::spawn(move||{ + let handle = thread::spawn(move || { _this.ping(i).unwrap(); }); _send.fetch_add(1, Ordering::SeqCst); diff --git a/user/apps/test-uevent/src/main.rs b/user/apps/test-uevent/src/main.rs index 0ac1b7c0..d76b5727 100644 --- a/user/apps/test-uevent/src/main.rs +++ b/user/apps/test-uevent/src/main.rs @@ -1,7 +1,7 @@ use libc::{sockaddr, recvfrom, bind, sendto, socket, AF_NETLINK, SOCK_DGRAM, getpid, c_void}; use nix::libc; use std::os::unix::io::RawFd; -use std::{ mem, io}; +use std::{io, mem}; #[repr(C)] struct Nlmsghdr { @@ -33,7 +33,11 @@ fn bind_netlink_socket(sock: RawFd) -> io::Result<()> { addr.nl_groups = 1; let ret = unsafe { - bind(sock, &addr as *const _ as *const sockaddr, mem::size_of::() as u32) + bind( + sock, + &addr as *const _ as *const sockaddr, + mem::size_of::() as u32, + ) }; if ret < 0 { @@ -90,7 +94,10 @@ fn receive_uevent(sock: RawFd) -> io::Result { // 检查套接字文件描述符是否有效 if sock < 0 { println!("Invalid socket file descriptor: {}", sock); - return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid socket file descriptor")); + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Invalid socket file descriptor", + )); } let mut buf = [0u8; 1024]; @@ -100,7 +107,10 @@ fn receive_uevent(sock: RawFd) -> io::Result { // 检查缓冲区指针和长度是否有效 if buf.is_empty() { println!("Buffer is empty"); - return Err(io::Error::new(io::ErrorKind::InvalidInput, "Buffer is empty")); + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Buffer is empty", + )); } let len = unsafe { recvfrom( @@ -122,13 +132,19 @@ fn receive_uevent(sock: RawFd) -> io::Result { let nlmsghdr_size = mem::size_of::(); if (len as usize) < nlmsghdr_size { println!("Received message is too short"); - return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is too short")); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Received message is too short", + )); } let nlmsghdr = unsafe { &*(buf.as_ptr() as *const Nlmsghdr) }; if nlmsghdr.nlmsg_len as isize > len { println!("Received message is incomplete"); - return Err(io::Error::new(io::ErrorKind::InvalidData, "Received message is incomplete")); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Received message is incomplete", + )); } let message_data = &buf[nlmsghdr_size..nlmsghdr.nlmsg_len as usize]; diff --git a/user/apps/test_seqpacket/src/main.rs b/user/apps/test_seqpacket/src/main.rs index dc1953e2..9657b36a 100644 --- a/user/apps/test_seqpacket/src/main.rs +++ b/user/apps/test_seqpacket/src/main.rs @@ -1,8 +1,8 @@ -mod seq_socket; mod seq_pair; +mod seq_socket; -use seq_socket::test_seq_socket; use seq_pair::test_seq_pair; +use seq_socket::test_seq_socket; fn main() -> Result<(), std::io::Error> { if let Err(e) = test_seq_socket() { @@ -187,4 +187,4 @@ fn main() -> Result<(), std::io::Error> { // let len = socket1.read(&mut buf)?; // println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len])); // Ok(()) -// } \ No newline at end of file +// } diff --git a/user/apps/test_seqpacket/src/seq_pair.rs b/user/apps/test_seqpacket/src/seq_pair.rs index f474b200..3c9c3818 100644 --- a/user/apps/test_seqpacket/src/seq_pair.rs +++ b/user/apps/test_seqpacket/src/seq_pair.rs @@ -1,16 +1,17 @@ use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType}; use std::fs::File; -use std::io::{Read, Write,Error}; +use std::io::{Error, Read, Write}; use std::os::fd::FromRawFd; -pub fn test_seq_pair()->Result<(),Error>{ +pub fn test_seq_pair() -> Result<(), Error> { // 创建 socket pair let (sock1, sock2) = socketpair( AddressFamily::Unix, SockType::SeqPacket, // 使用 SeqPacket 类型 None, // 协议默认 SockFlag::empty(), - ).expect("Failed to create socket pair"); + ) + .expect("Failed to create socket pair"); let mut socket1 = unsafe { File::from_raw_fd(sock1) }; let mut socket2 = unsafe { File::from_raw_fd(sock2) }; @@ -36,4 +37,4 @@ pub fn test_seq_pair()->Result<(),Error>{ let len = socket1.read(&mut buf)?; println!("sock1 receive: {:?}", String::from_utf8_lossy(&buf[..len])); Ok(()) -} \ No newline at end of file +} diff --git a/user/apps/test_seqpacket/src/seq_socket.rs b/user/apps/test_seqpacket/src/seq_socket.rs index a2f08c11..81b3db5b 100644 --- a/user/apps/test_seqpacket/src/seq_socket.rs +++ b/user/apps/test_seqpacket/src/seq_socket.rs @@ -1,16 +1,14 @@ - use libc::*; -use std::{fs, str}; use std::ffi::CString; use std::io::Error; use std::mem; use std::os::unix::io::RawFd; +use std::{fs, str}; const SOCKET_PATH: &str = "/test.seqpacket"; const MSG1: &str = "Hello, Unix SEQPACKET socket from Client!"; const MSG2: &str = "Hello, Unix SEQPACKET socket from Server!"; - fn create_seqpacket_socket() -> Result { unsafe { let fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); @@ -33,7 +31,12 @@ fn bind_socket(fd: RawFd) -> Result<(), Error> { addr.sun_path[i] = byte as i8; } - if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 { + if bind( + fd, + &addr as *const _ as *const sockaddr, + mem::size_of_val(&addr) as socklen_t, + ) == -1 + { return Err(Error::last_os_error()); } } @@ -68,7 +71,13 @@ fn accept_connection(fd: RawFd) -> Result { fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> { unsafe { let msg_bytes = msg.as_bytes(); - if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0) == -1 { + if send( + fd, + msg_bytes.as_ptr() as *const libc::c_void, + msg_bytes.len(), + 0, + ) == -1 + { return Err(Error::last_os_error()); } } @@ -78,7 +87,12 @@ fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> { fn receive_message(fd: RawFd) -> Result { let mut buffer = [0; 1024]; unsafe { - let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(), 0); + let len = recv( + fd, + buffer.as_mut_ptr() as *mut libc::c_void, + buffer.len(), + 0, + ); if len == -1 { return Err(Error::last_os_error()); } @@ -86,70 +100,82 @@ fn receive_message(fd: RawFd) -> Result { } } -pub fn test_seq_socket() ->Result<(), Error>{ - // Create and bind the server socket - fs::remove_file(&SOCKET_PATH).ok(); +pub fn test_seq_socket() -> Result<(), Error> { + // Create and bind the server socket + fs::remove_file(&SOCKET_PATH).ok(); - let server_fd = create_seqpacket_socket()?; - bind_socket(server_fd)?; - listen_socket(server_fd)?; + let server_fd = create_seqpacket_socket()?; + bind_socket(server_fd)?; + listen_socket(server_fd)?; - // Accept connection in a separate thread - let server_thread = std::thread::spawn(move || { - let client_fd = accept_connection(server_fd).expect("Failed to accept connection"); - - // Receive and print message - let received_msg = receive_message(client_fd).expect("Failed to receive message"); - println!("Server: Received message: {}", received_msg); - - send_message(client_fd, MSG2).expect("Failed to send message"); - - // Close client connection - unsafe { close(client_fd) }; - }); - - // Create and connect the client socket - let client_fd = create_seqpacket_socket()?; - unsafe { - let mut addr = sockaddr_un { - sun_family: AF_UNIX as u16, - sun_path: [0; 108], - }; - let path_cstr = CString::new(SOCKET_PATH).unwrap(); - let path_bytes = path_cstr.as_bytes(); - // Convert u8 to i8 - for (i, &byte) in path_bytes.iter().enumerate() { - addr.sun_path[i] = byte as i8; - } - if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 { - return Err(Error::last_os_error()); - } - } - send_message(client_fd, MSG1)?; + // Accept connection in a separate thread + let server_thread = std::thread::spawn(move || { + let client_fd = accept_connection(server_fd).expect("Failed to accept connection"); + + // Receive and print message let received_msg = receive_message(client_fd).expect("Failed to receive message"); - println!("Client: Received message: {}", received_msg); - // get peer_name - unsafe { - let mut addrss = sockaddr_un { - sun_family: AF_UNIX as u16, - sun_path: [0; 108], - }; - let mut len = mem::size_of_val(&addrss) as socklen_t; - let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len); - if res == -1 { - return Err(Error::last_os_error()); - } - let sun_path = addrss.sun_path.clone(); - let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::>().try_into().unwrap(); - println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path)); + println!("Server: Received message: {}", received_msg); + + send_message(client_fd, MSG2).expect("Failed to send message"); - } - - server_thread.join().expect("Server thread panicked"); - let received_msg = receive_message(client_fd).expect("Failed to receive message"); - println!("Client: Received message: {}", received_msg); // Close client connection unsafe { close(client_fd) }; - fs::remove_file(&SOCKET_PATH).ok(); - Ok(()) -} \ No newline at end of file + }); + + // Create and connect the client socket + let client_fd = create_seqpacket_socket()?; + unsafe { + let mut addr = sockaddr_un { + sun_family: AF_UNIX as u16, + sun_path: [0; 108], + }; + let path_cstr = CString::new(SOCKET_PATH).unwrap(); + let path_bytes = path_cstr.as_bytes(); + // Convert u8 to i8 + for (i, &byte) in path_bytes.iter().enumerate() { + addr.sun_path[i] = byte as i8; + } + if connect( + client_fd, + &addr as *const _ as *const sockaddr, + mem::size_of_val(&addr) as socklen_t, + ) == -1 + { + return Err(Error::last_os_error()); + } + } + send_message(client_fd, MSG1)?; + let received_msg = receive_message(client_fd).expect("Failed to receive message"); + println!("Client: Received message: {}", received_msg); + // get peer_name + unsafe { + let mut addrss = sockaddr_un { + sun_family: AF_UNIX as u16, + sun_path: [0; 108], + }; + let mut len = mem::size_of_val(&addrss) as socklen_t; + let res = getpeername(client_fd, &mut addrss as *mut _ as *mut sockaddr, &mut len); + if res == -1 { + return Err(Error::last_os_error()); + } + let sun_path = addrss.sun_path.clone(); + let peer_path: [u8; 108] = sun_path + .iter() + .map(|&x| x as u8) + .collect::>() + .try_into() + .unwrap(); + println!( + "Client: Connected to server at path: {}", + String::from_utf8_lossy(&peer_path) + ); + } + + server_thread.join().expect("Server thread panicked"); + let received_msg = receive_message(client_fd).expect("Failed to receive message"); + println!("Client: Received message: {}", received_msg); + // Close client connection + unsafe { close(client_fd) }; + fs::remove_file(&SOCKET_PATH).ok(); + Ok(()) +} diff --git a/user/apps/test_unix_stream_socket/src/main.rs b/user/apps/test_unix_stream_socket/src/main.rs index 1e52748b..27b1cc8c 100644 --- a/user/apps/test_unix_stream_socket/src/main.rs +++ b/user/apps/test_unix_stream_socket/src/main.rs @@ -1,19 +1,19 @@ -use std::io::Error; -use std::os::fd::RawFd; -use std::fs; use libc::*; use std::ffi::CString; +use std::fs; +use std::io::Error; use std::mem; +use std::os::fd::RawFd; const SOCKET_PATH: &str = "/test.stream"; const MSG1: &str = "Hello, unix stream socket from Client!"; const MSG2: &str = "Hello, unix stream socket from Server!"; -fn create_stream_socket() -> Result{ +fn create_stream_socket() -> Result { unsafe { let fd = socket(AF_UNIX, SOCK_STREAM, 0); if fd == -1 { - return Err(Error::last_os_error()) + return Err(Error::last_os_error()); } Ok(fd) } @@ -31,7 +31,12 @@ fn bind_socket(fd: RawFd) -> Result<(), Error> { addr.sun_path[i] = byte as i8; } - if bind(fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 { + if bind( + fd, + &addr as *const _ as *const sockaddr, + mem::size_of_val(&addr) as socklen_t, + ) == -1 + { return Err(Error::last_os_error()); } } @@ -61,7 +66,13 @@ fn accept_conn(fd: RawFd) -> Result { fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> { unsafe { let msg_bytes = msg.as_bytes(); - if send(fd, msg_bytes.as_ptr() as *const libc::c_void, msg_bytes.len(), 0)== -1 { + if send( + fd, + msg_bytes.as_ptr() as *const libc::c_void, + msg_bytes.len(), + 0, + ) == -1 + { return Err(Error::last_os_error()); } } @@ -71,7 +82,12 @@ fn send_message(fd: RawFd, msg: &str) -> Result<(), Error> { fn recv_message(fd: RawFd) -> Result { let mut buffer = [0; 1024]; unsafe { - let len = recv(fd, buffer.as_mut_ptr() as *mut libc::c_void, buffer.len(),0); + let len = recv( + fd, + buffer.as_mut_ptr() as *mut libc::c_void, + buffer.len(), + 0, + ); if len == -1 { return Err(Error::last_os_error()); } @@ -82,7 +98,7 @@ fn recv_message(fd: RawFd) -> Result { fn test_stream() -> Result<(), Error> { fs::remove_file(&SOCKET_PATH).ok(); - let server_fd = create_stream_socket()?; + let server_fd = create_stream_socket()?; bind_socket(server_fd)?; listen_socket(server_fd)?; @@ -95,7 +111,7 @@ fn test_stream() -> Result<(), Error> { send_message(client_fd, MSG2).expect("Failed to send message"); println!("Server send finish"); - unsafe {close(client_fd)}; + unsafe { close(client_fd) }; }); let client_fd = create_stream_socket()?; @@ -111,9 +127,14 @@ fn test_stream() -> Result<(), Error> { addr.sun_path[i] = byte as i8; } - if connect(client_fd, &addr as *const _ as *const sockaddr, mem::size_of_val(&addr) as socklen_t) == -1 { + if connect( + client_fd, + &addr as *const _ as *const sockaddr, + mem::size_of_val(&addr) as socklen_t, + ) == -1 + { return Err(Error::last_os_error()); - } + } } send_message(client_fd, MSG1)?; @@ -129,9 +150,16 @@ fn test_stream() -> Result<(), Error> { return Err(Error::last_os_error()); } let sun_path = addrss.sun_path.clone(); - let peer_path:[u8;108] = sun_path.iter().map(|&x| x as u8).collect::>().try_into().unwrap(); - println!("Client: Connected to server at path: {}", String::from_utf8_lossy(&peer_path)); - + let peer_path: [u8; 108] = sun_path + .iter() + .map(|&x| x as u8) + .collect::>() + .try_into() + .unwrap(); + println!( + "Client: Connected to server at path: {}", + String::from_utf8_lossy(&peer_path) + ); } server_thread.join().expect("Server thread panicked"); @@ -139,7 +167,7 @@ fn test_stream() -> Result<(), Error> { let recv_msg = recv_message(client_fd).expect("Failed to receive message from server"); println!("Client Received message: {}", recv_msg); - unsafe {close(client_fd)}; + unsafe { close(client_fd) }; fs::remove_file(&SOCKET_PATH).ok(); Ok(()) @@ -148,6 +176,6 @@ fn test_stream() -> Result<(), Error> { fn main() { match test_stream() { Ok(_) => println!("test for unix stream success"), - Err(_) => println!("test for unix stream failed") + Err(_) => println!("test for unix stream failed"), } -} \ No newline at end of file +}