소스 검색

实现free指令+修复 mountfs的内存泄露问题(#394)

* 实现meminfo文件

* 成功实现free指令,添加了一些string有关函数,并进行一些无影响的小改动


* 解决内存泄露的问题:mountfs inode的wrap方法使用了Arc::into_raw而没有from_raw,导致inode始终无法释放

---------

Co-authored-by: LoGin <[email protected]>
Co-authored-by: longjin <[email protected]>
yuyi2439 1 년 전
부모
커밋
34e6d6c80f

+ 23 - 10
docs/userland/libc/apis/api-list/string.md

@@ -6,20 +6,33 @@
 
 ## 函数列表:
 
-    ``size_t strlen(const char *s)`` : 返回字符串长度
-    
-    ``int strcmp(const char *a,const char *b)`` 比较字符串的字典序
+    ``size_t strlen(const char *s)`` : 获取字符串的长度
 
-    ``char* strncpy(char *dst,const char *src,size_t count)`` 
+    ``int strcmp(const char *a,const char *b)`` : 比较字符串的字典序
 
-        拷贝制定字节数的字符串
+    ``char *strncpy(char *dst, const char *src, size_t count)`` 
 
+        拷贝制定字节数的字符串
         dst: 目标地址
-
         src: 原字符串
-
         count: 字节数
-    
-    ``char* strcpy(char *dst,const char *src)`` : 复制整个字符串
 
-    ``char* strcat(char *dest,const char* src)`` : 拼接两个字符串
+    ``char *strcpy(char *dst,const char *src)`` : 复制整个字符串
+
+    ``char *strcat(char *dest,const char* src)`` : 拼接两个字符串
+
+    ``char *strtok(char *str, const char *delim)`` : 分割字符串
+
+    ``char *strtok_r(char *str, const char *delim, char **saveptr)`` : 分割字符串
+
+**以下函数没有经过检验,不确保正常工作**
+
+    ``size_t strspn(const char *str1, const char *str2)`` : 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标
+
+    ``size_t strcspn(const char *str1, const char *str2)`` : 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符
+
+    ``char *strpbrk(const char *str1, const char *str2)`` : 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符
+
+    ``char *strchr(const char *str, int c)`` : 在字符串中查找第一次出现的字符
+
+    ``char *strrchr(const char *str, int c)`` : 在字符串中查找最后一次出现的字符

+ 15 - 12
kernel/src/arch/x86_64/mm/mod.rs

@@ -14,7 +14,7 @@ use crate::libs::lib_ui::screen_manager::scm_disable_put_to_window;
 use crate::libs::printk::PrintkWriter;
 use crate::libs::spinlock::SpinLock;
 
-use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount};
+use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
 use crate::mm::mmio_buddy::mmio_init;
 use crate::{
     arch::MMArch,
@@ -512,10 +512,7 @@ pub fn test_buddy() {
 pub struct LockedFrameAllocator;
 
 impl FrameAllocator for LockedFrameAllocator {
-    unsafe fn allocate(
-        &mut self,
-        count: crate::mm::allocator::page_frame::PageFrameCount,
-    ) -> Option<(PhysAddr, PageFrameCount)> {
+    unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
             return allocator.allocate(count);
         } else {
@@ -523,19 +520,25 @@ impl FrameAllocator for LockedFrameAllocator {
         }
     }
 
-    unsafe fn free(
-        &mut self,
-        address: crate::mm::PhysAddr,
-        count: crate::mm::allocator::page_frame::PageFrameCount,
-    ) {
+    unsafe fn free(&mut self, address: crate::mm::PhysAddr, count: PageFrameCount) {
         assert!(count.data().is_power_of_two());
         if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
             return allocator.free(address, count);
         }
     }
 
-    unsafe fn usage(&self) -> crate::mm::allocator::page_frame::PageFrameUsage {
-        todo!()
+    unsafe fn usage(&self) -> PageFrameUsage {
+        if let Some(ref mut allocator) = *INNER_ALLOCATOR.lock_irqsave() {
+            return allocator.usage();
+        } else {
+            panic!("usage error");
+        }
+    }
+}
+
+impl LockedFrameAllocator {
+    pub fn get_usage(&self) -> PageFrameUsage {
+        unsafe { self.usage() }
     }
 }
 

+ 1 - 1
kernel/src/filesystem/devfs/mod.rs

@@ -562,7 +562,7 @@ pub fn devfs_init() -> Result<(), SystemError> {
     static INIT: Once = Once::new();
     let mut result = None;
     INIT.call_once(|| {
-        kinfo!("Initializing ProcFS...");
+        kinfo!("Initializing DevFS...");
         // 创建 devfs 实例
         let devfs: Arc<DevFS> = DevFS::new();
         // devfs 挂载

+ 64 - 14
kernel/src/filesystem/procfs/mod.rs

@@ -10,6 +10,7 @@ use alloc::{
 };
 
 use crate::{
+    arch::mm::LockedFrameAllocator,
     filesystem::vfs::{
         core::{generate_inode_id, ROOT_INODE},
         FileType,
@@ -37,6 +38,8 @@ use super::vfs::{
 pub enum ProcFileType {
     ///展示进程状态信息
     ProcStatus = 0,
+    /// meminfo
+    ProcMeminfo = 1,
     //todo: 其他文件类型
     ///默认文件类型
     Default,
@@ -46,6 +49,7 @@ impl From<u8> for ProcFileType {
     fn from(value: u8) -> Self {
         match value {
             0 => ProcFileType::ProcStatus,
+            1 => ProcFileType::ProcMeminfo,
             _ => ProcFileType::Default,
         }
     }
@@ -204,8 +208,34 @@ impl ProcFSInode {
         return Ok((pdata.len() * size_of::<u8>()) as i64);
     }
 
-    /// status文件读取函数
-    fn read_status(
+    /// 打开 meminfo 文件
+    fn open_meminfo(&self, pdata: &mut ProcfsFilePrivateData) -> Result<i64, SystemError> {
+        // 获取内存信息
+        let usage = LockedFrameAllocator.get_usage();
+
+        // 传入数据
+        let data: &mut Vec<u8> = &mut pdata.data;
+
+        data.append(
+            &mut format!("MemTotal:\t{} kB\n", usage.total().bytes() >> 10)
+                .as_bytes()
+                .to_owned(),
+        );
+
+        data.append(
+            &mut format!("MemFree:\t{} kB\n", usage.free().bytes() >> 10)
+                .as_bytes()
+                .to_owned(),
+        );
+
+        // 去除多余的\0
+        self.trim_string(data);
+
+        return Ok((data.len() * size_of::<u8>()) as i64);
+    }
+
+    /// proc文件系统读取函数
+    fn proc_read(
         &self,
         offset: usize,
         len: usize,
@@ -263,7 +293,7 @@ impl ProcFS {
                     mtime: TimeSpec::default(),
                     ctime: TimeSpec::default(),
                     file_type: FileType::Dir,
-                    mode: ModeType::from_bits_truncate(0o777),
+                    mode: ModeType::from_bits_truncate(0o555),
                     nlinks: 1,
                     uid: 0,
                     gid: 0,
@@ -286,6 +316,24 @@ impl ProcFS {
         // 释放锁
         drop(root_guard);
 
+        // 创建meminfo文件
+        let inode = result.root_inode();
+        let binding = inode.create(
+            "meminfo",
+            FileType::File,
+            ModeType::from_bits_truncate(0o444),
+        );
+        if let Ok(meminfo) = binding {
+            let meminfo_file = meminfo
+                .as_any_ref()
+                .downcast_ref::<LockedProcFSInode>()
+                .unwrap();
+            meminfo_file.0.lock().fdata.pid = Pid::new(0);
+            meminfo_file.0.lock().fdata.ftype = ProcFileType::ProcMeminfo;
+        } else {
+            panic!("create meminfo error");
+        }
+
         return result;
     }
 
@@ -293,26 +341,26 @@ impl ProcFS {
     /// @usage 在进程中调用并创建进程对应文件
     pub fn register_pid(&self, pid: Pid) -> Result<(), SystemError> {
         // 获取当前inode
-        let proc: Arc<dyn IndexNode> = self.root_inode();
+        let inode: Arc<dyn IndexNode> = self.root_inode();
         // 创建对应进程文件夹
-        let _pf: Arc<dyn IndexNode> = proc.create(
+        let pid_dir: Arc<dyn IndexNode> = inode.create(
             &pid.to_string(),
             FileType::Dir,
-            ModeType::from_bits_truncate(0o777),
+            ModeType::from_bits_truncate(0o555),
         )?;
         // 创建相关文件
         // status文件
-        let binding: Arc<dyn IndexNode> = _pf.create(
+        let binding: Arc<dyn IndexNode> = pid_dir.create(
             "status",
             FileType::File,
-            ModeType::from_bits_truncate(0o777),
+            ModeType::from_bits_truncate(0o444),
         )?;
-        let _sf: &LockedProcFSInode = binding
+        let status_file: &LockedProcFSInode = binding
             .as_any_ref()
             .downcast_ref::<LockedProcFSInode>()
             .unwrap();
-        _sf.0.lock().fdata.pid = pid;
-        _sf.0.lock().fdata.ftype = ProcFileType::ProcStatus;
+        status_file.0.lock().fdata.pid = pid;
+        status_file.0.lock().fdata.ftype = ProcFileType::ProcStatus;
 
         //todo: 创建其他文件
 
@@ -352,6 +400,7 @@ impl IndexNode for LockedProcFSInode {
         // 根据文件类型获取相应数据
         let file_size = match inode.fdata.ftype {
             ProcFileType::ProcStatus => inode.open_status(&mut private_data)?,
+            ProcFileType::ProcMeminfo => inode.open_meminfo(&mut private_data)?,
             _ => {
                 todo!()
             }
@@ -409,7 +458,8 @@ impl IndexNode for LockedProcFSInode {
 
         // 根据文件类型读取相应数据
         match inode.fdata.ftype {
-            ProcFileType::ProcStatus => return inode.read_status(offset, len, buf, private_data),
+            ProcFileType::ProcStatus => return inode.proc_read(offset, len, buf, private_data),
+            ProcFileType::ProcMeminfo => return inode.proc_read(offset, len, buf, private_data),
             ProcFileType::Default => (),
         };
 
@@ -720,10 +770,10 @@ pub fn procfs_init() -> Result<(), SystemError> {
     let mut result = None;
     INIT.call_once(|| {
         kinfo!("Initializing ProcFS...");
-        // 创建 sysfs 实例
+        // 创建 procfs 实例
         let procfs: Arc<ProcFS> = ProcFS::new();
 
-        // sysfs 挂载
+        // procfs 挂载
         let _t = ROOT_INODE()
             .find("proc")
             .expect("Cannot find /proc")

+ 1 - 1
kernel/src/filesystem/vfs/file.rs

@@ -261,7 +261,6 @@ impl File {
             self.readdir_subdirs_name = inode.list()?;
             self.readdir_subdirs_name.sort();
         }
-
         // kdebug!("sub_entries={sub_entries:?}");
         if self.readdir_subdirs_name.is_empty() {
             self.offset = 0;
@@ -513,6 +512,7 @@ impl FileDescriptorVec {
 
         // 把文件描述符数组对应位置设置为空
         let file = self.fds[fd as usize].take().unwrap();
+
         assert!(Arc::strong_count(&file) == 1);
         return Ok(());
     }

+ 3 - 3
kernel/src/filesystem/vfs/mount.rs

@@ -63,11 +63,11 @@ impl MountFS {
         let weak: Weak<MountFS> = Arc::downgrade(&mount_fs);
 
         // 将Arc指针转为Raw指针并对其内部的self_ref字段赋值
-        let ptr: *mut MountFS = Arc::into_raw(mount_fs) as *mut Self;
+        let ptr: *mut MountFS = mount_fs.as_ref() as *const Self as *mut Self;
         unsafe {
             (*ptr).self_ref = weak;
             // 返回初始化好的MountFS对象
-            return Arc::from_raw(ptr);
+            return mount_fs;
         }
     }
 
@@ -97,7 +97,7 @@ impl MountFSInode {
         let weak: Weak<MountFSInode> = Arc::downgrade(&inode);
         // 将Arc指针转为Raw指针并对其内部的self_ref字段赋值
         compiler_fence(Ordering::SeqCst);
-        let ptr: *mut MountFSInode = Arc::into_raw(inode.clone()) as *mut Self;
+        let ptr: *mut MountFSInode = inode.as_ref() as *const Self as *mut Self;
         compiler_fence(Ordering::SeqCst);
         unsafe {
             (*ptr).self_ref = weak;

+ 8 - 2
kernel/src/filesystem/vfs/syscall.rs

@@ -184,6 +184,7 @@ impl Syscall {
         }
 
         // 创建文件对象
+
         let mut file: File = File::new(inode, mode)?;
 
         // 打开模式为“追加”
@@ -210,7 +211,9 @@ impl Syscall {
         let binding = ProcessManager::current_pcb().fd_table();
         let mut fd_table_guard = binding.write();
 
-        return fd_table_guard.drop_fd(fd as i32).map(|_| 0);
+        let res = fd_table_guard.drop_fd(fd as i32).map(|_| 0);
+
+        return res;
     }
 
     /// @brief 根据文件描述符,读取文件数据。尝试读取的数据长度与buf的长度相同。
@@ -389,7 +392,10 @@ impl Syscall {
 
         // drop guard 以避免无法调度的问题
         drop(fd_table_guard);
-        return file.lock_no_preempt().readdir(dirent).map(|x| x as usize);
+
+        let res = file.lock_no_preempt().readdir(dirent).map(|x| x as usize);
+
+        return res;
     }
 
     /// @brief 创建文件夹

+ 16 - 3
kernel/src/mm/allocator/buddy.rs

@@ -65,6 +65,8 @@ impl<A> PageList<A> {
 pub struct BuddyAllocator<A> {
     // 存放每个阶的空闲“链表”的头部地址
     free_area: [PhysAddr; (MAX_ORDER - MIN_ORDER) as usize],
+    /// 总页数
+    total: PageFrameCount,
     phantom: PhantomData<A>,
 }
 
@@ -227,9 +229,9 @@ impl<A: MemoryManagementArch> BuddyAllocator<A> {
         assert!(remain_bytes == 0);
         assert!(paddr == initial_bump_offset + pages_to_buddy.data() * A::PAGE_SIZE);
 
-        // Self::print_free_area(free_area);
         let allocator = Self {
             free_area,
+            total: pages_to_buddy,
             phantom: PhantomData,
         };
 
@@ -357,7 +359,6 @@ impl<A: MemoryManagementArch> BuddyAllocator<A> {
             }
             return None;
         };
-
         let result: Option<PhysAddr> = alloc_in_specific_order(order as u8);
         // kdebug!("result={:?}", result);
         if result.is_some() {
@@ -662,7 +663,19 @@ impl<A: MemoryManagementArch> FrameAllocator for BuddyAllocator<A> {
     }
 
     unsafe fn usage(&self) -> PageFrameUsage {
-        todo!("BuddyAllocator::usage")
+        let mut free_page_num: usize = 0;
+        for index in 0..(MAX_ORDER - MIN_ORDER) {
+            let mut pagelist: PageList<A> = Self::read_page(self.free_area[index]);
+            loop {
+                free_page_num += pagelist.entry_num << index;
+                if pagelist.next_page.is_null() {
+                    break;
+                }
+                pagelist = Self::read_page(pagelist.next_page);
+            }
+        }
+        let free = PageFrameCount::new(free_page_num);
+        PageFrameUsage::new(self.total - free, self.total)
     }
 }
 

+ 1 - 1
kernel/src/mm/allocator/page_frame.rs

@@ -273,7 +273,7 @@ impl PageFrameUsage {
     }
     // @brief 获取空闲的页帧数量
     pub fn free(&self) -> PageFrameCount {
-        return PageFrameCount(self.total.0 - self.used.0);
+        return self.total - self.used;
     }
     // @brief 获取总的页帧数量
     pub fn total(&self) -> PageFrameCount {

+ 6 - 2
kernel/src/syscall/mod.rs

@@ -417,9 +417,9 @@ impl Syscall {
                     Err(SystemError::EINVAL)
                 } else {
                     let path: &str = path.unwrap();
+
                     let flags = args[1];
                     let open_flags: FileMode = FileMode::from_bits_truncate(flags as u32);
-
                     Self::open(path, open_flags)
                 };
 
@@ -427,7 +427,10 @@ impl Syscall {
             }
             SYS_CLOSE => {
                 let fd = args[0];
-                Self::close(fd)
+
+                let res = Self::close(fd);
+
+                res
             }
             SYS_READ => {
                 let fd = args[0] as i32;
@@ -545,6 +548,7 @@ impl Syscall {
 
             SYS_GET_DENTS => {
                 let fd = args[0] as i32;
+
                 let buf_vaddr = args[1];
                 let len = args[2];
                 let virt_addr: VirtAddr = VirtAddr::new(buf_vaddr);

+ 5 - 5
user/apps/shell/cmd.c

@@ -320,7 +320,7 @@ int shell_cmd_cat(int argc, char **argv)
     char *file_path = get_target_filepath(argv[1], &path_len);
 
     // 打开文件
-    int fd = open(file_path, 0);
+    int fd = open(file_path, O_RDONLY);
     if (fd <= 0)
     {
         printf("ERROR: Cannot open file: %s, fd=%d\n", file_path, fd);
@@ -593,13 +593,13 @@ int shell_cmd_free(int argc, char **argv)
     printf("Mem:\t");
     if (argc == 1) // 按照kb显示
     {
-        printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 10, mst.used >> 10, mst.free >> 10, mst.shared >> 10,
-               mst.cache_used >> 10, mst.available >> 10);
+        printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total, mst.used, mst.free, mst.shared,
+               mst.cache_used, mst.available);
     }
     else // 按照MB显示
     {
-        printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 20, mst.used >> 20, mst.free >> 20, mst.shared >> 20,
-               mst.cache_used >> 20, mst.available >> 20);
+        printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 10, mst.used >> 10, mst.free >> 10, mst.shared >> 10,
+               mst.cache_used >> 10, mst.available >> 10);
     }
 
 done:;

+ 74 - 8
user/libs/libc/src/include/export/string.h

@@ -7,21 +7,21 @@ extern  "C"  {
 #endif
 
 void *memset(void *dst, unsigned char C, uint64_t size);
+
 /**
- * @brief 获取字符串的大小
+ * @brief 获取字符串的长度
  *
  * @param s 字符串
- * @return size_t 大小
+ * @return size_t 长度
  */
 size_t strlen(const char *s);
 
 /*
-        比较字符串 FirstPart and SecondPart
-        FirstPart = SecondPart =>  0
-        FirstPart > SecondPart =>  1
-        FirstPart < SecondPart => -1
+    比较字符串 FirstPart and SecondPart
+    FirstPart = SecondPart =>  0
+    FirstPart > SecondPart =>  1
+    FirstPart < SecondPart => -1
 */
-
 int strcmp(const char *FirstPart, const char *SecondPart);
 
 /**
@@ -32,7 +32,7 @@ int strcmp(const char *FirstPart, const char *SecondPart);
  * @param Count 字节数
  * @return char*
  */
-char *strncpy(char *dst, const char *src, size_t Count);
+char *strncpy(char *dst, const char *src, size_t count);
 
 /**
  * @brief 拷贝整个字符串
@@ -82,6 +82,72 @@ static void *memcpy(void *dst, const void *src, long Num)
     return dst;
 }
 
+/**
+ * @brief 分割字符串
+ *
+ * @param str 要被分解成一组小字符串的字符串
+ * @param delim 包含分隔符的字符串
+ * @return 分割结果
+ */
+char *strtok(char *str, const char *delim);
+
+/**
+ * @brief 分割字符串
+ *
+ * @param str 要被分解成一组小字符串的字符串
+ * @param delim 包含分隔符的字符串
+ * @param saveptr 用于存储当前操作的字符串
+ * @return 分割结果
+ */
+char *strtok_r(char *str, const char *delim, char **saveptr);
+
+//! 以下函数没有经过检验,不确保正常工作
+
+/**
+ * @brief 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标
+ *
+ * @param str1 被检索的字符串
+ * @param str2 进行匹配的字符列表
+ * @return str1 中第一个不在字符串 str2 中出现的字符下标
+ */
+size_t strspn(const char *str1, const char *str2);
+
+/**
+ * @brief 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符
+ *
+ * @param str1 被检索的字符串
+ * @param str2 进行匹配的字符列表
+ * @return str1 开头连续都不含字符串 str2 中字符的字符数
+ */
+size_t strcspn(const char *str1, const char *str2);
+
+/**
+ * @brief 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符
+ *
+ * @param str1 被检索的字符串
+ * @param str2 进行匹配的字符列表
+ * @return str1 中第一个匹配字符串 str2 中字符的指针,如果未找到字符则返回 NULL
+ */
+char *strpbrk(const char *str1, const char *str2);
+
+/**
+ * @brief 在字符串中查找第一次出现的字符
+ *
+ * @param str 被查找的字符串
+ * @param c 要查找的字符
+ * @return 指向找到的字符的指针,如果未找到该字符则返回 NULL
+ */
+char *strchr(const char *str, int c);
+
+/**
+ * @brief 在字符串中查找最后一次出现的字符
+ *
+ * @param str 被查找的字符串
+ * @param c 要查找的字符
+ * @return 指向找到的字符的指针,如果未找到该字符则返回 NULL
+ */
+char *strrchr(const char *str, int c);
+
 #if defined(__cplusplus) 
 }  /* extern "C" */ 
 #endif

+ 1 - 1
user/libs/libc/src/include/export/sys/stat.h

@@ -2,7 +2,7 @@
 #include <sys/types.h>
 
 /**
- * @brief 系统内存信息结构体(单位:字节
+ * @brief 系统内存信息结构体(单位:kB
  *
  */
 struct mstat_t

+ 139 - 24
user/libs/libc/src/string.c

@@ -1,4 +1,5 @@
 #include <string.h>
+#include <stddef.h>
 
 size_t strlen(const char *s)
 {
@@ -57,15 +58,7 @@ void *memset(void *dst, unsigned char C, uint64_t size)
     return dst;
 }
 
-/**
- * @brief 拷贝指定字节数的字符串
- *
- * @param dst 目标地址
- * @param src 源字符串
- * @param Count 字节数
- * @return char*
- */
-char *strncpy(char *dst, const char *src, size_t Count)
+char *strncpy(char *dst, const char *src, size_t count)
 {
     __asm__ __volatile__("cld	\n\t"
                          "1:	\n\t"
@@ -79,31 +72,17 @@ char *strncpy(char *dst, const char *src, size_t Count)
                          "stosb	\n\t"
                          "2:	\n\t"
                          :
-                         : "S"(src), "D"(dst), "c"(Count)
+                         : "S"(src), "D"(dst), "c"(count)
                          : "ax", "memory");
     return dst;
 }
 
-/**
- * @brief 拼接两个字符串(将src接到dest末尾)
- *
- * @param dest 目标串
- * @param src 源串
- * @return char*
- */
 char *strcat(char *dest, const char *src)
 {
     strcpy(dest + strlen(dest), src);
     return dest;
 }
 
-/**
- * @brief 拷贝整个字符串
- *
- * @param dst 目标地址
- * @param src 源地址
- * @return char* 目标字符串
- */
 char *strcpy(char *dst, const char *src)
 {
     while (*src)
@@ -113,4 +92,140 @@ char *strcpy(char *dst, const char *src)
     *dst = 0;
 
     return dst;
+}
+
+char *strtok(char *str, const char *delim)
+{
+    static char *saveptr;
+    return strtok_r(str, delim, &saveptr);
+}
+
+char *strtok_r(char *str, const char *delim, char **saveptr)
+{
+    char *end;
+    if (str == NULL)
+        str = *saveptr;
+    if (*str == '\0')
+    {
+        *saveptr = str;
+        return NULL;
+    }
+    str += strspn(str, delim);
+    if (*str == '\0')
+    {
+        *saveptr = str;
+        return NULL;
+    }
+    end = str + strcspn(str, delim);
+    if (*end == '\0')
+    {
+        *saveptr = end;
+        return str;
+    }
+    *end = '\0';
+    *saveptr = end + 1;
+    return str;
+}
+
+size_t strspn(const char *str1, const char *str2)
+{
+    if (str1 == NULL || str2 == NULL)
+        return 0;
+    bool cset[256] = {0};
+    while ((*str2) != '\0')
+    {
+        cset[*str2] = 1;
+        ++str2;
+    }
+    int index = 0;
+    while (str1[index] != '\0')
+    {
+        if (cset[str1[index]])
+            index++;
+        else
+            break;
+    }
+    return index;
+}
+
+size_t strcspn(const char *str1, const char *str2)
+{
+    if (str1 == NULL || str2 == NULL)
+        return 0;
+    bool cset[256] = {0};
+    while ((*str2) != '\0')
+    {
+        cset[*str2] = 1;
+        ++str2;
+    }
+    int len = 0;
+    while (str1[len] != '\0')
+    {
+        if (!cset[str1[len]])
+            len++;
+        else
+            break;
+    }
+    return len;
+}
+
+char *strpbrk(const char *str1, const char *str2)
+{
+    typedef unsigned char uchar;
+
+    if (str1 == NULL || str2 == NULL)
+        return NULL;
+    uchar cset[32] = {0};
+    while ((*str2) != '\0')
+    {
+        uchar t = (uchar)*str2++;
+        cset[t % 32] |= 1 << (t / 32);
+    }
+    while ((*str1) != '\0')
+    {
+        uchar t = (uchar)*str1;
+        if (cset[t % 32] & (1 << (t / 32)))
+        {
+            return (char *)str1;
+        }
+        else
+        {
+            ++str1;
+        }
+    }
+    return NULL;
+}
+
+char *strchr(const char *str, int c)
+{
+    if (str == NULL)
+        return NULL;
+
+    while (*str != '\0')
+    {
+        if (*str == c)
+        {
+            return str;
+        }
+        str++;
+    }
+    return NULL;
+}
+
+char *strrchr(const char *str, int c)
+{
+    if (str == NULL)
+        return NULL;
+
+    char *p_char = NULL;
+    while (*str != '\0')
+    {
+        if (*str == (char)c)
+        {
+            p_char = (char *)str;
+        }
+        str++;
+    }
+
+    return p_char;
 }

+ 42 - 1
user/libs/libc/src/sys/stat.c

@@ -1,5 +1,10 @@
 #include <sys/stat.h>
 #include <libsystem/syscall.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
 
 int mkdir(const char *path, mode_t mode)
 {
@@ -14,5 +19,41 @@ int mkdir(const char *path, mode_t mode)
  */
 int mstat(struct mstat_t *stat)
 {
-    return syscall_invoke(SYS_MSTAT, (uint64_t)stat, 0, 0, 0, 0, 0, 0, 0);
+    char *buf = (char *)malloc(128);
+    memset(buf, 0, 128);
+    int fd = open("/proc/meminfo", O_RDONLY);
+    if (fd <= 0)
+    {
+        printf("ERROR: Cannot open file: /proc/meminfo, fd=%d\n", fd);
+        return -1;
+    }
+    read(fd, buf, 127);
+    close(fd);
+    char *str = strtok(buf, "\n\t");
+    char *value = (char *)malloc(strlen(str) - 3);
+    int count = 0;
+    while (str != NULL)
+    {
+        // printf("%d: %s\n", count, str);
+        switch (count)
+        {
+        case 1:
+            strncpy(value, str, strlen(str) - 3);
+            stat->total = atoi(value);
+            break;
+        case 3:
+            strncpy(value, str, strlen(str) - 3);
+            stat->free = atoi(value);
+            break;
+        default:
+            break;
+        }
+        str = strtok(NULL, "\n\t");
+        count++;
+    }
+    stat->used = stat->total - stat->free;
+
+    free(buf);
+    free(value);
+    return 0;
 }

+ 2 - 1
user/libs/libsystem/syscall.h

@@ -26,7 +26,8 @@
 #define SYS_CLOCK 19     // 获取当前cpu时间
 #define SYS_PIPE 20
 
-#define SYS_MSTAT 21        // 获取系统的内存状态信息
+// 现在已经废弃
+// #define SYS_MSTAT 21        // 获取系统的内存状态信息
 #define SYS_UNLINK_AT 22    // 删除文件夹/删除文件链接
 #define SYS_KILL 23         // kill一个进程(向这个进程发出信号)
 #define SYS_SIGACTION 24    // 设置进程的信号处理动作