From e4b84bdd838cc5600f554e88d3bf23d5c55b75bd Mon Sep 17 00:00:00 2001 From: Carl Fredrik Samson Date: Sun, 6 Dec 2020 01:34:53 +0100 Subject: [PATCH] Fixed error in green threads example. See: https://github.com/cfsamson/example-greenthreads/issues/20. Ugh... But it works now! --- src/0_background_information.md | 136 ++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 58 deletions(-) diff --git a/src/0_background_information.md b/src/0_background_information.md index a9b2396..387f3c7 100644 --- a/src/0_background_information.md +++ b/src/0_background_information.md @@ -149,30 +149,32 @@ _**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 { @@ -183,8 +185,9 @@ _**Press the expand icon in the top right corner to show the example code.**_ # r12: u64, # rbx: u64, # rbp: u64, +# thread_ptr: u64, # } -# +# # impl Thread { # fn new(id: usize) -> Self { # Thread { @@ -192,10 +195,11 @@ _**Press the expand icon in the top right corner to show the example code.**_ # 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 { @@ -203,37 +207,39 @@ _**Press the expand icon in the top right corner to show the example code.**_ # 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 { @@ -245,85 +251,99 @@ _**Press the expand icon in the top right corner to show the example code.**_ # 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(); -# } -# self.threads.len() > 0 +# 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(&mut self, f: fn()) { -# let available = self -# .threads -# .iter_mut() -# .find(|t| t.state == State::Available) -# .expect("no available thread."); -# -# let size = available.stack.len(); +# +# 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, f 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; # } -# available.state = State::Ready; # } # } -# +# +# fn call(thread: u64) { +# let thread = unsafe { &*(thread as *const Thread) }; +# if let Some(f) = &thread.task { +# f(); +# } +# } +# # #[naked] # fn skip() { } -# +# # fn guard() { # unsafe { # let rt_ptr = RUNTIME as *mut Runtime; -# (*rt_ptr).t_return(); +# 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)] # 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 %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 +# " +# ); # } # #[cfg(not(windows))] fn main() {