diff --git a/kernel/src/fs/device.rs b/kernel/src/fs/device.rs index a6b0dcc95..80e05599c 100644 --- a/kernel/src/fs/device.rs +++ b/kernel/src/fs/device.rs @@ -41,49 +41,64 @@ pub enum DeviceType { MiscDevice, } -/// Device Id -#[derive(Clone, Copy)] -pub struct DeviceId(u64); - -impl DeviceId { - pub fn new(major: u32, minor: u32) -> Self { - let major = major as u64; - let minor = minor as u64; - Self( - ((major & 0xffff_f000) << 32) - | ((major & 0x0000_0fff) << 8) - | ((minor & 0xffff_ff00) << 12) - | (minor & 0x0000_00ff), - ) - } - - pub fn major(&self) -> u32 { - ((self.0 >> 32) & 0xffff_f000 | (self.0 >> 8) & 0x0000_0fff) as u32 - } - - pub fn minor(&self) -> u32 { - ((self.0 >> 12) & 0xffff_ff00 | self.0 & 0x0000_00ff) as u32 - } +/// A device ID, containing a major device number and a minor device number. +#[derive(Clone, Copy, Debug)] +pub struct DeviceId { + major: u32, + minor: u32, } -impl Debug for DeviceId { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - f.debug_struct("DeviceId") - .field("major", &self.major()) - .field("minor", &self.minor()) - .finish() +impl DeviceId { + /// Creates a device ID from the major device number and the minor device number. + pub fn new(major: u32, minor: u32) -> Self { + Self { major, minor } + } + + /// Returns the major device number. + pub fn major(&self) -> u32 { + self.major + } + + /// Returns the minor device number. + pub fn minor(&self) -> u32 { + self.minor + } + + /// Encodes the device ID as a `u32` value. + /// + /// The encoding strategy here is the same as in Linux. See the Linux implementation at: + /// + pub fn as_encoded_u32(&self) -> u32 { + self.as_encoded_u64() as u32 + } + + /// Encodes the device ID as a `u64` value. + fn as_encoded_u64(&self) -> u64 { + let major = self.major() as u64; + let minor = self.minor() as u64; + ((major & 0xffff_f000) << 32) + | ((major & 0x0000_0fff) << 8) + | ((minor & 0xffff_ff00) << 12) + | (minor & 0x0000_00ff) + } + + /// Decodes the device ID from a `u64` value. + fn decode_from_u64(raw: u64) -> Self { + let major = ((raw >> 32) & 0xffff_f000 | (raw >> 8) & 0x0000_0fff) as u32; + let minor = ((raw >> 12) & 0xffff_ff00 | raw & 0x0000_00ff) as u32; + Self::new(major, minor) } } impl From for u64 { fn from(value: DeviceId) -> Self { - value.0 + value.as_encoded_u64() } } impl From for DeviceId { fn from(raw: u64) -> Self { - Self(raw) + Self::decode_from_u64(raw) } } diff --git a/kernel/src/fs/procfs/pid/mod.rs b/kernel/src/fs/procfs/pid/mod.rs index ef8ed8e80..b222815b1 100644 --- a/kernel/src/fs/procfs/pid/mod.rs +++ b/kernel/src/fs/procfs/pid/mod.rs @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 use self::{ - cmdline::CmdlineFileOps, comm::CommFileOps, exe::ExeSymOps, fd::FdDirOps, task::TaskDirOps, + cmdline::CmdlineFileOps, comm::CommFileOps, exe::ExeSymOps, fd::FdDirOps, stat::StatFileOps, + status::StatusFileOps, task::TaskDirOps, }; use super::template::{DirOps, ProcDir, ProcDirBuilder}; use crate::{ @@ -64,8 +65,12 @@ impl DirOps for PidDirOps { "comm" => CommFileOps::new_inode(self.0.clone(), this_ptr.clone()), "fd" => FdDirOps::new_inode(self.0.clone(), this_ptr.clone()), "cmdline" => CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()), - "status" => status::StatusFileOps::new_inode(self.0.clone(), this_ptr.clone()), - "stat" => stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()), + "status" => { + StatusFileOps::new_inode(self.0.clone(), self.0.main_thread(), this_ptr.clone()) + } + "stat" => { + StatFileOps::new_inode(self.0.clone(), self.0.main_thread(), true, this_ptr.clone()) + } "task" => TaskDirOps::new_inode(self.0.clone(), this_ptr.clone()), _ => return_errno!(Errno::ENOENT), }; @@ -91,10 +96,10 @@ impl DirOps for PidDirOps { CmdlineFileOps::new_inode(self.0.clone(), this_ptr.clone()) }); cached_children.put_entry_if_not_found("status", || { - status::StatusFileOps::new_inode(self.0.clone(), this_ptr.clone()) + StatusFileOps::new_inode(self.0.clone(), self.0.main_thread(), this_ptr.clone()) }); cached_children.put_entry_if_not_found("stat", || { - stat::StatFileOps::new_inode(self.0.clone(), this_ptr.clone()) + StatFileOps::new_inode(self.0.clone(), self.0.main_thread(), true, this_ptr.clone()) }); cached_children.put_entry_if_not_found("task", || { TaskDirOps::new_inode(self.0.clone(), this_ptr.clone()) diff --git a/kernel/src/fs/procfs/pid/stat.rs b/kernel/src/fs/procfs/pid/stat.rs index ce483c5cc..6d72b48b3 100644 --- a/kernel/src/fs/procfs/pid/stat.rs +++ b/kernel/src/fs/procfs/pid/stat.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use core::fmt::Write; +use core::{fmt::Write, sync::atomic::Ordering}; use crate::{ fs::{ @@ -8,13 +8,18 @@ use crate::{ utils::Inode, }, prelude::*, + process::posix_thread::AsPosixThread, + thread::Thread, + vm::vmar::RssType, Process, }; -/// Represents the inode at `/proc/[pid]/stat`. -/// The fields are the same as the ones in `/proc/[pid]/status`. But the format is different. -/// See https://github.com/torvalds/linux/blob/ce1c54fdff7c4556b08f5b875a331d8952e8b6b7/fs/proc/array.c#L467 -/// FIXME: Some fields are not implemented yet. +/// Represents the inode at either `/proc/[pid]/stat` or `/proc/[pid]/task/[tid]/stat`. +/// +/// The fields are the same as the ones in `/proc/[pid]/status`, but the format is different. +/// See . +/// +/// FIXME: Some fields are not implemented or contain placeholders yet. /// /// Fields: /// - pid : Process ID. @@ -68,36 +73,133 @@ use crate::{ /// - env_start : Start address of environment variables. /// - env_end : End address of environment variables. /// - exit_code : Process exit code as returned by waitpid(2). -pub struct StatFileOps(Arc); +pub struct StatFileOps { + process_ref: Arc, + thread_ref: Arc, + /// If `is_pid_stat` is true, this file corresponds to a process-level `/proc/[pid]/stat`. + /// Otherwise, this file corresponds to the thread-level `/proc/[pid]/task/[tid]/stat`. + is_pid_stat: bool, +} impl StatFileOps { - pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { - ProcFileBuilder::new(Self(process_ref)) - .parent(parent) - .build() - .unwrap() + pub fn new_inode( + process_ref: Arc, + thread_ref: Arc, + is_pid_stat: bool, + parent: Weak, + ) -> Arc { + ProcFileBuilder::new(Self { + process_ref, + thread_ref, + is_pid_stat, + }) + .parent(parent) + .build() + .unwrap() } } impl FileOps for StatFileOps { fn data(&self) -> Result> { - let process = &self.0; + let process = &self.process_ref; + let thread = &self.thread_ref; + let posix_thread = thread.as_posix_thread().unwrap(); - let pid = process.pid(); - let comm = process.executable_path(); - let state = if process.status().is_zombie() { - 'Z' - } else { - 'R' - }; + // According to the Linux implementation, a process's `/proc//stat` should be + // almost identical to its main thread's `/proc//task//stat`, except for + // fields `exit_code`, `wchan`, `min_flt`, `maj_flt`, `gtime`, `utime`, and `stime`. + // + // Reference: + + let pid = posix_thread.tid(); + let comm = posix_thread + .thread_name() + .lock() + .as_ref() + .and_then(|name| name.as_string()) + .unwrap_or_else(|| process.executable_path()); + let state = if thread.is_exited() { 'Z' } else { 'R' }; let ppid = process.parent().pid(); let pgrp = process.pgid(); + let session = process.sid(); + + let (tty_nr, tpgid) = if let Some(terminal) = process.terminal() { + ( + terminal.id().as_encoded_u32(), + terminal + .job_control() + .foreground() + .map(|pgrp| pgrp.pgid() as i64) + .unwrap_or(-1), + ) + } else { + (0, -1) + }; + + let flags = 0; + let min_flt = 0; + let cmin_flt = 0; + let maj_flt = 0; + let cmaj_flt = 0; + + let (utime, stime) = { + let prof_clock = if self.is_pid_stat { + process.prof_clock() + } else { + posix_thread.prof_clock() + }; + ( + prof_clock.user_clock().read_jiffies().as_u64(), + prof_clock.kernel_clock().read_jiffies().as_u64(), + ) + }; + + let cutime = 0; + let cstime = 0; + let priority = 0; + let nice = process.nice().load(Ordering::Relaxed).value().get(); + let num_threads = process.tasks().lock().as_slice().len(); + let itrealvalue = 0; + let starttime = 0; + + let (vsize, rss) = if let Some(vmar_ref) = process.lock_root_vmar().as_ref() { + let vsize = vmar_ref.get_mappings_total_size(); + let anon = vmar_ref.get_rss_counter(RssType::RSS_ANONPAGES); + let file = vmar_ref.get_rss_counter(RssType::RSS_FILEPAGES); + let rss = anon + file; + (vsize, rss) + } else { + (0, 0) + }; let mut stat_output = String::new(); writeln!( stat_output, - "{} ({}) {} {} {}", - pid, comm, state, ppid, pgrp + "{} ({}) {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", + pid, + comm, + state, + ppid, + pgrp, + session, + tty_nr, + tpgid, + flags, + min_flt, + cmin_flt, + maj_flt, + cmaj_flt, + utime, + stime, + cutime, + cstime, + priority, + nice, + num_threads, + itrealvalue, + starttime, + vsize, + rss ) .unwrap(); Ok(stat_output.into_bytes()) diff --git a/kernel/src/fs/procfs/pid/status.rs b/kernel/src/fs/procfs/pid/status.rs index 9dc0cd38d..1a3e72a5c 100644 --- a/kernel/src/fs/procfs/pid/status.rs +++ b/kernel/src/fs/procfs/pid/status.rs @@ -9,11 +9,12 @@ use crate::{ }, prelude::*, process::posix_thread::AsPosixThread, + thread::Thread, vm::vmar::RssType, Process, }; -/// Represents the inode at `/proc/[pid]/status`. +/// Represents the inode at either `/proc/[pid]/status` or `/proc/[pid]/task/[tid]/status`. /// See https://github.com/torvalds/linux/blob/ce1c54fdff7c4556b08f5b875a331d8952e8b6b7/fs/proc/array.c#L148 /// FIXME: Some fields are not implemented yet. /// @@ -59,54 +60,95 @@ use crate::{ /// - Mems_allowed_list: List of memory nodes allowed for this process. /// - voluntary_ctxt_switches: Number of voluntary context switches. /// - nonvoluntary_ctxt_switches: Number of nonvoluntary context switches. -pub struct StatusFileOps(Arc); +pub struct StatusFileOps { + process_ref: Arc, + thread_ref: Arc, +} impl StatusFileOps { - pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { - ProcFileBuilder::new(Self(process_ref)) - .parent(parent) - .build() - .unwrap() + pub fn new_inode( + process_ref: Arc, + thread_ref: Arc, + parent: Weak, + ) -> Arc { + ProcFileBuilder::new(Self { + process_ref, + thread_ref, + }) + .parent(parent) + .build() + .unwrap() } } impl FileOps for StatusFileOps { fn data(&self) -> Result> { - let process = &self.0; - let main_thread = process.main_thread(); - let file_table = main_thread.as_posix_thread().unwrap().file_table(); + let process = &self.process_ref; + let thread = &self.thread_ref; + let posix_thread = thread.as_posix_thread().unwrap(); + + // According to the Linux implementation, a process's `/proc//status` + // is exactly the same as its main thread's `/proc//task//status`. + // + // Reference: + // + // let mut status_output = String::new(); - writeln!(status_output, "Name:\t{}", process.executable_path()).unwrap(); + + writeln!( + status_output, + "Name:\t{}", + posix_thread + .thread_name() + .lock() + .as_ref() + .and_then(|name| name.as_string()) + .unwrap_or_else(|| process.executable_path()) + ) + .unwrap(); + + let state = if thread.is_exited() { + "Z (zombie)" + } else { + "R (running)" + }; + writeln!(status_output, "State:\t{}", state).unwrap(); + writeln!(status_output, "Tgid:\t{}", process.pid()).unwrap(); - writeln!(status_output, "Pid:\t{}", process.pid()).unwrap(); + writeln!(status_output, "Pid:\t{}", posix_thread.tid()).unwrap(); writeln!(status_output, "PPid:\t{}", process.parent().pid()).unwrap(); - writeln!(status_output, "TracerPid:\t{}", process.parent().pid()).unwrap(); // Assuming TracerPid is the same as PPid + writeln!(status_output, "TracerPid:\t{}", 0).unwrap(); writeln!( status_output, "FDSize:\t{}", - file_table + posix_thread + .file_table() .lock() .as_ref() .map(|file_table| file_table.read().len()) .unwrap_or(0) ) .unwrap(); - writeln!( - status_output, - "Threads:\t{}", - process.tasks().lock().as_slice().len() - ) - .unwrap(); if let Some(vmar_ref) = process.lock_root_vmar().as_ref() { + let vsize = vmar_ref.get_mappings_total_size(); let anon = vmar_ref.get_rss_counter(RssType::RSS_ANONPAGES) * (PAGE_SIZE / 1024); let file = vmar_ref.get_rss_counter(RssType::RSS_FILEPAGES) * (PAGE_SIZE / 1024); let rss = anon + file; writeln!( status_output, - "VmRSS:\t{} kB\nRssAnon:\t{} kB\nRssFile:\t{} kB", - rss, anon, file + "VmSize:\t{} kB\nVmRSS:\t{} kB\nRssAnon:\t{} kB\nRssFile:\t{} kB", + vsize, rss, anon, file + ) + .unwrap(); + } + + if Arc::ptr_eq(thread, &process.main_thread()) { + writeln!( + status_output, + "Threads:\t{}", + process.tasks().lock().as_slice().len() ) .unwrap(); } diff --git a/kernel/src/fs/procfs/pid/task.rs b/kernel/src/fs/procfs/pid/task.rs index adcbdbf7c..307226655 100644 --- a/kernel/src/fs/procfs/pid/task.rs +++ b/kernel/src/fs/procfs/pid/task.rs @@ -9,6 +9,7 @@ use crate::{ utils::{DirEntryVecExt, Inode}, }, process::posix_thread::AsPosixThread, + thread::{AsThread, Thread}, Process, }; @@ -25,22 +26,43 @@ impl TaskDirOps { } /// Represents the inode at `/proc/[pid]/task/[tid]`. -struct ThreadDirOps(Arc); +struct TidDirOps { + process_ref: Arc, + thread_ref: Arc, +} -impl ThreadDirOps { - pub fn new_inode(process_ref: Arc, parent: Weak) -> Arc { - ProcDirBuilder::new(Self(process_ref)) - .parent(parent) - .build() - .unwrap() +impl TidDirOps { + pub fn new_inode( + process_ref: Arc, + thread_ref: Arc, + parent: Weak, + ) -> Arc { + ProcDirBuilder::new(Self { + process_ref, + thread_ref, + }) + .parent(parent) + .build() + .unwrap() } } -impl DirOps for ThreadDirOps { +impl DirOps for TidDirOps { fn lookup_child(&self, this_ptr: Weak, name: &str) -> Result> { let inode = match name { - "fd" => FdDirOps::new_inode(self.0.clone(), this_ptr.clone()), - "exe" => ExeSymOps::new_inode(self.0.clone(), this_ptr.clone()), + "fd" => FdDirOps::new_inode(self.process_ref.clone(), this_ptr.clone()), + "exe" => ExeSymOps::new_inode(self.process_ref.clone(), this_ptr.clone()), + "stat" => StatFileOps::new_inode( + self.process_ref.clone(), + self.thread_ref.clone(), + false, + this_ptr.clone(), + ), + "status" => StatusFileOps::new_inode( + self.process_ref.clone(), + self.thread_ref.clone(), + this_ptr.clone(), + ), _ => return_errno!(Errno::ENOENT), }; Ok(inode) @@ -49,14 +71,29 @@ impl DirOps for ThreadDirOps { fn populate_children(&self, this_ptr: Weak) { let this = { let this = this_ptr.upgrade().unwrap(); - this.downcast_ref::>().unwrap().this() + this.downcast_ref::>().unwrap().this() }; let mut cached_children = this.cached_children().write(); cached_children.put_entry_if_not_found("fd", || { - FdDirOps::new_inode(self.0.clone(), this_ptr.clone()) + FdDirOps::new_inode(self.process_ref.clone(), this_ptr.clone()) }); cached_children.put_entry_if_not_found("exe", || { - ExeSymOps::new_inode(self.0.clone(), this_ptr.clone()) + ExeSymOps::new_inode(self.process_ref.clone(), this_ptr.clone()) + }); + cached_children.put_entry_if_not_found("stat", || { + StatFileOps::new_inode( + self.process_ref.clone(), + self.thread_ref.clone(), + false, + this_ptr.clone(), + ) + }); + cached_children.put_entry_if_not_found("status", || { + StatusFileOps::new_inode( + self.process_ref.clone(), + self.thread_ref.clone(), + this_ptr.clone(), + ) }); } } @@ -68,10 +105,15 @@ impl DirOps for TaskDirOps { }; for task in self.0.tasks().lock().as_slice() { - if task.as_posix_thread().unwrap().tid() != tid { + let thread = task.as_thread().unwrap(); + if thread.as_posix_thread().unwrap().tid() != tid { continue; } - return Ok(ThreadDirOps::new_inode(self.0.clone(), this_ptr)); + return Ok(TidDirOps::new_inode( + self.0.clone(), + thread.clone(), + this_ptr, + )); } return_errno_with_message!(Errno::ENOENT, "No such thread") } @@ -83,9 +125,10 @@ impl DirOps for TaskDirOps { }; let mut cached_children = this.cached_children().write(); for task in self.0.tasks().lock().as_slice() { + let thread = task.as_thread().unwrap(); cached_children.put_entry_if_not_found( &format!("{}", task.as_posix_thread().unwrap().tid()), - || ThreadDirOps::new_inode(self.0.clone(), this_ptr.clone()), + || TidDirOps::new_inode(self.0.clone(), thread.clone(), this_ptr.clone()), ); } } diff --git a/kernel/src/process/clone.rs b/kernel/src/process/clone.rs index 215c70129..c48a39679 100644 --- a/kernel/src/process/clone.rs +++ b/kernel/src/process/clone.rs @@ -257,6 +257,9 @@ fn clone_child_task( // Inherit sigmask from current thread let sig_mask = posix_thread.sig_mask().load(Ordering::Relaxed).into(); + // Inherit the thread name. + let thread_name = posix_thread.thread_name().lock().as_ref().cloned(); + let child_tid = allocate_posix_tid(); let child_task = { let credentials = { @@ -266,6 +269,7 @@ fn clone_child_task( let mut thread_builder = PosixThreadBuilder::new(child_tid, child_user_ctx, credentials) .process(posix_thread.weak_process()) + .thread_name(thread_name) .sig_mask(sig_mask) .file_table(child_file_table) .fs(child_fs); diff --git a/kernel/src/process/posix_thread/name.rs b/kernel/src/process/posix_thread/name.rs index 8d8c3e53d..29a1b5a96 100644 --- a/kernel/src/process/posix_thread/name.rs +++ b/kernel/src/process/posix_thread/name.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MPL-2.0 +use alloc::borrow::ToOwned; + use crate::prelude::*; pub const MAX_THREAD_NAME_LEN: usize = 16; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ThreadName { inner: [u8; MAX_THREAD_NAME_LEN], count: usize, @@ -50,7 +52,12 @@ impl ThreadName { Ok(()) } - pub fn name(&self) -> Result> { - Ok(Some(CStr::from_bytes_until_nul(&self.inner)?)) + pub fn name(&self) -> Option<&CStr> { + CStr::from_bytes_until_nul(&self.inner).ok() + } + + pub fn as_string(&self) -> Option { + let name = self.name()?; + name.to_str().ok().map(|name| name.to_owned()) } } diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index 4aaa34ca1..9f3f4f2fa 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -95,7 +95,7 @@ pub struct Process { /// Whether the process has a subreaper that will reap it when the /// process becomes orphaned. - /// + /// /// If `has_child_subreaper` is true in a `Process`, this attribute should /// also be true for all of its descendants. pub(super) has_child_subreaper: AtomicBool, diff --git a/kernel/src/process/process/terminal.rs b/kernel/src/process/process/terminal.rs index b9c411aed..e53cb6bf1 100644 --- a/kernel/src/process/process/terminal.rs +++ b/kernel/src/process/process/terminal.rs @@ -5,7 +5,7 @@ use alloc::sync::Arc; use super::{session::SessionGuard, JobControl, Pgid, Process, Session, Sid}; use crate::{ current_userspace, - fs::{inode_handle::FileIo, utils::IoctlCmd}, + fs::{device::Device, inode_handle::FileIo, utils::IoctlCmd}, prelude::{current, return_errno_with_message, warn, Errno, Error, Result}, process::process_table, }; @@ -14,7 +14,7 @@ use crate::{ /// /// We currently support two kinds of terminal, the TTY and PTY. They're associated with a /// `JobControl` to track the session and the foreground process group. -pub trait Terminal: FileIo { +pub trait Terminal: FileIo + Device { /// Returns the job control of the terminal. fn job_control(&self) -> &JobControl; } diff --git a/kernel/src/process/process/timer_manager.rs b/kernel/src/process/process/timer_manager.rs index 1ff0fdd8b..17475988e 100644 --- a/kernel/src/process/process/timer_manager.rs +++ b/kernel/src/process/process/timer_manager.rs @@ -5,14 +5,9 @@ use alloc::{ sync::{Arc, Weak}, vec::Vec, }; -use core::time::Duration; use id_alloc::IdAlloc; -use ostd::{ - arch::{timer::TIMER_FREQ, trap::is_kernel_interrupted}, - sync::Mutex, - timer, -}; +use ostd::{arch::trap::is_kernel_interrupted, sync::Mutex, timer}; use super::Process; use crate::{ @@ -48,25 +43,15 @@ fn update_cpu_time() { return; }; let timer_manager = process.timer_manager(); - let jiffies_interval = Duration::from_millis(1000 / TIMER_FREQ); // Based on whether the timer interrupt occurs in kernel mode or user mode, // the function will add the duration of one timer interrupt interval to the // corresponding CPU clocks. if is_kernel_interrupted() { - posix_thread - .prof_clock() - .kernel_clock() - .add_time(jiffies_interval); - process - .prof_clock() - .kernel_clock() - .add_time(jiffies_interval); + posix_thread.prof_clock().kernel_clock().add_jiffies(1); + process.prof_clock().kernel_clock().add_jiffies(1); } else { - posix_thread - .prof_clock() - .user_clock() - .add_time(jiffies_interval); - process.prof_clock().user_clock().add_time(jiffies_interval); + posix_thread.prof_clock().user_clock().add_jiffies(1); + process.prof_clock().user_clock().add_jiffies(1); timer_manager .virtual_timer() .timer_manager() diff --git a/kernel/src/syscall/prctl.rs b/kernel/src/syscall/prctl.rs index 7c85cb6ba..e6587d5b2 100644 --- a/kernel/src/syscall/prctl.rs +++ b/kernel/src/syscall/prctl.rs @@ -63,7 +63,7 @@ pub fn sys_prctl( PrctlCmd::PR_GET_NAME(write_to_addr) => { let thread_name = ctx.posix_thread.thread_name().lock(); if let Some(thread_name) = &*thread_name { - if let Some(thread_name) = thread_name.name()? { + if let Some(thread_name) = thread_name.name() { ctx.user_space().write_bytes( write_to_addr, &mut VmReader::from(thread_name.to_bytes_with_nul()), diff --git a/kernel/src/time/clocks/cpu_clock.rs b/kernel/src/time/clocks/cpu_clock.rs index c9f2c273c..3b61c87f7 100644 --- a/kernel/src/time/clocks/cpu_clock.rs +++ b/kernel/src/time/clocks/cpu_clock.rs @@ -3,13 +3,16 @@ use alloc::sync::Arc; use core::time::Duration; -use ostd::sync::SpinLock; +use ostd::{ + sync::{LocalIrqDisabled, SpinLock}, + timer::Jiffies, +}; use crate::time::Clock; /// A clock used to record the CPU time for processes and threads. pub struct CpuClock { - time: SpinLock, + time: SpinLock, } /// A profiling clock that contains a user CPU clock and a kernel CPU clock. @@ -25,19 +28,24 @@ impl CpuClock { /// Creates a new `CpuClock`. The recorded time is initialized to 0. pub fn new() -> Arc { Arc::new(Self { - time: SpinLock::new(Duration::ZERO), + time: SpinLock::new(Jiffies::new(0)), }) } - /// Adds `interval` to the original recorded time to update the `CpuClock`. - pub fn add_time(&self, interval: Duration) { - *self.time.disable_irq().lock() += interval; + /// Adds `jiffies` to the original recorded time to update the `CpuClock`. + pub fn add_jiffies(&self, jiffies: u64) { + self.time.lock().add(jiffies); + } + + /// Reads the current time of this clock in [`Jiffies`]. + pub fn read_jiffies(&self) -> Jiffies { + *self.time.lock() } } impl Clock for CpuClock { fn read_time(&self) -> Duration { - *self.time.disable_irq().lock() + self.read_jiffies().as_duration() } } diff --git a/kernel/src/vm/vmar/mod.rs b/kernel/src/vm/vmar/mod.rs index f586dd5de..d438939ab 100644 --- a/kernel/src/vm/vmar/mod.rs +++ b/kernel/src/vm/vmar/mod.rs @@ -813,6 +813,11 @@ impl Vmar { pub fn get_rss_counter(&self, rss_type: RssType) -> usize { self.0.get_rss_counter(rss_type) } + + /// Returns the total size of the mappings in bytes. + pub fn get_mappings_total_size(&self) -> usize { + self.0.inner.read().total_vm + } } /// Options for creating a new mapping. The mapping is not allowed to overlap diff --git a/ostd/src/timer/jiffies.rs b/ostd/src/timer/jiffies.rs index 3b1c1dbf8..1f4cc7dab 100644 --- a/ostd/src/timer/jiffies.rs +++ b/ostd/src/timer/jiffies.rs @@ -17,6 +17,9 @@ pub struct Jiffies(u64); pub(crate) static ELAPSED: AtomicU64 = AtomicU64::new(0); impl Jiffies { + /// The maximum value of [`Jiffies`]. + pub const MAX: Self = Self(u64::MAX); + /// Creates a new instance. pub fn new(value: u64) -> Self { Self(value) @@ -32,9 +35,16 @@ impl Jiffies { self.0 } + /// Adds the given number of jiffies, saturating at [`Jiffies::MAX`] on overflow. + pub fn add(&mut self, jiffies: u64) { + self.0 = self.0.saturating_add(jiffies); + } + /// Gets the [`Duration`] calculated from the jiffies counts. pub fn as_duration(self) -> Duration { - Duration::from_millis(self.0 * 1000 / TIMER_FREQ) + let secs = self.0 / TIMER_FREQ; + let nanos = ((self.0 % TIMER_FREQ) * 1_000_000_000) / TIMER_FREQ; + Duration::new(secs, nanos as u32) } } diff --git a/test/apps/scripts/shell_cmd.sh b/test/apps/scripts/shell_cmd.sh index a30f0b1b0..c8293f7ea 100755 --- a/test/apps/scripts/shell_cmd.sh +++ b/test/apps/scripts/shell_cmd.sh @@ -28,12 +28,14 @@ unlink tesk_cmd_hard_link sed 3q shell_cmd.sh -find . -name "*shell_cmd*" +find . -name "*shell_cmd*" mkdir foo -rmdir foo +rmdir foo echo "Hello world from asterinas" > hello.txt rm hello.txt cd .. + +ps -T | grep ps \ No newline at end of file