shape_value/v2/
refcount.rs1use super::heap_header::HeapHeader;
8use std::sync::atomic::Ordering;
9
10#[inline(always)]
15pub unsafe fn v2_retain(ptr: *const HeapHeader) {
16 unsafe { (*ptr).refcount.fetch_add(1, Ordering::Relaxed) };
17}
18
19#[inline(always)]
30pub unsafe fn v2_release(ptr: *const HeapHeader) -> bool {
31 let old = unsafe { (*ptr).refcount.fetch_sub(1, Ordering::Release) };
32 if old == 1 {
33 std::sync::atomic::fence(Ordering::Acquire);
34 true } else {
36 false
37 }
38}
39
40#[inline(always)]
45pub unsafe fn v2_get_refcount(ptr: *const HeapHeader) -> u32 {
46 unsafe { (*ptr).refcount.load(Ordering::Relaxed) }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::v2::heap_header::HEAP_KIND_V2_TYPED_ARRAY;
53
54 #[test]
55 fn test_v2_retain_increments() {
56 let h = HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY);
57 unsafe {
58 let ptr = &h as *const HeapHeader;
59 assert_eq!(v2_get_refcount(ptr), 1);
60
61 v2_retain(ptr);
62 assert_eq!(v2_get_refcount(ptr), 2);
63
64 v2_retain(ptr);
65 assert_eq!(v2_get_refcount(ptr), 3);
66 }
67 }
68
69 #[test]
70 fn test_v2_release_decrements() {
71 let h = HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY);
72 unsafe {
73 let ptr = &h as *const HeapHeader;
74 v2_retain(ptr); v2_retain(ptr); assert!(!v2_release(ptr)); assert_eq!(v2_get_refcount(ptr), 2);
79
80 assert!(!v2_release(ptr)); assert_eq!(v2_get_refcount(ptr), 1);
82
83 assert!(v2_release(ptr)); }
85 }
86
87 #[test]
88 fn test_v2_release_returns_true_on_last_ref() {
89 let h = HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY);
90 unsafe {
91 let ptr = &h as *const HeapHeader;
92 assert!(v2_release(ptr)); }
94 }
95
96 #[test]
97 fn test_v2_retain_release_thread_safety() {
98 use std::sync::Arc;
99
100 let header = Arc::new(HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY));
102
103 let threads: Vec<_> = (0..8)
104 .map(|_| {
105 let h = Arc::clone(&header);
106 std::thread::spawn(move || {
107 let ptr = &*h as *const HeapHeader;
108 for _ in 0..1000 {
109 unsafe { v2_retain(ptr) };
110 }
111 for _ in 0..1000 {
112 unsafe { v2_release(ptr) };
113 }
114 })
115 })
116 .collect();
117
118 for t in threads {
119 t.join().unwrap();
120 }
121
122 unsafe {
123 let ptr = &*header as *const HeapHeader;
124 assert_eq!(v2_get_refcount(ptr), 1);
125 }
126 }
127
128 #[test]
129 fn test_v2_refcount_operations_match_header_methods() {
130 let h = HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY);
131 unsafe {
132 let ptr = &h as *const HeapHeader;
133
134 assert_eq!(v2_get_refcount(ptr), h.get_refcount());
136
137 v2_retain(ptr);
138 assert_eq!(v2_get_refcount(ptr), h.get_refcount());
139 assert_eq!(h.get_refcount(), 2);
140
141 let should_dealloc = v2_release(ptr);
142 assert!(!should_dealloc);
143 assert_eq!(v2_get_refcount(ptr), h.get_refcount());
144 assert_eq!(h.get_refcount(), 1);
145 }
146 }
147}