Browse Source

增加getrusage,并把apic timer的频率调整为系统HZ (#435)

LoGin 1 year ago
parent
commit
be8cdf4b8e

+ 2 - 1
kernel/src/arch/x86_64/driver/apic/apic_timer.rs

@@ -8,6 +8,7 @@ use crate::mm::percpu::PerCpu;
 use crate::sched::core::sched_update_jiffies;
 use crate::smp::core::smp_get_processor_id;
 use crate::syscall::SystemError;
+use crate::time::clocksource::HZ;
 pub use drop;
 use x86::cpuid::cpuid;
 use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT};
@@ -110,7 +111,7 @@ pub enum LocalApicTimerMode {
 
 impl LocalApicTimer {
     /// 定时器中断的间隔
-    pub const INTERVAL_MS: u64 = 5;
+    pub const INTERVAL_MS: u64 = 1000 / HZ as u64;
     pub const DIVISOR: u64 = 3;
 
     /// IoApicManager 初值为0或false

+ 0 - 8
kernel/src/common/time.h

@@ -4,11 +4,3 @@
 
 // 操作系统定义时间以ns为单位
 #define CLOCKS_PER_SEC 1000000
-
-
-/**
- * @brief 获取当前的CPU时间
- *
- * @return uint64_t timer_jiffies
- */
-extern uint64_t rs_clock();

+ 1 - 0
kernel/src/process/mod.rs

@@ -61,6 +61,7 @@ pub mod init;
 pub mod kthread;
 pub mod pid;
 pub mod process;
+pub mod resource;
 pub mod syscall;
 
 /// 系统中所有进程的pcb

+ 85 - 0
kernel/src/process/resource.rs

@@ -0,0 +1,85 @@
+use crate::{syscall::SystemError, time::TimeSpec};
+
+use super::ProcessControlBlock;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[repr(C)]
+pub struct RUsage {
+    /// User time used
+    pub ru_utime: TimeSpec,
+    /// System time used
+    pub ru_stime: TimeSpec,
+
+    // 以下是linux的rusage结构体扩展
+    /// Maximum resident set size
+    pub ru_maxrss: usize,
+    /// Integral shared memory size
+    pub ru_ixrss: usize,
+    /// Integral unshared data size
+    pub ru_idrss: usize,
+    /// Integral unshared stack size
+    pub ru_isrss: usize,
+    /// Page reclaims (soft page faults)
+    pub ru_minflt: usize,
+    /// Page faults (hard page faults)
+    pub ru_majflt: usize,
+    /// Swaps
+    pub ru_nswap: usize,
+    /// Block input operations
+    pub ru_inblock: usize,
+    /// Block output operations
+    pub ru_oublock: usize,
+    /// IPC messages sent
+    pub ru_msgsnd: usize,
+    /// IPC messages received
+    pub ru_msgrcv: usize,
+    /// Signals received
+    pub ru_nsignals: usize,
+    /// Voluntary context switches
+    pub ru_nvcsw: usize,
+    /// Involuntary context switches
+    pub ru_nivcsw: usize,
+}
+
+///
+///  Definition of struct rusage taken from BSD 4.3 Reno
+///
+///  We don't support all of these yet, but we might as well have them....
+///  Otherwise, each time we add new items, programs which depend on this
+///  structure will lose.  This reduces the chances of that happening.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum RUsageWho {
+    RUsageSelf = 0,
+    RUsageChildren = -1,
+    /// sys_wait4() uses this
+    RUsageBoth = -2,
+    /// only the calling thread
+    RusageThread = 1,
+}
+
+impl TryFrom<i32> for RUsageWho {
+    type Error = SystemError;
+
+    fn try_from(value: i32) -> Result<Self, Self::Error> {
+        match value {
+            0 => Ok(RUsageWho::RUsageSelf),
+            -1 => Ok(RUsageWho::RUsageChildren),
+            -2 => Ok(RUsageWho::RUsageBoth),
+            1 => Ok(RUsageWho::RusageThread),
+            _ => Err(SystemError::EINVAL),
+        }
+    }
+}
+
+impl ProcessControlBlock {
+    /// 获取进程资源使用情况
+    ///
+    /// ## TODO
+    ///
+    /// 当前函数尚未实现,只是返回了一个默认的RUsage结构体
+    pub fn get_rusage(&self, _who: RUsageWho) -> Option<RUsage> {
+        let rusage = RUsage::default();
+
+        Some(rusage)
+    }
+}

+ 13 - 0
kernel/src/process/syscall.rs

@@ -9,6 +9,7 @@ use alloc::{
 use super::{
     abi::WaitOption,
     fork::{CloneFlags, KernelCloneArgs},
+    resource::{RUsage, RUsageWho},
     KernelStack, Pid, ProcessManager, ProcessState,
 };
 use crate::{
@@ -320,4 +321,16 @@ impl Syscall {
         // todo: 增加credit功能之后,需要修改
         return Ok(0);
     }
+
+    pub fn get_rusage(who: i32, rusage: *mut RUsage) -> Result<usize, SystemError> {
+        let who = RUsageWho::try_from(who)?;
+        let mut writer = UserBufferWriter::new(rusage, core::mem::size_of::<RUsage>(), true)?;
+        let pcb = ProcessManager::current_pcb();
+        let rusage = pcb.get_rusage(who).ok_or(SystemError::EINVAL)?;
+
+        let ubuf = writer.buffer::<RUsage>(0).unwrap();
+        ubuf.copy_from_slice(&[rusage]);
+
+        return Ok(0);
+    }
 }

+ 7 - 1
kernel/src/syscall/mod.rs

@@ -5,7 +5,7 @@ use core::{
 
 use crate::{
     libs::{futex::constant::FutexFlag, rand::GRandFlags},
-    process::fork::KernelCloneArgs,
+    process::{fork::KernelCloneArgs, resource::RUsage},
 };
 
 use num_traits::{FromPrimitive, ToPrimitive};
@@ -400,6 +400,7 @@ pub const SYS_CHDIR: usize = 80;
 pub const SYS_MKDIR: usize = 83;
 
 pub const SYS_GETTIMEOFDAY: usize = 96;
+pub const SYS_GETRUSAGE: usize = 98;
 
 pub const SYS_GETUID: usize = 102;
 pub const SYS_SYSLOG: usize = 103;
@@ -1164,6 +1165,11 @@ impl Syscall {
             }
             SYS_GETEUID => Self::geteuid().map(|euid| euid.into()),
             SYS_GETEGID => Self::getegid().map(|egid| egid.into()),
+            SYS_GETRUSAGE => {
+                let who = args[0] as c_int;
+                let rusage = args[1] as *mut RUsage;
+                Self::get_rusage(who, rusage)
+            }
 
             _ => panic!("Unsupported syscall ID: {}", syscall_num),
         };

+ 1 - 1
kernel/src/time/clocksource.rs

@@ -40,7 +40,7 @@ pub static mut FINISHED_BOOTING: AtomicBool = AtomicBool::new(false);
 
 /// Interval: 0.5sec Threshold: 0.0625s
 /// 系统节拍率
-pub const HZ: u64 = 1000;
+pub const HZ: u64 = 250;
 /// watchdog检查间隔
 pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
 /// 最大能接受的误差大小

+ 4 - 6
kernel/src/time/timekeeping.rs

@@ -1,6 +1,5 @@
 use alloc::sync::Arc;
 use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering};
-use x86_64::align_up;
 
 use crate::{
     arch::CurrentIrqArch,
@@ -238,9 +237,6 @@ pub fn timekeeping_init() {
 
 /// # 使用当前时钟源增加wall time
 pub fn update_wall_time() {
-    let rsp = unsafe { crate::include::bindings::bindings::get_rsp() } as usize;
-    let _stack_use = align_up(rsp as u64, 32768) - rsp as u64;
-
     // kdebug!("enter update_wall_time, stack_use = {:}",stack_use);
     compiler_fence(Ordering::SeqCst);
     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
@@ -267,7 +263,8 @@ pub fn update_wall_time() {
     // }
     // ================
     compiler_fence(Ordering::SeqCst);
-    // 一分钟同步一次
+
+    // !!! todo: 这里是硬编码了HPET的500us中断,需要修改
     __ADDED_USEC.fetch_add(500, Ordering::SeqCst);
     compiler_fence(Ordering::SeqCst);
     let mut retry = 10;
@@ -279,6 +276,7 @@ pub fn update_wall_time() {
         __ADDED_SEC.fetch_add(1, Ordering::SeqCst);
         compiler_fence(Ordering::SeqCst);
     }
+    // 一分钟同步一次
     loop {
         if (usec & !((1 << 26) - 1)) != 0 {
             if __ADDED_USEC
@@ -289,7 +287,7 @@ pub fn update_wall_time() {
                 // 同步时间
                 // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
                 // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
-                let mut timekeeper = timekeeper().0.write();
+                let mut timekeeper = timekeeper().0.write_irqsave();
                 timekeeper.xtime.tv_nsec = ktime_get_real_ns();
                 timekeeper.xtime.tv_sec = 0;
                 __ADDED_SEC.store(0, Ordering::SeqCst);

+ 0 - 4
kernel/src/time/timer.h

@@ -7,9 +7,5 @@
 #define MAX_TIMEOUT (int64_t)((1ul << 63) - 1)
 
 extern void rs_timer_init();
-extern int64_t rs_timer_get_first_expire();
-extern uint64_t rs_timer_next_n_ms_jiffies(uint64_t expire_ms);
-extern int64_t rs_schedule_timeout(int64_t timeout);
 
-extern uint64_t rs_clock();
 extern void rs_jiffies_init();

+ 6 - 42
kernel/src/time/timer.rs

@@ -16,7 +16,7 @@ use crate::{
         softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
         InterruptArch,
     },
-    kdebug, kerror, kinfo,
+    kerror, kinfo,
     libs::spinlock::SpinLock,
     process::{ProcessControlBlock, ProcessManager},
     syscall::SystemError,
@@ -253,6 +253,7 @@ pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 {
 pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
     // kdebug!("schedule_timeout");
     if timeout == MAX_TIMEOUT {
+        ProcessManager::mark_sleep(true).ok();
         sched();
         return Ok(MAX_TIMEOUT);
     } else if timeout < 0 {
@@ -287,7 +288,7 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
     // FIXME
     // kdebug!("rs_timer_get_first_expire,timer_jif = {:?}", TIMER_JIFFIES);
     for _ in 0..10 {
-        match TIMER_LIST.try_lock() {
+        match TIMER_LIST.try_lock_irqsave() {
             Ok(timer_list) => {
                 // kdebug!("rs_timer_get_first_expire TIMER_LIST lock successfully");
                 if timer_list.is_empty() {
@@ -305,6 +306,9 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
     return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
 }
 
+/// 更新系统时间片
+///
+/// todo: 这里的实现有问题,貌似把HPET的500us当成了500个jiffies,然后update_wall_time()里面也硬编码了这个500us
 pub fn update_timer_jiffies(add_jiffies: u64) -> u64 {
     let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);
     compiler_fence(Ordering::SeqCst);
@@ -317,50 +321,10 @@ pub fn update_timer_jiffies(add_jiffies: u64) -> u64 {
 pub fn clock() -> u64 {
     return TIMER_JIFFIES.load(Ordering::SeqCst);
 }
-// ====== 重构完成后请删掉extern C ======
-#[no_mangle]
-pub extern "C" fn rs_clock() -> u64 {
-    clock()
-}
 
 // ====== 以下为给C提供的接口 ======
-#[no_mangle]
-pub extern "C" fn rs_schedule_timeout(timeout: i64) -> i64 {
-    match schedule_timeout(timeout) {
-        Ok(v) => {
-            return v;
-        }
-        Err(e) => {
-            kdebug!("rs_schedule_timeout run failed");
-            return e.to_posix_errno() as i64;
-        }
-    }
-}
 
 #[no_mangle]
 pub extern "C" fn rs_timer_init() {
     timer_init();
 }
-
-#[no_mangle]
-pub extern "C" fn rs_timer_next_n_ms_jiffies(expire_ms: u64) -> u64 {
-    return next_n_ms_timer_jiffies(expire_ms);
-}
-
-#[no_mangle]
-pub extern "C" fn rs_timer_next_n_us_jiffies(expire_us: u64) -> u64 {
-    return next_n_us_timer_jiffies(expire_us);
-}
-
-#[no_mangle]
-pub extern "C" fn rs_timer_get_first_expire() -> i64 {
-    match timer_get_first_expire() {
-        Ok(v) => return v as i64,
-        Err(_) => return 0,
-    }
-}
-
-#[no_mangle]
-pub extern "C" fn rs_update_timer_jiffies(add_jiffies: u64) -> u64 {
-    return update_timer_jiffies(add_jiffies);
-}