use std::ptr;
use super::g::{current_g, set_current_g, G, GRUNNABLE, GRUNNING, GWAITING, WaitReason};
use super::m::current_m;
use super::sched::{sched, schedule, startm};
#[cfg(target_arch = "x86_64")]
use super::asm_amd64::mcall;
#[cfg(target_arch = "aarch64")]
use super::asm_arm64::mcall;
pub(crate) unsafe fn gopark(reason: WaitReason) {
let gp = current_g();
debug_assert!(!gp.is_null(), "gopark: called from g0");
unsafe { (*gp).waitreason = reason };
unsafe { mcall(gp, park_fn) };
}
unsafe extern "C" fn park_fn(gp: *mut G) {
let m = current_m();
unsafe {
(*gp).atomicstatus.store(GWAITING, std::sync::atomic::Ordering::Release);
(*gp).m = ptr::null_mut();
(*m).curg = ptr::null_mut();
set_current_g(ptr::null_mut());
}
unsafe { schedule() };
}
pub(crate) unsafe fn goready(gp: *mut G) {
use std::sync::atomic::Ordering::Acquire;
loop {
let s = unsafe { (*gp).atomicstatus.load(Acquire) };
if s == GWAITING {
break;
}
debug_assert!(
s == GRUNNING,
"goready: unexpected status {s} — G must be GRUNNING or GWAITING"
);
std::hint::spin_loop();
}
unsafe { (*gp).atomicstatus.store(GRUNNABLE, std::sync::atomic::Ordering::Release) };
let sc = sched();
let m = current_m();
if !m.is_null() {
let p = unsafe { (*m).p };
if !p.is_null() {
unsafe { (*p).runqput(gp, true, &sc.global_run_q) };
unsafe { startm(ptr::null_mut()) };
return;
}
}
unsafe {
(*gp).schedlink = ptr::null_mut();
sc.global_run_q.push_batch(gp, gp, 1);
startm(ptr::null_mut());
}
}
#[cfg(all(test, not(loom)))]
mod tests {
use crate::runtime::g::{Stack, G};
fn make_g(id: u64) -> Box<G> {
let lo = (id as usize + 1) << 20;
G::new(Stack { lo, hi: lo + 65536 }, id)
}
#[test]
fn goready_pushes_to_global_queue() {
use crate::runtime::sched::run_impl;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
let ran = Arc::new(AtomicBool::new(false));
let ran2 = Arc::clone(&ran);
run_impl(move || {
unsafe {
crate::runtime::sched::spawn_goroutine(move || {
ran2.store(true, Ordering::Release);
});
}
for _ in 0..200 { crate::gosched(); }
});
assert!(ran.load(Ordering::Acquire), "goroutine should have run via goready path");
}
}