Updated inline asm from llvm_asm to new asm syntax

This commit is contained in:
Carl Fredrik Samson
2022-01-26 00:43:09 +01:00
committed by GitHub
parent 6adb910e51
commit 250918b362

View File

@@ -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.**_ _**Press the expand icon in the top right corner to show the example code.**_
```rust, edition2018 ```rust, edition2021
# #![feature(llvm_asm, naked_functions)] # #![feature(naked_functions)]
# use std::ptr; # use std::{arch::asm, ptr};
# #
# const DEFAULT_STACK_SIZE: usize = 1024 * 1024 * 2; # const DEFAULT_STACK_SIZE: usize = 1024 * 1024 * 2;
# const MAX_THREADS: usize = 4; # const MAX_THREADS: usize = 4;
# static mut RUNTIME: usize = 0; # static mut RUNTIME: usize = 0;
# #
# pub struct Runtime { # pub struct Runtime {
# threads: Vec<Thread>, # threads: Vec<Thread>,
# current: usize, # current: usize,
# } # }
# #
# #[derive(PartialEq, Eq, Debug)] # #[derive(PartialEq, Eq, Debug)]
# enum State { # enum State {
# Available, # Available,
# Running, # Running,
# Ready, # Ready,
# } # }
# #
# struct Thread { # struct Thread {
# id: usize, # id: usize,
# stack: Vec<u8>, # stack: Vec<u8>,
# ctx: ThreadContext, # ctx: ThreadContext,
# state: State, # state: State,
# task: Option<Box<dyn Fn()>>, # task: Option<Box<dyn Fn()>>,
# } # }
# #
# #[derive(Debug, Default)] # #[derive(Debug, Default)]
# #[repr(C)] # #[repr(C)]
# struct ThreadContext { # struct ThreadContext {
# rsp: u64, # rsp: u64,
# r15: u64, # r15: u64,
# r14: u64, # r14: u64,
# r13: u64, # r13: u64,
# r12: u64, # r12: u64,
# rbx: u64, # rbx: u64,
# rbp: u64, # rbp: u64,
# thread_ptr: u64, # thread_ptr: u64,
# } # }
# #
# impl Thread { # impl Thread {
# fn new(id: usize) -> Self { # fn new(id: usize) -> Self {
# Thread { # Thread {
# id, # id,
# stack: vec![0_u8; DEFAULT_STACK_SIZE], # stack: vec![0_u8; DEFAULT_STACK_SIZE],
# ctx: ThreadContext::default(), # ctx: ThreadContext::default(),
# state: State::Available, # state: State::Available,
# task: None, # 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<Thread> = (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"));
# } # }
# } # self.threads.len() > 0
# } # }
# #
# impl Runtime { # pub fn spawn<F: Fn() + 'static>(f: F){
# pub fn new() -> Self { # unsafe {
# let base_thread = Thread { # let rt_ptr = RUNTIME as *mut Runtime;
# id: 0, # let available = (*rt_ptr)
# stack: vec![0_u8; DEFAULT_STACK_SIZE], # .threads
# ctx: ThreadContext::default(), # .iter_mut()
# state: State::Running, # .find(|t| t.state == State::Available)
# task: None, # .expect("no available thread.");
# }; #
# # let size = available.stack.len();
# let mut threads = vec![base_thread]; # let s_ptr = available.stack.as_mut_ptr().offset(size as isize);
# threads[0].ctx.thread_ptr = &threads[0] as *const Thread as u64; # let s_ptr = (s_ptr as usize & !15) as *mut u8;
# let mut available_threads: Vec<Thread> = (1..MAX_THREADS).map(|i| Thread::new(i)).collect(); # available.task = Some(Box::new(f));
# threads.append(&mut available_threads); # 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);
# Runtime { # std::ptr::write(s_ptr.offset(-16) as *mut u64, guard as u64);
# threads, # std::ptr::write(s_ptr.offset(-24) as *mut u64, skip as u64);
# current: 0, # 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;
# # }
# pub fn init(&self) { # }
# unsafe { # }
# let r_ptr: *const Runtime = self; #
# RUNTIME = r_ptr as usize; # fn call(thread: u64) {
# } # let thread = unsafe { &*(thread as *const Thread) };
# } # if let Some(f) = &thread.task {
# # f();
# pub fn run(&mut self) -> ! { # }
# while self.t_yield() {} # }
# std::process::exit(0); #
# } # #[naked]
# # unsafe fn skip() {
# fn t_return(&mut self) { # asm!("ret", options(noreturn))
# if self.current != 0 { # }
# self.threads[self.current].state = State::Available; #
# self.t_yield(); # fn guard() {
# } # unsafe {
# } # let rt_ptr = RUNTIME as *mut Runtime;
# # let rt = &mut *rt_ptr;
# fn t_yield(&mut self) -> bool { # println!("THREAD {} FINISHED.", rt.threads[rt.current].id);
# let mut pos = self.current; # rt.t_return();
# while self.threads[pos].state != State::Ready { # };
# pos += 1; # }
# if pos == self.threads.len() { #
# pos = 0; # pub fn yield_thread() {
# } # unsafe {
# if pos == self.current { # let rt_ptr = RUNTIME as *mut Runtime;
# return false; # (*rt_ptr).t_yield();
# } # };
# } # }
#
# 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: Fn() + 'static>(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] # #[naked]
# fn skip() { } # #[no_mangle]
#
# 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)]
# unsafe fn switch() { # unsafe fn switch() {
# llvm_asm!(" # asm!(
# mov %rsp, 0x00(%rdi) # "mov 0x00[rdi], rsp",
# mov %r15, 0x08(%rdi) # "mov 0x08[rdi], r15",
# mov %r14, 0x10(%rdi) # "mov 0x10[rdi], r14",
# mov %r13, 0x18(%rdi) # "mov 0x18[rdi], r13",
# mov %r12, 0x20(%rdi) # "mov 0x20[rdi], r12",
# mov %rbx, 0x28(%rdi) # "mov 0x28[rdi], rbx",
# mov %rbp, 0x30(%rdi) # "mov 0x30[rdi], rbp",
# # "mov rsp, 0x00[rsi]",
# mov 0x00(%rsi), %rsp # "mov r15, 0x08[rsi]",
# mov 0x08(%rsi), %r15 # "mov r14, 0x10[rsi]",
# mov 0x10(%rsi), %r14 # "mov r13, 0x18[rsi]",
# mov 0x18(%rsi), %r13 # "mov r12, 0x20[rsi]",
# mov 0x20(%rsi), %r12 # "mov rbx, 0x28[rsi]",
# mov 0x28(%rsi), %rbx # "mov rbp, 0x30[rsi]",
# mov 0x30(%rsi), %rbp # "mov rdi, 0x38[rsi]",
# mov 0x38(%rsi), %rdi # "ret", options(noreturn)
# " # );
# );
# } # }
# #[cfg(not(windows))] # #[cfg(not(windows))]
fn main() { pub fn run() {
let mut runtime = Runtime::new(); let mut runtime = Runtime::new();
runtime.init(); runtime.init();
Runtime::spawn(|| { Runtime::spawn(|| {