增加内存分配日志监视器 (#424)

* 完成内存日志监视,并输出日志到文件
* 修复进程退出后,procfs查看进程status文件会崩溃的问题
* 修复signal唤醒进程的判断条件问题
This commit is contained in:
LoGin
2023-11-07 21:39:27 +08:00
committed by GitHub
parent 70a4e5550a
commit 7b32f5080f
46 changed files with 2033 additions and 59 deletions

@ -11,7 +11,7 @@ use alloc::{
vec::Vec,
};
use memoffset::offset_of;
use kdepends::memoffset::offset_of;
use x86::{controlregs::Cr4, segmentation::SegmentSelector};
use crate::{

@ -4,7 +4,7 @@ use core::{
sync::atomic::{compiler_fence, AtomicBool, Ordering},
};
use memoffset::offset_of;
use kdepends::memoffset::offset_of;
use crate::{
arch::process::table::TSSManager, exception::InterruptArch,

@ -0,0 +1,78 @@
extern crate klog_types;
use core::intrinsics::unlikely;
use klog_types::{AllocatorLog, AllocatorLogType, LogSource, MMLogChannel};
use crate::{
arch::CurrentTimeArch,
process::{Pid, ProcessManager},
time::TimeArch,
};
/// 全局的内存分配器日志通道
///
/// 标记为`no_mangle`是为了让调试器能够找到这个变量
#[no_mangle]
static __MM_ALLOCATOR_LOG_CHANNEL: MMLogChannel<{ MMDebugLogManager::MAX_ALLOC_LOG_NUM }> =
MMLogChannel::new(MMDebugLogManager::MAX_ALLOC_LOG_NUM);
/// 全局的内存分配器日志id分配器
///
/// id从1开始, 因为0是无效的id
static __MM_DEBUG_LOG_IDA: ida::IdAllocator = ida::IdAllocator::new(1, usize::MAX);
/// 记录内存分配器的日志
///
/// ## 参数
///
/// - `log_type`:日志类型
/// - `source`:日志来源
pub fn mm_debug_log(log_type: AllocatorLogType, source: LogSource) {
let pid = if unlikely(!ProcessManager::initialized()) {
Some(Pid::new(0))
} else {
Some(ProcessManager::current_pcb().pid())
};
MMDebugLogManager::log(log_type, source, pid);
}
#[derive(Debug)]
pub(super) struct MMDebugLogManager;
impl MMDebugLogManager {
/// 最大的内存分配器日志数量
pub const MAX_ALLOC_LOG_NUM: usize = 100000;
/// 记录内存分配器的日志
///
/// ## 参数
///
/// - `log_type`:日志类型
/// - `source`:日志来源
/// - `pid`日志来源的pid
pub fn log(log_type: AllocatorLogType, source: LogSource, pid: Option<Pid>) {
let id = __MM_DEBUG_LOG_IDA.alloc().unwrap();
let log = AllocatorLog::new(
id as u64,
log_type,
source,
pid.map(|p| p.data()),
CurrentTimeArch::get_cycles() as u64,
);
let mut log = log;
loop {
let r = __MM_ALLOCATOR_LOG_CHANNEL.buf.push(log);
if let Err(r) = r {
// 如果日志通道满了,就把最早的日志丢弃
if __MM_ALLOCATOR_LOG_CHANNEL.buf.remaining() == 0 {
__MM_ALLOCATOR_LOG_CHANNEL.buf.pop();
}
log = r.into_inner();
} else {
break;
}
}
}
}

@ -0,0 +1 @@
pub mod mm;

1
kernel/src/debug/mod.rs Normal file

@ -0,0 +1 @@
pub mod klog;

@ -26,7 +26,7 @@ use crate::{
use super::{super::device::DeviceState, platform_bus, platform_bus_device, CompatibleTable};
/// 平台设备id分配器
static PLATFORM_DEVID_IDA: IdAllocator = IdAllocator::new(i32::MAX as usize);
static PLATFORM_DEVID_IDA: IdAllocator = IdAllocator::new(0, i32::MAX as usize);
#[inline(always)]
pub fn platform_device_manager() -> &'static PlatformDeviceManager {

@ -2,7 +2,7 @@ use core::intrinsics::unlikely;
use alloc::string::String;
use thingbuf::mpsc::{
use kdepends::thingbuf::mpsc::{
self,
errors::{TryRecvError, TrySendError},
};

@ -179,23 +179,24 @@ impl ProcFSInode {
);
pdata.append(&mut format!("\nvrtime:\t{}", vrtime).as_bytes().to_owned());
let binding = pcb.basic().user_vm().unwrap();
let address_space_guard = binding.read();
// todo: 当前进程运行过程中占用内存的峰值
let hiwater_vm: u64 = 0;
// 进程代码段的大小
let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024;
// 进程数据段的大小
let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024;
drop(address_space_guard);
if let Some(user_vm) = pcb.basic().user_vm() {
let address_space_guard = user_vm.read();
// todo: 当前进程运行过程中占用内存的峰值
let hiwater_vm: u64 = 0;
// 进程代码段的大小
let text = (address_space_guard.end_code - address_space_guard.start_code) / 1024;
// 进程数据段的大小
let data = (address_space_guard.end_data - address_space_guard.start_data) / 1024;
drop(address_space_guard);
pdata.append(
&mut format!("\nVmPeak:\t{} kB", hiwater_vm)
.as_bytes()
.to_owned(),
);
pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned());
pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned());
}
pdata.append(
&mut format!("\nVmPeak:\t{} kB", hiwater_vm)
.as_bytes()
.to_owned(),
);
pdata.append(&mut format!("\nVmData:\t{} kB", data).as_bytes().to_owned());
pdata.append(&mut format!("\nVmExe:\t{} kB", text).as_bytes().to_owned());
pdata.append(
&mut format!("\nflags: {:?}\n", pcb.flags().clone())
.as_bytes()

@ -50,10 +50,13 @@ impl Signal {
kwarn!("No such process.");
return retval;
}
let pcb = pcb.unwrap();
// println!("Target pcb = {:?}", pcb.as_ref().unwrap());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 发送信号
retval = self.send_signal(info, pcb.unwrap(), PidType::PID);
retval = self.send_signal(info, pcb.clone(), PidType::PID);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return retval;
}
@ -282,8 +285,33 @@ fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStr
// 如果不是 fatal 的就只唤醒 stop 的进程来响应
// kdebug!("signal_wake_up");
// 如果目标进程已经在运行则发起一个ipi使得它陷入内核
let r = ProcessManager::wakeup_stop(&pcb);
if r.is_ok() {
let state = pcb.sched_info().state();
let mut wakeup_ok = true;
if state.is_blocked_interruptable() {
ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
wakeup_ok = false;
kwarn!(
"Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
ProcessManager::current_pcb().pid(),
pcb.pid(),
e
);
});
} else if state.is_stopped() {
ProcessManager::wakeup_stop(&pcb).unwrap_or_else(|e| {
wakeup_ok = false;
kwarn!(
"Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
ProcessManager::current_pcb().pid(),
pcb.pid(),
e
);
});
} else {
wakeup_ok = false;
}
if wakeup_ok {
ProcessManager::kick(&pcb);
} else {
if fatal {

@ -39,6 +39,7 @@ mod arch;
mod libs;
#[macro_use]
mod include;
mod debug;
mod driver; // 如果driver依赖了libs应该在libs后面导出
mod exception;
mod filesystem;
@ -60,17 +61,17 @@ extern crate bitflags;
extern crate elf;
#[macro_use]
extern crate lazy_static;
extern crate memoffset;
extern crate num;
#[macro_use]
extern crate num_derive;
extern crate smoltcp;
extern crate thingbuf;
#[macro_use]
extern crate intertrait;
#[cfg(target_arch = "x86_64")]
extern crate x86;
extern crate klog_types;
use crate::mm::allocator::kernel_allocator::KernelAllocator;
use crate::process::ProcessManager;

@ -16,9 +16,9 @@ pub struct IdAllocator {
impl IdAllocator {
/// 创建一个新的id分配器
pub const fn new(max_id: usize) -> Self {
pub const fn new(initial_id: usize, max_id: usize) -> Self {
Self {
current_id: AtomicUsize::new(0),
current_id: AtomicUsize::new(initial_id),
max_id,
dead: AtomicBool::new(false),
}

@ -1,5 +1,8 @@
use klog_types::AllocLogItem;
use crate::{
arch::mm::LockedFrameAllocator,
debug::klog::mm::mm_debug_log,
libs::align::page_align_up,
mm::{MMArch, MemoryManagementArch, VirtAddr},
};
@ -81,15 +84,46 @@ impl LocalAlloc for KernelAllocator {
/// 为内核slab分配器实现GlobalAlloc特性
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
return self.local_alloc(layout);
let r = self.local_alloc(layout);
mm_debug_log(
klog_types::AllocatorLogType::Alloc(AllocLogItem::new(
layout.clone(),
Some(r as usize),
None,
)),
klog_types::LogSource::Buddy,
);
return r;
// self.local_alloc_zeroed(layout, 0)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.local_alloc_zeroed(layout)
let r = self.local_alloc_zeroed(layout);
mm_debug_log(
klog_types::AllocatorLogType::AllocZeroed(AllocLogItem::new(
layout.clone(),
Some(r as usize),
None,
)),
klog_types::LogSource::Buddy,
);
return r;
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
mm_debug_log(
klog_types::AllocatorLogType::Free(AllocLogItem::new(
layout.clone(),
Some(ptr as usize),
None,
)),
klog_types::LogSource::Buddy,
);
self.local_dealloc(ptr, layout);
}
}

@ -121,6 +121,11 @@ impl ProcessManager {
kinfo!("Process Manager initialized.");
}
/// 判断进程管理器是否已经初始化完成
pub fn initialized() -> bool {
unsafe { __PROCESS_MANAGEMENT_INIT_DONE }
}
/// 获取当前进程的pcb
pub fn current_pcb() -> Arc<ProcessControlBlock> {
if unlikely(unsafe { !__PROCESS_MANAGEMENT_INIT_DONE }) {
@ -461,6 +466,11 @@ impl ProcessState {
return matches!(self, ProcessState::Blocked(_));
}
#[inline(always)]
pub fn is_blocked_interruptable(&self) -> bool {
return matches!(self, ProcessState::Blocked(true));
}
#[inline(always)]
pub fn is_exited(&self) -> bool {
return matches!(self, ProcessState::Exited(_));