diff --git a/Cargo.toml b/Cargo.toml index c8377fb..a91328e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ repository = "https://github.com/Starry-OS/scope-local" [dependencies] percpu = "0.2" -spin = { version = "0.9", default-features = false, features = ["lazy"] } +spin = { version = "0.10", default-features = false, features = ["lazy"] } [dev-dependencies] -ctor = "0.4.2" +ctor = "0.6" +percpu = { version = "0.2", features = ["non-zero-vma"] } diff --git a/percpu.x b/percpu.x index 5c1950e..9bbb52a 100644 --- a/percpu.x +++ b/percpu.x @@ -5,11 +5,12 @@ SECTIONS . = ALIGN(4K); _percpu_start = .; _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + .percpu (NOLOAD) : AT(_percpu_start) { _percpu_load_start = .; *(.percpu .percpu.*) _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; + _percpu_load_end_aligned = ALIGN(64); + . = _percpu_load_start + (_percpu_load_end_aligned - _percpu_load_start) * CPU_NUM; } . = _percpu_end; } diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 90d1e61..7c99278 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -1,10 +1,17 @@ -use std::sync::Arc; +use std::{ + panic, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, + thread, +}; use ctor::ctor; use scope_local::{ActiveScope, Scope, scope_local}; #[ctor] -fn init() { +fn init_percpu() { percpu::init(); unsafe { percpu::write_percpu_reg(percpu::percpu_area_base(0)) }; @@ -14,18 +21,22 @@ fn init() { println!("per-CPU area size = {}", percpu::percpu_area_size()); } -scope_local! { - static DATA: usize = 0; -} - #[test] -fn global() { - assert_eq!(*DATA, 0); +fn scope_init() { + scope_local! { + static DATA: usize = 42; + } + assert_eq!(*DATA, 42); } #[test] fn scope() { + scope_local! { + static DATA: usize = 0; + } + let mut scope = Scope::new(); + assert_eq!(*DATA, 0); assert_eq!(*DATA.scope(&scope), 0); *DATA.scope_mut(&mut scope) = 42; @@ -35,14 +46,16 @@ fn scope() { assert_eq!(*DATA, 42); ActiveScope::set_global(); -} - -scope_local! { - static SHARED: Arc = Arc::new("qwq".to_string()); + assert_eq!(*DATA, 0); + assert_eq!(*DATA.scope(&scope), 42); } #[test] -fn shared() { +fn scope_drop() { + scope_local! { + static SHARED: Arc<()> = Arc::new(()); + } + assert_eq!(Arc::strong_count(&SHARED), 1); { @@ -55,3 +68,110 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); } + +#[test] +fn scope_panic_unwind_drop() { + scope_local! { + static SHARED: Arc<()> = Arc::new(()); + } + + let panic = panic::catch_unwind(|| { + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = SHARED.clone(); + assert_eq!(Arc::strong_count(&SHARED), 2); + panic!("panic"); + }); + assert!(panic.is_err()); + + assert_eq!(Arc::strong_count(&SHARED), 1); +} + +#[test] +fn thread_share_item() { + scope_local! { + static SHARED: Arc<()> = Arc::new(()); + } + + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(move || { + let global = &*SHARED; + + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = global.clone(); + + unsafe { ActiveScope::set(&scope) }; + + assert!(Arc::strong_count(&SHARED) >= 2); + assert!(Arc::ptr_eq(&SHARED, global)); + + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(Arc::strong_count(&SHARED), 1); +} + +#[test] +fn thread_share_scope() { + scope_local! { + static SHARED: Arc<()> = Arc::new(()); + } + + let scope = Arc::new(Scope::new()); + + let handles: Vec<_> = (0..10) + .map(|_| { + let scope = scope.clone(); + thread::spawn(move || { + unsafe { ActiveScope::set(&scope) }; + assert_eq!(Arc::strong_count(&SHARED), 1); + assert!(Arc::ptr_eq(&SHARED, &SHARED.scope(&scope))); + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(Arc::strong_count(&SHARED), 1); + assert_eq!(Arc::strong_count(&SHARED.scope(&scope)), 1); +} + +#[test] +fn thread_isolation() { + scope_local! { + static DATA: usize = 42; + static DATA2: AtomicUsize = AtomicUsize::new(42); + } + + let handles: Vec<_> = (0..10) + .map(|i| { + thread::spawn(move || { + let mut scope = Scope::new(); + *DATA.scope_mut(&mut scope) = i; + + unsafe { ActiveScope::set(&scope) }; + assert_eq!(*DATA, i); + + DATA2.store(i, Ordering::Relaxed); + + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(*DATA, 42); + assert_eq!(DATA2.load(Ordering::Relaxed), 42); +}