From 3173e8093667d6a04e615d1306f5716ea0e70e7f Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Fri, 12 Dec 2025 12:13:03 +0800 Subject: [PATCH 01/10] test: add more tests --- Cargo.toml | 1 + percpu.x | 2 +- tests/tests.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 tests/tests.rs diff --git a/Cargo.toml b/Cargo.toml index c8377fb..a277436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ spin = { version = "0.9", default-features = false, features = ["lazy"] } [dev-dependencies] ctor = "0.4.2" +serial_test = "3" diff --git a/percpu.x b/percpu.x index 5c1950e..7baecb7 100644 --- a/percpu.x +++ b/percpu.x @@ -5,7 +5,7 @@ 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 = .; diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..d843b5d --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,110 @@ +use std::{ + panic, + sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, + }, + thread, +}; + +use ctor::ctor; +use scope_local::{ActiveScope, Scope, scope_local}; +use serial_test::serial; + +#[ctor] +fn init() { + percpu::init(); + + unsafe { percpu::write_percpu_reg(percpu::percpu_area_base(0)) }; + + let base = percpu::read_percpu_reg(); + println!("per-CPU area base = {base:#x}"); + println!("per-CPU area size = {}", percpu::percpu_area_size()); +} + +scope_local! { + static DATA: usize = 0; +} + +#[test] +#[serial] +fn isolation() { + 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); + + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(*DATA, 0); +} + +#[test] +#[serial] +fn nested() { + let mut outer = Scope::new(); + unsafe { ActiveScope::set(&outer) }; + *DATA.scope_mut(&mut outer) = 1; + + let mut inner = Scope::new(); + unsafe { ActiveScope::set(&inner) }; + *DATA.scope_mut(&mut inner) = 2; + assert_eq!(*DATA, 2); + + unsafe { ActiveScope::set(&outer) }; + assert_eq!(*DATA, 1); + + ActiveScope::set_global(); +} + +static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); + +#[allow(dead_code)] +struct Counter; + +impl Drop for Counter { + fn drop(&mut self) { + DROP_COUNT.fetch_add(1, Ordering::SeqCst); + } +} + +scope_local! { + static COUNTER: Arc = Arc::new(Counter); +} + +#[test] +#[serial] +fn drop() { + DROP_COUNT.store(0, Ordering::SeqCst); + + let handles: Vec<_> = (0..9) + .map(|_| { + thread::spawn(move || { + let _scope = Scope::new(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + let panic = panic::catch_unwind(|| { + let _scope = Scope::new(); + panic!("panic"); + }); + assert!(panic.is_err()); + + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 10); +} From 28a78f60b47f4ec04a8ca812fbdaf0d9a004566a Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Fri, 12 Dec 2025 20:57:50 +0800 Subject: [PATCH 02/10] test: correct drop count --- tests/tests.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index d843b5d..bbd80a6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -71,7 +71,9 @@ fn nested() { static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); #[allow(dead_code)] -struct Counter; +struct Counter { + id: usize, +} impl Drop for Counter { fn drop(&mut self) { @@ -80,7 +82,7 @@ impl Drop for Counter { } scope_local! { - static COUNTER: Arc = Arc::new(Counter); + static COUNTER: Arc = Arc::new(Counter{id: 0}); } #[test] @@ -89,9 +91,10 @@ fn drop() { DROP_COUNT.store(0, Ordering::SeqCst); let handles: Vec<_> = (0..9) - .map(|_| { + .map(|i| { thread::spawn(move || { - let _scope = Scope::new(); + let mut scope = Scope::new(); + *COUNTER.scope_mut(&mut scope) = Arc::new(Counter { id: i }); }) }) .collect(); @@ -101,10 +104,11 @@ fn drop() { } let panic = panic::catch_unwind(|| { - let _scope = Scope::new(); + let mut scope = Scope::new(); + *COUNTER.scope_mut(&mut scope) = Arc::new(Counter { id: 99 }); panic!("panic"); }); assert!(panic.is_err()); - assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 10); + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 20); } From 7a822ee84029ff8dca2b1d56749b62a6ce71097f Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Sun, 14 Dec 2025 15:37:05 +0800 Subject: [PATCH 03/10] test: format and split --- Cargo.toml | 1 - tests/drop.rs | 62 +++++++++++++++++++++++ tests/scope_local.rs | 45 ++++++++++++++++- tests/tests.rs | 114 ------------------------------------------- 4 files changed, 106 insertions(+), 116 deletions(-) create mode 100644 tests/drop.rs delete mode 100644 tests/tests.rs diff --git a/Cargo.toml b/Cargo.toml index a277436..c8377fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,3 @@ spin = { version = "0.9", default-features = false, features = ["lazy"] } [dev-dependencies] ctor = "0.4.2" -serial_test = "3" diff --git a/tests/drop.rs b/tests/drop.rs new file mode 100644 index 0000000..d45c0d3 --- /dev/null +++ b/tests/drop.rs @@ -0,0 +1,62 @@ +use std::{ + panic, + sync::atomic::{AtomicUsize, Ordering}, + thread, +}; + +use ctor::ctor; +use scope_local::{Scope, scope_local}; + +#[ctor] +fn init() { + percpu::init(); + + unsafe { percpu::write_percpu_reg(percpu::percpu_area_base(0)) }; + + let base = percpu::read_percpu_reg(); + println!("per-CPU area base = {base:#x}"); + println!("per-CPU area size = {}", percpu::percpu_area_size()); +} + +static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); + +struct Counter(AtomicUsize); + +impl Drop for Counter { + fn drop(&mut self) { + DROP_COUNT.fetch_add(1, Ordering::SeqCst); + } +} + +scope_local! { + static COUNTER: Counter = Counter(AtomicUsize::new(0)); +} + +#[test] +fn drop() { + DROP_COUNT.store(0, Ordering::SeqCst); + + let handles: Vec<_> = (0..9) + .map(|i| { + thread::spawn(move || { + let mut scope = Scope::new(); + let counter = COUNTER.scope_mut(&mut scope); + counter.0.store(i, Ordering::SeqCst); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + let panic = panic::catch_unwind(|| { + let mut scope = Scope::new(); + let counter = COUNTER.scope_mut(&mut scope); + counter.0.store(99, Ordering::SeqCst); + panic!("panic"); + }); + assert!(panic.is_err()); + + assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 10); +} diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 90d1e61..b8a368f 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -1,4 +1,7 @@ -use std::sync::Arc; +use std::{ + sync::Arc, + thread, +}; use ctor::ctor; use scope_local::{ActiveScope, Scope, scope_local}; @@ -55,3 +58,43 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); } + +#[test] +fn isolation() { + 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); + + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(*DATA, 0); +} + +#[test] +fn nested() { + let mut outer = Scope::new(); + unsafe { ActiveScope::set(&outer) }; + *DATA.scope_mut(&mut outer) = 1; + + let mut inner = Scope::new(); + unsafe { ActiveScope::set(&inner) }; + *DATA.scope_mut(&mut inner) = 2; + assert_eq!(*DATA, 2); + + unsafe { ActiveScope::set(&outer) }; + assert_eq!(*DATA, 1); + + ActiveScope::set_global(); +} diff --git a/tests/tests.rs b/tests/tests.rs deleted file mode 100644 index bbd80a6..0000000 --- a/tests/tests.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::{ - panic, - sync::{ - Arc, - atomic::{AtomicUsize, Ordering}, - }, - thread, -}; - -use ctor::ctor; -use scope_local::{ActiveScope, Scope, scope_local}; -use serial_test::serial; - -#[ctor] -fn init() { - percpu::init(); - - unsafe { percpu::write_percpu_reg(percpu::percpu_area_base(0)) }; - - let base = percpu::read_percpu_reg(); - println!("per-CPU area base = {base:#x}"); - println!("per-CPU area size = {}", percpu::percpu_area_size()); -} - -scope_local! { - static DATA: usize = 0; -} - -#[test] -#[serial] -fn isolation() { - 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); - - ActiveScope::set_global(); - }) - }) - .collect(); - - for h in handles { - h.join().unwrap(); - } - - assert_eq!(*DATA, 0); -} - -#[test] -#[serial] -fn nested() { - let mut outer = Scope::new(); - unsafe { ActiveScope::set(&outer) }; - *DATA.scope_mut(&mut outer) = 1; - - let mut inner = Scope::new(); - unsafe { ActiveScope::set(&inner) }; - *DATA.scope_mut(&mut inner) = 2; - assert_eq!(*DATA, 2); - - unsafe { ActiveScope::set(&outer) }; - assert_eq!(*DATA, 1); - - ActiveScope::set_global(); -} - -static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); - -#[allow(dead_code)] -struct Counter { - id: usize, -} - -impl Drop for Counter { - fn drop(&mut self) { - DROP_COUNT.fetch_add(1, Ordering::SeqCst); - } -} - -scope_local! { - static COUNTER: Arc = Arc::new(Counter{id: 0}); -} - -#[test] -#[serial] -fn drop() { - DROP_COUNT.store(0, Ordering::SeqCst); - - let handles: Vec<_> = (0..9) - .map(|i| { - thread::spawn(move || { - let mut scope = Scope::new(); - *COUNTER.scope_mut(&mut scope) = Arc::new(Counter { id: i }); - }) - }) - .collect(); - - for h in handles { - h.join().unwrap(); - } - - let panic = panic::catch_unwind(|| { - let mut scope = Scope::new(); - *COUNTER.scope_mut(&mut scope) = Arc::new(Counter { id: 99 }); - panic!("panic"); - }); - assert!(panic.is_err()); - - assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 20); -} From 72beafa1e729d838e1301932af7403531d24294b Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Wed, 17 Dec 2025 17:23:24 +0800 Subject: [PATCH 04/10] use strong_count and merge --- tests/drop.rs | 62 -------------------------------------------- tests/scope_local.rs | 30 ++++++++++++++++++--- 2 files changed, 26 insertions(+), 66 deletions(-) delete mode 100644 tests/drop.rs diff --git a/tests/drop.rs b/tests/drop.rs deleted file mode 100644 index d45c0d3..0000000 --- a/tests/drop.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::{ - panic, - sync::atomic::{AtomicUsize, Ordering}, - thread, -}; - -use ctor::ctor; -use scope_local::{Scope, scope_local}; - -#[ctor] -fn init() { - percpu::init(); - - unsafe { percpu::write_percpu_reg(percpu::percpu_area_base(0)) }; - - let base = percpu::read_percpu_reg(); - println!("per-CPU area base = {base:#x}"); - println!("per-CPU area size = {}", percpu::percpu_area_size()); -} - -static DROP_COUNT: AtomicUsize = AtomicUsize::new(0); - -struct Counter(AtomicUsize); - -impl Drop for Counter { - fn drop(&mut self) { - DROP_COUNT.fetch_add(1, Ordering::SeqCst); - } -} - -scope_local! { - static COUNTER: Counter = Counter(AtomicUsize::new(0)); -} - -#[test] -fn drop() { - DROP_COUNT.store(0, Ordering::SeqCst); - - let handles: Vec<_> = (0..9) - .map(|i| { - thread::spawn(move || { - let mut scope = Scope::new(); - let counter = COUNTER.scope_mut(&mut scope); - counter.0.store(i, Ordering::SeqCst); - }) - }) - .collect(); - - for h in handles { - h.join().unwrap(); - } - - let panic = panic::catch_unwind(|| { - let mut scope = Scope::new(); - let counter = COUNTER.scope_mut(&mut scope); - counter.0.store(99, Ordering::SeqCst); - panic!("panic"); - }); - assert!(panic.is_err()); - - assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 10); -} diff --git a/tests/scope_local.rs b/tests/scope_local.rs index b8a368f..ac00f69 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -1,7 +1,4 @@ -use std::{ - sync::Arc, - thread, -}; +use std::{panic, sync::Arc, thread}; use ctor::ctor; use scope_local::{ActiveScope, Scope, scope_local}; @@ -57,6 +54,31 @@ fn shared() { } assert_eq!(Arc::strong_count(&SHARED), 1); + + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(move || { + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = SHARED.clone(); + assert!(Arc::strong_count(&SHARED) >= 2); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + + assert_eq!(Arc::strong_count(&SHARED), 1); + + let panic = panic::catch_unwind(|| { + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = SHARED.clone(); + panic!("panic"); + }); + assert!(panic.is_err()); + + assert_eq!(Arc::strong_count(&SHARED), 1); } #[test] From d6fe88c439ba31721619f65a5014dcabac965a60 Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Thu, 18 Dec 2025 00:58:39 +0800 Subject: [PATCH 05/10] add a test for multiple threads share one scope --- tests/scope_local.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/scope_local.rs b/tests/scope_local.rs index ac00f69..40a34f4 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -71,6 +71,30 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); + { + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = SHARED.clone(); + let scope = Arc::new(scope); + + let handles: Vec<_> = (0..10) + .map(|_| { + let scope = scope.clone(); + thread::spawn(move || { + unsafe { ActiveScope::set(&scope) }; + assert_eq!(Arc::strong_count(&SHARED), 2); + assert_eq!(*SHARED, Arc::new("qwq".to_string())); + ActiveScope::set_global(); + }) + }) + .collect(); + + for h in handles { + h.join().unwrap(); + } + } + + assert_eq!(Arc::strong_count(&SHARED), 1); + let panic = panic::catch_unwind(|| { let mut scope = Scope::new(); *SHARED.scope_mut(&mut scope) = SHARED.clone(); From 84c322dca8bc47502c319957cc29f676d35e1a92 Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Sat, 20 Dec 2025 18:59:12 +0800 Subject: [PATCH 06/10] split test shared --- tests/scope_local.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 40a34f4..0128f7e 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -55,12 +55,25 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); + let panic = panic::catch_unwind(|| { + let mut scope = Scope::new(); + *SHARED.scope_mut(&mut scope) = SHARED.clone(); + panic!("panic"); + }); + assert!(panic.is_err()); + + assert_eq!(Arc::strong_count(&SHARED), 1); +} + +#[test] +fn threads_shared() { let handles: Vec<_> = (0..10) .map(|_| { thread::spawn(move || { let mut scope = Scope::new(); *SHARED.scope_mut(&mut scope) = SHARED.clone(); assert!(Arc::strong_count(&SHARED) >= 2); + assert_eq!(*SHARED, Arc::new("qwq".to_string())); }) }) .collect(); @@ -94,15 +107,6 @@ fn shared() { } assert_eq!(Arc::strong_count(&SHARED), 1); - - let panic = panic::catch_unwind(|| { - let mut scope = Scope::new(); - *SHARED.scope_mut(&mut scope) = SHARED.clone(); - panic!("panic"); - }); - assert!(panic.is_err()); - - assert_eq!(Arc::strong_count(&SHARED), 1); } #[test] From d6c928386a53620ee9d5f80da6d2672f32af2923 Mon Sep 17 00:00:00 2001 From: HoshimiP Date: Sat, 20 Dec 2025 23:40:40 +0800 Subject: [PATCH 07/10] data isolate --- tests/scope_local.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 0128f7e..3be1dfa 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -65,15 +65,21 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); } +scope_local! { + static T_SHARED: Arc = Arc::new("qwq".to_string()); +} + #[test] fn threads_shared() { + assert_eq!(Arc::strong_count(&SHARED), 1); + let handles: Vec<_> = (0..10) .map(|_| { thread::spawn(move || { let mut scope = Scope::new(); - *SHARED.scope_mut(&mut scope) = SHARED.clone(); - assert!(Arc::strong_count(&SHARED) >= 2); - assert_eq!(*SHARED, Arc::new("qwq".to_string())); + *T_SHARED.scope_mut(&mut scope) = T_SHARED.clone(); + assert!(Arc::strong_count(&T_SHARED) >= 2); + assert_eq!(*T_SHARED, Arc::new("qwq".to_string())); }) }) .collect(); @@ -82,11 +88,11 @@ fn threads_shared() { h.join().unwrap(); } - assert_eq!(Arc::strong_count(&SHARED), 1); + assert_eq!(Arc::strong_count(&T_SHARED), 1); { let mut scope = Scope::new(); - *SHARED.scope_mut(&mut scope) = SHARED.clone(); + *T_SHARED.scope_mut(&mut scope) = T_SHARED.clone(); let scope = Arc::new(scope); let handles: Vec<_> = (0..10) @@ -94,8 +100,8 @@ fn threads_shared() { let scope = scope.clone(); thread::spawn(move || { unsafe { ActiveScope::set(&scope) }; - assert_eq!(Arc::strong_count(&SHARED), 2); - assert_eq!(*SHARED, Arc::new("qwq".to_string())); + assert_eq!(Arc::strong_count(&T_SHARED), 2); + assert_eq!(*T_SHARED, Arc::new("qwq".to_string())); ActiveScope::set_global(); }) }) @@ -106,7 +112,7 @@ fn threads_shared() { } } - assert_eq!(Arc::strong_count(&SHARED), 1); + assert_eq!(Arc::strong_count(&T_SHARED), 1); } #[test] From 6f5e8adde3d2ca3d64f69c8158e1882576984293 Mon Sep 17 00:00:00 2001 From: Asakura Mizu Date: Mon, 22 Dec 2025 20:48:57 +0800 Subject: [PATCH 08/10] build: update deps, fix percpu --- Cargo.toml | 5 +++-- percpu.x | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) 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 7baecb7..9bbb52a 100644 --- a/percpu.x +++ b/percpu.x @@ -9,7 +9,8 @@ SECTIONS _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; } From 39d16b36e63fa7d9ca0d7dd361cea6ee6aead436 Mon Sep 17 00:00:00 2001 From: Asakura Mizu Date: Mon, 22 Dec 2025 20:51:11 +0800 Subject: [PATCH 09/10] test: improve --- tests/scope_local.rs | 141 +++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 3be1dfa..6badde8 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -1,10 +1,17 @@ -use std::{panic, sync::Arc, thread}; +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); { @@ -54,10 +67,18 @@ 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()); @@ -65,21 +86,26 @@ fn shared() { assert_eq!(Arc::strong_count(&SHARED), 1); } -scope_local! { - static T_SHARED: Arc = Arc::new("qwq".to_string()); -} - #[test] -fn threads_shared() { - assert_eq!(Arc::strong_count(&SHARED), 1); +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(); - *T_SHARED.scope_mut(&mut scope) = T_SHARED.clone(); - assert!(Arc::strong_count(&T_SHARED) >= 2); - assert_eq!(*T_SHARED, Arc::new("qwq".to_string())); + *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(); @@ -88,35 +114,44 @@ fn threads_shared() { h.join().unwrap(); } - assert_eq!(Arc::strong_count(&T_SHARED), 1); + assert_eq!(Arc::strong_count(&SHARED), 1); +} - { - let mut scope = Scope::new(); - *T_SHARED.scope_mut(&mut scope) = T_SHARED.clone(); - let scope = Arc::new(scope); - - let handles: Vec<_> = (0..10) - .map(|_| { - let scope = scope.clone(); - thread::spawn(move || { - unsafe { ActiveScope::set(&scope) }; - assert_eq!(Arc::strong_count(&T_SHARED), 2); - assert_eq!(*T_SHARED, Arc::new("qwq".to_string())); - ActiveScope::set_global(); - }) +#[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(); + }) + .collect(); - for h in handles { - h.join().unwrap(); - } + for h in handles { + h.join().unwrap(); } - assert_eq!(Arc::strong_count(&T_SHARED), 1); + assert_eq!(Arc::strong_count(&SHARED), 1); + assert_eq!(Arc::strong_count(&SHARED.scope(&scope)), 1); } #[test] -fn isolation() { +fn thread_isolation() { + scope_local! { + static DATA: usize = 0; + static DATA2: AtomicUsize = AtomicUsize::new(0); + } + let handles: Vec<_> = (0..10) .map(|i| { thread::spawn(move || { @@ -126,6 +161,8 @@ fn isolation() { unsafe { ActiveScope::set(&scope) }; assert_eq!(*DATA, i); + DATA2.store(i, Ordering::Relaxed); + ActiveScope::set_global(); }) }) @@ -136,21 +173,5 @@ fn isolation() { } assert_eq!(*DATA, 0); -} - -#[test] -fn nested() { - let mut outer = Scope::new(); - unsafe { ActiveScope::set(&outer) }; - *DATA.scope_mut(&mut outer) = 1; - - let mut inner = Scope::new(); - unsafe { ActiveScope::set(&inner) }; - *DATA.scope_mut(&mut inner) = 2; - assert_eq!(*DATA, 2); - - unsafe { ActiveScope::set(&outer) }; - assert_eq!(*DATA, 1); - - ActiveScope::set_global(); + assert_eq!(DATA2.load(Ordering::Relaxed), 0); } From 998b49737065c1e9bfe23a228dc88a18ec784617 Mon Sep 17 00:00:00 2001 From: Asakura Mizu Date: Mon, 22 Dec 2025 21:04:27 +0800 Subject: [PATCH 10/10] test: fix thread_isolation ambiguity --- tests/scope_local.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/scope_local.rs b/tests/scope_local.rs index 6badde8..7c99278 100644 --- a/tests/scope_local.rs +++ b/tests/scope_local.rs @@ -148,8 +148,8 @@ fn thread_share_scope() { #[test] fn thread_isolation() { scope_local! { - static DATA: usize = 0; - static DATA2: AtomicUsize = AtomicUsize::new(0); + static DATA: usize = 42; + static DATA2: AtomicUsize = AtomicUsize::new(42); } let handles: Vec<_> = (0..10) @@ -172,6 +172,6 @@ fn thread_isolation() { h.join().unwrap(); } - assert_eq!(*DATA, 0); - assert_eq!(DATA2.load(Ordering::Relaxed), 0); + assert_eq!(*DATA, 42); + assert_eq!(DATA2.load(Ordering::Relaxed), 42); }