add example for 'thread' crate

master
WangRunji 6 years ago
parent 5bffce787b
commit 1541282ad7

@ -0,0 +1,19 @@
[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"
]

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

@ -0,0 +1,199 @@
#![no_std]
#![no_main]
#![feature(asm)]
#![feature(alloc)]
#![feature(naked_functions)]
#![feature(panic_info_message)]
#![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 = Box::new(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!("I'm thread {}! yield...", tid);
thread::yield_now();
serial_println!("I'm thread {}! exit...", tid);
});
thread::spawn(|| {
let tid = processor().tid();
serial_println!("I'm thread {}! yield...", tid);
thread::yield_now();
serial_println!("I'm thread {}! 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" )
}
}
}
/// 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) -> ! {
let location = info.location().unwrap();
let message = info.message().unwrap();
serial_println!("\nPANIC @ {}\n\t{}", location, message);
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");
}

@ -0,0 +1,15 @@
{
"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"
}
Loading…
Cancel
Save