arcshift/lib.rs
1#![no_std]
2#![cfg_attr(feature = "nightly", feature(ptr_metadata))]
3#![deny(warnings)]
4#![forbid(clippy::undocumented_unsafe_blocks)]
5#![deny(missing_docs)]
6
7//! # Introduction to ArcShift
8//!
9//! [`ArcShift`] is a data type similar to `std::sync::Arc`, except that it allows updating
10//! the value pointed to. It can be used as a faster replacement for
11//! `std::sync::Arc<std::sync::RwLock<T>>`.
12//!
13//! Writing to ArcShift is significantly more expensive than for `std::sync::RwLock`, so
14//! ArcShift is most suited to use cases where updates are infrequent.
15//!
16//! ## Example
17//! ```
18//! # #[cfg(any(feature="loom",feature="shuttle"))]
19//! # pub fn main() {}
20//! # #[cfg(not(any(feature="loom",feature="shuttle")))]
21//! # pub fn main() {
22//! # extern crate arcshift;
23//! # use arcshift::ArcShift;
24//! use std::thread;
25//!
26//!
27//! let mut arc = ArcShift::new("Hello".to_string());
28//! let mut arc2 = arc.clone();
29//!
30//!
31//! let j1 = thread::spawn(move||{
32//! println!("Value in thread 1: '{}'", arc.get()); //Prints 'Hello'
33//! arc.update("New value".to_string());
34//! println!("Updated value in thread 1: '{}'", arc.get()); //Prints 'New value'
35//! });
36//!
37//! let j2 = thread::spawn(move||{
38//! // Prints either 'Hello' or 'New value', depending on scheduling:
39//! println!("Value in thread 2: '{}'", arc2.get());
40//! });
41//!
42//! j1.join().unwrap();
43//! j2.join().unwrap();
44//! # }
45//! ```
46//!
47//! # Strong points
48//! * Easy to use (similar to Arc)
49//! * All functions are lock free (see <https://en.wikipedia.org/wiki/Non-blocking_algorithm> )
50//! * For use cases where no modification of values occurs, performance is very good (much
51//! better than RwLock or Mutex).
52//! * Modifying values is reasonably fast (think, 50-150 nanoseconds), but much slower than Mutex or
53//! RwLock.
54//! * The function [`ArcShift::shared_get`] allows access without any overhead
55//! at compared to regular Arc (benchmarks show identical performance to Arc).
56//! * ArcShift does not rely on thread-local variables.
57//! * ArcShift is no_std compatible (though 'alloc' is required, since ArcShift is a heap
58//! allocating data structure). Compile with "default-features=false" to enable no_std compatibility.
59//!
60//! # Limitations
61//!
62//! ArcShift achieves its performance at the expense of the following disadvantages:
63//!
64//! * When modifying the value, the old version of the value lingers in memory until
65//! the last ArcShift that uses it has updated. Such an update only happens when the ArcShift
66//! is accessed using a unique (`&mut`) access (like [`ArcShift::get`] or [`ArcShift::reload`]).
67//! This can be partially mitigated by using the [`ArcShiftWeak`]-type for long-lived
68//! never-reloaded instances.
69//! * Modifying the value is approximately 10x more expensive than modifying an `Arc<Mutex<T>>`.
70//! That said, if you're storing anything significantly more complex than an integer, the overhead
71//! of ArcShift may be insignificant.
72//! * When the value is modified, the next subsequent reload is slower than an `Arc<RwLock<T>>`
73//! access.
74//! * ArcShift is its own datatype. It is in no way compatible with `Arc<T>`.
75//! * At most usize::MAX/8 instances of ArcShift or ArcShiftWeak can be created for each value.
76//! (this is because it uses some bits of its weak refcount to store metadata).
77//! * ArcShift instances should ideally be owned (or be mutably accessible). This is because
78//! reloading ArcShift requires mutable access to the ArcShift object itself.
79//!
80//! The last limitation might seem unacceptable, but for many applications it is not
81//! hard to make sure each thread/scope has its own instance of ArcShift pointing to
82//! the resource. Cloning ArcShift instances is reasonably fast.
83//!
84//! # Implementation
85//!
86//! When ArcShift values are updated, a linked list of all updates is formed. Whenever
87//! an ArcShift-instance is reloaded (using [`ArcShift::reload`], [`ArcShift::get`],
88//! that instance advances along the linked list to the last
89//! node in the list. When no instance exists pointing at a node in the list, it is dropped.
90//! It is thus important to periodically call [`ArcShift::reload`] or [`ArcShift::get`] to avoid retaining unneeded values.
91//!
92//! # Motivation
93//!
94//! The primary raison d'ĂȘtre for [`ArcShift`] is to be a version of Arc which allows
95//! modifying the stored value, with very little overhead over regular Arc for read heavy
96//! loads.
97//!
98//! The motivating use-case for ArcShift is hot-reloadable assets in computer games.
99//! During normal usage, assets do not change. All benchmarks and play experience will
100//! be dependent only on this baseline performance. Ideally, we therefore want to have
101//! a very small performance penalty for the case when assets are *not* updated, comparable
102//! to using regular `std::sync::Arc`.
103//!
104//! During game development, artists may update assets, and hot-reload is a very
105//! time-saving feature. A performance hit during asset-reload is acceptable though.
106//! ArcShift prioritizes base performance, while accepting a penalty when updates are made.
107//!
108//! ArcShift can, of course, be useful in other domains than computer games.
109//!
110//! # Performance properties
111//!
112//! Accessing the value stored in an ArcShift instance only requires a regular memory access,
113//! not any form of atomic operation. Checking for new values requires a single
114//! atomic operation, of the least expensive kind (Ordering::Relaxed). On x86_64,
115//! this is the exact same machine operation as a regular memory access, and also
116//! on arm it is not an expensive operation.
117//! The cost of such access is much smaller than a mutex access, even an uncontended one.
118//! In the case where a reload is actually necessary, there is a significant performance impact
119//! (but still typically below 150ns for modern machines (2025)).
120//!
121//! # Panicking drop methods
122//! If a drop implementation panics, ArcShift will make sure that the internal data structures
123//! remain uncorrupted. When run without the std-library, some memory leakage will occur every
124//! time a drop method panics. With the std-library, only memory owned by the payload type
125//! might leak.
126//!
127//! # No_std
128//! By default, arcshift uses the rust standard library. This is enabled by the 'std' feature, which
129//! is enabled by default. ArcShift can work without the full rust std library. However, this
130//! comes at a slight performance cost. When the 'std' feature is enabled (which it is by default),
131//! `catch_unwind` is used to guard drop functions, to make sure memory structures are not corrupted
132//! if a user supplied drop method panics. However, to ensure the same guarantee when running
133//! without std, arcshift presently moves allocations to temporary boxes to be able to run drop
134//! after all memory traversal is finished. This requires multiple allocations, which makes
135//! operation without 'std' slightly slower. Panicking drop methods can also lead to memory leaks
136//! without the std. The memory structures remain intact, and no undefined behavior occurs.
137//!
138//! If the overhead mentioned in the previous paragraph is unacceptable, and if the final binary
139//! is compiled with panic=abort, this extra cost can be mitigated. Enable the feature
140//! "nostd_unchecked_panics" to do this. This must never be done if the process will ever continue
141//! executing after a panic, since it can lead to memory reclamation essentially being disabled
142//! for any ArcShift-chain that has had a panicking drop. However, no UB will result, in any case.
143//!
144//! # Implementation
145//!
146//! The basic idea of ArcShift is that each ArcShift instance points to a small heap block,
147//! that contains the pointee value of type T, three reference counts, and 'prev'/'next'-pointers.
148//! The 'next'-pointer starts out as null, but when the value in an ArcShift is updated, the
149//! 'next'-pointer is set to point to the updated value.
150//!
151//! This means that each ArcShift-instance always points at valid value of type T. No locking
152//! or synchronization is required to get at this value. This is why ArcShift instances are fast
153//! to use. There is the drawback that as long as an ArcShift-instance exists, whatever value
154//! it points to must be kept alive. Each time an ArcShift instance is accessed mutably, we have
155//! an opportunity to update its pointer to the 'next' value. The operation to update the pointer
156//! is called a 'reload'.
157//!
158//! When the last ArcShift-instance releases a particular value, it will be dropped.
159//!
160//! ArcShiftWeak-instances also keep pointers to the heap blocks mentioned above, but value T
161//! in the block can be dropped while being held by an ArcShiftWeak. This means that an ArcShiftWeak-
162//! instance only consumes `std::mem::size_of::<T>()` bytes plus 5 words of memory, when the value
163//! it points to has been dropped. When the ArcShiftWeak-instance is reloaded, or dropped, that memory
164//! is also released.
165//!
166//!
167//! # Pitfall #1 - lingering memory usage
168//!
169//! Be aware that ArcShift instances that are just "lying around" without ever being reloaded,
170//! will keep old values around, taking up memory. This is a fundamental drawback of the approach
171//! taken by ArcShift. One workaround is to replace any long-lived infrequently reloaded instances of
172//! [`ArcShift`] with [`ArcShiftWeak`]. This alleviates the problem, though heap storage of approx
173//! `size_of<T>` + 5 words is still expended.
174//!
175//! # Pitfall #2 - reference count limitations
176//!
177//! ArcShift uses usize data type for the reference counts. However, it reserves two bits for
178//! tracking some metadata. This leaves usize::MAX/4 as the maximum usable reference count. To
179//! avoid having to check the refcount twice (once before increasing the count), we set the limit
180//! at usize::MAX/8, and check the count after the atomic operation. This has the effect that if more
181//! than usize::MAX/8 threads clone the same ArcShift instance concurrently, the unsoundness will occur.
182//! However, this is considered acceptable, because this exceeds the possible number
183//! of concurrent threads by a huge safety margin. Also note that usize::MAX/8 ArcShift instances would
184//! take up usize::MAX bytes of memory, which is very much impossible in practice. By leaking
185//! ArcShift instances in a tight loop it is still possible to achieve a weak count of usize::MAX/8,
186//! in which case ArcShift will panic.
187//!
188//! # A larger example
189//!
190//! ```no_run
191//! # extern crate arcshift;
192//! # use arcshift::ArcShift;
193//!
194//! struct CharacterModel {
195//! /* 3D model, textures, etc*/
196//! }
197//!
198//! struct World {
199//! models: Vec<ArcShift<CharacterModel>>
200//! }
201//!
202//! /// Loads models. Regularly scans filesystem,
203//! /// updates models when their files change on disk.
204//! fn load_models() -> Vec<ArcShift<CharacterModel>> {
205//! let models: Vec<ArcShift<CharacterModel>> = vec![];
206//!
207//! /* Somehow load models */
208//!
209//! let mut models_for_reloader = models.clone();
210//! std::thread::spawn(move||{
211//! loop {
212//! /* detect file system changes*/
213//! let changed_model = 0usize;
214//!
215//! models_for_reloader[changed_model].update(CharacterModel{/* newly loaded*/});
216//! }
217//!
218//! });
219//!
220//! models
221//! }
222//!
223//! fn run_game() {
224//! let mut world = World {
225//! models: load_models()
226//! };
227//! loop {
228//! run_game_logic(&mut world);
229//! }
230//! }
231//!
232//! fn run_game_logic(world: &mut World) {
233//! /*
234//! Do game logic, possibly in multiple threads, accessing different parts of World,
235//! possibly cloning 'ArcShift' instances for use by other threads
236//! */
237//!
238//! for model in world.models.iter_mut() {
239//! // Accessing ArcShift using 'get' ensures
240//! // old versions do not linger in RAM.
241//! let model_ref : &CharacterModel = model.get();
242//! // Do stuff with 'model_ref'
243//! }
244//! }
245//!
246//!
247//! ```
248//!
249
250#[cfg(feature = "std")]
251extern crate std;
252
253extern crate alloc;
254
255use alloc::boxed::Box;
256
257use core::alloc::Layout;
258
259use crate::deferred_panics_helper::DropHandler;
260use crate::deferred_panics_helper::IDropHandler;
261use core::cell::UnsafeCell;
262use core::fmt::{Debug, Formatter};
263use core::marker::PhantomData;
264#[allow(unused)]
265use core::mem::align_of_val;
266use core::mem::size_of;
267#[allow(unused)]
268use core::mem::size_of_val;
269use core::mem::{transmute, ManuallyDrop};
270use core::panic::UnwindSafe;
271use core::ptr::{addr_of_mut, null, null_mut, NonNull};
272use core::sync::atomic::Ordering;
273// About unsafe code in this crate:
274// Some private functions contain unsafe code, and place limitations on their
275// callers, without these private functions being marked unsafe.
276// The rationale is that there are lots of operations that simply aren't unsafe, like
277// assigning null to a pointer, that could cause UB in unsafe code in this crate.
278// This crate is inherently dependent on all the code in it being correct. Therefore,
279// marking more functions unsafe buys us very little.
280// Note! The API of this crate is 100% safe and UB should be impossible to trigger by using it.
281// All public methods are 100% sound, this argument only concerns private methods.
282
283// All atomic primitives are reexported from a
284// local module called 'atomic', so we can easily change between using
285// types from 'std' (normal case) and types from shuttle/loom testing libraries.
286
287mod deferred_panics_helper;
288
289/// Declarations of atomic ops for using Arcshift in production
290#[cfg(all(not(loom), not(feature = "shuttle")))]
291mod atomic {
292 pub use core::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering};
293 #[allow(unused)]
294 #[cfg(feature = "std")]
295 pub use std::sync::{Arc, Mutex};
296 #[allow(unused)]
297 #[cfg(feature = "std")]
298 pub use std::thread;
299}
300
301/// Declarations for verifying Arcshift using 'shuttle'
302#[cfg(feature = "shuttle")]
303mod atomic {
304 #[allow(unused)]
305 pub use shuttle::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering};
306 #[allow(unused)]
307 pub use shuttle::sync::{Arc, Mutex};
308 #[allow(unused)]
309 pub use shuttle::thread;
310}
311
312/// Declarations for verifying Arcshift using 'loom'
313#[cfg(loom)]
314mod atomic {
315 pub use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering};
316 #[allow(unused)]
317 pub use loom::sync::{Arc, Mutex};
318 #[allow(unused)]
319 pub use loom::thread;
320}
321
322#[doc(hidden)]
323#[cfg(all(feature = "std", feature = "debug", not(loom)))]
324#[macro_export]
325macro_rules! debug_println {
326 ($($x:tt)*) => {
327 std::println!("{:?}: {}", $crate::atomic::thread::current().id(), std::format!($($x)*))
328 }
329}
330
331#[doc(hidden)]
332#[cfg(all(feature = "std", feature = "debug", loom))]
333#[macro_export]
334macro_rules! debug_println {
335 ($($x:tt)*) => { std::println!($($x)*) }
336}
337
338#[doc(hidden)]
339#[cfg(any(not(feature = "std"), not(feature = "debug")))]
340#[macro_export]
341macro_rules! debug_println {
342 ($($x:tt)*) => {{}};
343}
344
345/// Smart pointer with similar use case as std::sync::Arc, but with
346/// the added ability to atomically replace the contents of the Arc.
347/// See `crate` documentation for more information.
348///
349/// ```rust
350/// # extern crate arcshift;
351/// # #[cfg(any(feature="loom",feature="shuttle"))]
352/// # fn main() {}
353/// # #[cfg(not(any(feature="loom",feature="shuttle")))]
354/// # pub fn main() {
355/// # use arcshift::ArcShift;
356/// let mut instance = ArcShift::new("test");
357/// println!("Value: {:?}", instance.get());
358/// # }
359/// ```
360pub struct ArcShift<T: ?Sized> {
361 item: NonNull<ItemHolderDummy<T>>,
362
363 // Make sure ArcShift is invariant.
364 // ArcShift instances with different lifetimes of T should not be compatible,
365 // since could lead to a short-lived value T being insert into a chain which
366 // also has long-lived ArcShift instances with long-lived T.
367 pd: PhantomData<*mut T>,
368}
369impl<T> UnwindSafe for ArcShift<T> {}
370
371impl<T: ?Sized> Debug for ArcShift<T>
372where
373 T: Debug,
374{
375 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
376 write!(f, "ArcShift({:?})", self.shared_get())
377 }
378}
379
380impl<T: ?Sized> Debug for ArcShiftWeak<T>
381where
382 T: Debug,
383{
384 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
385 write!(f, "ArcShiftWeak(..)")
386 }
387}
388
389/// ArcShiftWeak is a way to keep a pointer to an object without preventing said object
390/// from being deallocated. This can be useful when creating cyclic data structure, to avoid
391/// memory leaks.
392///
393/// ```no_run
394/// # use arcshift::ArcShift;
395/// # #[cfg(any(feature="loom",feature="shuttle"))]
396/// # fn main() {}
397/// # #[cfg(not(any(feature="loom",feature="shuttle")))]
398/// # fn main() {
399/// # extern crate arcshift;
400/// # use arcshift::ArcShiftWeak;
401/// let original_instance = ArcShift::new("test");
402/// let light_instance = ArcShift::downgrade(&original_instance);
403/// let mut instance = light_instance.upgrade().unwrap();
404/// println!("Value: {:?}", instance.get());
405/// # }
406/// ```
407///
408/// WARNING! Because of implementation reasons, each instance of ArcShiftWeak will claim
409/// a memory equal to `size_of::<T>` (plus 5 words), even if the value inside it has freed,
410/// and even if all other instances of ArcShift/ArcShiftWeak have been dropped.
411/// If this limitation is unacceptable, consider using `ArcShiftWeak<Box<T>>` as your datatype,
412/// or possibly using a different crate.
413pub struct ArcShiftWeak<T: ?Sized> {
414 item: NonNull<ItemHolderDummy<T>>,
415}
416
417/// A handle that allows reloading an ArcShift instance without having 'mut' access.
418/// However, it does not implement `Sync`.
419pub mod cell;
420
421const fn is_sized<T: ?Sized>() -> bool {
422 size_of::<&T>() == size_of::<&()>()
423}
424
425/// SAFETY:
426/// If `T` is `Sync` and `Send`, `ArcShift<T>` can also be `Sync`
427unsafe impl<T: Sync + Send + ?Sized> Sync for ArcShift<T> {}
428
429/// SAFETY:
430/// If `T` is `Sync` and `Send`, `ArcShift<T>` can also be `Send`
431unsafe impl<T: Sync + Send + ?Sized> Send for ArcShift<T> {}
432
433/// SAFETY:
434/// If `T` is `Sync` and `Send`, `ArcShiftWeak<T>` can also be `Sync`
435unsafe impl<T: Sync + Send + ?Sized> Sync for ArcShiftWeak<T> {}
436
437/// SAFETY:
438/// If `T` is `Sync` and `Send`, `ArcShiftWeak<T>` can also be `Send`
439unsafe impl<T: Sync + Send + ?Sized> Send for ArcShiftWeak<T> {}
440
441#[repr(transparent)]
442struct UnsizedMetadata<T: ?Sized> {
443 #[cfg(feature = "nightly")]
444 meta: <T as std::ptr::Pointee>::Metadata,
445 #[cfg(not(feature = "nightly"))]
446 meta: *const (),
447 phantom: PhantomData<T>,
448}
449impl<T: ?Sized> Clone for UnsizedMetadata<T> {
450 fn clone(&self) -> Self {
451 *self
452 }
453}
454impl<T: ?Sized> Copy for UnsizedMetadata<T> {}
455impl<T: ?Sized> core::fmt::Debug for UnsizedMetadata<T> {
456 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
457 write!(f, "Metadata({:?})", self.meta)
458 }
459}
460
461#[allow(dead_code)]
462#[repr(C)]
463struct FatPtr<T: ?Sized> {
464 ptr: *mut u8,
465 meta: UnsizedMetadata<T>,
466}
467
468#[inline]
469fn arc_from_raw_parts_mut<T: ?Sized, M: IMetadata>(
470 data_ptr: *mut u8,
471 metadata: UnsizedMetadata<T>,
472) -> *mut ItemHolder<T, M> {
473 // SAFETY:
474 // This is the best I managed without using nightly-only features (August 2024).
475 // It is sound as long as the actual internal representation of fat pointers doesn't change.
476 #[cfg(not(feature = "nightly"))]
477 unsafe {
478 core::mem::transmute_copy(&FatPtr {
479 ptr: data_ptr,
480 meta: metadata,
481 })
482 }
483 #[cfg(feature = "nightly")]
484 {
485 std::ptr::from_raw_parts_mut(data_ptr, metadata.meta)
486 }
487}
488
489#[inline]
490#[cfg(not(any(feature = "std", feature = "nostd_unchecked_panics")))]
491#[cfg_attr(test, mutants::skip)]
492pub(crate) fn ptr_from_raw_parts_mut<T: ?Sized>(
493 data_ptr: *mut u8,
494 metadata: UnsizedMetadata<T>,
495) -> *mut T {
496 // SAFETY:
497 // This is the best I managed without using nightly-only features (August 2024).
498 // It is sound as long as the actual internal representation of fat pointers doesn't change.
499 #[cfg(not(feature = "nightly"))]
500 unsafe {
501 core::mem::transmute_copy(&FatPtr {
502 ptr: data_ptr,
503 meta: metadata,
504 })
505 }
506 #[cfg(feature = "nightly")]
507 {
508 std::ptr::from_raw_parts_mut(data_ptr, metadata.meta)
509 }
510}
511
512impl<T: ?Sized> UnsizedMetadata<T> {
513 #[inline]
514 #[cfg(not(feature = "nightly"))]
515 fn polyfill_metadata(cur_ptr: *const T) -> *const () {
516 if is_sized::<T>() {
517 unreachable!() //We're never using this function for sized data
518 } else {
519 let ptrptr = &cur_ptr as *const *const T as *const *const ();
520 // SAFETY:
521 // This is a trick to get at the 'metadata'-part of the fat-ptr 'cur_ptr'.
522 // It works in practice, as long as the internal representation of fat pointers doesn't
523 // change.
524 unsafe { *ptrptr.wrapping_offset(1) }
525 }
526 }
527
528 #[inline]
529 pub fn new(cur_ptr: *const T) -> UnsizedMetadata<T> {
530 UnsizedMetadata {
531 #[cfg(feature = "nightly")]
532 meta: std::ptr::metadata(cur_ptr),
533 #[cfg(not(feature = "nightly"))]
534 meta: Self::polyfill_metadata(cur_ptr),
535 phantom: PhantomData,
536 }
537 }
538}
539
540fn get_holder_layout<T: ?Sized>(ptr: *const T) -> Layout {
541 // SAFETY:
542 // The pointer 'ptr' is a valid pointer
543 let payload_layout = Layout::for_value(unsafe { &*ptr });
544 if is_sized::<T>() {
545 let layout = Layout::new::<ItemHolder<(), SizedMetadata>>();
546 let (layout, _) = layout.extend(payload_layout).unwrap();
547 layout.pad_to_align()
548 } else {
549 let layout = Layout::new::<UnsizedMetadata<T>>();
550 let (layout, _) = layout
551 .extend(Layout::new::<ItemHolder<(), UnsizedMetadata<T>>>())
552 .unwrap();
553 let (layout, _) = layout.extend(payload_layout).unwrap();
554 layout.pad_to_align()
555 }
556}
557
558fn to_dummy<T: ?Sized, M: IMetadata>(ptr: *const ItemHolder<T, M>) -> *const ItemHolderDummy<T> {
559 ptr as *mut ItemHolderDummy<T>
560}
561fn from_dummy<T: ?Sized, M: IMetadata>(ptr: *const ItemHolderDummy<T>) -> *const ItemHolder<T, M> {
562 get_full_ptr_raw::<T, M>(ptr)
563}
564
565macro_rules! with_holder {
566 ($p: expr, $t: ty, $item: ident, $f:expr) => {
567 if is_sized::<$t>() {
568 let $item = from_dummy::<$t, SizedMetadata>($p.as_ptr());
569 $f
570 } else {
571 let $item = from_dummy::<$t, UnsizedMetadata<$t>>($p.as_ptr());
572 $f
573 }
574 };
575}
576
577fn make_sized_or_unsized_holder_from_box<T: ?Sized>(
578 item: Box<T>,
579 prev: *mut ItemHolderDummy<T>,
580) -> *const ItemHolderDummy<T> {
581 if is_sized::<T>() {
582 to_dummy(make_sized_holder_from_box(item, prev))
583 } else {
584 to_dummy(make_unsized_holder_from_box(item, prev))
585 }
586}
587
588#[allow(clippy::let_and_return)]
589fn get_weak_count(count: usize) -> usize {
590 let count = count & ((1 << (usize::BITS - 2)) - 1);
591 #[cfg(feature = "validate")]
592 assert!(count < MAX_REF_COUNT / 2);
593 count
594}
595
596/// Node has next, or will soon have next. Note! It may seem this is unnecessary,
597/// since if there's a "next", then that next node will hold a weak ref, so a lonely
598/// reference could detect that there was a 'next' anyway.
599///
600/// Consider the following sequence:
601/// * Instance A and B point to Node N1
602/// * A starts dropping. It loads weak count '2'.
603/// * B updates, creating N2, and advanced to N2, and is then dropped.
604/// * Weak count of N1 is now still 2, so the compare_exchange for A *succeeds*
605///
606/// Having this flag makes it impossible for N1 to succeed
607const WEAK_HAVE_NEXT: usize = 1 << (usize::BITS - 1);
608const WEAK_HAVE_PREV: usize = 1 << (usize::BITS - 2);
609
610/// To avoid potential unsafety if refcounts overflow and wrap around,
611/// we have a maximum limit for ref count values. This limit is set with a large margin relative
612/// to the actual wraparound value. Note that this
613/// limit is enforced post fact, meaning that if there are more than usize::MAX/8 or so
614/// simultaneous threads, unsoundness can occur. This is deemed acceptable, because it is
615/// impossible to achieve in practice. Especially since it basically requires an extremely long
616/// running program with memory leaks, or leaking memory very fast in a tight loop. Without leaking,
617/// is impractical to achieve such high refcounts, since having usize::MAX/8 ArcShift instances
618/// alive on a 64-bit machine is impossible, since this would require usize::MAX/2 bytes of memory,
619/// orders of magnitude larger than any existing machine (in 2025).
620const MAX_REF_COUNT: usize = usize::MAX / 8;
621
622fn get_weak_prev(count: usize) -> bool {
623 (count & WEAK_HAVE_PREV) != 0
624}
625
626#[allow(unused)]
627fn get_weak_next(count: usize) -> bool {
628 (count & WEAK_HAVE_NEXT) != 0
629}
630
631#[cfg_attr(test, mutants::skip)]
632fn initial_weak_count<T: ?Sized>(prev: *const ItemHolderDummy<T>) -> usize {
633 if prev.is_null() {
634 1
635 } else {
636 1 | WEAK_HAVE_PREV
637 }
638}
639
640#[allow(unused)]
641#[cfg(all(feature = "std", feature = "debug"))]
642#[cfg_attr(test, mutants::skip)]
643fn format_weak(weak: usize) -> std::string::String {
644 let count = weak & ((1 << (usize::BITS - 2)) - 1);
645 let have_next = (weak & WEAK_HAVE_NEXT) != 0;
646 let have_prev = (weak & WEAK_HAVE_PREV) != 0;
647 std::format!("(weak: {} prev: {} next: {})", count, have_prev, have_next)
648}
649
650#[allow(unused)]
651fn make_unsized_holder_from_box<T: ?Sized>(
652 item: Box<T>,
653 prev: *mut ItemHolderDummy<T>,
654) -> *const ItemHolder<T, UnsizedMetadata<T>> {
655 let cur_ptr = Box::into_raw(item);
656
657 debug_println!("thesize: {:?}", cur_ptr);
658 let item_holder_ptr: *mut ItemHolder<T, UnsizedMetadata<T>>;
659
660 // SAFETY:
661 // The pointer 'cur_ptr' is a valid pointer (it's just been created by 'Box::into_raw'
662 let payload_layout = Layout::for_value(unsafe { &*cur_ptr });
663 let the_size = payload_layout.size();
664
665 if is_sized::<T>() {
666 unreachable!()
667 } else {
668 let layout = get_holder_layout::<T>(cur_ptr);
669
670 let metadata = UnsizedMetadata::new(cur_ptr);
671 debug_println!("Layout: {:?}, meta: {:?}", layout, metadata);
672 item_holder_ptr =
673 // SAFETY:
674 // core::alloc::alloc requires the allocated layout to have a nonzero size. This
675 // is fulfilled, since ItemHolder is non-zero sized even if T is zero-sized.
676 // The returned memory is uninitialized, but we will initialize the required parts of it
677 // below.
678 unsafe { arc_from_raw_parts_mut(alloc::alloc::alloc(layout) as *mut _, metadata) };
679 debug_println!("Sized result ptr: {:?}", item_holder_ptr);
680 // SAFETY:
681 // result_ptr is a valid pointer
682 unsafe {
683 addr_of_mut!((*item_holder_ptr).the_meta).write(metadata);
684 }
685 }
686
687 // SAFETY:
688 // The copy is safe because MaybeUninit<ItemHolder<T>> is guaranteed to have the same
689 // memory layout as ItemHolder<T>, so we're just copying a value of T to a new location.
690 unsafe {
691 (addr_of_mut!((*item_holder_ptr).payload) as *mut u8)
692 .copy_from(cur_ptr as *mut u8, the_size);
693 }
694 // SAFETY:
695 // next is just an AtomicPtr-type, for which all bit patterns are valid.
696 unsafe {
697 addr_of_mut!((*item_holder_ptr).prev).write(atomic::AtomicPtr::new(prev as *mut _));
698 }
699 // SAFETY:
700 // refcount is just an AtomicPtr-type, for which all bit patterns are valid.
701 unsafe {
702 addr_of_mut!((*item_holder_ptr).next).write(atomic::AtomicPtr::default());
703 }
704 // SAFETY:
705 // strong_count is just an AtomicUsize-type, for which all bit patterns are valid.
706 unsafe {
707 addr_of_mut!((*item_holder_ptr).strong_count).write(atomic::AtomicUsize::new(1));
708 }
709 // SAFETY:
710 // weak_count is just an AtomicUsize-type, for which all bit patterns are valid.
711 unsafe {
712 addr_of_mut!((*item_holder_ptr).weak_count)
713 .write(atomic::AtomicUsize::new(initial_weak_count(prev)));
714 }
715 // SAFETY:
716 // advance_count is just an AtomicUsize-type, for which all bit patterns are valid.
717 unsafe {
718 addr_of_mut!((*item_holder_ptr).advance_count).write(atomic::AtomicUsize::new(0));
719 }
720
721 // SAFETY:
722 // result_ptr is a valid pointer
723 #[cfg(feature = "validate")]
724 unsafe {
725 addr_of_mut!((*item_holder_ptr).magic1)
726 .write(std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111));
727 }
728
729 // SAFETY:
730 // result_ptr is a valid pointer
731 #[cfg(feature = "validate")]
732 unsafe {
733 addr_of_mut!((*item_holder_ptr).magic2)
734 .write(std::sync::atomic::AtomicU64::new(0x1234123412348111));
735 }
736
737 // SAFETY:
738 // input_ptr is a *mut T that has been created from a Box<T>.
739 // Converting it to a Box<MaybeUninit<T>> is safe, and will make sure that any drop-method
740 // of T is not run. We must not drop T here, since we've moved it to the 'result_ptr'.
741 let _t: Box<ManuallyDrop<T>> = unsafe { Box::from_raw(cur_ptr as *mut ManuallyDrop<T>) }; //Free the memory, but don't drop 'input'
742
743 item_holder_ptr
744}
745
746#[allow(unused)]
747fn make_sized_holder<T>(
748 payload: T,
749 prev: *const ItemHolderDummy<T>,
750) -> *mut ItemHolder<T, SizedMetadata> {
751 let holder = ItemHolder {
752 the_meta: SizedMetadata,
753 #[cfg(feature = "validate")]
754 magic1: std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111),
755 next: Default::default(),
756 prev: atomic::AtomicPtr::new(prev as *mut _),
757 strong_count: atomic::AtomicUsize::new(1),
758 weak_count: atomic::AtomicUsize::new(initial_weak_count::<T>(prev)),
759 advance_count: atomic::AtomicUsize::new(0),
760 #[cfg(feature = "validate")]
761 magic2: std::sync::atomic::AtomicU64::new(0x1234123412348111),
762 payload: UnsafeCell::new(ManuallyDrop::new(payload)),
763 };
764
765 Box::into_raw(Box::new(holder))
766}
767
768#[allow(unused)]
769fn make_sized_holder_from_box<T: ?Sized>(
770 item: Box<T>,
771 prev: *mut ItemHolderDummy<T>,
772) -> *mut ItemHolder<T, SizedMetadata> {
773 let cur_ptr = Box::into_raw(item);
774
775 debug_println!("thesize: {:?}", cur_ptr);
776
777 // SAFETY:
778 // 'cur_ptr' is a valid pointer, it's just been created by Box::into_raw
779 let payload_layout = Layout::for_value(unsafe { &*cur_ptr });
780 let the_size = payload_layout.size();
781
782 let layout = get_holder_layout::<T>(cur_ptr);
783
784 // SAFETY:
785 // The type '*mut ItemHolder<T, NoMeta>' is not actually a fat pointer. But since T:?Sized,
786 // the compiler treats it like a fat pointer with a zero-size metadata, which is not
787 // the exact same thing as a thin pointer (is my guess).
788 // Using transmute_copy to trim off the metadata is sound.
789 let item_holder_ptr: *mut ItemHolder<T, SizedMetadata> =
790 unsafe { core::mem::transmute_copy(&alloc::alloc::alloc(layout)) };
791
792 // SAFETY:
793 // The copy is safe because MaybeUninit<ItemHolder<T>> is guaranteed to have the same
794 // memory layout as ItemHolder<T>, so we're just copying a value of T to a new location.
795 unsafe {
796 (addr_of_mut!((*item_holder_ptr).payload) as *mut u8)
797 .copy_from(cur_ptr as *mut u8, the_size);
798 }
799 // SAFETY:
800 // next is just an AtomicPtr-type, for which all bit patterns are valid.
801 unsafe {
802 addr_of_mut!((*item_holder_ptr).prev).write(atomic::AtomicPtr::new(prev as *mut _));
803 }
804 // SAFETY:
805 // refcount is just an AtomicPtr-type, for which all bit patterns are valid.
806 unsafe {
807 addr_of_mut!((*item_holder_ptr).next).write(atomic::AtomicPtr::default());
808 }
809 // SAFETY:
810 // strong_count is just an AtomicUsize-type, for which all bit patterns are valid.
811 unsafe {
812 addr_of_mut!((*item_holder_ptr).strong_count).write(atomic::AtomicUsize::new(1));
813 }
814 // SAFETY:
815 // weak_count is just an AtomicUsize-type, for which all bit patterns are valid.
816 unsafe {
817 addr_of_mut!((*item_holder_ptr).weak_count)
818 .write(atomic::AtomicUsize::new(initial_weak_count(prev)));
819 }
820 // SAFETY:
821 // advance_count is just an AtomicUsize-type, for which all bit patterns are valid.
822 unsafe {
823 addr_of_mut!((*item_holder_ptr).advance_count).write(atomic::AtomicUsize::new(0));
824 }
825
826 // SAFETY:
827 // result_ptr is a valid pointer
828 #[cfg(feature = "validate")]
829 unsafe {
830 addr_of_mut!((*item_holder_ptr).magic1)
831 .write(std::sync::atomic::AtomicU64::new(0xbeefbeefbeef8111));
832 }
833
834 // SAFETY:
835 // result_ptr is a valid pointer
836 #[cfg(feature = "validate")]
837 unsafe {
838 addr_of_mut!((*item_holder_ptr).magic2)
839 .write(std::sync::atomic::AtomicU64::new(0x1234123412348111));
840 }
841
842 // SAFETY:
843 // input_ptr is a *mut T that has been created from a Box<T>.
844 // Converting it to a Box<MaybeUninit<T>> is safe, and will make sure that any drop-method
845 // of T is not run. We must not drop T here, since we've moved it to the 'result_ptr'.
846 let _t: Box<ManuallyDrop<T>> = unsafe { Box::from_raw(cur_ptr as *mut ManuallyDrop<T>) }; //Free the memory, but don't drop 'input'
847
848 item_holder_ptr
849}
850fn get_full_ptr_raw<T: ?Sized, M: IMetadata>(
851 dummy: *const ItemHolderDummy<T>,
852) -> *const ItemHolder<T, M> {
853 if is_sized::<T>() {
854 assert_eq!(
855 size_of::<*const ItemHolder<T, M>>(),
856 size_of::<*const ItemHolderDummy<T>>()
857 ); //<- Verify that *const T is not a fat ptr
858
859 // SAFETY:
860 // '*const ItemHolder<T, M>' is not _actually_ a fat pointer (it is just pointer sized),
861 // so transmuting from dummy to it is correct.
862 unsafe { core::mem::transmute_copy(&dummy) }
863 } else {
864 assert_eq!(size_of::<M>(), size_of::<usize>()); //<- Verify that *const ItemHolder<T> is a fat ptr
865
866 let ptr_data = dummy as *mut _;
867 debug_println!("Dummy data: {:?}", ptr_data);
868 let metadata_ptr = dummy as *const UnsizedMetadata<T>;
869 debug_println!(
870 "Unsized, meta: {:?}, val: {:?}",
871 metadata_ptr,
872 // SAFETY:
873 // metadata_ptr is a valid pointer
874 unsafe { *metadata_ptr }
875 );
876 // SAFETY:
877 // metadata_ptr is a valid pointer
878 let metadata = unsafe { *metadata_ptr };
879 arc_from_raw_parts_mut(ptr_data, metadata)
880 }
881}
882
883pub(crate) struct SizedMetadata;
884trait IMetadata {}
885impl IMetadata for SizedMetadata {}
886impl<T: ?Sized> IMetadata for UnsizedMetadata<T> {}
887
888#[repr(transparent)]
889struct ItemHolderDummy<T: ?Sized> {
890 // void pointers should point to u8
891 _dummy: u8,
892 _phantom_data: PhantomData<T>,
893}
894
895/*
896Invariants:
897 * ItemHolder cannot be deallocated if weak-count > 0
898 * When strong-count goes from 0->1, weak-count must be incremented by 1
899 * When strong-count goes from 1->0, weak-count must be decremented by 1
900 * The rightmost ItemHolder cannot be dropped if there are other items (to the left).
901 (But it may be possible to apply the janitor operation and drop them)
902 * An ItemHolder can have its strong-count increased even if it is dropped,
903 so just because strong-count is > 0 doesn't mean the item isn't dropped.
904 * If strong-count > 0, weak-count is also > 0.
905 * ItemHolder cannot be dropped if item.prev.advance_count > 0
906 * Linked list defined by prev-pointers is the nominal order of the chain
907 * ItemHolder can only be dropped when holding a lock on item,
908 and a lock on item 'item.next', after having set 'item.prev.next' to 'item.next' (or further to the right).
909 See do_advance_impl for details regarding 'advance_count'.
910 * While dropping, the janitor process must be run. If a concurrent janitor task is detected,
911 it must be marked as 'disturbed', and the disturbed task must re-run from the beginning
912 after completing.
913 * The weak-count has encoded in it 2 flags: HAVE_WEAK_NEXT and HAVE_WEAK_PREV. These decide
914 if the item has an item to the right (next) and/or to the left (prev). The HAVE_WEAK_NEXT
915 means there is, or soon will be, a neighbor to the right. HAVE_WEAK_PREV there isn't,
916 or soon won't be, a neighbor to the left. When using compare_exchange to set the weak_count
917 to 0, the code will atomically ensure no prev/next exist and that count is 0, in one operation.
918
919*/
920
921/// This structure represents the heap allocation in which ArcShift payloads reside.
922/// Align 8 is needed, since we store flags in the lower 2 bits of the ItemHolder-pointers
923/// In practice, the alignment of ItemHolder is 8 anyway, but we specify it here for clarity.
924#[repr(align(8))]
925#[repr(C)] // Just to get the 'magic' first and last in memory. Shouldn't hurt.
926struct ItemHolder<T: ?Sized, M: IMetadata> {
927 the_meta: M,
928 #[cfg(feature = "validate")]
929 magic1: std::sync::atomic::AtomicU64,
930 /// Can be incremented to keep the 'next' value alive. If 'next' is set to a new value, and
931 /// 'advance_count' is read as 0 after, then this node is definitely not going to advance to
932 /// some node *before* 'next'.
933 advance_count: atomic::AtomicUsize,
934
935 /// Pointer to the prev value, or null.
936 prev: atomic::AtomicPtr<ItemHolderDummy<T>>,
937 /// Strong count. When 0, the item is dropped.
938 /// Count must never be incremented from 0. This means increment must be done with
939 /// compare-exchange, not fetch_add.
940 strong_count: atomic::AtomicUsize,
941 /// Weak count. When reaches 0, the 'janitor' task may deallocate the node, iff
942 /// there are no previous nodes with 'advance_count' > 0.
943 /// The next node holds a weak ref to the prev. But prev nodes don't
944 /// hold weak counts on next.
945 /// MSB of 'weak_count' is a 'nonext' flag, that tells that this item is the last in the
946 /// chain. It is set to 1 *before* 'next' is assigned, so this is 0 when it is known
947 /// that this won't be the last ever.
948 weak_count: atomic::AtomicUsize,
949 #[cfg(feature = "validate")]
950 magic2: std::sync::atomic::AtomicU64,
951
952 /// Pointer to the next value or null. Possibly decorated (i.e, least significant bit set)
953 /// The decoration determines:
954 /// * If janitor process is currently active for this node and those left of it
955 /// * If payload has been deallocated
956 /// * The current lock-holder (janitor) has been disturbed (i.e, some other thread couldn't
957 /// do its job because it encountered the lock, and set the disturbed flag).
958 next: atomic::AtomicPtr<ItemHolderDummy<T>>,
959 pub(crate) payload: UnsafeCell<ManuallyDrop<T>>,
960}
961
962impl<T: ?Sized, M: IMetadata> PartialEq for ItemHolder<T, M> {
963 #[allow(clippy::ptr_eq)] //We actually want to use addr_eq, but it's not available on older rust versions. Let's just use this for now.
964 fn eq(&self, other: &ItemHolder<T, M>) -> bool {
965 self as *const _ as *const u8 == other as *const _ as *const u8
966 }
967}
968
969impl<T: ?Sized, M: IMetadata> ItemHolder<T, M> {
970 fn set_next(&self, undecorated_new_next: *const ItemHolderDummy<T>) {
971 #[cfg(feature = "validate")]
972 assert_eq!(
973 get_decoration(undecorated_new_next),
974 ItemStateEnum::UndisturbedUndecorated
975 );
976
977 // Synchronizes with:
978 // * 'has_payload' - irrelevant, has payload only cares about 'Dropped'-flag, not changed here
979 // * 'lock_node_for_gc' - irrelevant, we already own the lock, and we're not changing the lock-bit
980 // * 'do_upgrade_weak'
981 //
982 // Lock-free because we only loop if 'next' changes, which means
983 // some other node has made progress.
984 let mut prior_next = self.next.load(atomic::Ordering::Relaxed);
985 loop {
986 let new_next = decorate(undecorated_new_next, get_decoration(prior_next));
987 match self.next.compare_exchange(
988 prior_next,
989 new_next as *mut _,
990 atomic::Ordering::SeqCst, //atomic set_next
991 atomic::Ordering::SeqCst,
992 ) {
993 Ok(_) => {
994 debug_println!(
995 "set {:x?}.next = {:x?}",
996 to_dummy(self as *const _),
997 new_next
998 );
999 return;
1000 }
1001 Err(err) => {
1002 prior_next = err;
1003 }
1004 }
1005 }
1006 }
1007
1008 /// Includes self
1009 #[allow(unused)]
1010 #[cfg(test)]
1011 #[cfg(feature = "std")]
1012 fn debug_all_to_left<'a>(&self) -> std::vec::Vec<&'a ItemHolder<T, M>> {
1013 let mut ret = alloc::vec::Vec::new();
1014 let mut item_ptr = self as *const ItemHolder<T, M>;
1015 // Lock-free because this loop is run in debug harness, and doesn't do any synchronization
1016 loop {
1017 // SAFETY:
1018 // item_ptr has just been created from the reference 'self', or was a non-null
1019 // 'prev' pointer of some valid reference, recursively. This method is only called
1020 // from the debug_validate machinery, that is 'unsafe' and requires the user to
1021 // make sure no concurrent access is occurring. At rest, 'prev' pointers are always
1022 // valid.
1023 ret.push(unsafe { &*item_ptr });
1024 // SAFETY:
1025 // See above. item_ptr is a valid pointer.
1026 let prev = from_dummy::<T, M>(unsafe { (*item_ptr).prev.load(Ordering::Relaxed) });
1027 if prev.is_null() {
1028 break;
1029 }
1030 item_ptr = prev;
1031 }
1032
1033 ret
1034 }
1035
1036 #[inline(always)]
1037 unsafe fn payload<'a>(&self) -> &'a T {
1038 // SAFETY:
1039 // Lifetime extension of shared references like this is permissible, as long as the object,
1040 // remains alive. Because of our refcounting, the object is kept alive as long as
1041 // the accessor (ArcShift-type) that calls this remains alive.
1042 unsafe { transmute::<&T, &'a T>(&*(self.payload.get())) }
1043 }
1044
1045 // SAFETY:
1046 // Node must be uniquely owned, and payload must never be accessed again
1047 #[cfg(not(any(feature = "std", feature = "nostd_unchecked_panics")))]
1048 unsafe fn take_boxed_payload(&self) -> Box<T> {
1049 let payload = &self.payload;
1050 debug_println!("boxing payload");
1051
1052 // SAFETY: item_ptr is now uniquely owned. We can drop it.
1053 let payload_val: &mut T = unsafe { &mut **(&mut *payload.get()) };
1054 let size = size_of_val(payload_val);
1055 let align = align_of_val(payload_val);
1056 let layout = Layout::from_size_align(size, align).unwrap();
1057 let thin_dest_ptr = if size == 0 {
1058 1 as *mut u8
1059 } else {
1060 alloc::alloc::alloc(layout)
1061 };
1062
1063 let fat_dest_ptr = if is_sized::<T>() {
1064 core::ptr::copy_nonoverlapping(payload_val as *mut _ as *mut u8, thin_dest_ptr, size);
1065 core::mem::transmute_copy(&thin_dest_ptr)
1066 } else {
1067 core::ptr::copy_nonoverlapping(payload_val as *mut _ as *mut u8, thin_dest_ptr, size);
1068 let meta = UnsizedMetadata::new(payload_val);
1069 ptr_from_raw_parts_mut(thin_dest_ptr, meta)
1070 };
1071
1072 Box::from_raw(fat_dest_ptr)
1073 }
1074
1075 /// Returns true if the node could be atomically locked
1076 fn lock_node_for_gc(&self) -> bool {
1077 // Lock free, see comment for each 'continue' statement, which are the only statements
1078 // that lead to looping.
1079 loop {
1080 // This can't be 'Relaxed', because if we read it as already locked and disturbed,
1081 // we must make sure that this is still the case at this point in the total order.
1082 // When dropping, after exiting here, we won't clean up the entire chain. Our current
1083 // thread is not going to stop this from occurring (we've advanced to the rightmost), but
1084 // if it doesn't do it itself, we must make sure some other thread does it.
1085 //
1086 // If we read a stale value here, it may have been written by some other node _before_
1087 // we advanced, in which case that node may have already retried the GC, and failed
1088 // (since we hadn't advanced). This would then lead to a memory leak.
1089 let cur_next = self.next.load(atomic::Ordering::SeqCst);
1090
1091 let decoration = get_decoration(cur_next);
1092 debug_println!(
1093 "loaded {:x?}.next, got {:?} (decoration: {:?})",
1094 self as *const ItemHolder<T, M>,
1095 cur_next,
1096 decoration
1097 );
1098 if decoration.is_unlocked() {
1099 let decorated = decorate(undecorate(cur_next), decoration.with_gc());
1100 let success = self
1101 .next
1102 .compare_exchange(
1103 cur_next,
1104 decorated as *mut _,
1105 Ordering::SeqCst, //atomic gc lock
1106 atomic::Ordering::SeqCst,
1107 )
1108 .is_ok();
1109 debug_println!(
1110 "Locking node {:x?}, result: {} (prior decoration: {:?}, new {:?})",
1111 self as *const ItemHolder<T, M>,
1112 success,
1113 decoration,
1114 get_decoration(decorated)
1115 );
1116 if !success {
1117 // Lock free, because we only end up here if some other thread did one of:
1118 // 1) added a new node, which is considered progress
1119 // 2) has locked the node, which is not progress, but will only lead to us
1120 // setting the 'disturbed' flag, which is only one step, and thus lock free.
1121 continue;
1122 }
1123 return true;
1124 } else {
1125 debug_println!(
1126 "Locking node {:x?} failed, already decorated: {:?}",
1127 self as *const ItemHolder<T, M>,
1128 decoration
1129 );
1130 if !decoration.is_disturbed() {
1131 let decorated = decorate(undecorate(cur_next), decoration.with_disturbed());
1132 match self.next.compare_exchange(
1133 cur_next,
1134 decorated as *mut _,
1135 Ordering::SeqCst, //atomic gc disturb
1136 atomic::Ordering::SeqCst,
1137 ) {
1138 Ok(_) => {
1139 debug_println!("Locking node {:x?} failed, set disturbed flag, new value: {:x?} (={:?})", self as * const ItemHolder<T, M>, decorated, get_decoration(decorated));
1140 }
1141 Err(prior) => {
1142 if !get_decoration(prior).is_disturbed() {
1143 // Lock free, because we can only end up here if some other thread did either:
1144 // 1) Add a new node, which is considered progress
1145 // 2) Removed the lock, which will lead to the other node advancing
1146 // to new things (which is progress), unless it was disturbed.
1147 // However, if it was disturbed, it wasn't due to us, since we
1148 // failed to set the disturbed flag.
1149 continue;
1150 }
1151 }
1152 }
1153 }
1154
1155 // Already decorated
1156 return false;
1157 }
1158 }
1159 }
1160
1161 /// Return true if node was disturbed
1162 #[must_use] //Not safe to leave a re-run request un-handled
1163 fn unlock_node(&self) -> bool {
1164 debug_println!("Unlocking node {:x?}", self as *const ItemHolder<T, M>);
1165 // Lock free, because we only loop if some other node modified 'next',
1166 // The only possible modifications are:
1167 // 1) Adding a new node, which is considered progress.
1168 // 2) Setting the disturbed flag, which means the other node has offloaded
1169 // work on us, and is now proceeding to is next task, which means there is
1170 // system progress, so algorithm remains lock free.
1171 loop {
1172 let cur_next = self.next.load(atomic::Ordering::Relaxed);
1173 let decoration = get_decoration(cur_next);
1174 let undecorated = decorate(undecorate(cur_next), decoration.without_gc_and_disturbed());
1175
1176 #[cfg(feature = "validate")]
1177 assert!(
1178 decoration.is_locked(),
1179 "node {:x?} was not actually locked, decoration: {:?}",
1180 self as *const _,
1181 decoration
1182 );
1183
1184 debug_println!("Unlocked dec {:x?}: {:x?}", self as *const Self, decoration);
1185 if self
1186 .next
1187 .compare_exchange(
1188 cur_next,
1189 undecorated as *mut _,
1190 Ordering::SeqCst, //atomic gc unlock
1191 Ordering::Relaxed,
1192 )
1193 .is_ok()
1194 {
1195 return decoration.is_disturbed();
1196 }
1197 }
1198 }
1199}
1200
1201#[cfg(all(feature = "std", any(loom, feature = "shuttle"), feature = "validate"))]
1202static MAGIC: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(0);
1203
1204impl<T: ?Sized, M: IMetadata> ItemHolder<T, M> {
1205 #[cfg_attr(test, mutants::skip)]
1206 #[cfg(feature = "validate")]
1207 fn verify(ptr2: *const ItemHolder<T, M>) {
1208 {
1209 let ptr = ptr2 as *const ItemHolder<(), M>;
1210
1211 // SAFETY:
1212 // This function is never called with a null-ptr. Also, this is
1213 // just used for testing.
1214 let atomic_magic1 = unsafe { &*std::ptr::addr_of!((*ptr).magic1) };
1215 // SAFETY:
1216 // This function is never called with a null-ptr. Also, this is
1217 // just used for testing.
1218 let atomic_magic2 = unsafe { &*std::ptr::addr_of!((*ptr).magic2) };
1219
1220 let magic1 = atomic_magic1.load(Ordering::Relaxed);
1221 let magic2 = atomic_magic2.load(Ordering::Relaxed);
1222 if magic1 >> 16 != 0xbeefbeefbeef {
1223 debug_println!(
1224 "Internal error - bad magic1 in {:?}: {} ({:x})",
1225 ptr,
1226 magic1,
1227 magic1
1228 );
1229 debug_println!("Backtrace: {}", std::backtrace::Backtrace::capture());
1230 std::process::abort();
1231 }
1232 if magic2 >> 16 != 0x123412341234 {
1233 debug_println!(
1234 "Internal error - bad magic2 in {:?}: {} ({:x})",
1235 ptr,
1236 magic2,
1237 magic2
1238 );
1239 debug_println!("Backtrace: {}", std::backtrace::Backtrace::capture());
1240 std::process::abort();
1241 }
1242 #[cfg(not(any(loom, feature = "shuttle")))]
1243 {
1244 let m1 = magic1 & 0xffff;
1245 let m2 = magic2 & 0xffff;
1246 if m1 != 0x8111 || m2 != 0x8111 {
1247 debug_println!("Internal error - bad magic in {:?} {:x} {:x}", ptr, m1, m2);
1248 }
1249 }
1250
1251 #[cfg(any(loom, feature = "shuttle"))]
1252 {
1253 let diff = (magic1 & 0xffff) as isize - (magic2 & 0xffff) as isize;
1254 if diff != 0 {
1255 debug_println!(
1256 "Internal error - bad magics in {:?}: {} ({:x}) and {} ({:x})",
1257 ptr,
1258 magic1,
1259 magic1,
1260 magic2,
1261 magic2
1262 );
1263 debug_println!("Backtrace: {}", std::backtrace::Backtrace::capture());
1264 panic!();
1265 }
1266 let magic = MAGIC.fetch_add(1, Ordering::Relaxed);
1267 let magic = magic as i64 as u64;
1268 atomic_magic1.fetch_and(0xffff_ffff_ffff_0000, Ordering::Relaxed);
1269 atomic_magic2.fetch_and(0xffff_ffff_ffff_0000, Ordering::Relaxed);
1270 atomic_magic1.fetch_or(magic, Ordering::Relaxed);
1271 atomic_magic2.fetch_or(magic, Ordering::Relaxed);
1272 }
1273 }
1274 }
1275}
1276
1277/// Check the magic values of the supplied pointer, validating it in a best-effort fashion
1278#[inline]
1279#[allow(unused)]
1280#[cfg_attr(test, mutants::skip)]
1281fn verify_item_impl<T: ?Sized, M: IMetadata>(_ptr: *const ItemHolderDummy<T>) {
1282 #[cfg(feature = "validate")]
1283 {
1284 assert_is_undecorated::<T, M>(_ptr);
1285
1286 let ptr = _ptr;
1287 let x = undecorate(ptr);
1288 if x != ptr {
1289 panic!("Internal error in ArcShift: Pointer given to verify was decorated, it shouldn't have been! {:?}", ptr);
1290 }
1291 if x.is_null() {
1292 return;
1293 }
1294 ItemHolder::<T, M>::verify(from_dummy::<T, M>(x))
1295 }
1296}
1297/// Check the magic values of the supplied pointer, validating it in a best-effort fashion
1298#[inline]
1299#[cfg_attr(test, mutants::skip)]
1300fn verify_item<T: ?Sized>(_ptr: *const ItemHolderDummy<T>) {
1301 #[cfg(feature = "validate")]
1302 {
1303 if is_sized::<T>() {
1304 verify_item_impl::<T, SizedMetadata>(_ptr)
1305 } else {
1306 verify_item_impl::<T, UnsizedMetadata<T>>(_ptr)
1307 }
1308 }
1309}
1310
1311const ITEM_STATE_LOCKED_FLAG: u8 = 1;
1312const ITEM_STATE_DROPPED_FLAG: u8 = 2;
1313const ITEM_STATE_DISTURBED_FLAG: u8 = 4;
1314
1315#[repr(u8)]
1316#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1317#[allow(unused)]
1318enum ItemStateEnum {
1319 /// Pointer is not decorated
1320 UndisturbedUndecorated = 0,
1321 UndisturbedGcIsActive = 1,
1322 UndisturbedPayloadDropped = 2,
1323 UndisturbedPayloadDroppedAndGcActive = 3,
1324 DisturbedUndecorated = 4,
1325 DisturbedGcIsActive = 5,
1326 DisturbedPayloadDropped = 6,
1327 DisturbedPayloadDroppedAndGcActive = 7,
1328}
1329
1330impl ItemStateEnum {
1331 #[allow(unused)]
1332 fn is_locked(self) -> bool {
1333 (self as u8 & ITEM_STATE_LOCKED_FLAG) != 0
1334 }
1335 fn is_disturbed(self) -> bool {
1336 (self as u8 & ITEM_STATE_DISTURBED_FLAG) != 0
1337 }
1338 fn is_unlocked(self) -> bool {
1339 (self as u8 & ITEM_STATE_LOCKED_FLAG) == 0
1340 }
1341 fn dropped(self) -> ItemStateEnum {
1342 // SAFETY:
1343 // All 3-bit values are legal ItemStateEnum values, so oring on 4 is ok
1344 unsafe { core::mem::transmute::<u8, ItemStateEnum>(self as u8 | ITEM_STATE_DROPPED_FLAG) }
1345 }
1346 fn with_gc(self) -> ItemStateEnum {
1347 // SAFETY:
1348 // All 3-bit values are legal ItemStateEnum values, so oring on 1 is ok
1349 unsafe { core::mem::transmute::<u8, ItemStateEnum>(self as u8 | ITEM_STATE_LOCKED_FLAG) }
1350 }
1351 fn with_disturbed(self) -> ItemStateEnum {
1352 // SAFETY:
1353 // All 3-bit values are legal ItemStateEnum values, so oring on 1 is ok
1354 unsafe { core::mem::transmute::<u8, ItemStateEnum>(self as u8 | ITEM_STATE_DISTURBED_FLAG) }
1355 }
1356 fn without_gc_and_disturbed(self) -> ItemStateEnum {
1357 // SAFETY:
1358 // All 3-bit values are legal ItemStateEnum values, so anding out 1 is ok
1359 unsafe {
1360 core::mem::transmute::<u8, ItemStateEnum>(
1361 self as u8 & (!ITEM_STATE_LOCKED_FLAG) & (!ITEM_STATE_DISTURBED_FLAG),
1362 )
1363 }
1364 }
1365 fn is_dropped(self) -> bool {
1366 (self as u8 & ITEM_STATE_DROPPED_FLAG) != 0
1367 }
1368}
1369
1370fn decorate<T: ?Sized>(
1371 ptr: *const ItemHolderDummy<T>,
1372 e: ItemStateEnum,
1373) -> *const ItemHolderDummy<T> {
1374 let curdecoration = (ptr as usize) & 7;
1375 ((ptr as *const u8).wrapping_offset((e as isize) - (curdecoration as isize)))
1376 as *const ItemHolderDummy<T>
1377}
1378
1379/// Get the state encoded in the decoration, if any.
1380/// Returns None if the pointer is undecorated null.
1381/// The pointer must be valid.
1382fn get_decoration<T: ?Sized>(ptr: *const ItemHolderDummy<T>) -> ItemStateEnum {
1383 if ptr.is_null() {
1384 return ItemStateEnum::UndisturbedUndecorated;
1385 }
1386 let raw = ((ptr as usize) & 7) as u8;
1387 // SAFETY:
1388 // All values `0..=7` are valid ItemStateEnum.
1389 // And the bitmask produces a value `0..=7`
1390 unsafe { core::mem::transmute::<u8, ItemStateEnum>(raw) }
1391}
1392
1393/// Panic if the pointer is decorated
1394#[allow(unused)]
1395#[cfg_attr(test, mutants::skip)]
1396#[inline]
1397fn assert_is_undecorated<T: ?Sized, M: IMetadata>(_ptr: *const ItemHolderDummy<T>) {
1398 #[cfg(feature = "validate")]
1399 {
1400 let raw = _ptr as usize & 7;
1401 if raw != 0 {
1402 panic!("Internal error in ArcShift - unexpected decorated pointer");
1403 }
1404 }
1405}
1406
1407/// Return an undecorated version of the given pointer.
1408/// Supplying an already undecorated pointer is not an error, and returns
1409/// the value unmodified.
1410fn undecorate<T: ?Sized>(cand: *const ItemHolderDummy<T>) -> *const ItemHolderDummy<T> {
1411 let raw = cand as usize & 7;
1412 (cand as *const u8).wrapping_offset(-(raw as isize)) as *const ItemHolderDummy<T>
1413}
1414
1415impl<T: ?Sized> Clone for ArcShift<T> {
1416 fn clone(&self) -> Self {
1417 let t = with_holder!(self.item, T, item, {
1418 let mut drop_jobs = DropHandler::default();
1419 let result = do_clone_strong(item, &mut drop_jobs);
1420 drop_jobs.resume_any_panics();
1421 result
1422 });
1423 ArcShift {
1424 // SAFETY:
1425 // The pointer returned by 'do_clone_strong' is always valid and non-null.
1426 item: unsafe { NonNull::new_unchecked(t as *mut _) },
1427 pd: PhantomData,
1428 }
1429 }
1430}
1431impl<T: ?Sized> Clone for ArcShiftWeak<T> {
1432 fn clone(&self) -> Self {
1433 let t = with_holder!(self.item, T, item, do_clone_weak(item));
1434 ArcShiftWeak {
1435 // SAFETY:
1436 // The pointer returned by 'do_clone_weak' is always valid and non-null.
1437 item: unsafe { NonNull::new_unchecked(t as *mut _) },
1438 }
1439 }
1440}
1441
1442fn do_clone_strong<T: ?Sized, M: IMetadata>(
1443 item_ptr: *const ItemHolder<T, M>,
1444 drop_job_queue: &mut impl IDropHandler<T, M>,
1445) -> *const ItemHolderDummy<T> {
1446 // SAFETY:
1447 // do_clone_strong must be called with a valid item_ptr
1448 let item = unsafe { &*item_ptr };
1449 debug_println!(
1450 "Strong clone, about to access strong count of {:x?}",
1451 item_ptr
1452 );
1453 let strong_count = item.strong_count.fetch_add(1, Ordering::Relaxed);
1454
1455 if strong_count > MAX_REF_COUNT {
1456 item.strong_count.fetch_sub(1, Ordering::Relaxed);
1457 panic!("strong ref count max limit exceeded")
1458 }
1459
1460 debug_println!(
1461 "strong-clone, new strong count: {:x?} is {}",
1462 item_ptr,
1463 strong_count + 1
1464 );
1465 #[cfg(feature = "validate")]
1466 assert!(strong_count > 0);
1467
1468 do_advance_strong::<T, M>(to_dummy::<T, M>(item_ptr), drop_job_queue)
1469}
1470
1471fn do_clone_weak<T: ?Sized, M: IMetadata>(
1472 item_ptr: *const ItemHolder<T, M>,
1473) -> *const ItemHolderDummy<T> {
1474 // SAFETY:
1475 // do_clone_weak must be called with a valid item_ptr
1476 let item = unsafe { &*item_ptr };
1477 let weak_count = item.weak_count.fetch_add(1, Ordering::Relaxed);
1478 if get_weak_count(weak_count) > MAX_REF_COUNT {
1479 item.weak_count.fetch_sub(1, Ordering::Relaxed);
1480 panic!("weak ref count max limit exceeded")
1481 }
1482 debug_println!(
1483 "==> weak-clone, fetch_add, new weak count: {:x?} is {}",
1484 item_ptr,
1485 format_weak(weak_count + 1)
1486 );
1487 #[cfg(feature = "validate")]
1488 assert!(weak_count > 0);
1489 to_dummy(item_ptr)
1490}
1491
1492fn do_upgrade_weak<T: ?Sized, M: IMetadata>(
1493 item_ptr: *const ItemHolder<T, M>,
1494 jobq: &mut DropHandler<T>,
1495) -> Option<*const ItemHolderDummy<T>> {
1496 debug_println!("executing do_upgrade_weak");
1497 // SAFETY:
1498 // do_upgrade_weak must be called with a valid item_ptr
1499 let start_item = unsafe { &*(item_ptr) };
1500 {
1501 // This is needed, since ostensibly, this method works on a weak clone of 'item_ptr'.
1502 // It is this weak clone that is converted to a strong item.
1503 // A Relaxed add is sufficient here, since we don't need to synchronize with anything.
1504 // We already have a weak link. The extra weak link added here only becomes relevant
1505 // the next time we _decrease_ weak_count, and since that will be an op on the same
1506 // atomic, it will definitely see the value written here, which is all we require.
1507 let weak_count = start_item.weak_count.fetch_add(1, Ordering::Relaxed);
1508 if get_weak_count(weak_count) > MAX_REF_COUNT {
1509 start_item.weak_count.fetch_sub(1, Ordering::Relaxed);
1510 panic!("weak ref count max limit exceeded")
1511 }
1512 debug_println!(
1513 "==> do_upgrade_weak {:x?} incr weak count to {}",
1514 item_ptr,
1515 format_weak(weak_count + 1)
1516 );
1517 }
1518 let mut item_ptr = to_dummy(item_ptr);
1519 // Lock free: See comment on each 'continue'
1520 loop {
1521 item_ptr = do_advance_weak::<T, M>(item_ptr);
1522 // We still have one weak count on 'item_ptr' at this point. do_advance_weak
1523 // decrements the weak on the original value, and gives you an advanced value with
1524 // one count on.
1525
1526 // SAFETY:
1527 // do_advance_weak always returns a valid non-null pointer
1528 let item = unsafe { &*from_dummy::<T, M>(item_ptr) };
1529 let prior_strong_count = item.strong_count.load(Ordering::SeqCst); //atomic upgrade read strong
1530 let item_next = item.next.load(Ordering::SeqCst); //atomic upgrade read next
1531 if !get_decoration(item_next).is_dropped() {
1532 if prior_strong_count == 0 {
1533 let _prior_weak_count = item.weak_count.fetch_add(1, Ordering::SeqCst); //atomic upgrade inc weak
1534 debug_println!(
1535 "==> pre-upgrade strong=0 {:x?}, increase weak to {}",
1536 item_ptr,
1537 get_weak_count(_prior_weak_count) + 1
1538 );
1539 }
1540
1541 if item
1542 .strong_count
1543 .compare_exchange(
1544 prior_strong_count,
1545 prior_strong_count + 1,
1546 Ordering::SeqCst, //atomic upgrade inc strong
1547 Ordering::Relaxed,
1548 )
1549 .is_ok()
1550 {
1551 // SAFETY:
1552 // item_ptr has been advanced to, and we thus hold a weak ref.
1553 // it is a valid pointer.
1554 let item = unsafe { &*from_dummy::<T, M>(item_ptr) };
1555 let item_next = item.next.load(Ordering::SeqCst); //atomic upgrade check next drop
1556 if !undecorate(item_next).is_null() {
1557 let new_prior_strong = item.strong_count.fetch_sub(1, Ordering::SeqCst); //atomic upgrade fail dropped
1558 if new_prior_strong == 1 {
1559 let _prior_weak_count = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic upgrade fail dec last strong
1560 #[cfg(feature = "validate")]
1561 assert!(get_weak_count(_prior_weak_count) > 1);
1562 debug_println!(
1563 "==> {:x?} reduced weak to {}",
1564 item_ptr,
1565 get_weak_count(_prior_weak_count - 1)
1566 );
1567 }
1568 // Lock free. We only get here if some other node has added a new node,
1569 // which is considered progress.
1570 continue;
1571 }
1572
1573 let _reduce_weak = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic upgrade sub weak
1574 debug_println!(
1575 "==> upgrade success, new strong_count: {}, new weak: {}",
1576 prior_strong_count + 1,
1577 format_weak(_reduce_weak - 1)
1578 );
1579 #[cfg(feature = "validate")]
1580 assert!(
1581 get_weak_count(_reduce_weak) > 1,
1582 "assertion failed: in do_upgrade_weak(1), reduced weak {:x?} to 0",
1583 item_ptr
1584 );
1585
1586 return Some(item_ptr);
1587 } else {
1588 if prior_strong_count == 0 {
1589 let _prior_weak_count = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic upgrade race dec weak
1590 debug_println!(
1591 "==> pre-upgrade strong=0 race2 {:x?}, decrease weak to {}",
1592 item_ptr,
1593 get_weak_count(_prior_weak_count) - 1
1594 );
1595 #[cfg(feature = "validate")]
1596 assert!(get_weak_count(_prior_weak_count) > 1);
1597 }
1598 debug_println!("Race on strong_count _increase_ - loop.");
1599 // Lcok free. We only get here if some other node has succeeded in increasing or
1600 // decreasing strong count, which only happens if there is progress, unless
1601 // the node undid a strong_count modification because of a detected race.
1602 // The possible strong_count undo operations are:
1603 // 1) If ArcShift::clone exceeds the maximum strong count limit. This is an
1604 // error case, but we'll also consider it progress.
1605 // 2) If ArcShift::upgrade detects a race on 'next' (new node added), which
1606 // is considered system-wide progress.
1607 // 3) In ArcShift::update, if it races with adding a new node, which is
1608 // considered progress.
1609 continue; //Race on strong count, try again
1610 }
1611 } else {
1612 do_drop_weak::<T, M>(item_ptr, jobq);
1613 return None;
1614 }
1615 }
1616}
1617
1618/// Returns an up-to-date pointer.
1619/// The closure is called with references to the old and new items, and allows
1620/// the caller to, for instance, decrease/inrcease strong counts. If no advance could be done,
1621/// this is always because we're already at the most up-to-date value. The closure is not called
1622/// in this case.
1623/// If the update closure fails, this can only be because there's a new 'next', and the
1624/// current item has been dropped.
1625///
1626/// This function requires the caller to have some sort of reference to 'item_ptr', so that
1627/// it can't go away during execution. This method does not touch that reference count.
1628///
1629/// The 'update' closure is called with a weak-ref taken on 'b', and 'a' in its original state.
1630/// It must either keep the weak ref, or possibly convert it to a strong ref.
1631/// It must also release whatever refcount it had on the original 'item_ptr'.
1632///
1633/// Guaranteed to return a valid, non-null pointer
1634fn do_advance_impl<T: ?Sized, M: IMetadata>(
1635 mut item_ptr: *const ItemHolderDummy<T>,
1636 mut update: impl FnMut(*const ItemHolder<T, M>, *const ItemHolder<T, M>) -> bool,
1637) -> *const ItemHolderDummy<T> {
1638 let start_ptr = item_ptr;
1639 verify_item(item_ptr);
1640
1641 debug_println!("advancing from {:x?}", item_ptr);
1642 // Lock free, because we traverse the chain and eventually reach the end,
1643 // except that we may fail 'update', in which case we loop.
1644 // However, update fails only if there has been system-wide progress (see comment in
1645 // do_advance_strong).
1646 loop {
1647 debug_println!("In advance-loop, item_ptr: {:x?}", item_ptr);
1648 // SAFETY:
1649 // item_ptr is a pointer we have advanced to. Forward advance always visits only
1650 // valid pointers. This is a core algorithm of ArcShift. By the careful atomic operations
1651 // below, and by knowing how the janitor-task works, we make sure that either 'advance_count'
1652 // or 'weak_count' keep all visited references alive, such that they cannot be garbage
1653 // collected.
1654 let item: &ItemHolder<T, M> = unsafe { &*from_dummy(item_ptr as *mut _) };
1655
1656 let next_ptr = undecorate(item.next.load(Ordering::SeqCst)); //atomic advance load next
1657 debug_println!("advancing from {:x?}, next_ptr = {:x?}", item_ptr, next_ptr);
1658 if next_ptr.is_null() {
1659 #[allow(clippy::collapsible_if)]
1660 if item_ptr != start_ptr {
1661 if !update(from_dummy(start_ptr), from_dummy(item_ptr)) {
1662 debug_println!("upgrade failed, probably no payload");
1663 continue;
1664 }
1665 }
1666 return item_ptr;
1667 }
1668
1669 let _advanced = item.advance_count.fetch_add(1, Ordering::SeqCst); //atomic advance inc advance_count
1670 debug_println!(
1671 "advance: Increasing {:x?}.advance_count to {}",
1672 item_ptr,
1673 _advanced + 1
1674 );
1675
1676 // This fence shouldn't be necessary, but without it loom fails, because
1677 // it doesn't actually model 'SeqCst' correctly. In principle, we could
1678 // have this fence only when running under loom, but then we'd not be testing
1679 // exactly the same thing as we run in prod, which seems unfortunate.
1680 //
1681 // Specifically, without this fence, loom might reorder this load before
1682 // the 'fetch_add' above, opening up the possibility that 'item.next' may be
1683 // dropped before we can do 'advance_count', and we'd still get that 'next'
1684 // in the load below.
1685 atomic::fence(Ordering::SeqCst);
1686
1687 // We must reload next, because it's only the next that is _now_ set that is actually
1688 // protected by 'advance_count' above!
1689 let next_ptr = undecorate(item.next.load(Ordering::SeqCst)); //atomic advance reload next
1690
1691 #[cfg(feature = "validate")]
1692 assert_ne!(next_ptr, item_ptr);
1693 // SAFETY:
1694 // next_ptr is guarded by our advance_count ref that we grabbed above.
1695 let next: &ItemHolder<T, M> = unsafe { &*from_dummy(next_ptr) };
1696 debug_println!("advance: Increasing next(={:x?}).weak_count", next_ptr);
1697 let _res = next.weak_count.fetch_add(1, Ordering::SeqCst); //atomic
1698 debug_println!(
1699 "==> do_advance_impl: increment weak of {:?}, was {}, now {}",
1700 next_ptr,
1701 format_weak(_res),
1702 format_weak(_res + 1),
1703 );
1704
1705 let _advanced = item.advance_count.fetch_sub(1, Ordering::SeqCst); //atomic advance dec advance_count
1706 debug_println!(
1707 "advance: Decreasing {:x?}.advance_count to {}",
1708 item_ptr,
1709 _advanced - 1
1710 );
1711
1712 if item_ptr != start_ptr {
1713 debug_println!("do_advance_impl: decrease weak from {:x?}", item_ptr);
1714 let _res = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic advance dec weak_count
1715 debug_println!(
1716 "==> do_advance_impl: decrease weak from {:x?} - decreased to {}",
1717 item_ptr,
1718 format_weak(_res - 1)
1719 );
1720
1721 // This should never reach 0 here. We _know_ that 'item' has a 'next'. Thus, this 'next'
1722 // must hold a reference count on this.
1723 #[cfg(feature = "validate")]
1724 assert!(
1725 get_weak_count(_res) > 1,
1726 "non rightmost node {:x?} can't be left with 0 weak count, but weak became {}",
1727 item_ptr,
1728 get_weak_count(_res) - 1
1729 );
1730 }
1731 item_ptr = next_ptr;
1732 }
1733}
1734
1735// Guaranteed to return a valid, non-null pointer
1736fn do_advance_weak<T: ?Sized, M: IMetadata>(
1737 item_ptr: *const ItemHolderDummy<T>,
1738) -> *const ItemHolderDummy<T> {
1739 do_advance_impl(
1740 item_ptr,
1741 |a: *const ItemHolder<T, M>, _b: *const ItemHolder<T, M>| {
1742 // SAFETY:
1743 // a is a valid pointer. do_advance_impl only supplies usable pointers to the callback.
1744 let _a_weak = unsafe { (*a).weak_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance weak dec weak_count a
1745
1746 // We have a weak ref count on 'b' given to use by `do_advance_impl`,
1747 // which we're fine with this and don't need to adjust b.weak_count
1748
1749 debug_println!(
1750 "==> weak advance {:x?}, decremented weak counts to a:{:x?}={}",
1751 a,
1752 a,
1753 format_weak(_a_weak.wrapping_sub(1)),
1754 );
1755 #[cfg(feature = "validate")]
1756 assert!(get_weak_count(_a_weak) > 1);
1757 true
1758 },
1759 )
1760}
1761
1762// Always returns valid, non-null, pointers
1763#[inline(never)]
1764fn do_advance_strong<T: ?Sized, M: IMetadata>(
1765 item_ptr: *const ItemHolderDummy<T>,
1766 drop_job_queue: &mut impl IDropHandler<T, M>,
1767) -> *const ItemHolderDummy<T> {
1768 do_advance_impl::<_, M>(item_ptr, move |a, b| {
1769 // SAFETY:
1770 // b is a valid pointer. do_advance_impl supplies the closure with only valid pointers.
1771 let mut b_strong = unsafe { (*b).strong_count.load(Ordering::SeqCst) }; //atomic advance strong load b strong_count
1772
1773 // Lock free, since we only loop when compare_exchange fails on 'strong_count', something
1774 // which only occurs when 'strong_count' changes, which only occurs when there is
1775 // system wide progress.
1776 //
1777 // Note, do_advance_strong_impl will loop if this returns false. See each
1778 // such return for an argument why this only happens if there's been system side
1779 // progress.
1780 loop {
1781 debug_println!(
1782 "do_advance_strong {:x?} -> {:x?} (b-count = {})",
1783 a,
1784 b,
1785 b_strong
1786 );
1787
1788 if b_strong == 0 {
1789 // a strong ref must _always_ imply a weak count, and that weak count must
1790 // always be decrementable by whoever happens to decrement the count to 0.
1791 // That might not be us (because we might race with another invocation of this code),
1792 // that might also increment the count.
1793 // SAFETY:
1794 // b is a valid pointer (see above)
1795 let _prior_weak = unsafe { (*b).weak_count.fetch_add(1, Ordering::SeqCst) }; //atomic advance strong inc b weak_count
1796 debug_println!(
1797 "==> Prior to strong_count increment {:x?} from 0, added weak count. Weak now: {}",
1798 b,
1799 format_weak(_prior_weak + 1)
1800 );
1801 }
1802
1803 // SAFETY:
1804 // b is a valid pointer. See above.
1805 match unsafe {
1806 (*b).strong_count.compare_exchange(
1807 b_strong,
1808 b_strong + 1,
1809 Ordering::SeqCst, //atomic advance icn b strong_count
1810 atomic::Ordering::SeqCst,
1811 )
1812 } {
1813 Ok(_) => {
1814 debug_println!(
1815 "b-strong increased {:x?}: {} -> {}",
1816 b,
1817 b_strong,
1818 b_strong + 1
1819 );
1820 // SAFETY:
1821 // b is a valid pointer. See above.
1822 let next_ptr = unsafe { (*b).next.load(Ordering::SeqCst) }; //atomic advance reload next
1823 if !undecorate(next_ptr).is_null() {
1824 // Race - even though _did_ have payload prior to us grabbing the strong count, it now might not.
1825 // This can only happen if there's some other node to the right that _does_ have a payload.
1826
1827 // SAFETY:
1828 // b is a valid pointer. See above.
1829 let prior_strong =
1830 unsafe { (*b).strong_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance fail dec b strong_count
1831 debug_println!("do_advance_strong:rare race, new _next_ appeared when increasing strong count: {:?} (decr strong back to {}) <|||||||||||||||||||||||||||||||||||||||||||||||||||||||>", b, prior_strong -1);
1832 #[cfg(feature = "validate")]
1833 assert!(
1834 prior_strong > 0,
1835 "strong count {:x?} must be >0, but was 0",
1836 b
1837 );
1838
1839 // If b_strong was not 0, it had a weak count. Our increment of it above would have made it so that
1840 // no other thread could observe it going to 0. After our decrement below, it might go to zero.
1841 // If it goes to zero in our decrement, and b_strong was not 0, it falls on us to free the weak_count.
1842 // Note, in the span from the increment to this decrement, it could be argued that the implicitly owned weak count
1843 // is "wrong". However, this is not observable, since the weak count is definitely not 0 (this closure does own a
1844 // weak ref).
1845 if prior_strong == 1 {
1846 // SAFETY:
1847 // b is a valid pointer. See above.
1848 let _b_weak_count =
1849 unsafe { (*b).weak_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance fail dec weak_count
1850 debug_println!("==> do_advance_strong:rare2 {:x?} reduced strong count back to 0, reduced weak to: {}", b, get_weak_count(_b_weak_count-1));
1851 #[cfg(feature = "validate")]
1852 assert!(get_weak_count(_b_weak_count) > 1);
1853 }
1854 debug_println!("race, other thread added new node");
1855 // Lock free, we can only get here if another thread has added a new node.
1856 return false;
1857 }
1858 #[cfg(feature = "validate")]
1859 assert!(!get_decoration(next_ptr).is_dropped());
1860
1861 // SAFETY:
1862 // b is a valid pointer. See above.
1863 let _b_weak_count = unsafe { (*b).weak_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance dec weak_count
1864 debug_println!(
1865 "==> strong advance {:x?}, reducing free weak b-count to {:?}",
1866 b,
1867 format_weak(_b_weak_count - 1)
1868 );
1869 #[cfg(feature = "validate")]
1870 assert!(get_weak_count(_b_weak_count) > 1);
1871
1872 // SAFETY:
1873 // a is a valid pointer. See above.
1874 let a_strong = unsafe { (*a).strong_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance dec a strong_count
1875 #[cfg(feature = "validate")]
1876 assert_ne!(a_strong, 0);
1877 debug_println!(
1878 "a-strong {:x?} decreased {} -> {}",
1879 a,
1880 a_strong,
1881 a_strong - 1,
1882 );
1883 if a_strong == 1 {
1884 do_drop_payload_if_possible(a, false, drop_job_queue);
1885 // Remove the implicit weak granted by the strong
1886 // SAFETY:
1887 // a is a valid pointer. See above.
1888 let _a_weak = unsafe { (*a).weak_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance drop payload a
1889 debug_println!("==> do_advance_strong:maybe dropping payload of a {:x?} (because strong-count is now 0). Adjusted weak to {}", a, format_weak(_a_weak.wrapping_sub(1)));
1890 #[cfg(feature = "validate")]
1891 assert!(get_weak_count(_a_weak) > 0);
1892 }
1893 return true;
1894 }
1895 Err(err_value) => {
1896 if b_strong == 0 {
1897 // SAFETY:
1898 // b is a valid pointer. See above.
1899 let _prior_weak = unsafe { (*b).weak_count.fetch_sub(1, Ordering::SeqCst) }; //atomic advance race
1900 debug_println!("==> do_advance_strong: race on strong_count for {:x?} (restore-decr weak to {})", b, get_weak_count(_prior_weak - 1));
1901 #[cfg(feature = "validate")]
1902 assert!(get_weak_count(_prior_weak) > 1);
1903 }
1904 b_strong = err_value;
1905 }
1906 }
1907 }
1908 })
1909}
1910
1911fn raw_deallocate_node<T: ?Sized, M: IMetadata>(
1912 item_ptr: *const ItemHolder<T, M>,
1913 jobq: &mut impl IDropHandler<T, M>,
1914) {
1915 verify_item(to_dummy(item_ptr));
1916 raw_do_unconditional_drop_payload_if_not_dropped(item_ptr as *mut ItemHolder<T, M>, jobq);
1917
1918 // SAFETY:
1919 // item_ptr is going to be deallocated, and the caller must make sure
1920 // that it has exclusive access.
1921 #[cfg(feature = "validate")]
1922 assert_eq!(
1923 // SAFETY:
1924 // item_ptr is guaranteed valid by caller
1925 unsafe { (*item_ptr).strong_count.load(Ordering::SeqCst) },
1926 0,
1927 "{:x?} strong count must be 0 when deallocating",
1928 item_ptr
1929 );
1930
1931 #[cfg(feature = "validate")]
1932 {
1933 // SAFETY:
1934 // item_ptr is guaranteed valid by caller
1935 let item_ref = unsafe { &*(item_ptr as *mut ItemHolder<T, M>) };
1936 item_ref.magic1.store(0xdeaddead, Ordering::Relaxed);
1937 item_ref.magic2.store(0xdeaddea2, Ordering::Relaxed);
1938 }
1939
1940 do_dealloc(item_ptr);
1941}
1942
1943#[derive(PartialEq)]
1944enum NodeStrongStatus {
1945 // We saw nodes with strong refs, that weren't the rightmost node
1946 StrongRefsFound,
1947 // We visited all nodes all the way to the leftmost one, and there were no strong refs
1948 // to the left of the rightmost one.
1949 NoStrongRefsExist,
1950 // We had to stop our leftward traverse, because nodes were locked, so we couldn't
1951 // say for sure if strong refs existed. This means that some other node is running an
1952 // old gc, and upon completion of this gc it will realize it has to advance, so this
1953 // other node will have a chance to detect that no strong refs exist.
1954 Indeterminate,
1955}
1956
1957fn do_janitor_task<T: ?Sized, M: IMetadata>(
1958 start_ptr: *const ItemHolder<T, M>,
1959 jobq: &mut impl IDropHandler<T, M>,
1960) -> (bool /*need re-run*/, NodeStrongStatus) {
1961 verify_item(to_dummy(start_ptr));
1962
1963 let mut have_seen_left_strong_refs = false;
1964 fn get_strong_status(strong: bool, leftmost: bool) -> NodeStrongStatus {
1965 if strong {
1966 NodeStrongStatus::StrongRefsFound
1967 } else if leftmost {
1968 NodeStrongStatus::NoStrongRefsExist
1969 } else {
1970 NodeStrongStatus::Indeterminate
1971 }
1972 }
1973
1974 debug_println!("Janitor task for {:x?}", start_ptr);
1975 // SAFETY:
1976 // start_ptr must be a valid pointer. This falls on the caller toensure.
1977 let start = unsafe { &*start_ptr };
1978
1979 let start_ptr = to_dummy(start_ptr);
1980
1981 if !start.lock_node_for_gc() {
1982 debug_println!("Janitor task for {:x?} - gc already active!", start_ptr);
1983 return (false, get_strong_status(have_seen_left_strong_refs, false));
1984 }
1985
1986 debug_println!("Loading prev of {:x?}", start_ptr);
1987 let mut cur_ptr: *const _ = start.prev.load(Ordering::SeqCst); //atomic janitor load prev
1988 debug_println!("Loaded prev of {:x?}, got: {:x?}", start_ptr, cur_ptr);
1989 let rightmost_candidate_ptr = cur_ptr;
1990 if cur_ptr.is_null() {
1991 debug_println!("Janitor task for {:x?} - no earlier nodes exist", start_ptr);
1992 // There are no earlier nodes to clean up
1993 let need_rerun = start.unlock_node();
1994 return (
1995 need_rerun,
1996 get_strong_status(have_seen_left_strong_refs, true),
1997 );
1998 }
1999
2000 let mut rightmost_deletable = null();
2001
2002 // It may seems that we iterate through the chain in many different ways
2003 // in this method, and that it should be possible to abstract this.
2004 // However, it turns out to be slightly tricky, since the iteration is always
2005 // done in a very careful way to maintain correctness, and exchanging the order
2006 // of two innocent looking statements can cause it to fail.
2007
2008 {
2009 let mut any_failed_locks = false;
2010 let cur_lock_start = cur_ptr;
2011 let mut cur_ptr = cur_ptr;
2012 debug_println!("Lock sweep start at {:x?}", cur_lock_start);
2013 let mut failed_lock = null();
2014 loop {
2015 // SAFETY: cur_ptr is a valid pointer It starts out equal to
2016 // 'start.prev', which is always valid or null, and we check it for null.
2017 // We then fetch 'cur.prev' pointers, which is valid, since we only do so if
2018 // we managed to take a lock. No other thread may free prev if it is locked.
2019 let cur: &ItemHolder<T, M> = unsafe { &*from_dummy(cur_ptr) };
2020
2021 if !cur.lock_node_for_gc() {
2022 failed_lock = cur_ptr;
2023 any_failed_locks = true;
2024 debug_println!(
2025 "Janitor task for {:x?} - found node already being gced: {:x?}",
2026 start_ptr,
2027 cur_ptr
2028 );
2029 break;
2030 }
2031
2032 let prev_ptr: *const _ = cur.prev.load(Ordering::SeqCst); //atomic janitor load prev 2
2033 debug_println!("Janitor loop considering {:x?} -> {:x?}", cur_ptr, prev_ptr);
2034 if prev_ptr.is_null() {
2035 debug_println!(
2036 "Janitor task for {:x?} - found leftmost node: {:x?}",
2037 start_ptr,
2038 cur_ptr
2039 );
2040 break;
2041 }
2042 cur_ptr = prev_ptr;
2043 }
2044 if any_failed_locks {
2045 let mut cur_ptr = cur_lock_start;
2046 debug_println!("Cleanup sweep start at {:x?}", cur_lock_start);
2047 let mut anyrerun = false;
2048 loop {
2049 debug_println!("Cleanup sweep at {:x?}", cur_ptr);
2050 if cur_ptr.is_null() {
2051 anyrerun = true;
2052 break;
2053 }
2054 if cur_ptr == failed_lock {
2055 debug_println!("Cleanup sweep is at end {:x?}", cur_ptr);
2056 break;
2057 }
2058 // SAFETY:
2059 // cur_ptr is a valid pointer. It's just the left traverse, across
2060 // a chain of locked nodes.
2061 let cur: &ItemHolder<T, M> = unsafe { &*from_dummy(cur_ptr) };
2062
2063 let prev_ptr: *const _ = cur.prev.load(Ordering::SeqCst); //atomic janitor cleanup load prev
2064 anyrerun |= cur.unlock_node();
2065 debug_println!("Cleanup sweep going to {:x?}", prev_ptr);
2066 cur_ptr = prev_ptr;
2067 }
2068 anyrerun |= start.unlock_node();
2069 debug_println!("Janitor failed to grab locks. Rerun: {:?}", anyrerun);
2070 return (
2071 anyrerun,
2072 get_strong_status(have_seen_left_strong_refs, false),
2073 );
2074 }
2075 }
2076
2077 // Lock free, since this just iterates through the chain of nodes,
2078 // which has a bounded length.
2079 loop {
2080 debug_println!("Accessing {:x?} in first janitor loop", cur_ptr);
2081 // SAFETY:
2082 // cur_ptr remains a valid pointer. Our lock on the nodes, as we traverse them backward,
2083 // ensures that no other janitor task can free them.
2084 let cur: &ItemHolder<T, M> = unsafe { &*from_dummy(cur_ptr) };
2085 debug_println!("Setting next of {:x?} to {:x?}", cur_ptr, start_ptr,);
2086 #[cfg(feature = "validate")]
2087 assert_ne!(cur_ptr, start_ptr);
2088
2089 if cur.strong_count.load(Ordering::SeqCst) > 0 {
2090 //atomic janitor check strong_count
2091 have_seen_left_strong_refs = true;
2092 }
2093
2094 let prev_ptr: *const _ = cur.prev.load(Ordering::SeqCst); //atomic janitor load prev 4
2095 debug_println!("Janitor loop considering {:x?} -> {:x?}", cur_ptr, prev_ptr);
2096 if prev_ptr.is_null() {
2097 debug_println!(
2098 "Janitor task for {:x?} - found leftmost node: {:x?}",
2099 start_ptr,
2100 cur_ptr
2101 );
2102 break;
2103 }
2104
2105 // SAFETY:
2106 // We guarded 'cur_ptr', and it is thus alive. It holds a weak-ref on its 'prev', which
2107 // means that ref must now be keeping 'prev' alive. This means 'prev' is known to be a
2108 // valid pointer. We never decorate prev-pointers, so no undecorate is needed.
2109 let prev: &ItemHolder<T, M> = unsafe { &*from_dummy(prev_ptr) };
2110 #[cfg(feature = "validate")]
2111 assert_ne!(prev_ptr, start_ptr);
2112
2113 prev.set_next(start_ptr);
2114
2115 // We need a fence here, because otherwise this load could be reordered before the
2116 // `set_next`call above, while running under loom. This could lead to a situation
2117 // where a thread reads the previous next-pointer, and we still don't see the new
2118 // 'advance_count' here. With the fence, we know that either:
2119 // 1) The other thread has seen our new 'next' value supplied above
2120 // or
2121 // 2) We see their incremented 'advance_count'.
2122 // Note, we may thus block the deletion of next unnecessarily, if the other thread
2123 // read our new 'next' value just after we wrote it, and incremented 'advance_count'
2124 // here before we loaded it. This race condition is benign however, the other thread
2125 // will also try janitoring, and will delete the node if necessary.
2126 atomic::fence(Ordering::SeqCst);
2127
2128 let adv_count = prev.advance_count.load(Ordering::SeqCst); //atomic janitor check advance_count
2129 debug_println!("advance_count of {:x?} is {}", prev_ptr, adv_count);
2130 if adv_count > 0 {
2131 debug_println!(
2132 "Janitor task for {:x?} - node {:x?} has advance in progress",
2133 start_ptr,
2134 prev_ptr
2135 );
2136 // All to the right of cur_ptr could be targets of the advance.
2137 // Because of races, we don't know that their target is actually 'start_ptr'
2138 // (though it could be).
2139 rightmost_deletable = cur_ptr;
2140 }
2141 cur_ptr = prev_ptr;
2142 }
2143
2144 fn delete_nodes_that_can_be_deleted<T: ?Sized, M: IMetadata>(
2145 mut item_ptr: *const ItemHolderDummy<T>,
2146 jobq: &mut impl IDropHandler<T, M>,
2147 ) -> Option<*const ItemHolderDummy<T>> {
2148 let mut deleted_count = 0;
2149
2150 // Lock free, since this loop at most iterates once per node in the chain.
2151 loop {
2152 if item_ptr.is_null() {
2153 debug_println!(
2154 "Find non-deleted {:x?}, count = {}, item_ptr = {:x?}",
2155 item_ptr,
2156 deleted_count,
2157 item_ptr,
2158 );
2159 return (deleted_count > 0).then_some(item_ptr);
2160 }
2161 // SAFETY:
2162 // caller must ensure item_ptr is valid, or null. And it is not null, we checked above.
2163 let item: &ItemHolder<T, M> = unsafe { &*from_dummy(item_ptr as *mut _) };
2164 // Item is *known* to have a 'next'!=null here, so
2165 // we know weak_count == 1 implies it is only referenced by its 'next'
2166 let item_weak_count = item.weak_count.load(Ordering::SeqCst); //atomic janitor load weak_count
2167 if get_weak_count(item_weak_count) > 1 {
2168 debug_println!(
2169 "==> Find non-deleted {:x?}, count = {}, found node with weak count > 1 ({})",
2170 item_ptr,
2171 deleted_count,
2172 format_weak(item_weak_count)
2173 );
2174 return (deleted_count > 0).then_some(item_ptr);
2175 }
2176 debug_println!(
2177 "==> Deallocating node in janitor task: {:x?}, dec: ?, weak count: {}",
2178 item_ptr,
2179 // SAFETY:
2180 // item_ptr is valid
2181 format_weak(item_weak_count),
2182 );
2183
2184 #[cfg(feature = "validate")]
2185 {
2186 let prior_item_weak_count = item.weak_count.load(Ordering::SeqCst);
2187 #[cfg(feature = "validate")]
2188 assert_eq!(
2189 get_weak_count(prior_item_weak_count),
2190 1,
2191 "{:x?} weak_count should still be 1, and we decrement it to 0",
2192 item_ptr
2193 );
2194 }
2195
2196 let prev_item_ptr = item.prev.load(Ordering::SeqCst); //atomic janitor deletion load prev
2197 raw_deallocate_node(from_dummy::<T, M>(item_ptr as *mut _), jobq);
2198 deleted_count += 1;
2199 item_ptr = prev_item_ptr;
2200 }
2201 }
2202
2203 let mut cur_ptr = rightmost_candidate_ptr;
2204 let mut right_ptr = start_ptr;
2205 let mut must_see_before_deletes_can_be_made = rightmost_deletable;
2206 debug_println!("Starting final janitor loop");
2207 let mut need_rerun = false;
2208 // We must retain the locks one-past the node with the lock (lock works leftward)
2209 let mut unlock_carry: Option<*const ItemHolder<T, M>> = None;
2210 let mut do_unlock = |node: Option<*const ItemHolder<T, M>>| {
2211 if let Some(unlock) = unlock_carry.take() {
2212 // SAFETY:
2213 // Caller ensures pointer is valid.
2214 need_rerun |= unsafe { (*unlock).unlock_node() };
2215 }
2216 unlock_carry = node;
2217 };
2218
2219 #[cfg(feature = "validate")]
2220 assert!(!cur_ptr.is_null());
2221
2222 // Iterate through chain, deleting nodes when possible
2223 // Lock free, since this loop just iterates through each node in the chain.
2224 while !cur_ptr.is_null() {
2225 let new_predecessor = must_see_before_deletes_can_be_made
2226 .is_null()
2227 .then(|| delete_nodes_that_can_be_deleted::<T, M>(cur_ptr, jobq))
2228 .flatten();
2229
2230 if cur_ptr == must_see_before_deletes_can_be_made {
2231 debug_println!("Found must_see node: {:x?}", cur_ptr);
2232 // cur_ptr can't be deleted itself, but nodes further to the left can
2233 must_see_before_deletes_can_be_made = null_mut();
2234 }
2235
2236 if let Some(new_predecessor_ptr) = new_predecessor {
2237 // SAFETY:
2238 // right_ptr is always the start pointer, or the previous pointer we visited.
2239 // in any case, it is non-null and valid.
2240 let right: &ItemHolder<T, M> = unsafe { &*from_dummy(right_ptr) };
2241 debug_println!(
2242 "After janitor delete, setting {:x?}.prev = {:x?}",
2243 right_ptr,
2244 new_predecessor_ptr
2245 );
2246 if new_predecessor_ptr.is_null() {
2247 right
2248 .weak_count
2249 .fetch_and(!WEAK_HAVE_PREV, Ordering::SeqCst); //atomic janitor clear prev
2250 }
2251 right
2252 .prev
2253 .store(new_predecessor_ptr as *mut _, Ordering::SeqCst); //atomic janitor unlink
2254
2255 if new_predecessor_ptr.is_null() {
2256 debug_println!("new_predecessor is null");
2257 break;
2258 }
2259 debug_println!("found new_predecessor: {:x?}", new_predecessor_ptr);
2260 right_ptr = new_predecessor_ptr;
2261 // SAFETY:
2262 // We only visit nodes we have managed to lock. new_predecessor is such a node
2263 // and it is not being deleted. It is safe to access.
2264 let new_predecessor = unsafe { &*from_dummy::<T, M>(new_predecessor_ptr) };
2265 cur_ptr = new_predecessor.prev.load(Ordering::SeqCst); //atomic janitor load prev 6
2266 #[cfg(feature = "validate")]
2267 assert_ne!(
2268 new_predecessor_ptr as *const _,
2269 null(),
2270 "assert failed, {:?} was endptr",
2271 new_predecessor_ptr
2272 );
2273 do_unlock(Some(new_predecessor));
2274 debug_println!("New candidate advanced to {:x?}", cur_ptr);
2275 } else {
2276 debug_println!("Advancing to left, no node to delete found {:x?}", cur_ptr);
2277 // SAFETY:
2278 // All the pointers we traverse (leftward) through the chain are valid,
2279 // since we lock them succesively as we traverse.
2280 let cur: &ItemHolder<T, M> = unsafe { &*from_dummy(cur_ptr) };
2281 right_ptr = cur_ptr;
2282 cur_ptr = cur.prev.load(Ordering::SeqCst); //atomic janitor load prev 7
2283 debug_println!("Advancing to left, advanced to {:x?}", cur_ptr);
2284 do_unlock(Some(cur));
2285 }
2286 }
2287 do_unlock(None);
2288 debug_println!("Unlock start-node {:x?}", start_ptr);
2289 need_rerun |= start.unlock_node();
2290 debug_println!("start-node unlocked: {:x?}", start_ptr);
2291 (
2292 need_rerun,
2293 get_strong_status(have_seen_left_strong_refs, true),
2294 )
2295}
2296
2297/// drop_payload should be set to drop the payload of 'original_item_ptr' iff it is
2298/// either not rightmost, or all refs to all nodes are just weak refs (i.e, no strong refs exist)
2299fn do_drop_weak<T: ?Sized, M: IMetadata>(
2300 original_item_ptr: *const ItemHolderDummy<T>,
2301 drop_job_queue: &mut impl IDropHandler<T, M>,
2302) {
2303 debug_println!("drop weak {:x?}", original_item_ptr);
2304 let mut item_ptr = original_item_ptr;
2305 // Lock free, since we only loop in these cases:
2306 // 1) If the janitor task was disturbed. If it was, some other thread has offloaded
2307 // work on us, which means the other thread could carry on and do other stuff, which
2308 // means there is system wide progress.
2309 // 2) If a new 'next' pointer has been set, i.e, a new node has been added. This is
2310 // considered progress.
2311 // 3) Some other node changed the weak_count. In that case, there are two cases:
2312 // 3a) That other node was running 'do_drop_weak'. After changing the weak_count
2313 // there are no more loop conditions, so it has definitely made progress.
2314 // 3b) That node was running some other work. It managed to change the weak count,
2315 // and is not running 'do_drop_weak', so the system is making progress as long as
2316 // that other thread is making progress, which it must be (see all other comments),
2317 // and it cannot have been obstructed by this thread.
2318 loop {
2319 debug_println!("drop weak loop {:?}", item_ptr);
2320 item_ptr = do_advance_weak::<T, M>(item_ptr);
2321 let (need_rerun, strong_refs) =
2322 do_janitor_task(from_dummy::<T, M>(item_ptr), drop_job_queue);
2323 if need_rerun {
2324 debug_println!("Janitor {:?} was disturbed. Need rerun", item_ptr);
2325 continue;
2326 }
2327
2328 // When we get here, we know we are advanced to the most recent node
2329
2330 debug_println!("Accessing {:?}", item_ptr);
2331 // SAFETY:
2332 // item_ptr is a pointer that was returned by 'do_advance_weak'. The janitor task
2333 // never deallocates the pointer given to it (only prev pointers of that pointer).
2334 // do_advance_weak always returns valid non-null pointers.
2335 let item: &ItemHolder<T, M> = unsafe { &*from_dummy(item_ptr) };
2336 let prior_weak = item.weak_count.load(Ordering::SeqCst); //atomic drop_weak load weak_count
2337
2338 #[cfg(feature = "validate")]
2339 assert!(get_weak_count(prior_weak) > 0);
2340
2341 let next_ptr = item.next.load(Ordering::SeqCst); //atomic drop_weak load next
2342 let have_next = !undecorate(next_ptr).is_null();
2343 if have_next {
2344 // drop_weak raced with 'add'.
2345 debug_println!(
2346 "add race {:x?}, prior_weak: {}",
2347 item_ptr,
2348 format_weak(prior_weak)
2349 );
2350 continue;
2351 }
2352 // Note, 'next' may be set here, immediately after us loading 'next' above.
2353 // This is benign. In this case, 'prior_weak' will also have get_weak_next(prior_weak)==true
2354 // and get_weak_count(prior_weak)>1. We will not drop the entire chain, but whoever
2355 // just set 'next' definitely will.
2356
2357 #[cfg(feature = "debug")]
2358 if get_weak_next(prior_weak) {
2359 debug_println!("raced in drop weak - {:x?} was previously advanced to rightmost, but now it has a 'next' again (next is ?)", item_ptr);
2360 }
2361
2362 debug_println!("No add race, prior_weak: {}", format_weak(prior_weak));
2363
2364 // We now have enough information to know if we can drop payload, if desired
2365 {
2366 // SAFETY:
2367 // item_ptr was returned by do_advance_weak, and is thus valid.
2368 let o_item = unsafe { &*from_dummy::<T, M>(item_ptr) };
2369 let o_strong = o_item.strong_count.load(Ordering::SeqCst); //atomic drop_weak check strong_count
2370 if o_strong == 0 {
2371 let can_drop_now_despite_next_check = if strong_refs
2372 == NodeStrongStatus::NoStrongRefsExist
2373 {
2374 debug_println!("final drop analysis {:x?}: Can drop this payload, because no strong refs exists anywhere", item_ptr);
2375 true
2376 } else {
2377 debug_println!("final drop analysis {:x?}: no exemption condition found, can't drop this payload", item_ptr);
2378 false
2379 };
2380 if can_drop_now_despite_next_check {
2381 do_drop_payload_if_possible(
2382 o_item,
2383 can_drop_now_despite_next_check,
2384 drop_job_queue,
2385 );
2386 }
2387 }
2388 }
2389
2390 match item.weak_count.compare_exchange(
2391 prior_weak,
2392 prior_weak - 1,
2393 Ordering::SeqCst, //atomic drop_weak dec weak
2394 Ordering::SeqCst,
2395 ) {
2396 Ok(_) => {
2397 debug_println!(
2398 "==> drop weak {:x?}, did reduce weak to {}",
2399 item_ptr,
2400 format_weak(prior_weak - 1)
2401 );
2402 }
2403 Err(_err_weak) => {
2404 debug_println!(
2405 "drop weak {:x?}, raced on count decrement (was {}, expected {})",
2406 item_ptr,
2407 format_weak(_err_weak),
2408 format_weak(prior_weak)
2409 );
2410
2411 // Note:
2412 // This case occurs if two threads race to drop a weak ref.
2413 // Crucially, it is also in play to distinguish between these two scenarios:
2414 // 1: Two nodes have weak refs. One of them (A) is dropped, the other (B) remains.
2415 // 2: Two nodes have weak refs. One of them (A) updates the value, and is then
2416 // dropped. The other (B) remains.
2417 //
2418 // In both cases, when B is dropped, it will see a total weak count of 2.
2419 // However, in case 2, B must re-run 'advance', and do another janitor cycle.
2420 // This *has* to be checked during the weak_count compare_exchange, since doing
2421 // it at any point prior to that opens up the risk of a race where node A above
2422 // manages to update and drop before the compare-exchange.
2423
2424 continue;
2425 }
2426 }
2427
2428 debug_println!(
2429 "Prior weak of {:x?} is {}",
2430 item_ptr,
2431 format_weak(prior_weak)
2432 );
2433 if get_weak_count(prior_weak) == 1 {
2434 #[cfg(feature = "validate")]
2435 if get_weak_next(prior_weak) {
2436 std::eprintln!("This case should not be possible, since it implies the 'next' object didn't increase the refcount");
2437 std::process::abort();
2438 }
2439 // We know there's no next here either, since we checked 'get_weak_next' before the cmpxch, so we _KNOW_ we're the only user now.
2440 if !get_weak_prev(prior_weak) {
2441 debug_println!("drop weak {:x?}, prior count = 1, raw deallocate", item_ptr);
2442 drop_job_queue.report_sole_user();
2443 raw_deallocate_node(from_dummy::<T, M>(item_ptr), drop_job_queue);
2444 } else {
2445 debug_println!(
2446 "drop weak {:x?}, couldn't drop node, because there are nodes to the left",
2447 item_ptr
2448 );
2449 // These nodes will presumably realize they're holding leftwise refs, and before dropping
2450 // they must advance. And thus the whole chain _will_ be collected.
2451 }
2452 }
2453 return;
2454 }
2455}
2456
2457fn do_update<T: ?Sized, M: IMetadata>(
2458 initial_item_ptr: *const ItemHolder<T, M>,
2459 mut val_dummy_factory: impl FnMut(&ItemHolder<T, M>) -> Option<*const ItemHolderDummy<T>>,
2460 drop_job_queue: &mut impl IDropHandler<T, M>,
2461) -> *const ItemHolderDummy<T> {
2462 let mut item_ptr = to_dummy::<T, M>(initial_item_ptr);
2463 verify_item(item_ptr);
2464
2465 // Lock free. This loop only loops if another thread has changed 'next', which
2466 // means there is system wide progress.
2467 loop {
2468 item_ptr = do_advance_strong::<T, M>(item_ptr, drop_job_queue);
2469
2470 // SAFETY:
2471 // item_ptr was returned by do_advance_strong, and is thus valid.
2472 let item = unsafe { &*from_dummy::<T, M>(item_ptr) };
2473 debug_println!(
2474 "Updating {:x?} , loading next of {:x?}",
2475 initial_item_ptr,
2476 item_ptr
2477 );
2478
2479 let cur_next = item.next.load(Ordering::SeqCst); //atomic update check_next
2480 if !undecorate(cur_next).is_null() {
2481 continue;
2482 }
2483 let Some(val_dummy) = val_dummy_factory(item) else {
2484 return item_ptr;
2485 };
2486 let new_next = decorate(val_dummy, get_decoration(cur_next));
2487
2488 debug_println!("Updating {:x?} to {:x?}", item_ptr, val_dummy);
2489 let val = from_dummy::<T, M>(val_dummy) as *mut ItemHolder<T, M>;
2490 // SAFETY:
2491 // val is the new value supplied by the caller. It is always valid, and it is not
2492 // yet linked into the chain, so no other node could free it.
2493 unsafe { (*val).prev = atomic::AtomicPtr::new(item_ptr as *mut _) };
2494
2495 // We must increment weak_count here, because this is the signal that
2496 // causes the drop_weak impl to realize that it is racing with an 'update',
2497 // (in contrast to perhaps racing with another drop, in which case it might
2498 // win the race and might be required to deallocate, to avoid memory leaks).
2499 let _weak_was = item.weak_count.fetch_add(1, Ordering::SeqCst);
2500
2501 #[cfg(feature = "validate")]
2502 assert!(_weak_was > 0);
2503 debug_println!(
2504 "do_update: increment weak of {:?} (weak now: {})",
2505 item_ptr,
2506 format_weak(_weak_was + 1)
2507 );
2508
2509 debug_println!("bef item.next.compare_exchange");
2510 match item.next.compare_exchange(
2511 cur_next,
2512 new_next as *mut _,
2513 Ordering::SeqCst, //atomic update exchange next
2514 Ordering::SeqCst,
2515 ) {
2516 Ok(_) => {
2517 item.weak_count.fetch_or(WEAK_HAVE_NEXT, Ordering::SeqCst); //atomic update mark have next
2518 debug_println!("aft1 item.next.compare_exchange");
2519 }
2520 Err(_) => {
2521 debug_println!("aft2 item.next.compare_exchange");
2522 debug_println!("race, update of {:x?} to {:x?} failed", item_ptr, new_next);
2523 let _res = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic update fail dec weak_count
2524 debug_println!(
2525 "==> race, decreasing {:x?} weak to {}",
2526 item_ptr,
2527 format_weak(_res - 1)
2528 );
2529 #[cfg(feature = "validate")]
2530 assert!(get_weak_count(_res) > 1);
2531
2532 continue;
2533 }
2534 }
2535
2536 let strong_count = item.strong_count.fetch_sub(1, Ordering::SeqCst); //atomic update dec strong_count
2537 debug_println!(
2538 "do_update: strong count {:x?} is now decremented to {}",
2539 item_ptr,
2540 strong_count - 1,
2541 );
2542 if strong_count == 1 {
2543 // It's safe to drop payload here, we've just now added a new item
2544 // that has its payload un-dropped, so there exists something to advance to.
2545 do_drop_payload_if_possible(from_dummy::<T, M>(item_ptr), false, drop_job_queue);
2546 let _weak_count = item.weak_count.fetch_sub(1, Ordering::SeqCst); //atomic update dec weak_count
2547 debug_println!(
2548 "==> do_update: decrement weak of {:?}, new weak: {}",
2549 item_ptr,
2550 format_weak(_weak_count.saturating_sub(1))
2551 );
2552 #[cfg(feature = "validate")]
2553 assert!(get_weak_count(_weak_count) > 1);
2554 }
2555
2556 item_ptr = val_dummy;
2557
2558 //If the strong_count of the previous went to 0, do a janitor-cycle
2559 if strong_count == 1 {
2560 // Lock free
2561 // Only loops if another thread has set the 'disturbed' flag, meaning it has offloaded
2562 // work on us, and it has made progress, which means there is system wide progress.
2563 loop {
2564 let (need_rerun, _strong_refs) =
2565 do_janitor_task(from_dummy::<T, M>(item_ptr), drop_job_queue);
2566 if need_rerun {
2567 item_ptr = do_advance_strong::<T, M>(item_ptr, drop_job_queue);
2568 debug_println!("Janitor {:?} was disturbed. Need rerun", item_ptr);
2569 continue;
2570 }
2571 break;
2572 }
2573 }
2574 return item_ptr;
2575 }
2576}
2577
2578// Drops payload, unless either:
2579// * We're the rightmost node
2580// * The payload is already dropped
2581// the item_ptr must be valid.
2582fn do_drop_payload_if_possible<T: ?Sized, M: IMetadata>(
2583 item_ptr: *const ItemHolder<T, M>,
2584 override_rightmost_check: bool,
2585 drop_queue: &mut impl IDropHandler<T, M>,
2586) {
2587 // SAFETY:
2588 // caller must supply valid pointer.
2589 let item = unsafe { &*(item_ptr) };
2590 // Lock free. This only loops if another thread has changed next, which implies
2591 // progress.
2592 loop {
2593 let next_ptr = item.next.load(Ordering::Relaxed);
2594 let decoration = get_decoration(next_ptr);
2595 if decoration.is_dropped() || (undecorate(next_ptr).is_null() && !override_rightmost_check)
2596 {
2597 debug_println!(
2598 "Not dropping {:x?} payload, because it's rightmost",
2599 item_ptr
2600 );
2601 return;
2602 }
2603 debug_println!(
2604 "Drop if possible, {:x?}, cur dec: {:?}, dropped dec {:?}",
2605 item_ptr,
2606 decoration,
2607 decoration.dropped()
2608 );
2609 match item.next.compare_exchange(
2610 next_ptr,
2611 decorate(undecorate(next_ptr), decoration.dropped()) as *mut _,
2612 Ordering::SeqCst, //atomic mark dropped
2613 Ordering::SeqCst,
2614 ) {
2615 Ok(_) => {
2616 break;
2617 }
2618 Err(err_ptr) => {
2619 if !get_decoration(err_ptr).is_dropped() {
2620 debug_println!("Raced, new attempt to drop {:x?} payload", item_ptr);
2621 continue;
2622 }
2623 debug_println!("Raced, {:x?} now already dropped", item_ptr);
2624 return;
2625 }
2626 }
2627 }
2628 debug_println!("Dropping payload {:x?} (dec: ?)", item_ptr,);
2629 // SAFETY: item_ptr must be valid, guaranteed by caller.
2630 drop_queue.do_drop(item_ptr as *mut _);
2631}
2632
2633// Caller must guarantee poiner is uniquely owned
2634fn raw_do_unconditional_drop_payload_if_not_dropped<T: ?Sized, M: IMetadata>(
2635 item_ptr: *mut ItemHolder<T, M>,
2636 drop_job_queue: &mut impl IDropHandler<T, M>,
2637) {
2638 debug_println!("Unconditional drop of payload {:x?}", item_ptr);
2639 // SAFETY: Caller must guarantee pointer is uniquely owned
2640 let item = unsafe { &*(item_ptr) };
2641 let next_ptr = item.next.load(Ordering::SeqCst); //atomic drop check dropped
2642 let decoration = get_decoration(next_ptr);
2643 if !decoration.is_dropped() {
2644 debug_println!(
2645 "Actual drop of payload {:x?}, it wasn't already dropped",
2646 item_ptr
2647 );
2648 drop_job_queue.do_drop(item_ptr);
2649 }
2650}
2651fn do_dealloc<T: ?Sized, M: IMetadata>(item_ptr: *const ItemHolder<T, M>) {
2652 // SAFETY:
2653 // item_ptr is still a valid, exclusively owned pointer
2654 let layout = get_holder_layout(&unsafe { &*item_ptr }.payload);
2655 // SAFETY:
2656 // fullptr is a valid uniquely owned pointer that we must deallocate
2657 debug_println!("Calling dealloc {:x?}", item_ptr);
2658
2659 #[cfg(feature = "validate")]
2660 {
2661 // SAFETY:
2662 // item_ptr is valid
2663 let item_ref = unsafe { &*(item_ptr as *mut ItemHolder<T, M>) };
2664 item_ref.magic1.store(0xdeaddead, Ordering::Relaxed);
2665 item_ref.magic2.store(0xdeaddea2, Ordering::Relaxed);
2666 }
2667
2668 // SAFETY:
2669 // item_ptr is still a valid, exclusively owned pointer
2670 unsafe { alloc::alloc::dealloc(item_ptr as *mut _, layout) }
2671}
2672
2673fn do_drop_strong<T: ?Sized, M: IMetadata>(
2674 full_item_ptr: *const ItemHolder<T, M>,
2675 drop_job_queue: &mut impl IDropHandler<T, M>,
2676) {
2677 debug_println!("drop strong of {:x?}", full_item_ptr,);
2678 let mut item_ptr = to_dummy(full_item_ptr);
2679
2680 item_ptr = do_advance_strong::<T, M>(item_ptr, drop_job_queue);
2681 // SAFETY: do_advance_strong always returns a valid pointer
2682 let item: &ItemHolder<T, M> = unsafe { &*from_dummy(item_ptr) };
2683
2684 let prior_strong = item.strong_count.fetch_sub(1, Ordering::SeqCst); //atomic drop dec strong_count
2685 debug_println!(
2686 "drop strong of {:x?}, prev count: {}, now {}",
2687 item_ptr,
2688 prior_strong,
2689 prior_strong - 1,
2690 );
2691 if prior_strong == 1 {
2692 // This is the only case where we actually might need to drop the rightmost node's payload
2693 // (if all nodes have only weak references)
2694 do_drop_weak::<T, M>(item_ptr, drop_job_queue);
2695 }
2696}
2697
2698impl<T: ?Sized> Drop for ArcShift<T> {
2699 fn drop(&mut self) {
2700 verify_item(self.item.as_ptr());
2701 debug_println!("executing ArcShift::drop({:x?})", self.item.as_ptr());
2702 with_holder!(self.item, T, item, {
2703 let mut jobq = DropHandler::default();
2704 do_drop_strong(item, &mut jobq);
2705 jobq.resume_any_panics();
2706 })
2707 }
2708}
2709impl<T: ?Sized> Drop for ArcShiftWeak<T> {
2710 fn drop(&mut self) {
2711 verify_item(self.item.as_ptr());
2712
2713 fn drop_weak_helper<T: ?Sized, M: IMetadata>(item: *const ItemHolder<T, M>) {
2714 let mut jobq = DropHandler::default();
2715 do_drop_weak::<T, M>(to_dummy(item), &mut jobq);
2716 jobq.resume_any_panics();
2717 }
2718
2719 with_holder!(self.item, T, item, drop_weak_helper(item))
2720 }
2721}
2722
2723/// This is a marker for methods that have been removed in the
2724/// most recent version of ArcShift.
2725///
2726/// Any methods that take this type as parameters, is completely
2727/// impossible to call. This is by design. The methods have been
2728/// kept, to hopefully make migration easier.
2729pub struct NoLongerAvailableMarker {
2730 _priv: (),
2731}
2732
2733impl<T: ?Sized> ArcShiftWeak<T> {
2734 /// Upgrade this ArcShiftWeak instance to a full ArcShift.
2735 /// This is required to be able to access any stored value.
2736 /// If the ArcShift instance has no value (because the last ArcShift instance
2737 /// had been deallocated), this method returns None.
2738 pub fn upgrade(&self) -> Option<ArcShift<T>> {
2739 let t = with_holder!(self.item, T, item, {
2740 let mut drop_handler = DropHandler::default();
2741 let temp = do_upgrade_weak(item, &mut drop_handler);
2742 drop_handler.resume_any_panics();
2743 temp
2744 });
2745 Some(ArcShift {
2746 // SAFETY:
2747 // do_upgrade_weak returns a valid upgraded pointer
2748 item: unsafe { NonNull::new_unchecked(t? as *mut _) },
2749 pd: PhantomData,
2750 })
2751 }
2752}
2753impl<T> ArcShift<T> {
2754 /// Crate a new ArcShift instance with the given value.
2755 pub fn new(val: T) -> ArcShift<T> {
2756 let holder = make_sized_holder(val, null_mut());
2757 ArcShift {
2758 // SAFETY:
2759 // The newly created holder-pointer is valid and non-null
2760 item: unsafe { NonNull::new_unchecked(to_dummy(holder) as *mut _) },
2761 pd: PhantomData,
2762 }
2763 }
2764
2765 /// Drops this ArcShift instance. If this was the last instance of the entire chain,
2766 /// the payload value is returned.
2767 pub fn try_into_inner(self) -> Option<T> {
2768 let mut drop_handler =
2769 deferred_panics_helper::stealing_drop::StealingDropHandler::default();
2770 verify_item(self.item.as_ptr());
2771 debug_println!("executing ArcShift::into_inner({:x?})", self.item.as_ptr());
2772 do_drop_strong(
2773 from_dummy::<T, SizedMetadata>(self.item.as_ptr()),
2774 &mut drop_handler,
2775 );
2776 core::mem::forget(self);
2777 drop_handler.take_stolen()
2778 }
2779
2780 /// Update the value of this ArcShift instance (and all derived from it) to the given value.
2781 ///
2782 /// Note, other ArcShift instances will not see the new value until they call the
2783 /// [`ArcShift::get`] or [`ArcShift::reload`] methods.
2784 pub fn update(&mut self, val: T) {
2785 let holder = make_sized_holder(val, self.item.as_ptr() as *const ItemHolderDummy<T>);
2786
2787 with_holder!(self.item, T, item, {
2788 let mut jobq = DropHandler::default();
2789 // SAFETY:
2790 // * do_update returns non-null values.
2791 // * 'holder' is in fact a thin pointer, just what we need for T, since T is Sized.
2792 let new_item = unsafe {
2793 NonNull::new_unchecked(
2794 do_update(item, |_| Some(holder as *const _), &mut jobq) as *mut _
2795 )
2796 };
2797 jobq.resume_any_panics();
2798 self.item = new_item;
2799 });
2800 }
2801 /// Atomically update the value.
2802 ///
2803 /// The supplied closure 'update' is called with the previous value as an argument.
2804 /// It then constructs a new, updated value. This value replaces the previous value
2805 /// of the ArcShift instance. Note, if other threads are updating the arcshift chain
2806 /// concurrently, it may take multiple retries for the update to succeed. The closure
2807 /// will be called once for every attempt, until an attempt is successful. This means that
2808 /// the final updated value will have always been calculated from the previous set value.
2809 pub fn rcu(&mut self, mut update: impl FnMut(&T) -> T) -> &T {
2810 self.rcu_maybe(|x| Some(update(x)));
2811 (*self).shared_get()
2812 }
2813
2814 /// Atomically update the value.
2815 ///
2816 /// The supplied closure 'update' is called with the previous value as an argument.
2817 /// It then constructs a new, updated value. This value replaces the previous value
2818 /// of the ArcShift instance. Note, if other threads are updating the arcshift chain
2819 /// concurrently, it may take multiple retries for the update to succeed. The closure
2820 /// will be called once for every attempt, until an attempt is successful. This means that
2821 /// the final updated value will have always been calculated from the previous set value.
2822 ///
2823 /// If the closure returns None, the update is cancelled, and this method returns false.
2824 pub fn rcu_maybe(&mut self, mut update: impl FnMut(&T) -> Option<T>) -> bool {
2825 let mut holder: Option<*const ItemHolderDummy<T>> = None;
2826
2827 let mut cancelled = false;
2828
2829 let mut jobq = DropHandler::default();
2830 // SAFETY:
2831 // do_update returns a valid non-null pointer
2832 let new_item_ptr = do_update(
2833 from_dummy::<T, SizedMetadata>(self.item.as_ptr()),
2834 |prev: &ItemHolder<T, SizedMetadata>| -> Option<*const ItemHolderDummy<T>> {
2835 // SAFETY:
2836 // we hold a strong ref on prev, so it cannot be dropped. Shared
2837 // access to 'payload' is thus sound.
2838 let prev_payload: &ManuallyDrop<T> = unsafe { &*prev.payload.get() };
2839 let prev_payload: &T = prev_payload;
2840 let new_candidate: Option<T> = update(prev_payload);
2841 let Some(new_candidate) = new_candidate else {
2842 // Ok, the closure decided to NOT do an update after all
2843 // We must now free any previous allocated candidate (both payload and holder).
2844 if let Some(holder) = holder {
2845 let mut jobq = DropHandler::default();
2846 let full_ptr = from_dummy::<T, SizedMetadata>(holder);
2847 raw_do_unconditional_drop_payload_if_not_dropped(
2848 full_ptr as *mut ItemHolder<T, SizedMetadata>,
2849 &mut jobq,
2850 );
2851 do_dealloc(full_ptr);
2852 jobq.resume_any_panics();
2853 }
2854 cancelled = true;
2855 return None;
2856 };
2857 if let Some(holder) = holder {
2858 // SAFETY:
2859 // If we get called when we already have a holder, then this is a retry
2860 // and that holder was never visible to any other thread. We still have
2861 // unique access to it.
2862 let holder_mut: &mut ItemHolder<T, SizedMetadata> =
2863 unsafe { &mut *(from_dummy::<T, SizedMetadata>(holder) as *mut _) };
2864 // SAFETY:
2865 // See above
2866 unsafe {
2867 ManuallyDrop::drop(&mut *holder_mut.payload.get());
2868 }
2869 holder_mut.payload = UnsafeCell::new(ManuallyDrop::new(new_candidate));
2870 Some(holder)
2871 } else {
2872 let new_holder = to_dummy(make_sized_holder(
2873 new_candidate,
2874 self.item.as_ptr() as *const ItemHolderDummy<T>,
2875 ));
2876 holder = Some(new_holder);
2877 Some(new_holder)
2878 }
2879 },
2880 &mut jobq,
2881 );
2882 // SAFETY:
2883 // new_item_ptr returned by do_update is never null
2884 let new_unique_ptr = unsafe { NonNull::new_unchecked(new_item_ptr as *mut _) };
2885 jobq.resume_any_panics();
2886 self.item = new_unique_ptr;
2887 !cancelled
2888 }
2889}
2890
2891#[doc(hidden)]
2892#[deprecated = "ArcShiftLight has been removed. Please consider using ArcShiftWeak. It is similar, though not a direct replacement."]
2893pub struct ArcShiftLight {}
2894
2895impl<T: ?Sized> ArcShift<T> {
2896 #[doc(hidden)]
2897 #[cfg_attr(test, mutants::skip)]
2898 #[deprecated = "rcu_project was completely removed in ArcShift 0.2. Please use method 'rcu' instead, and just manually access the desired field."]
2899 pub fn rcu_project(&mut self, _marker: NoLongerAvailableMarker) {
2900 unreachable!("method cannot be called")
2901 }
2902 #[doc(hidden)]
2903 #[cfg_attr(test, mutants::skip)]
2904 #[deprecated = "rcu_maybe2 was completely removed in ArcShift 0.2. Please use 'rcu_maybe' instead. It has the same features."]
2905 pub fn rcu_maybe2(&mut self, _marker: NoLongerAvailableMarker) {
2906 unreachable!("method cannot be called")
2907 }
2908
2909 #[doc(hidden)]
2910 #[cfg_attr(test, mutants::skip)]
2911 #[deprecated = "update_shared_box was completely removed in ArcShift 0.2. Shared references can no longer be updated. Please file an issue if this is a blocker!"]
2912 pub fn update_shared_box(&mut self, _marker: NoLongerAvailableMarker) {
2913 unreachable!("method cannot be called")
2914 }
2915 #[doc(hidden)]
2916 #[cfg_attr(test, mutants::skip)]
2917 #[deprecated = "update_shared was completely removed in ArcShift 0.2. Shared references can no longer be updated. Please file an issue if this is a blocker!"]
2918 pub fn update_shared(&mut self, _marker: NoLongerAvailableMarker) {
2919 unreachable!("method cannot be called")
2920 }
2921 #[doc(hidden)]
2922 #[cfg_attr(test, mutants::skip)]
2923 #[deprecated = "make_light was completely removed in ArcShift 0.2. Please use ArcShift::downgrade(&item) instead."]
2924 pub fn make_light(&mut self, _marker: NoLongerAvailableMarker) {
2925 unreachable!("method cannot be called")
2926 }
2927 #[doc(hidden)]
2928 #[cfg_attr(test, mutants::skip)]
2929 #[deprecated = "shared_non_reloading_get now does the same thing as 'shared_get', please use the latter instead."]
2930 pub fn shared_non_reloading_get(&self) -> &T {
2931 self.shared_get()
2932 }
2933
2934 /// Basically the same as doing [`ArcShift::new`], but avoids copying the contents of 'input'
2935 /// to the stack, even as a temporary variable. This can be useful, if the type is too large
2936 /// to fit on the stack.
2937 pub fn from_box(input: Box<T>) -> ArcShift<T> {
2938 let holder = make_sized_or_unsized_holder_from_box(input, null_mut());
2939 ArcShift {
2940 // SAFETY:
2941 // from_box_impl never creates a null-pointer from a Box.
2942 item: unsafe { NonNull::new_unchecked(holder as *mut _) },
2943 pd: PhantomData,
2944 }
2945 }
2946
2947 /// Returns a mutable reference to the inner value.
2948 ///
2949 /// This method returns None if there are any other ArcShift or ArcShiftWeak instances
2950 /// pointing to the same object chain.
2951 pub fn try_get_mut(&mut self) -> Option<&mut T> {
2952 self.reload();
2953 with_holder!(self.item, T, item_ptr, {
2954 // SAFETY:
2955 // self.item is always a valid pointer for shared access
2956 let item = unsafe { &*item_ptr };
2957 let weak_count = item.weak_count.load(Ordering::SeqCst); //atomic try_get_mut check weak_count
2958 if get_weak_count(weak_count) == 1
2959 && !get_weak_prev(weak_count)
2960 // There can't be a 'next', since if so we wouldn't have a weak count of 1
2961 && item.strong_count.load(Ordering::SeqCst) == 1
2962 //atomic try_get_mut check strong count
2963 {
2964 // Yes, we need to check this again, see comment further down.
2965 let weak_count = item.weak_count.load(Ordering::SeqCst); //atomic try_get_mut double check weak_count
2966 if get_weak_count(weak_count) == 1 {
2967 // SAFETY:
2968 // The above constraints actually guarantee there can be no concurrent access.
2969 //
2970 // If we can prove that no such thread existed at time of 'weak_count.load' above,
2971 // no such thread can later appear, since we hold '&mut self' to the only
2972 // ArcShift referencing the chain. I.e, if we can prove this, we're done.
2973 // No other weak-ref can exist, since we've checked that weak count is 1.
2974 //
2975 // Since the weak ref flags say there's no next and no prev, the only possible other
2976 // ref that could exist at 'weak_count.load'-time would be a strong ref.
2977 //
2978 // We therefore check the strong count. If it is 1, there's only three possible cases:
2979 // 1: We truly are the only remaining ref
2980 // 2: There was one, and it has since gone away
2981 // 3: There was one, and it has updated the chain and added a new value.
2982 // 4: There was one, and it has downgraded to a weak ref.
2983 //
2984 // Cases 1 and 2 are benign. We guard against case 3 by loading 'weak_count'
2985 // again. If it still shows there's no 'next', then case 3 is off the table.
2986 // If the count is also still 1, option 4 is off the table. Meaning, we truly
2987 // are alone.
2988 let temp: &mut ManuallyDrop<T> = unsafe { &mut *item.payload.get() };
2989 Some(&mut **temp)
2990 } else {
2991 None
2992 }
2993 } else {
2994 None
2995 }
2996 })
2997 }
2998
2999 /// See [`ArcShift::update`] .
3000 ///
3001 /// This method allows converting from [`Box<T>`]. This can be useful since it means it's
3002 /// possible to use unsized types, such as [`str`] or [`[u8]`].
3003 pub fn update_box(&mut self, new_payload: Box<T>) {
3004 let holder = make_sized_or_unsized_holder_from_box(new_payload, self.item.as_ptr());
3005
3006 with_holder!(self.item, T, item, {
3007 let mut jobq = DropHandler::default();
3008 // SAFETY:
3009 // do_update returns a valid non-null pointer
3010 let new_item = unsafe {
3011 NonNull::new_unchecked(do_update(item, |_| Some(holder), &mut jobq) as *mut _)
3012 };
3013 jobq.resume_any_panics();
3014 self.item = new_item;
3015 });
3016 }
3017
3018 /// Reload this ArcShift instance, and return the latest value.
3019 #[inline(always)]
3020 pub fn get(&mut self) -> &T {
3021 if is_sized::<T>() {
3022 let ptr = from_dummy::<T, SizedMetadata>(self.item.as_ptr());
3023 // SAFETY:
3024 // self.item is always a valid pointer
3025 let item = unsafe { &*ptr };
3026 let next = item.next.load(Ordering::Relaxed);
3027 if next.is_null() {
3028 // SAFETY:
3029 // self.item is always a valid pointer
3030 return unsafe { item.payload() };
3031 }
3032 Self::advance_strong_helper2::<SizedMetadata>(&mut self.item)
3033 } else {
3034 let ptr = from_dummy::<T, UnsizedMetadata<T>>(self.item.as_ptr());
3035 // SAFETY:
3036 // self.item is always a valid pointer
3037 let item = unsafe { &*ptr };
3038 let next = item.next.load(Ordering::Relaxed);
3039 if next.is_null() {
3040 // SAFETY:
3041 // self.item is always a valid pointer
3042 return unsafe { item.payload() };
3043 }
3044 Self::advance_strong_helper2::<UnsizedMetadata<T>>(&mut self.item)
3045 }
3046 }
3047
3048 /// Get the current value of this ArcShift instance.
3049 ///
3050 /// WARNING! This does not reload the pointer. Use [`ArcShift::reload()`] to reload
3051 /// the value, or [`ArcShift::get()`] to always get the newest value.
3052 ///
3053 /// This method has the advantage that it doesn't require `&mut self` access.
3054 #[inline(always)]
3055 pub fn shared_get(&self) -> &T {
3056 with_holder!(self.item, T, item, {
3057 // SAFETY:
3058 // ArcShift has a strong ref, so payload must not have been dropped.
3059 unsafe { (*item).payload() }
3060 })
3061 }
3062
3063 /// Create an [`ArcShiftWeak<T>`] instance.
3064 ///
3065 /// Weak pointers do not prevent the inner from being dropped.
3066 ///
3067 /// The returned pointer can later be upgraded back to a regular ArcShift instance, if
3068 /// there is at least one remaining strong reference (i.e, [`ArcShift<T>`] instance).
3069 #[must_use = "this returns a new `ArcShiftWeak` pointer, \
3070 without modifying the original `ArcShift`"]
3071 pub fn downgrade(this: &ArcShift<T>) -> ArcShiftWeak<T> {
3072 let t = with_holder!(this.item, T, item, do_clone_weak(item));
3073 ArcShiftWeak {
3074 // SAFETY:
3075 // do_clone_weak returns a valid, non-null pointer
3076 item: unsafe { NonNull::new_unchecked(t as *mut _) },
3077 }
3078 }
3079
3080 /// Note, if there is at least one strong count, these collectively hold a weak count.
3081 #[allow(unused)]
3082 pub(crate) fn weak_count(&self) -> usize {
3083 with_holder!(self.item, T, item, {
3084 // SAFETY:
3085 // self.item is a valid pointer
3086 unsafe { get_weak_count((*item).weak_count.load(Ordering::SeqCst)) }
3087 })
3088 }
3089 #[allow(unused)]
3090 pub(crate) fn strong_count(&self) -> usize {
3091 with_holder!(self.item, T, item, {
3092 // SAFETY:
3093 // self.item is a valid pointer
3094 unsafe { (*item).strong_count.load(Ordering::SeqCst) }
3095 })
3096 }
3097 #[inline(never)]
3098 #[cold]
3099 fn advance_strong_helper2<M: IMetadata>(old_item_ptr: &mut NonNull<ItemHolderDummy<T>>) -> &T {
3100 let mut jobq = DropHandler::default();
3101 let mut item_ptr = old_item_ptr.as_ptr() as *const _;
3102 // Lock free. Only loops if disturb-flag was set, meaning other thread
3103 // has offloaded work on us, and it has made progress.
3104 loop {
3105 item_ptr = do_advance_strong::<T, M>(item_ptr, &mut jobq);
3106 let (need_rerun, _strong_refs) =
3107 do_janitor_task(from_dummy::<T, M>(item_ptr), &mut jobq);
3108 if need_rerun {
3109 debug_println!("Janitor {:?} was disturbed. Need rerun", item_ptr);
3110 continue;
3111 }
3112 jobq.resume_any_panics();
3113 // SAFETY:
3114 // pointer returned by do_advance_strong is always a valid pointer
3115 *old_item_ptr = unsafe { NonNull::new_unchecked(item_ptr as *mut _) };
3116 // SAFETY:
3117 // pointer returned by do_advance_strong is always a valid pointer
3118 let item = unsafe { &*from_dummy::<T, M>(item_ptr) };
3119 // SAFETY:
3120 // pointer returned by do_advance_strong is always a valid pointer
3121 return unsafe { item.payload() };
3122 }
3123 }
3124
3125 /// Reload this instance, making it point to the most recent value.
3126 #[inline(always)]
3127 pub fn reload(&mut self) {
3128 if is_sized::<T>() {
3129 let ptr = from_dummy::<T, SizedMetadata>(self.item.as_ptr());
3130 // SAFETY:
3131 // self.item is always a valid pointer
3132 let item = unsafe { &*ptr };
3133 let next = item.next.load(Ordering::Relaxed);
3134 if next.is_null() {
3135 return;
3136 }
3137 Self::advance_strong_helper2::<SizedMetadata>(&mut self.item);
3138 } else {
3139 let ptr = from_dummy::<T, UnsizedMetadata<T>>(self.item.as_ptr());
3140 // SAFETY:
3141 // self.item is always a valid pointer
3142 let item = unsafe { &*ptr };
3143 let next = item.next.load(Ordering::Relaxed);
3144 if next.is_null() {
3145 return;
3146 }
3147 Self::advance_strong_helper2::<UnsizedMetadata<T>>(&mut self.item);
3148 }
3149 }
3150
3151 /// Check all links and refcounts.
3152 ///
3153 /// # SAFETY
3154 /// This method requires that no other threads access the chain while it is running.
3155 /// It is up to the caller to actually ensure this.
3156 #[allow(unused)]
3157 #[cfg(test)]
3158 #[cfg(feature = "std")]
3159 pub(crate) unsafe fn debug_validate(
3160 strong_handles: &[&Self],
3161 weak_handles: &[&ArcShiftWeak<T>],
3162 ) {
3163 let first = if !strong_handles.is_empty() {
3164 &strong_handles[0].item
3165 } else {
3166 &weak_handles[0].item
3167 };
3168 with_holder!(first, T, item, {
3169 Self::debug_validate_impl(strong_handles, weak_handles, item);
3170 });
3171 }
3172 #[allow(unused)]
3173 #[cfg(test)]
3174 #[cfg(feature = "std")]
3175 fn debug_validate_impl<M: IMetadata>(
3176 strong_handles: &[&ArcShift<T>],
3177 weak_handles: &[&ArcShiftWeak<T>],
3178 prototype: *const ItemHolder<T, M>,
3179 ) {
3180 let mut last = prototype;
3181
3182 debug_println!("Start traverse right at {:?}", last);
3183 // Lock free - this is a debug method not used in production.
3184 loop {
3185 debug_println!("loop traverse right at {:?}", last);
3186 // SAFETY:
3187 // Caller guarantees that initial 'last' prototype is a valid pointer.
3188 // Other pointers are found by walking right from that.
3189 // Caller guarantees there are no concurrent updates.
3190 let next = unsafe { undecorate((*last).next.load(Ordering::SeqCst)) };
3191 debug_println!("Traversed to {:?}", next);
3192 if next.is_null() {
3193 break;
3194 }
3195 last = from_dummy::<T, M>(next);
3196 }
3197
3198 let mut true_weak_refs =
3199 std::collections::HashMap::<*const ItemHolderDummy<T>, usize>::new();
3200 let mut true_strong_refs =
3201 std::collections::HashMap::<*const ItemHolderDummy<T>, usize>::new();
3202 // SAFETY:
3203 // the loop above has yielded a valid last ptr
3204 let all_nodes = unsafe { (*last).debug_all_to_left() };
3205
3206 let strong_refs_exist = all_nodes
3207 .iter()
3208 .any(|x| x.strong_count.load(Ordering::SeqCst) > 0);
3209
3210 if strong_refs_exist {
3211 debug_println!("Reading {:?}.next", to_dummy(last));
3212 // SAFETY:
3213 // the loop above has yielded a valid last ptr
3214 let last_next = unsafe { (*last).next.load(Ordering::SeqCst) };
3215 debug_println!("Reading {:?}.next gave {:?}", to_dummy(last), last_next);
3216 assert!(!get_decoration(last_next).is_dropped(), "the rightmost node must never be dropped (at least at rest, but regardless of refcount)");
3217 }
3218
3219 for _node in all_nodes.iter() {
3220 debug_println!("Node: {:?}", *_node as *const ItemHolder<T, _>);
3221 }
3222 for node in all_nodes.iter().copied() {
3223 let next = undecorate(node.next.load(Ordering::SeqCst));
3224 if !next.is_null() {
3225 // SAFETY:
3226 // next pointer is valid
3227 assert!(all_nodes.contains(unsafe { &&*from_dummy::<T, M>(next) }));
3228 }
3229 let prev: *const _ = node.prev.load(Ordering::SeqCst);
3230 if !prev.is_null() {
3231 *true_weak_refs.entry(prev).or_default() += 1;
3232 // SAFETY:
3233 // prev pointer is valid
3234 assert!(all_nodes.contains(unsafe { &&*from_dummy::<T, M>(prev) }));
3235 }
3236 let advance_count = node.advance_count.load(Ordering::SeqCst);
3237 assert_eq!(advance_count, 0, "advance_count must always be 0 at rest");
3238 }
3239
3240 for handle in weak_handles.iter() {
3241 // SAFETY:
3242 // All ArcShiftWeak instances always have valid, non-null pointers
3243 assert!(all_nodes.contains(unsafe { &&*from_dummy::<T, M>(handle.item.as_ptr()) }));
3244 let true_weak_count = true_weak_refs.entry(handle.item.as_ptr()).or_default();
3245 *true_weak_count += 1;
3246 }
3247 for handle in strong_handles.iter() {
3248 // SAFETY:
3249 // All ArcShift instances always have valid, non-null pointers
3250 assert!(all_nodes.contains(unsafe { &&*from_dummy::<T, M>(handle.item.as_ptr()) }));
3251 // SAFETY:
3252 // All ArcShift instances always have valid, non-null pointers
3253 let handle_next: *const _ = unsafe {
3254 (*from_dummy::<T, M>(handle.item.as_ptr()))
3255 .next
3256 .load(Ordering::SeqCst)
3257 };
3258 assert!(
3259 !get_decoration(handle_next).is_dropped(),
3260 "nodes referenced by strong handles must not be dropped, but {:?} was",
3261 handle.item.as_ptr()
3262 );
3263
3264 let true_strong_count = true_strong_refs.entry(handle.item.as_ptr()).or_default();
3265 if *true_strong_count == 0 {
3266 *true_weak_refs.entry(handle.item.as_ptr()).or_default() += 1;
3267 }
3268 *true_strong_count += 1;
3269 }
3270 for node in all_nodes.iter().copied() {
3271 let node_dummy = to_dummy(node);
3272 let strong_count = node.strong_count.load(Ordering::SeqCst);
3273 let weak_count = get_weak_count(node.weak_count.load(Ordering::SeqCst));
3274 let expected_strong_count = true_strong_refs.get(&node_dummy).unwrap_or(&0);
3275 let expected_weak_count = true_weak_refs.get(&node_dummy).unwrap_or(&0);
3276 assert_eq!(
3277 strong_count, *expected_strong_count,
3278 "strong count of {:x?} should be {}",
3279 node as *const _, *expected_strong_count
3280 );
3281 assert_eq!(
3282 weak_count, *expected_weak_count,
3283 "weak count of {:x?} should be {}",
3284 node as *const _, *expected_weak_count
3285 );
3286
3287 let next = node.next.load(Ordering::SeqCst);
3288 if strong_count > 0 {
3289 assert!(
3290 !get_decoration(next).is_dropped(),
3291 "as strong count is >0, node {:x?} should not be dropped",
3292 node as *const _
3293 );
3294 }
3295 }
3296 }
3297}
3298
3299#[cfg(test)]
3300#[cfg(not(any(loom, feature = "shuttle")))]
3301pub(crate) mod no_std_tests;
3302
3303// Module for tests
3304#[cfg(all(test, feature = "std"))]
3305pub(crate) mod tests;