Skip to content

Commit 8e07390

Browse files
committed
Expand test with allocating from thread-local destructors
1 parent 64af367 commit 8e07390

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed

tests/ui/threads-sendsync/tls-in-global-alloc.rs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,46 @@
22
//@ needs-threads
33

44
use std::alloc::{GlobalAlloc, Layout, System};
5-
use std::thread::Thread;
6-
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
5+
use std::hint::black_box;
6+
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
7+
use std::thread::{Thread, ThreadId};
78

89
static GLOBAL: AtomicUsize = AtomicUsize::new(0);
10+
static SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS: AtomicBool = AtomicBool::new(false);
11+
static LOCAL_TRY_WITH_SUCCEEDED_ALLOC: AtomicBool = AtomicBool::new(false);
12+
static LOCAL_TRY_WITH_SUCCEEDED_DEALLOC: AtomicBool = AtomicBool::new(false);
913

10-
struct Local(Thread);
14+
struct LocalForAllocatorWithoutDrop(ThreadId);
1115

12-
thread_local! {
13-
static LOCAL: Local = {
14-
GLOBAL.fetch_or(1, Ordering::Relaxed);
15-
Local(std::thread::current())
16-
};
17-
}
16+
struct LocalForAllocatorWithDrop(Thread);
1817

19-
impl Drop for Local {
18+
impl Drop for LocalForAllocatorWithDrop {
2019
fn drop(&mut self) {
2120
GLOBAL.fetch_or(2, Ordering::Relaxed);
2221
}
2322
}
2423

25-
static SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS: AtomicBool = AtomicBool::new(false);
24+
struct LocalForUser(u32);
25+
26+
impl Drop for LocalForUser {
27+
// A user might call the global allocator in a thread-local drop.
28+
fn drop(&mut self) {
29+
self.0 += 1;
30+
drop(black_box(Box::new(self.0)))
31+
}
32+
}
33+
34+
thread_local! {
35+
static LOCAL_FOR_USER0: LocalForUser = LocalForUser(0);
36+
static LOCAL_FOR_ALLOCATOR_WITHOUT_DROP: LocalForAllocatorWithoutDrop = {
37+
LocalForAllocatorWithoutDrop(std::thread::current().id())
38+
};
39+
static LOCAL_FOR_ALLOCATOR_WITH_DROP: LocalForAllocatorWithDrop = {
40+
GLOBAL.fetch_or(1, Ordering::Relaxed);
41+
LocalForAllocatorWithDrop(std::thread::current())
42+
};
43+
static LOCAL_FOR_USER1: LocalForUser = LocalForUser(1);
44+
}
2645

2746
#[global_allocator]
2847
static ALLOC: Alloc = Alloc;
@@ -33,9 +52,19 @@ unsafe impl GlobalAlloc for Alloc {
3352
// Make sure we aren't re-entrant.
3453
assert!(!SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.load(Ordering::Relaxed));
3554
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(true, Ordering::Relaxed);
36-
LOCAL.with(|local| {
55+
56+
// Should be infallible.
57+
LOCAL_FOR_ALLOCATOR_WITHOUT_DROP.with(|local| {
58+
assert!(local.0 == std::thread::current().id());
59+
});
60+
61+
// May fail once thread-local destructors start running, and ours has
62+
// been ran.
63+
let try_with_ret = LOCAL_FOR_ALLOCATOR_WITH_DROP.try_with(|local| {
3764
assert!(local.0.id() == std::thread::current().id());
3865
});
66+
LOCAL_TRY_WITH_SUCCEEDED_ALLOC.fetch_or(try_with_ret.is_ok(), Ordering::Relaxed);
67+
3968
let ret = unsafe { System.alloc(layout) };
4069
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(false, Ordering::Relaxed);
4170
ret
@@ -45,20 +74,34 @@ unsafe impl GlobalAlloc for Alloc {
4574
// Make sure we aren't re-entrant.
4675
assert!(!SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.load(Ordering::Relaxed));
4776
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(true, Ordering::Relaxed);
48-
LOCAL.with(|local| {
77+
78+
// Should be infallible.
79+
LOCAL_FOR_ALLOCATOR_WITHOUT_DROP.with(|local| {
80+
assert!(local.0 == std::thread::current().id());
81+
});
82+
83+
// May fail once thread-local destructors start running, and ours has
84+
// been ran.
85+
let try_with_ret = LOCAL_FOR_ALLOCATOR_WITH_DROP.try_with(|local| {
4986
assert!(local.0.id() == std::thread::current().id());
5087
});
88+
LOCAL_TRY_WITH_SUCCEEDED_DEALLOC.fetch_or(try_with_ret.is_ok(), Ordering::Relaxed);
89+
5190
unsafe { System.dealloc(ptr, layout) }
5291
SHOULD_PANIC_ON_GLOBAL_ALLOC_ACCESS.store(false, Ordering::Relaxed);
5392
}
5493
}
5594

5695
fn main() {
5796
std::thread::spawn(|| {
97+
LOCAL_FOR_USER0.with(|l| assert!(l.0 == 0));
5898
std::hint::black_box(vec![1, 2]);
5999
assert!(GLOBAL.load(Ordering::Relaxed) == 1);
100+
LOCAL_FOR_USER1.with(|l| assert!(l.0 == 1));
60101
})
61102
.join()
62103
.unwrap();
63104
assert!(GLOBAL.load(Ordering::Relaxed) == 3);
105+
assert!(LOCAL_TRY_WITH_SUCCEEDED_ALLOC.load(Ordering::Relaxed));
106+
assert!(LOCAL_TRY_WITH_SUCCEEDED_DEALLOC.load(Ordering::Relaxed));
64107
}

0 commit comments

Comments
 (0)