move bit-allocator and rcore-thread crate to remote

master
WangRunji 6 years ago
parent c9a68634f5
commit b77a52dccb

@ -1,8 +1,6 @@
[workspace]
members = [
"crate/bit-allocator",
"crate/memory",
"crate/sync",
"crate/thread",
]
exclude = ["kernel", "bootloader", "user/rust"]

@ -1,7 +0,0 @@
[package]
name = "bit-allocator"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
[dependencies]
bit_field = "0.9"

@ -1,221 +0,0 @@
#![no_std]
#![feature(asm)]
extern crate bit_field;
use bit_field::BitField;
use core::ops::Range;
/// Allocator of a bitmap, able to allocate / free bits.
///
/// CAP: the bitmap has a total of CAP bits, numbered from 0 to CAP-1 inclusively.
///
/// alloc: allocate a free bit.
/// dealloc: free an allocated bit.
///
/// insert: mark bits in the range as allocated (available)
/// remove: reverse of insert
///
/// any: whether there are free bits remaining
/// test: whether a specific bit is free
pub trait BitAlloc: Default {
const CAP: usize;
fn alloc(&mut self) -> Option<usize>;
fn dealloc(&mut self, key: usize);
fn insert(&mut self, range: Range<usize>);
fn remove(&mut self, range: Range<usize>);
fn any(&self) -> bool;
fn test(&self, key: usize) -> bool;
}
pub type BitAlloc256 = BitAllocCascade16<BitAlloc16>;
pub type BitAlloc4K = BitAllocCascade16<BitAlloc256>;
pub type BitAlloc64K = BitAllocCascade16<BitAlloc4K>;
pub type BitAlloc1M = BitAllocCascade16<BitAlloc64K>;
pub type BitAlloc16M = BitAllocCascade16<BitAlloc1M>;
pub type BitAlloc256M = BitAllocCascade16<BitAlloc16M>;
/// Implement the bit allocator by segment tree algorithm.
#[derive(Default)]
pub struct BitAllocCascade16<T: BitAlloc> {
bitset: u16, // for each bit, 1 indicates available, 0 indicates inavailable
sub: [T; 16],
}
impl<T: BitAlloc> BitAlloc for BitAllocCascade16<T> {
const CAP: usize = T::CAP * 16;
fn alloc(&mut self) -> Option<usize> {
if self.any() {
let i = log2(self.bitset);
let res = self.sub[i].alloc().unwrap() + i * T::CAP;
self.bitset.set_bit(i, self.sub[i].any());
Some(res)
} else {
None
}
}
fn dealloc(&mut self, key: usize) {
let i = key / T::CAP;
self.sub[i].dealloc(key % T::CAP);
self.bitset.set_bit(i, true);
}
fn insert(&mut self, range: Range<usize>) {
self.for_range(range, |sub: &mut T, range| sub.insert(range));
}
fn remove(&mut self, range: Range<usize>) {
self.for_range(range, |sub: &mut T, range| sub.remove(range));
}
fn any(&self) -> bool {
self.bitset != 0
}
fn test(&self, key: usize) -> bool {
self.sub[key / T::CAP].test(key % T::CAP)
}
}
impl<T: BitAlloc> BitAllocCascade16<T> {
fn for_range(&mut self, range: Range<usize>, f: impl Fn(&mut T, Range<usize>)) {
let Range { start, end } = range;
assert!(start <= end);
assert!(end <= Self::CAP);
for i in start / T::CAP..=(end - 1) / T::CAP {
let begin = if start / T::CAP == i {
start % T::CAP
} else {
0
};
let end = if end / T::CAP == i {
end % T::CAP
} else {
T::CAP
};
f(&mut self.sub[i], begin..end);
self.bitset.set_bit(i, self.sub[i].any());
}
}
}
#[derive(Default)]
pub struct BitAlloc16(u16);
/// BitAlloc16 acts as the leaf (except the leaf bits of course) nodes
/// in the segment trees.
impl BitAlloc for BitAlloc16 {
const CAP: usize = 16;
fn alloc(&mut self) -> Option<usize> {
if self.any() {
let i = log2(self.0);
self.0.set_bit(i, false);
Some(i)
} else {
None
}
}
fn dealloc(&mut self, key: usize) {
assert!(!self.test(key));
self.0.set_bit(key, true);
}
fn insert(&mut self, range: Range<usize>) {
self.0.set_bits(range.clone(), 0xffff.get_bits(range));
}
fn remove(&mut self, range: Range<usize>) {
self.0.set_bits(range, 0);
}
fn any(&self) -> bool {
self.0 != 0
}
fn test(&self, key: usize) -> bool {
self.0.get_bit(key)
}
}
#[inline(always)]
#[cfg(target_arch = "x86_64")]
fn log2(x: u16) -> usize {
assert_ne!(x, 0);
let pos: u16;
unsafe { asm!("bsrw $1, $0" :"=r"(pos) :"r"(x) : :"volatile") };
pos as usize
}
#[inline(always)]
#[cfg(not(target_arch = "x86_64"))]
fn log2(x: u16) -> usize {
log2_naive(x)
}
#[cfg(not(target_arch = "x86_64"))]
#[inline(always)]
fn log2_naive(mut x: u16) -> usize {
//a naive implement
assert_ne!(x, 0);
let mut pos = -1;
while x != 0 {
pos += 1;
x >>= 1;
}
pos as usize
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(target_arch = "x86_64"))]
#[test]
fn log2_() {
for x in 1..=0xffff {
assert_eq!(log2(x), log2_naive(x), "log2 failed: {}", x);
}
}
#[test]
fn bitalloc16() {
let mut ba = BitAlloc16::default();
assert_eq!(BitAlloc16::CAP, 16);
ba.insert(0..16);
for i in 0..16 {
assert_eq!(ba.test(i), true);
}
ba.remove(8..14);
assert_eq!(ba.alloc(), Some(15));
assert_eq!(ba.alloc(), Some(14));
assert_eq!(ba.alloc(), Some(7));
ba.dealloc(14);
ba.dealloc(15);
ba.dealloc(7);
for _ in 0..10 {
assert!(ba.alloc().is_some());
}
assert!(!ba.any());
assert!(ba.alloc().is_none());
}
#[test]
fn bitalloc4k() {
let mut ba = BitAlloc4K::default();
assert_eq!(BitAlloc4K::CAP, 4096);
ba.insert(0..4096);
for i in 0..4096 {
assert_eq!(ba.test(i), true);
}
ba.remove(8..4094);
for i in 0..4096 {
assert_eq!(ba.test(i), i < 8 || i >= 4094);
}
assert_eq!(ba.alloc(), Some(4095));
assert_eq!(ba.alloc(), Some(4094));
assert_eq!(ba.alloc(), Some(7));
ba.dealloc(4095);
ba.dealloc(4094);
ba.dealloc(7);
for _ in 0..10 {
assert!(ba.alloc().is_some());
}
assert!(ba.alloc().is_none());
}
}

@ -1,11 +0,0 @@
[package]
name = "rcore-thread"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
description = "Bare-metal thread scheduler and executor"
edition = "2018"
[dependencies]
log = "0.4"
spin = "0.5"
deque = { git = "https://github.com/rcore-os/deque.git", branch = "no_std" }

@ -1 +0,0 @@
fn main() {}

@ -1,19 +0,0 @@
[package]
name = "example"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
edition = "2018"
[dependencies]
log = "0.4"
linked_list_allocator = "0.6"
blog_os = { git = "https://github.com/phil-opp/blog_os.git" }
rcore-thread = { path = ".." }
[package.metadata.bootimage]
default-target = "x86_64-blog_os.json"
run-command = ["qemu-system-x86_64",
"-drive", "format=raw,file={}",
"-serial", "mon:stdio",
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
]

@ -1,5 +0,0 @@
# Example of `rcore-thread` crate
```bash
bootimage run --release
```

@ -1,204 +0,0 @@
#![no_std]
#![no_main]
#![feature(asm)]
#![feature(alloc)]
#![feature(naked_functions)]
#![feature(lang_items)]
extern crate alloc;
use core::alloc::Layout;
use core::panic::PanicInfo;
use alloc::{boxed::Box, sync::Arc};
use blog_os::{exit_qemu, gdt, interrupts::init_idt, serial_println};
use linked_list_allocator::LockedHeap;
use rcore_thread::{*, std_thread as thread};
const STACK_SIZE: usize = 0x2000;
const HEAP_SIZE: usize = 0x100000;
const MAX_CPU_NUM: usize = 1;
const MAX_PROC_NUM: usize = 32;
/// The entry of the kernel
#[no_mangle]
pub extern "C" fn _start() -> ! {
// init x86
gdt::init();
init_idt();
// init log
init_log();
// init heap
unsafe { HEAP_ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); }
// init processor
let scheduler = scheduler::RRScheduler::new(5);
let thread_pool = Arc::new(ThreadPool::new(scheduler, MAX_PROC_NUM));
unsafe { processor().init(0, Thread::init(), thread_pool); }
// init threads
thread::spawn(|| {
let tid = processor().tid();
serial_println!("[{}] yield", tid);
thread::yield_now();
serial_println!("[{}] spawn", tid);
let t2 = thread::spawn(|| {
let tid = processor().tid();
serial_println!("[{}] yield", tid);
thread::yield_now();
serial_println!("[{}] return 8", tid);
8
});
serial_println!("[{}] join", tid);
let ret = t2.join();
serial_println!("[{}] get {:?}", tid, ret);
serial_println!("[{}] exit", tid);
});
// run threads
processor().run();
}
fn init_log() {
use log::*;
struct SimpleLogger;
impl Log for SimpleLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
serial_println!("[{:>5}] {}", record.level(), record.args());
}
fn flush(&self) {}
}
static LOGGER: SimpleLogger = SimpleLogger;
set_logger(&LOGGER).unwrap();
set_max_level(LevelFilter::Trace);
}
/// The context of a thread.
///
/// When a thread yield, its context will be stored at its stack.
#[derive(Debug, Default)]
#[repr(C)]
struct ContextData {
rdi: usize, // arg0
r15: usize,
r14: usize,
r13: usize,
r12: usize,
rbp: usize,
rbx: usize,
rip: usize,
}
impl ContextData {
fn new(entry: extern fn(usize) -> !, arg0: usize) -> Self {
ContextData {
rip: entry as usize,
rdi: arg0,
..ContextData::default()
}
}
}
#[repr(C)]
struct Thread {
rsp: usize,
stack: [u8; STACK_SIZE],
}
impl Thread {
unsafe fn init() -> Box<Self> {
Box::new(core::mem::uninitialized())
}
fn new(entry: extern fn(usize) -> !, arg0: usize) -> Box<Self> {
let mut thread = unsafe { Thread::init() };
let rsp = thread.stack.as_ptr() as usize + STACK_SIZE - core::mem::size_of::<ContextData>();
// push a Context at stack top
let init_context = ContextData::new(entry, arg0);
unsafe { (rsp as *mut ContextData).write(init_context); }
thread.rsp = rsp;
thread
}
}
/// Implement `switch_to` for a thread
impl Context for Thread {
/// Switch to another thread.
unsafe fn switch_to(&mut self, target: &mut Context) {
let (to, _): (*mut Thread, usize) = core::mem::transmute(target);
inner(self, to);
#[naked]
#[inline(never)]
unsafe extern "C" fn inner(_from: *mut Thread, _to: *mut Thread) {
asm!(
"
// push rip (by caller)
// Save self callee-save registers
push rbx
push rbp
push r12
push r13
push r14
push r15
push rdi
// Switch stacks
mov [rdi], rsp // *rdi = from_rsp
mov rsp, [rsi] // *rsi = to_rsp
// Restore target callee-save registers
pop rdi
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
// pop rip
ret"
: : : : "intel" "volatile" )
}
}
fn set_tid(&mut self, _tid: usize) {
}
}
/// Define global `Processor` for each core.
static PROCESSORS: [Processor; MAX_CPU_NUM] = [Processor::new()];
/// Now we only have one core.
fn cpu_id() -> usize { 0 }
/// Implement dependency for `rcore_thread::std_thread`
#[no_mangle]
pub fn processor() -> &'static Processor {
&PROCESSORS[cpu_id()]
}
/// Implement dependency for `rcore_thread::std_thread`
#[no_mangle]
pub fn new_kernel_context(entry: extern fn(usize) -> !, arg0: usize) -> Box<Context> {
Thread::new(entry, arg0)
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
serial_println!("\n{}", info);
unsafe { exit_qemu(); }
loop {}
}
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty();
static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
#[lang = "oom"]
fn oom(_: Layout) -> ! {
panic!("out of memory");
}

@ -1,15 +0,0 @@
{
"llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "-mmx,-sse,+soft-float"
}

@ -1,63 +0,0 @@
//! Enable and disable interrupt for each architecture.
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn disable_and_store() -> usize {
let rflags: usize;
asm!("pushfq; popq $0; cli" : "=r"(rflags) ::: "volatile");
rflags & (1 << 9)
}
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn restore(flags: usize) {
if flags != 0 {
asm!("sti" :::: "volatile");
}
}
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn enable_and_wfi() {
asm!("sti; hlt" :::: "volatile");
}
#[inline(always)]
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub unsafe fn disable_and_store() -> usize {
let sstatus: usize;
asm!("csrci sstatus, 1 << 1" : "=r"(sstatus) ::: "volatile");
sstatus & (1 << 1)
}
#[inline(always)]
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub unsafe fn restore(flags: usize) {
asm!("csrs sstatus, $0" :: "r"(flags) :: "volatile");
}
#[inline(always)]
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub unsafe fn enable_and_wfi() {
asm!("csrsi sstatus, 1 << 1; wfi" :::: "volatile");
}
#[inline(always)]
#[cfg(target_arch = "aarch64")]
pub unsafe fn disable_and_store() -> usize {
let daif: u32;
asm!("mrs $0, DAIF; msr daifset, #2": "=r"(daif) ::: "volatile");
daif as usize
}
#[inline(always)]
#[cfg(target_arch = "aarch64")]
pub unsafe fn restore(flags: usize) {
asm!("msr DAIF, $0" :: "r"(flags as u32) :: "volatile");
}
#[inline(always)]
#[cfg(target_arch = "aarch64")]
pub unsafe fn enable_and_wfi() {
asm!("msr daifclr, #2; wfi" :::: "volatile");
}

@ -1,19 +0,0 @@
#![cfg_attr(not(test), no_std)]
#![feature(alloc)]
#![feature(const_fn)]
#![feature(linkage)]
#![feature(vec_resize_default)]
#![feature(asm)]
#![feature(exact_size_is_empty)]
extern crate alloc;
mod interrupt;
mod processor;
pub mod scheduler;
pub mod std_thread;
mod thread_pool;
mod timer;
pub use crate::processor::Processor;
pub use crate::thread_pool::*;

@ -1,127 +0,0 @@
use crate::interrupt;
use crate::thread_pool::*;
use alloc::boxed::Box;
use alloc::sync::Arc;
use core::cell::UnsafeCell;
use log::*;
/// Thread executor
///
/// Per-CPU struct. Defined at global.
/// Only accessed by associated CPU with interrupt disabled.
#[derive(Default)]
pub struct Processor {
inner: UnsafeCell<Option<ProcessorInner>>,
}
unsafe impl Sync for Processor {}
struct ProcessorInner {
id: usize,
proc: Option<(Tid, Box<Context>)>,
loop_context: Box<Context>,
manager: Arc<ThreadPool>,
}
impl Processor {
pub const fn new() -> Self {
Processor {
inner: UnsafeCell::new(None),
}
}
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ThreadPool>) {
*self.inner.get() = Some(ProcessorInner {
id,
proc: None,
loop_context: context,
manager,
});
}
fn inner(&self) -> &mut ProcessorInner {
unsafe { &mut *self.inner.get() }
.as_mut()
.expect("Processor is not initialized")
}
/// Begin running processes after CPU setup.
///
/// This function never returns. It loops, doing:
/// - choose a process to run
/// - switch to start running that process
/// - eventually that process transfers control
/// via switch back to the scheduler.
pub fn run(&self) -> ! {
let inner = self.inner();
unsafe {
interrupt::disable_and_store();
}
loop {
if let Some(proc) = inner.manager.run(inner.id) {
trace!("CPU{} begin running thread {}", inner.id, proc.0);
inner.proc = Some(proc);
unsafe {
inner
.loop_context
.switch_to(&mut *inner.proc.as_mut().unwrap().1);
}
let (tid, context) = inner.proc.take().unwrap();
trace!("CPU{} stop running thread {}", inner.id, tid);
inner.manager.stop(tid, context);
} else {
trace!("CPU{} idle", inner.id);
unsafe {
interrupt::enable_and_wfi();
}
// wait for a timer interrupt
unsafe {
interrupt::disable_and_store();
}
}
}
}
/// Called by process running on this Processor.
/// Yield and reschedule.
///
/// The interrupt may be enabled.
pub fn yield_now(&self) {
let inner = self.inner();
unsafe {
let flags = interrupt::disable_and_store();
inner
.proc
.as_mut()
.unwrap()
.1
.switch_to(&mut *inner.loop_context);
interrupt::restore(flags);
}
}
pub fn tid(&self) -> Tid {
self.inner().proc.as_ref().unwrap().0
}
pub fn context(&self) -> &Context {
&*self.inner().proc.as_ref().unwrap().1
}
pub fn manager(&self) -> &ThreadPool {
&*self.inner().manager
}
/// Called by timer interrupt handler.
///
/// The interrupt should be disabled in the handler.
pub fn tick(&self) {
// If I'm idle, tid == None, need_reschedule == false.
// Will go back to `run()` after interrupt return.
let tid = self.inner().proc.as_ref().map(|p| p.0);
let need_reschedule = self.manager().tick(self.inner().id, tid);
if need_reschedule {
self.yield_now();
}
}
}

@ -1,34 +0,0 @@
use alloc::{collections::BinaryHeap, vec::Vec};
use log::*;
use spin::Mutex;
pub use self::o1::O1Scheduler;
pub use self::rr::RRScheduler;
pub use self::stride::StrideScheduler;
pub use self::work_stealing::WorkStealingScheduler;
mod o1;
mod rr;
mod stride;
mod work_stealing;
type Tid = usize;
/// The scheduler for a ThreadPool
pub trait Scheduler: 'static {
/// Push a thread to the back of ready queue.
fn push(&self, tid: Tid);
/// Select a thread to run, pop it from the queue.
fn pop(&self, cpu_id: usize) -> Option<Tid>;
/// Got a tick from CPU.
/// Return true if need reschedule.
fn tick(&self, current_tid: Tid) -> bool;
/// Set priority of a thread.
fn set_priority(&self, tid: Tid, priority: u8);
}
fn expand<T: Default + Clone>(vec: &mut Vec<T>, id: usize) {
let len = vec.len();
vec.resize(len.max(id + 1), T::default());
}

@ -1,65 +0,0 @@
//! O(1) scheduler introduced in Linux 2.6
//!
//! Two queues are maintained, one is active, another is inactive.
//! Take the first task from the active queue to run. When it is empty, swap active and inactive queues.
use super::*;
pub struct O1Scheduler {
inner: Mutex<O1SchedulerInner>,
}
struct O1SchedulerInner {
active_queue: usize,
queues: [Vec<Tid>; 2],
}
impl Scheduler for O1Scheduler {
fn push(&self, tid: usize) {
self.inner.lock().push(tid);
}
fn pop(&self, _cpu_id: usize) -> Option<usize> {
self.inner.lock().pop()
}
fn tick(&self, current_tid: usize) -> bool {
self.inner.lock().tick(current_tid)
}
fn set_priority(&self, _tid: usize, _priority: u8) {}
}
impl O1Scheduler {
pub fn new() -> Self {
let inner = O1SchedulerInner {
active_queue: 0,
queues: [Vec::new(), Vec::new()],
};
O1Scheduler {
inner: Mutex::new(inner),
}
}
}
impl O1SchedulerInner {
fn push(&mut self, tid: Tid) {
let inactive_queue = 1 - self.active_queue;
self.queues[inactive_queue].push(tid);
trace!("o1 push {}", tid - 1);
}
fn pop(&mut self) -> Option<Tid> {
let ret = match self.queues[self.active_queue].pop() {
Some(tid) => return Some(tid),
None => {
// active queue is empty, swap 'em
self.active_queue = 1 - self.active_queue;
self.queues[self.active_queue].pop()
}
};
trace!("o1 pop {:?}", ret);
ret
}
fn tick(&mut self, _current: Tid) -> bool {
true
}
}

@ -1,109 +0,0 @@
use super::*;
pub struct RRScheduler {
inner: Mutex<RRSchedulerInner>,
}
struct RRSchedulerInner {
max_time_slice: usize,
infos: Vec<RRProcInfo>,
}
#[derive(Debug, Default, Copy, Clone)]
struct RRProcInfo {
present: bool,
rest_slice: usize,
prev: Tid,
next: Tid,
}
impl Scheduler for RRScheduler {
fn push(&self, tid: usize) {
self.inner.lock().push(tid);
}
fn pop(&self, _cpu_id: usize) -> Option<usize> {
self.inner.lock().pop()
}
fn tick(&self, current_tid: usize) -> bool {
self.inner.lock().tick(current_tid)
}
fn set_priority(&self, _tid: usize, _priority: u8) {}
}
impl RRScheduler {
pub fn new(max_time_slice: usize) -> Self {
let inner = RRSchedulerInner {
max_time_slice,
infos: Vec::default(),
};
RRScheduler {
inner: Mutex::new(inner),
}
}
}
impl RRSchedulerInner {
fn push(&mut self, tid: Tid) {
let tid = tid + 1;
expand(&mut self.infos, tid);
{
let info = &mut self.infos[tid];
assert!(!info.present);
info.present = true;
if info.rest_slice == 0 {
info.rest_slice = self.max_time_slice;
}
}
self._list_add_before(tid, 0);
trace!("rr push {}", tid - 1);
}
fn pop(&mut self) -> Option<Tid> {
let ret = match self.infos[0].next {
0 => None,
tid => {
self.infos[tid].present = false;
self._list_remove(tid);
Some(tid - 1)
}
};
trace!("rr pop {:?}", ret);
ret
}
fn tick(&mut self, current: Tid) -> bool {
let current = current + 1;
expand(&mut self.infos, current);
assert!(!self.infos[current].present);
let rest = &mut self.infos[current].rest_slice;
if *rest > 0 {
*rest -= 1;
} else {
warn!("current process rest_slice = 0, need reschedule")
}
*rest == 0
}
}
impl RRSchedulerInner {
fn _list_add_before(&mut self, i: Tid, at: Tid) {
let prev = self.infos[at].prev;
self.infos[i].next = at;
self.infos[i].prev = prev;
self.infos[prev].next = i;
self.infos[at].prev = i;
}
fn _list_add_after(&mut self, i: Tid, at: Tid) {
let next = self.infos[at].next;
self._list_add_before(i, next);
}
fn _list_remove(&mut self, i: Tid) {
let next = self.infos[i].next;
let prev = self.infos[i].prev;
self.infos[next].prev = prev;
self.infos[prev].next = next;
self.infos[i].next = 0;
self.infos[i].prev = 0;
}
}

@ -1,113 +0,0 @@
//! Stride scheduler
//!
//! Each task is assigned a priority. Each task has a running stride.
//! The task with least stride is selected to run.
//! When a task is rescheduled, its stride is added to proportional to 1 / priority.
use super::*;
pub struct StrideScheduler {
inner: Mutex<StrideSchedulerInner>,
}
pub struct StrideSchedulerInner {
max_time_slice: usize,
infos: Vec<StrideProcInfo>,
queue: BinaryHeap<(Stride, Tid)>, // It's max heap, so pass < 0
}
#[derive(Debug, Default, Copy, Clone)]
struct StrideProcInfo {
present: bool,
rest_slice: usize,
stride: Stride,
priority: u8,
}
impl StrideProcInfo {
fn pass(&mut self) {
const BIG_STRIDE: Stride = 1 << 20;
let pass = if self.priority == 0 {
BIG_STRIDE
} else {
BIG_STRIDE / self.priority as Stride
};
// FIXME: overflowing_add is not working ???
// self.stride.overflowing_add(pass);
self.stride += pass;
}
}
type Stride = i32;
impl Scheduler for StrideScheduler {
fn push(&self, tid: usize) {
self.inner.lock().push(tid);
}
fn pop(&self, _cpu_id: usize) -> Option<usize> {
self.inner.lock().pop()
}
fn tick(&self, current_tid: usize) -> bool {
self.inner.lock().tick(current_tid)
}
fn set_priority(&self, tid: usize, priority: u8) {
self.inner.lock().set_priority(tid, priority);
}
}
impl StrideScheduler {
pub fn new(max_time_slice: usize) -> Self {
let inner = StrideSchedulerInner {
max_time_slice,
infos: Vec::default(),
queue: BinaryHeap::default(),
};
StrideScheduler {
inner: Mutex::new(inner),
}
}
}
impl StrideSchedulerInner {
fn push(&mut self, tid: Tid) {
expand(&mut self.infos, tid);
let info = &mut self.infos[tid];
assert!(!info.present);
info.present = true;
if info.rest_slice == 0 {
info.rest_slice = self.max_time_slice;
}
self.queue.push((-info.stride, tid));
trace!("stride push {}", tid);
}
fn pop(&mut self) -> Option<Tid> {
let ret = self.queue.pop().map(|(_, tid)| tid);
if let Some(tid) = ret {
let old_stride = self.infos[tid].stride;
self.infos[tid].pass();
let stride = self.infos[tid].stride;
trace!("stride {} {:#x} -> {:#x}", tid, old_stride, stride);
}
trace!("stride pop {:?}", ret);
ret
}
fn tick(&mut self, current: Tid) -> bool {
expand(&mut self.infos, current);
assert!(!self.infos[current].present);
let rest = &mut self.infos[current].rest_slice;
if *rest > 0 {
*rest -= 1;
} else {
warn!("current process rest_slice = 0, need reschedule")
}
*rest == 0
}
fn set_priority(&mut self, tid: Tid, priority: u8) {
self.infos[tid].priority = priority;
trace!("stride {} priority = {}", tid, priority);
}
}

@ -1,80 +0,0 @@
//! Work stealing scheduler
//!
//! Each CPU has its own queue, and each CPU takes new jobs from its own queue.
//! When its queue is empty, steal jobs from other CPU's queue.
use super::*;
use deque::{self, Stealer, Stolen, Worker};
pub struct WorkStealingScheduler {
/// The ready queue of each processors
workers: Vec<Worker<Tid>>,
/// Stealers to all processors' queue
stealers: Vec<Stealer<Tid>>,
}
impl WorkStealingScheduler {
pub fn new(core_num: usize) -> Self {
let (workers, stealers) = (0..core_num).map(|_| deque::new()).unzip();
WorkStealingScheduler { workers, stealers }
}
}
impl Scheduler for WorkStealingScheduler {
fn push(&self, tid: usize) {
// not random, but uniform
// no sync, because we don't need to
static mut WORKER_CPU: usize = 0;
let n = self.workers.len();
let mut cpu = unsafe {
WORKER_CPU = WORKER_CPU + 1;
if WORKER_CPU >= n {
WORKER_CPU -= n;
}
WORKER_CPU
};
// potential racing, so we just check once more
if cpu >= n {
cpu -= n;
}
self.workers[cpu].push(tid);
trace!("work-stealing: cpu{} push thread {}", cpu, tid);
}
fn pop(&self, cpu_id: usize) -> Option<usize> {
if let Some(tid) = self.workers[cpu_id].pop() {
trace!("work-stealing: cpu{} pop thread {}", cpu_id, tid);
return Some(tid);
}
let n = self.workers.len();
for i in 1..n {
let mut other_id = cpu_id + i;
if other_id >= n {
other_id -= n;
}
loop {
match self.stealers[other_id].steal() {
Stolen::Abort => {} // retry
Stolen::Empty => break,
Stolen::Data(tid) => {
trace!(
"work-stealing: cpu{} steal thread {} from cpu{}",
cpu_id,
tid,
other_id
);
return Some(tid);
}
}
}
}
None
}
fn tick(&self, _current_tid: usize) -> bool {
true
}
fn set_priority(&self, _tid: usize, _priority: u8) {}
}

@ -1,165 +0,0 @@
//! `std::thread`-like interface
//!
//! Based on Processor. Used in kernel.
//!
//! You need to implement the following functions before use:
//! - `processor`: Get a reference of the current `Processor`
//! - `new_kernel_context`: Construct a `Context` of the new kernel thread
use crate::processor::*;
use crate::thread_pool::*;
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::time::Duration;
use log::*;
#[linkage = "weak"]
#[no_mangle]
/// Get a reference of the current `Processor`
fn processor() -> &'static Processor {
unimplemented!("thread: Please implement and export `processor`")
}
#[linkage = "weak"]
#[no_mangle]
/// Construct a `Context` of the new kernel thread
fn new_kernel_context(_entry: extern "C" fn(usize) -> !, _arg: usize) -> Box<Context> {
unimplemented!("thread: Please implement and export `new_kernel_context`")
}
/// Gets a handle to the thread that invokes it.
pub fn current() -> Thread {
Thread {
tid: processor().tid(),
}
}
/// Puts the current thread to sleep for the specified amount of time.
pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur);
trace!("sleep: {:?} ticks", time);
processor().manager().sleep(current().id(), time);
park();
fn dur_to_ticks(dur: Duration) -> usize {
return dur.as_secs() as usize * 100 + dur.subsec_nanos() as usize / 10_000_000;
}
}
/// Spawns a new thread, returning a JoinHandle for it.
///
/// `F`: Type of the function `f`
/// `T`: Type of the return value of `f`
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
trace!("spawn:");
// 注意到下面的问题:
// Processor只能从入口地址entry+参数arg创建新线程
// 而我们现在需要让它执行一个未知类型的闭包函数f
// 首先把函数本体(代码数据)置于堆空间中
let f = Box::into_raw(Box::new(f));
// 定义一个静态函数作为新线程的入口点
// 其参数是函数f在堆上的指针
// 这样我们就把函数f传到了一个静态函数内部
//
// 注意到它具有泛型参数因此对每一次spawn调用
// 由于F类型是独特的因此都会生成一个新的kernel_thread_entry
extern "C" fn kernel_thread_entry<F, T>(f: usize) -> !
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
// 在静态函数内部:
// 根据传进来的指针恢复f
let f = unsafe { Box::from_raw(f as *mut F) };
// 调用f并将其返回值也放在堆上
let ret = Box::new(f());
// 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
let exit_code = Box::into_raw(ret) as usize;
processor().manager().exit(current().id(), exit_code);
processor().yield_now();
// 再也不会被调度回来了
unreachable!()
}
// 在Processor中创建新的线程
let context = new_kernel_context(kernel_thread_entry::<F, T>, f as usize);
let tid = processor().manager().add(context);
// 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的
return JoinHandle {
thread: Thread { tid },
mark: PhantomData,
};
}
/// Cooperatively gives up a time slice to the OS scheduler.
pub fn yield_now() {
trace!("yield:");
processor().yield_now();
}
/// Blocks unless or until the current thread's token is made available.
pub fn park() {
trace!("park:");
processor().manager().sleep(current().id(), 0);
processor().yield_now();
}
/// Blocks unless or until the current thread's token is made available.
/// Calls `f` before thread yields. Can be used to avoid racing.
pub fn park_action(f: impl FnOnce()) {
trace!("park:");
processor().manager().sleep(current().id(), 0);
f();
processor().yield_now();
}
/// A handle to a thread.
pub struct Thread {
tid: usize,
}
impl Thread {
/// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) {
processor().manager().wakeup(self.tid);
}
/// Gets the thread's unique identifier.
pub fn id(&self) -> usize {
self.tid
}
}
/// An owned permission to join on a thread (block on its termination).
pub struct JoinHandle<T> {
thread: Thread,
mark: PhantomData<T>,
}
impl<T> JoinHandle<T> {
/// Extracts a handle to the underlying thread.
pub fn thread(&self) -> &Thread {
&self.thread
}
/// Waits for the associated thread to finish.
pub fn join(self) -> Result<T, ()> {
loop {
trace!("try to join thread {}", self.thread.tid);
if let Some(exit_code) = processor().manager().try_remove(self.thread.tid) {
// Find return value on the heap from the exit code.
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
}
processor().manager().wait(current().id(), self.thread.tid);
processor().yield_now();
}
}
}

@ -1,221 +0,0 @@
use crate::scheduler::Scheduler;
use crate::timer::Timer;
use alloc::boxed::Box;
use alloc::vec::Vec;
use log::*;
use spin::{Mutex, MutexGuard};
struct Thread {
status: Status,
status_after_stop: Status,
waiter: Option<Tid>,
context: Option<Box<Context>>,
}
pub type Tid = usize;
type ExitCode = usize;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
Ready,
Running(usize),
Sleeping,
/// aka ZOMBIE. Its context was dropped.
Exited(ExitCode),
}
#[derive(Eq, PartialEq)]
enum Event {
Wakeup(Tid),
}
pub trait Context {
/// Switch to target context
unsafe fn switch_to(&mut self, target: &mut Context);
/// A tid is allocated for this context
fn set_tid(&mut self, tid: Tid);
}
pub struct ThreadPool {
threads: Vec<Mutex<Option<Thread>>>,
scheduler: Box<Scheduler>,
timer: Mutex<Timer<Event>>,
}
impl ThreadPool {
pub fn new(scheduler: impl Scheduler, max_proc_num: usize) -> Self {
ThreadPool {
threads: new_vec_default(max_proc_num),
scheduler: Box::new(scheduler),
timer: Mutex::new(Timer::new()),
}
}
fn alloc_tid(&self) -> (Tid, MutexGuard<Option<Thread>>) {
for (i, proc) in self.threads.iter().enumerate() {
let thread = proc.lock();
if thread.is_none() {
return (i, thread);
}
}
panic!("Thread number exceeded");
}
/// Add a new thread
/// Calls action with tid and thread context
pub fn add(&self, mut context: Box<Context>) -> Tid {
let (tid, mut thread) = self.alloc_tid();
context.set_tid(tid);
*thread = Some(Thread {
status: Status::Ready,
status_after_stop: Status::Ready,
waiter: None,
context: Some(context),
});
self.scheduler.push(tid);
tid
}
/// Make thread `tid` time slice -= 1.
/// Return true if time slice == 0.
/// Called by timer interrupt handler.
pub(crate) fn tick(&self, cpu_id: usize, tid: Option<Tid>) -> bool {
if cpu_id == 0 {
let mut timer = self.timer.lock();
timer.tick();
while let Some(event) = timer.pop() {
match event {
Event::Wakeup(tid) => self.set_status(tid, Status::Ready),
}
}
}
match tid {
Some(tid) => self.scheduler.tick(tid),
None => false,
}
}
/// Set the priority of thread `tid`
pub fn set_priority(&self, tid: Tid, priority: u8) {
self.scheduler.set_priority(tid, priority);
}
/// Called by Processor to get a thread to run.
/// The manager first mark it `Running`,
/// then take out and return its Context.
pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box<Context>)> {
self.scheduler.pop(cpu_id).map(|tid| {
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("thread not exist");
proc.status = Status::Running(cpu_id);
(tid, proc.context.take().expect("context not exist"))
})
}
/// Called by Processor to finish running a thread
/// and give its context back.
pub(crate) fn stop(&self, tid: Tid, context: Box<Context>) {
let mut proc_lock = self.threads[tid].lock();
let proc = proc_lock.as_mut().expect("thread not exist");
proc.status = proc.status_after_stop.clone();
proc.status_after_stop = Status::Ready;
proc.context = Some(context);
match proc.status {
Status::Ready => self.scheduler.push(tid),
Status::Exited(_) => self.exit_handler(proc),
_ => {}
}
}
/// Called by `JoinHandle` to let thread `tid` wait for `target`.
/// The `tid` is going to sleep, and will be woke up when `target` exit.
/// (see `exit_handler()`)
pub(crate) fn wait(&self, tid: Tid, target: Tid) {
self.set_status(tid, Status::Sleeping);
let mut target_lock = self.threads[target].lock();
let target = target_lock.as_mut().expect("thread not exist");
target.waiter = Some(tid);
}
/// Switch the status of a thread.
/// Insert/Remove it to/from scheduler if necessary.
fn set_status(&self, tid: Tid, status: Status) {
let mut proc_lock = self.threads[tid].lock();
if let Some(mut proc) = proc_lock.as_mut() {
trace!("thread {} {:?} -> {:?}", tid, proc.status, status);
match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return,
(Status::Ready, _) => panic!("can not remove a thread from ready queue"),
(Status::Exited(_), _) => panic!("can not set status for a exited thread"),
(Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)),
(Status::Running(_), Status::Ready) => {} // thread will be added to scheduler in stop()
(_, Status::Ready) => self.scheduler.push(tid),
_ => {}
}
match proc.status {
Status::Running(_) => proc.status_after_stop = status,
_ => proc.status = status,
}
match proc.status {
Status::Exited(_) => self.exit_handler(proc),
_ => {}
}
}
}
/// Try to remove an exited thread `tid`.
/// Return its exit code if success.
pub fn try_remove(&self, tid: Tid) -> Option<ExitCode> {
let mut proc_lock = self.threads[tid].lock();
let proc = proc_lock.as_ref().expect("thread not exist");
match proc.status {
Status::Exited(code) => {
// release the tid
*proc_lock = None;
Some(code)
}
_ => None,
}
}
/// Sleep `tid` for `time` ticks.
/// `time` == 0 means sleep forever
pub fn sleep(&self, tid: Tid, time: usize) {
self.set_status(tid, Status::Sleeping);
if time != 0 {
self.timer.lock().start(time, Event::Wakeup(tid));
}
}
pub fn wakeup(&self, tid: Tid) {
let mut proc_lock = self.threads[tid].lock();
if let Some(mut proc) = proc_lock.as_mut() {
trace!("thread {} {:?} -> {:?}", tid, proc.status, Status::Ready);
if let Status::Sleeping = proc.status {
proc.status = Status::Ready;
self.scheduler.push(tid);
}
}
}
pub fn exit(&self, tid: Tid, code: ExitCode) {
// NOTE: if `tid` is running, status change will be deferred.
self.set_status(tid, Status::Exited(code));
}
/// Called when a thread exit
fn exit_handler(&self, proc: &mut Thread) {
// wake up waiter
if let Some(waiter) = proc.waiter {
self.wakeup(waiter);
}
// drop its context
proc.context = None;
}
}
fn new_vec_default<T: Default>(size: usize) -> Vec<T> {
let mut vec = Vec::new();
vec.resize_with(size, Default::default);
vec
}

@ -1,65 +0,0 @@
//! A simple timer
use alloc::collections::VecDeque;
type Time = usize;
struct Event<T> {
time: Time,
data: T,
}
/// A simple timer using ordered dequeue
pub struct Timer<T> {
tick: Time,
timers: VecDeque<Event<T>>,
}
impl<T: PartialEq> Timer<T> {
/// Create a new timer.
pub fn new() -> Self {
Timer {
tick: 0,
timers: VecDeque::new(),
}
}
/// Called on each tick.
pub fn tick(&mut self) {
self.tick += 1;
}
/// Pop an expired timer after `tick`.
///
/// This must be called after calling `tick`,
/// and should be called multiple times until return `None`.
pub fn pop(&mut self) -> Option<T> {
match self.timers.front() {
None => return None,
Some(timer) if timer.time != self.tick => return None,
_ => {}
};
self.timers.pop_front().map(|t| t.data)
}
/// Start a timer with given time interval
pub fn start(&mut self, time_after: Time, data: T) {
//debug!("{:?} {:?}", self.tick, time_after);
let time = self.tick + time_after;
let event = Event { time, data };
let mut it = self.timers.iter();
let mut i: usize = 0;
loop {
match it.next() {
None => break,
Some(e) if e.time >= time => break,
_ => {}
}
i += 1;
}
self.timers.insert(i, event);
}
/// Stop a timer
pub fn stop(&mut self, data: T) {
if let Some(i) = self.timers.iter().position(|t| t.data == data) {
self.timers.remove(i);
}
}
}

22
kernel/Cargo.lock generated

@ -59,13 +59,6 @@ dependencies = [
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-allocator"
version = "0.1.0"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit_field"
version = "0.9.0"
@ -76,6 +69,14 @@ name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitmap-allocator"
version = "0.1.0"
source = "git+https://github.com/rcore-os/bitmap-allocator#891867c95bc81f2376ec6eca9e349c42dc26c7fb"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitvec"
version = "0.9.0"
@ -310,9 +311,9 @@ dependencies = [
"aarch64 2.2.2 (git+https://github.com/rcore-os/aarch64)",
"apic 0.1.0 (git+https://github.com/rcore-os/apic-rs)",
"bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)",
"bit-allocator 0.1.0",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)",
"bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)",
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)",
"buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -330,7 +331,7 @@ dependencies = [
"rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)",
"rcore-memory 0.1.0",
"rcore-thread 0.1.0",
"rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)",
"riscv 0.5.0 (git+https://github.com/rcore-os/riscv)",
"smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -367,6 +368,7 @@ dependencies = [
[[package]]
name = "rcore-thread"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#470634bc15de1532ab255555ff71adf112fd52e8"
dependencies = [
"deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -600,6 +602,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bcm2837 0.1.0 (git+https://github.com/rcore-os/bcm2837)" = "<none>"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)" = "<none>"
"checksum bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)" = "<none>"
"checksum bitvec 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfadef5c4e2c2e64067b9ecc061179f12ac7ec65ba613b1f60f3972bbada1f5b"
"checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>"
@ -635,6 +638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d"
"checksum rcore-fs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rcore-fs-sfs 0.1.0 (git+https://github.com/rcore-os/rcore-fs)" = "<none>"
"checksum rcore-thread 0.1.0 (git+https://github.com/rcore-os/rcore-thread)" = "<none>"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e10f31b6d2299e5620986ad9fcdd66463e125ad72af4f403f9aedf7592d5ccdb"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"

@ -50,9 +50,9 @@ device_tree = { git = "https://github.com/rcore-os/device_tree-rs" }
isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers" }
lazy_static = { version = "1.3", features = ["spin_no_std"] }
smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
bit-allocator = { path = "../crate/bit-allocator" }
bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator" }
rcore-memory = { path = "../crate/memory" }
rcore-thread = { path = "../crate/thread" }
rcore-thread = { git = "https://github.com/rcore-os/rcore-thread" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs" }

@ -1,5 +1,5 @@
use crate::consts::KERNEL_OFFSET;
use bit_allocator::BitAlloc;
use bitmap_allocator::BitAlloc;
// Depends on kernel
use super::{BootInfo, MemoryRegionType};
use crate::memory::{active_table, alloc_frame, init_heap, FRAME_ALLOCATOR};

@ -3,7 +3,7 @@ pub use crate::arch::paging::*;
use crate::consts::MEMORY_OFFSET;
use crate::process::process_unsafe;
use crate::sync::SpinNoIrqLock;
use bit_allocator::BitAlloc;
use bitmap_allocator::BitAlloc;
use buddy_system_allocator::LockedHeap;
use lazy_static::*;
use log::*;
@ -14,15 +14,15 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet<InactivePageTable0>;
// x86_64 support up to 64G memory
#[cfg(target_arch = "x86_64")]
pub type FrameAlloc = bit_allocator::BitAlloc16M;
pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
// RISCV has 8M memory
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
pub type FrameAlloc = bit_allocator::BitAlloc4K;
pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
// Raspberry Pi 3 has 1G memory
#[cfg(target_arch = "aarch64")]
pub type FrameAlloc = bit_allocator::BitAlloc1M;
pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> =

Loading…
Cancel
Save