Fix the CI issues with static mut access (#763)

- [x] no changelog update needed
This commit is contained in:
Corwin 2024-09-23 22:25:26 +01:00 committed by GitHub
commit 1f6766e286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 33 additions and 12 deletions

View file

@ -4,7 +4,7 @@ use alloc::boxed::Box;
use critical_section::{CriticalSection, RawRestoreState}; use critical_section::{CriticalSection, RawRestoreState};
use portable_atomic::{AtomicBool, AtomicUsize, Ordering}; use portable_atomic::{AtomicBool, AtomicUsize, Ordering};
use crate::{display::DISPLAY_STATUS, memory_mapped::MemoryMapped}; use crate::{display::DISPLAY_STATUS, memory_mapped::MemoryMapped, util::SyncUnsafeCell};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Interrupt { pub enum Interrupt {
@ -123,7 +123,7 @@ impl InterruptRoot {
} }
} }
static mut INTERRUPT_TABLE: [InterruptRoot; 14] = [ static INTERRUPT_TABLE: SyncUnsafeCell<[InterruptRoot; 14]> = SyncUnsafeCell::new([
InterruptRoot::new(Interrupt::VBlank), InterruptRoot::new(Interrupt::VBlank),
InterruptRoot::new(Interrupt::HBlank), InterruptRoot::new(Interrupt::HBlank),
InterruptRoot::new(Interrupt::VCounter), InterruptRoot::new(Interrupt::VCounter),
@ -138,11 +138,12 @@ static mut INTERRUPT_TABLE: [InterruptRoot; 14] = [
InterruptRoot::new(Interrupt::Dma3), InterruptRoot::new(Interrupt::Dma3),
InterruptRoot::new(Interrupt::Keypad), InterruptRoot::new(Interrupt::Keypad),
InterruptRoot::new(Interrupt::Gamepak), InterruptRoot::new(Interrupt::Gamepak),
]; ]);
#[no_mangle] #[no_mangle]
extern "C" fn __RUST_INTERRUPT_HANDLER(interrupt: u16) -> u16 { #[export_name = "__RUST_INTERRUPT_HANDLER"]
for (i, root) in unsafe { INTERRUPT_TABLE.iter().enumerate() } { extern "C" fn interrupt_handler(interrupt: u16) -> u16 {
for (i, root) in unsafe { &mut *INTERRUPT_TABLE.get() }.iter().enumerate() {
if (1 << i) & interrupt != 0 { if (1 << i) & interrupt != 0 {
root.trigger_interrupts(); root.trigger_interrupts();
} }
@ -219,8 +220,8 @@ impl InterruptRoot {
} }
} }
fn interrupt_to_root(interrupt: Interrupt) -> &'static InterruptRoot { unsafe fn interrupt_to_root(interrupt: Interrupt) -> &'static InterruptRoot {
unsafe { &INTERRUPT_TABLE[interrupt as usize] } &(unsafe { &mut *INTERRUPT_TABLE.get() })[interrupt as usize]
} }
#[must_use] #[must_use]
@ -259,7 +260,7 @@ pub unsafe fn add_interrupt_handler(
) -> InterruptHandler { ) -> InterruptHandler {
fn do_with_inner(interrupt: Interrupt, inner: Pin<Box<InterruptInner>>) -> InterruptHandler { fn do_with_inner(interrupt: Interrupt, inner: Pin<Box<InterruptInner>>) -> InterruptHandler {
critical_section::with(|_| { critical_section::with(|_| {
let root = interrupt_to_root(interrupt); let root = unsafe { interrupt_to_root(interrupt) };
root.add(); root.add();
let mut c = root.next.get(); let mut c = root.next.get();
if c.is_null() { if c.is_null() {
@ -373,7 +374,7 @@ mod tests {
#[test_case] #[test_case]
fn test_interrupt_table_length(_gba: &mut crate::Gba) { fn test_interrupt_table_length(_gba: &mut crate::Gba) {
assert_eq!( assert_eq!(
unsafe { INTERRUPT_TABLE.len() }, unsafe { (*INTERRUPT_TABLE.get()).len() },
Interrupt::Gamepak as usize + 1, Interrupt::Gamepak as usize + 1,
"interrupt table should be able to store gamepak interrupt" "interrupt table should be able to store gamepak interrupt"
); );

View file

@ -190,6 +190,7 @@ mod sync;
pub mod syscall; pub mod syscall;
/// Interactions with the internal timers /// Interactions with the internal timers
pub mod timer; pub mod timer;
pub(crate) mod util;
mod no_game; mod no_game;
@ -326,6 +327,8 @@ impl Gba {
/// You can run the tests using `cargo test`, but it will work better through `mgba-test-runner` by /// You can run the tests using `cargo test`, but it will work better through `mgba-test-runner` by
/// running something along the lines of `CARGO_TARGET_THUMBV4T_NONE_EABI_RUNNER=mgba-test-runner cargo test`. /// running something along the lines of `CARGO_TARGET_THUMBV4T_NONE_EABI_RUNNER=mgba-test-runner cargo test`.
pub mod test_runner { pub mod test_runner {
use util::SyncUnsafeCell;
use super::*; use super::*;
#[doc(hidden)] #[doc(hidden)]
@ -373,7 +376,7 @@ pub mod test_runner {
} }
} }
static mut TEST_GBA: Option<Gba> = None; static TEST_GBA: SyncUnsafeCell<Option<Gba>> = SyncUnsafeCell::new(None);
#[doc(hidden)] #[doc(hidden)]
pub fn test_runner(tests: &[&dyn Testable]) { pub fn test_runner(tests: &[&dyn Testable]) {
@ -384,7 +387,7 @@ pub mod test_runner {
) )
.unwrap(); .unwrap();
let gba = unsafe { TEST_GBA.as_mut() }.unwrap(); let gba = unsafe { &mut *TEST_GBA.get() }.as_mut().unwrap();
for test in tests { for test in tests {
test.run(gba); test.run(gba);
@ -414,7 +417,7 @@ pub mod test_runner {
#[doc(hidden)] #[doc(hidden)]
pub fn agb_start_tests(gba: Gba, test_main: impl Fn()) -> ! { pub fn agb_start_tests(gba: Gba, test_main: impl Fn()) -> ! {
unsafe { TEST_GBA = Some(gba) }; *unsafe { &mut *TEST_GBA.get() } = Some(gba);
test_main(); test_main();
#[allow(clippy::empty_loop)] #[allow(clippy::empty_loop)]
loop {} loop {}

16
agb/src/util.rs Normal file
View file

@ -0,0 +1,16 @@
use core::cell::UnsafeCell;
pub struct SyncUnsafeCell<T>(UnsafeCell<T>);
unsafe impl<T> Sync for SyncUnsafeCell<T> {}
unsafe impl<T> Send for SyncUnsafeCell<T> {}
impl<T> SyncUnsafeCell<T> {
pub const fn new(t: T) -> Self {
Self(UnsafeCell::new(t))
}
pub unsafe fn get(&self) -> *mut T {
self.0.get()
}
}

View file

@ -1,6 +1,7 @@
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(improper_ctypes)]
mod ffi { mod ffi {
include!(concat!(env!("OUT_DIR"), "/bindings.rs")); include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
} }