From 250918b3629f23ef9b9d8d20904743be5713499c Mon Sep 17 00:00:00 2001 From: Carl Fredrik Samson Date: Wed, 26 Jan 2022 00:43:09 +0100 Subject: [PATCH] Updated inline asm from llvm_asm to new asm syntax --- src/0_background_information.md | 387 ++++++++++++++++---------------- 1 file changed, 192 insertions(+), 195 deletions(-) diff --git a/src/0_background_information.md b/src/0_background_information.md index b95de9e..be444bf 100644 --- a/src/0_background_information.md +++ b/src/0_background_information.md @@ -147,206 +147,203 @@ A green threads example could look something like this: _**Press the expand icon in the top right corner to show the example code.**_ -```rust, edition2018 -# #![feature(llvm_asm, naked_functions)] -# use std::ptr; -# -# const DEFAULT_STACK_SIZE: usize = 1024 * 1024 * 2; -# const MAX_THREADS: usize = 4; -# static mut RUNTIME: usize = 0; -# -# pub struct Runtime { -# threads: Vec, -# current: usize, -# } -# -# #[derive(PartialEq, Eq, Debug)] -# enum State { -# Available, -# Running, -# Ready, -# } -# -# struct Thread { -# id: usize, -# stack: Vec, -# ctx: ThreadContext, -# state: State, -# task: Option>, -# } -# -# #[derive(Debug, Default)] -# #[repr(C)] -# struct ThreadContext { -# rsp: u64, -# r15: u64, -# r14: u64, -# r13: u64, -# r12: u64, -# rbx: u64, -# rbp: u64, -# thread_ptr: u64, -# } -# -# impl Thread { -# fn new(id: usize) -> Self { -# Thread { -# id, -# stack: vec![0_u8; DEFAULT_STACK_SIZE], -# ctx: ThreadContext::default(), -# state: State::Available, -# task: None, +```rust, edition2021 +# #![feature(naked_functions)] +# use std::{arch::asm, ptr}; +# +# const DEFAULT_STACK_SIZE: usize = 1024 * 1024 * 2; +# const MAX_THREADS: usize = 4; +# static mut RUNTIME: usize = 0; +# +# pub struct Runtime { +# threads: Vec, +# current: usize, +# } +# +# #[derive(PartialEq, Eq, Debug)] +# enum State { +# Available, +# Running, +# Ready, +# } +# +# struct Thread { +# id: usize, +# stack: Vec, +# ctx: ThreadContext, +# state: State, +# task: Option>, +# } +# +# #[derive(Debug, Default)] +# #[repr(C)] +# struct ThreadContext { +# rsp: u64, +# r15: u64, +# r14: u64, +# r13: u64, +# r12: u64, +# rbx: u64, +# rbp: u64, +# thread_ptr: u64, +# } +# +# impl Thread { +# fn new(id: usize) -> Self { +# Thread { +# id, +# stack: vec![0_u8; DEFAULT_STACK_SIZE], +# ctx: ThreadContext::default(), +# state: State::Available, +# task: None, +# } +# } +# } +# +# impl Runtime { +# pub fn new() -> Self { +# let base_thread = Thread { +# id: 0, +# stack: vec![0_u8; DEFAULT_STACK_SIZE], +# ctx: ThreadContext::default(), +# state: State::Running, +# task: None, +# }; +# +# let mut threads = vec![base_thread]; +# threads[0].ctx.thread_ptr = &threads[0] as *const Thread as u64; +# let mut available_threads: Vec = (1..MAX_THREADS).map(|i| Thread::new(i)).collect(); +# threads.append(&mut available_threads); +# +# Runtime { +# threads, +# current: 0, +# } +# } +# +# pub fn init(&self) { +# unsafe { +# let r_ptr: *const Runtime = self; +# RUNTIME = r_ptr as usize; +# } +# } +# +# pub fn run(&mut self) -> ! { +# while self.t_yield() {} +# std::process::exit(0); +# } +# +# fn t_return(&mut self) { +# if self.current != 0 { +# self.threads[self.current].state = State::Available; +# self.t_yield(); +# } +# } +# +# #[inline(never)] +# fn t_yield(&mut self) -> bool { +# let mut pos = self.current; +# while self.threads[pos].state != State::Ready { +# pos += 1; +# if pos == self.threads.len() { +# pos = 0; +# } +# if pos == self.current { +# return false; +# } +# } +# +# if self.threads[self.current].state != State::Available { +# self.threads[self.current].state = State::Ready; +# } +# +# self.threads[pos].state = State::Running; +# let old_pos = self.current; +# self.current = pos; +# +# unsafe { +# let old: *mut ThreadContext = &mut self.threads[old_pos].ctx; +# let new: *const ThreadContext = &self.threads[pos].ctx; +# asm!("call switch", in("rdi") old, in("rsi") new, clobber_abi("C")); # } -# } -# } -# -# impl Runtime { -# pub fn new() -> Self { -# let base_thread = Thread { -# id: 0, -# stack: vec![0_u8; DEFAULT_STACK_SIZE], -# ctx: ThreadContext::default(), -# state: State::Running, -# task: None, -# }; -# -# let mut threads = vec![base_thread]; -# threads[0].ctx.thread_ptr = &threads[0] as *const Thread as u64; -# let mut available_threads: Vec = (1..MAX_THREADS).map(|i| Thread::new(i)).collect(); -# threads.append(&mut available_threads); -# -# Runtime { -# threads, -# current: 0, -# } -# } -# -# pub fn init(&self) { -# unsafe { -# let r_ptr: *const Runtime = self; -# RUNTIME = r_ptr as usize; -# } -# } -# -# pub fn run(&mut self) -> ! { -# while self.t_yield() {} -# std::process::exit(0); -# } -# -# fn t_return(&mut self) { -# if self.current != 0 { -# self.threads[self.current].state = State::Available; -# self.t_yield(); -# } -# } -# -# fn t_yield(&mut self) -> bool { -# let mut pos = self.current; -# while self.threads[pos].state != State::Ready { -# pos += 1; -# if pos == self.threads.len() { -# pos = 0; -# } -# if pos == self.current { -# return false; -# } -# } -# -# if self.threads[self.current].state != State::Available { -# self.threads[self.current].state = State::Ready; -# } -# -# self.threads[pos].state = State::Running; -# let old_pos = self.current; -# self.current = pos; -# -# unsafe { -# let old: *mut ThreadContext = &mut self.threads[old_pos].ctx; -# let new: *const ThreadContext = &self.threads[pos].ctx; -# llvm_asm!( -# "mov $0, %rdi -# mov $1, %rsi"::"r"(old), "r"(new) -# ); -# switch(); -# } -# true -# } -# -# pub fn spawn(f: F){ -# unsafe { -# let rt_ptr = RUNTIME as *mut Runtime; -# let available = (*rt_ptr) -# .threads -# .iter_mut() -# .find(|t| t.state == State::Available) -# .expect("no available thread."); -# -# let size = available.stack.len(); -# let s_ptr = available.stack.as_mut_ptr().offset(size as isize); -# let s_ptr = (s_ptr as usize & !15) as *mut u8; -# available.task = Some(Box::new(f)); -# available.ctx.thread_ptr = available as *const Thread as u64; -# //ptr::write(s_ptr.offset((size - 8) as isize) as *mut u64, guard as u64); -# std::ptr::write(s_ptr.offset(-16) as *mut u64, guard as u64); -# std::ptr::write(s_ptr.offset(-24) as *mut u64, skip as u64); -# std::ptr::write(s_ptr.offset(-32) as *mut u64, call as u64); -# available.ctx.rsp = s_ptr.offset(-32) as u64; -# available.state = State::Ready; -# } -# } -# } -# -# fn call(thread: u64) { -# let thread = unsafe { &*(thread as *const Thread) }; -# if let Some(f) = &thread.task { -# f(); -# } -# } -# +# self.threads.len() > 0 +# } +# +# pub fn spawn(f: F){ +# unsafe { +# let rt_ptr = RUNTIME as *mut Runtime; +# let available = (*rt_ptr) +# .threads +# .iter_mut() +# .find(|t| t.state == State::Available) +# .expect("no available thread."); +# +# let size = available.stack.len(); +# let s_ptr = available.stack.as_mut_ptr().offset(size as isize); +# let s_ptr = (s_ptr as usize & !15) as *mut u8; +# available.task = Some(Box::new(f)); +# available.ctx.thread_ptr = available as *const Thread as u64; +# //ptr::write(s_ptr.offset((size - 8) as isize) as *mut u64, guard as u64); +# std::ptr::write(s_ptr.offset(-16) as *mut u64, guard as u64); +# std::ptr::write(s_ptr.offset(-24) as *mut u64, skip as u64); +# std::ptr::write(s_ptr.offset(-32) as *mut u64, call as u64); +# available.ctx.rsp = s_ptr.offset(-32) as u64; +# available.state = State::Ready; +# } +# } +# } +# +# fn call(thread: u64) { +# let thread = unsafe { &*(thread as *const Thread) }; +# if let Some(f) = &thread.task { +# f(); +# } +# } +# +# #[naked] +# unsafe fn skip() { +# asm!("ret", options(noreturn)) +# } +# +# fn guard() { +# unsafe { +# let rt_ptr = RUNTIME as *mut Runtime; +# let rt = &mut *rt_ptr; +# println!("THREAD {} FINISHED.", rt.threads[rt.current].id); +# rt.t_return(); +# }; +# } +# +# pub fn yield_thread() { +# unsafe { +# let rt_ptr = RUNTIME as *mut Runtime; +# (*rt_ptr).t_yield(); +# }; +# } # #[naked] -# fn skip() { } -# -# fn guard() { -# unsafe { -# let rt_ptr = RUNTIME as *mut Runtime; -# let rt = &mut *rt_ptr; -# println!("THREAD {} FINISHED.", rt.threads[rt.current].id); -# rt.t_return(); -# }; -# } -# -# pub fn yield_thread() { -# unsafe { -# let rt_ptr = RUNTIME as *mut Runtime; -# (*rt_ptr).t_yield(); -# }; -# } -# -# #[naked] -# #[inline(never)] +# #[no_mangle] # unsafe fn switch() { -# llvm_asm!(" -# mov %rsp, 0x00(%rdi) -# mov %r15, 0x08(%rdi) -# mov %r14, 0x10(%rdi) -# mov %r13, 0x18(%rdi) -# mov %r12, 0x20(%rdi) -# mov %rbx, 0x28(%rdi) -# mov %rbp, 0x30(%rdi) -# -# mov 0x00(%rsi), %rsp -# mov 0x08(%rsi), %r15 -# mov 0x10(%rsi), %r14 -# mov 0x18(%rsi), %r13 -# mov 0x20(%rsi), %r12 -# mov 0x28(%rsi), %rbx -# mov 0x30(%rsi), %rbp -# mov 0x38(%rsi), %rdi -# " -# ); +# asm!( +# "mov 0x00[rdi], rsp", +# "mov 0x08[rdi], r15", +# "mov 0x10[rdi], r14", +# "mov 0x18[rdi], r13", +# "mov 0x20[rdi], r12", +# "mov 0x28[rdi], rbx", +# "mov 0x30[rdi], rbp", +# "mov rsp, 0x00[rsi]", +# "mov r15, 0x08[rsi]", +# "mov r14, 0x10[rsi]", +# "mov r13, 0x18[rsi]", +# "mov r12, 0x20[rsi]", +# "mov rbx, 0x28[rsi]", +# "mov rbp, 0x30[rsi]", +# "mov rdi, 0x38[rsi]", +# "ret", options(noreturn) +# ); # } # #[cfg(not(windows))] -fn main() { +pub fn run() { let mut runtime = Runtime::new(); runtime.init(); Runtime::spawn(|| {