Skip to content

Commit

Permalink
更改帧分配算法 chyyuu#12
Browse files Browse the repository at this point in the history
  • Loading branch information
Tuyixiang committed Apr 19, 2020
1 parent 70d8dd4 commit 828a94a
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 55 deletions.
61 changes: 20 additions & 41 deletions os/src/memory/frame/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
use super::frame::*;
use crate::memory::{address::*, config::*};
use alloc::{vec, vec::Vec};
use lazy_static::*;
use spin::Mutex;
use core::mem::size_of;

lazy_static! {
/// 帧分配器
Expand All @@ -25,66 +25,45 @@ lazy_static! {

/// 基于链表的帧分配 / 回收
pub struct FrameAllocator {
/// 记录空闲帧的链表
free_frame_list_head: PhysicalAddress,
/// 记录空闲帧的列表,每一项表示地址、从该地址开始连续多少帧空闲
free_frame_list: Vec<(PhysicalAddress, usize)>,
}

impl FrameAllocator {
/// 创建对象,其中 \[[`BEGIN_VPN`], [`END_VPN`]) 区间内的帧在其空闲链表中
/// 创建对象,其中 \[[`BEGIN_VPN`], [`END_VPN`]) 区间内的帧在其空闲列表中
pub fn new() -> Self {
// 定位到第一个可用的物理帧
let first_frame_ppn = PhysicalPageNumber::ceil(PhysicalAddress::from(*KERNEL_END_ADDRESS));
let first_frame_address = PhysicalAddress::from(first_frame_ppn);
let first_frame: &mut Frame = unsafe { first_frame_address.deref_kernel() };
// 初始化第一个帧
first_frame.next = PhysicalAddress(0);
first_frame.size = END_PPN - first_frame_ppn;
// 作为链表头
FrameAllocator {
free_frame_list_head: first_frame_address,
free_frame_list: vec![(first_frame_address, END_PPN - first_frame_ppn)],
}
}

/// 取链表第一个元素来分配帧
/// 取列表末尾元素来分配帧
///
/// - 如果第一个元素 `size > 1`,则相应修改 `size` 而保留元素
/// - 如果末尾元素 `size > 1`,则相应修改 `size` 而保留元素
/// - 如果没有剩余则返回 `Err`
pub fn alloc(&mut self) -> Result<FrameTracker, &'static str> {
unsafe {
if self.free_frame_list_head.valid() {
// 如果有元素,将要分配该地址对应的帧
let address_to_allocate = self.free_frame_list_head;
let head: &mut Frame = self.free_frame_list_head.deref_kernel();
if head.size > 1 {
// 如果其剩余帧数大于 1,则仅取出一个页面
// 原本的帧已经被分配,需要将原本的 next 和 size 写到下一个帧中,
// 并且相应修改 size 和 self.free_frame_list_head
let new_head_address: PhysicalAddress = self.free_frame_list_head + size_of::<Frame>();
let new_head: &mut Frame = new_head_address.deref_kernel();
new_head.next = head.next;
new_head.size = head.size - 1;
self.free_frame_list_head = new_head_address;
Ok(FrameTracker(address_to_allocate))
} else {
// 剩余帧数为 1,则从链表中移除
self.free_frame_list_head = head.next;
Ok(FrameTracker(address_to_allocate))
}
} else {
// 链表已空,返回 `Err`
Err("no available frame to allocate")
if let Some((address, page_count)) = self.free_frame_list.pop() {
// 如果有元素,将要分配该地址对应的帧
if page_count > 1 {
// 如果有连续的多个帧空余,则只取出一个,放回剩余部分
self.free_frame_list
.push((address + PAGE_SIZE, page_count - 1));
}
Ok(FrameTracker(address))
} else {
// 链表已空,返回 `Err`
Err("no available frame to allocate")
}
}

/// 将被释放的帧添加到空闲链表的头部
/// 将被释放的帧添加到空闲列表的尾部
///
/// 这个函数会在 [`FrameTracker`] 被 drop 时自动调用,不应在其他地方调用
pub(super) fn dealloc(&mut self, allocated_frame: &FrameTracker) {
let frame: &mut Frame = unsafe { allocated_frame.address().deref_kernel() };
frame.next = self.free_frame_list_head;
frame.size = 1;
self.free_frame_list_head = allocated_frame.address();
pub(super) fn dealloc(&mut self, frame: &FrameTracker) {
self.free_frame_list.push((frame.address(), 1));
}
}

Expand Down
14 changes: 0 additions & 14 deletions os/src/memory/frame/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::memory::{
address::*,
config::PAGE_SIZE,
frame::allocator::FRAME_ALLOCATOR,
};

Expand Down Expand Up @@ -41,17 +40,4 @@ impl Drop for FrameTracker {
fn drop(&mut self) {
FRAME_ALLOCATOR.lock().dealloc(self);
}
}

/// 表示一个实际在内存中的物理帧
///
/// 如果这个物理帧没有被使用,那么我们就用其前两个 usize 来存储信息
#[repr(C)]
pub struct Frame {
/// 下一个可用的物理帧的地址
pub(super) next: PhysicalAddress,
/// 从这一帧开始,有多少连续的物理帧是可用的
pub(super) size: usize,
/// 帧中其他未被使用的数据
_data: [u8; PAGE_SIZE - 16],
}

0 comments on commit 828a94a

Please sign in to comment.