1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Essential building blocks for thread-per-core libraries.
//!
//! This crate allows you to express migrations between NUMA nodes, threads, or specific CPU cores.
//! It can serve as a foundation for building components and runtimes that operate across multiple
//! memory affinities.
//!
//! # Theory of Operation
//!
//! At a high level, this crate enables thread migrations of state via the [`ThreadAware`] trait:
//! - Runtimes (and similar) can use it to inform types that they were just moved across a thread or NUMA boundary.
//! - The authors of said types can then act on this information to implement performance optimizations. Such optimizations
//! might include re-allocating memory in a new NUMA region, connecting to a thread-local I/O scheduler,
//! or detaching from shared, possibly contended memory with the previous thread.
//!
//! Similar to [`Clone`], there are no exact semantic prescriptions of how types should behave on relocation.
//! They might continue to share some state (e.g., a common cache) or fully detach from it for performance reasons.
//! The primary goal is performance, so types should aim to minimize contention on synchronization primitives
//! and cross-NUMA memory access. Like `Clone`, the relocation itself should be mostly transparent and predictable
//! to users.
//!
//! ## Implementing [`ThreadAware`], and `Arc<T, PerCore>`
//!
//! In most cases [`ThreadAware`] should be implemented via the provided derive macro.
//! As thread-awareness of a type usually involves letting all contained fields know of an ongoing
//! relocation, the derive macro does just that. A default impl is provided for many `std` types,
//! so the macro should 'just work' on most compounds of built-ins.
//!
//! External crates might often not implement [`ThreadAware`]. In many of these cases using our
//! [`thread_aware::Arc`](Arc) offers a convenient solution: It combines an upstream
//! [`std::sync::Arc`] with a relocation [`Strategy`](storage::Strategy), and implements [`ThreadAware`] for it. For
//! example, while an `Arc<Foo, PerProcess>` effectively acts as vanilla `Arc`, an
//! `Arc<Foo, PerCore>` ensures a separate `Foo` is available any time the types moves a core boundary.
//!
//!
//! ## Relation to [`Send`]
//!
//! [`ThreadAware`] requires [`Send`] as a supertrait. Types are first sent to another thread,
//! then the [`ThreadAware`] relocation notification is invoked.
//!
//!
//! ## Thread vs. Core Semantics
//!
//! As this library is primarily intended for use in thread-per-core runtimes,
//! we use the terms 'thread' and 'core' interchangeably. The assumption is that items
//! primarily relocate between different threads, where each thread is pinned to a different CPU core.
//! Should a runtime utilize more than one thread per core (e.g., for internal I/O) user code should
//! be able to observe this fact.
//!
//! ## [`ThreadAware`] vs. [`Unaware`]
//!
//! Sometimes you might need to move inert types as-is, essentially bypassing all
//! thread-aware handling. These might be foreign types that carry no allocation, do
//! no I/O, or otherwise do not require any thread-specific handling.
//!
//! [`Unaware`] can be used to encapsulate such types, a wrapper that itself implements [`ThreadAware`], but
//! otherwise does not react to it. You can think of it as a `MoveAsIs<T>`. However, it was
//! deliberately named `Unaware` to signal that only types which are genuinely unaware of their
//! thread relocations (i.e., don't impl [`ThreadAware`]) should be wrapped in such.
//!
//! Wrapping types that implement the trait is discouraged, as it will prevent them from properly
//! relocating and might have an impact on their performance, but not correctness, see below.
//!
//! ## Performance vs. Correctness
//!
//! It is important to note that [`ThreadAware`] is a cooperative performance optimization and contention avoidance
//! primitive, not a guarantee of behavior for either the caller or callee. In other words, callers and runtimes must
//! continue to operate correctly if the trait is invoked incorrectly.
//!
//! In particular, [`ThreadAware`] may not always be invoked when a type leaves the current thread.
//! While runtimes should reduce the incidence of that through their API design, it may nonetheless
//! happen via [`std::thread::spawn`] and other means. In these cases types should still function
//! correctly, although they might experience degraded performance through contention of now-shared
//! resources.
//!
//! ## Provided Implementations
//!
//! [`ThreadAware`] is implemented for many standard library types, including primitive types, Vec,
//! String, Option, Result, tuples, etc. However, it's explicitly not implemented for [`std::sync::Arc`]
//! as that type implies some level of cross-thread sharing and thus needs special attention when used
//! from types that implement [`ThreadAware`].
//!
//! # Features
//!
//! * **`derive`** *(default)*: Re-exports the `#[derive(ThreadAware)]` macro from the companion
//! `thread_aware_macros` crate. Disable to avoid pulling in proc-macro code in minimal
//! environments: `default-features = false`.
//! * **`threads`**: Enables features mainly used by async runtimes for OS interactions.
//!
//! # Examples
//!
//! ## Deriving [`ThreadAware`]
//!
//! When the `derive` feature (enabled by default) is active you can simply
//! derive [`ThreadAware`] instead of writing the implementation manually.
//!
//! ```rust
//! use thread_aware::ThreadAware;
//!
//! #[derive(Debug, Clone, ThreadAware)]
//! struct Point {
//! x: i32,
//! y: i32,
//! }
//! ```
//!
//! ## Enabling [`ThreadAware`] via `Arc<T, S>`
//!
//! For types containing fields not [`ThreadAware`], you can use [`Arc`] to specify a
//! strategy, and wrap them in an [`Arc`] that implements the trait.
//!
//!
//! ```rust
//! use thread_aware::{Arc, PerCore, ThreadAware};
//! # #[derive(Debug, Default)]
//! # struct Client;
//!
//! #[derive(Debug, Clone, ThreadAware)]
//! struct Service {
//! name: String,
//! client: Arc<Client, PerCore>,
//! }
//!
//! impl Service {
//! fn new() -> Self {
//! Self {
//! name: "MyService".to_string(),
//! client: Arc::new(|| Client::default()),
//! }
//! }
//! }
//! ```
pub use ThreadAware;
pub use ;
// Re-export the derive macro (behind the `derive` feature) so users can
// simply `use thread_aware::ThreadAware;`. Disable the feature to avoid the
// proc-macro dependency in minimal builds.
/// Derive macro implementing `ThreadAware` for structs and enums.
///
/// The generated implementation transfers each field by calling its own
/// `ThreadAware::relocate` method. Fields annotated with `#[thread_aware(skip)]` are
/// left as-is (moved without invoking `relocate`).
///
/// # Supported Items
/// * Structs (named, tuple, or unit)
/// * Enums (all variant field styles)
///
/// Unions are not supported and will produce a compile error.
///
/// # Attributes
/// * `#[thread_aware(skip)]`: Prevents a field from being recursively transferred.
///
/// # Generic Bounds
/// Generic type parameters appearing in non-skipped fields automatically receive a
/// `::thread_aware::ThreadAware` bound (occurrences only inside `PhantomData<..>` are ignored).
///
/// # Example
/// ```rust
/// use thread_aware::ThreadAware;
/// use thread_aware::affinity::Affinity;
/// #[derive(ThreadAware)]
/// struct Payload {
/// id: u64,
/// data: Vec<u8>,
/// }
///
/// #[derive(ThreadAware)]
/// struct Wrapper {
/// // This field will be recursively transferred.
/// inner: Payload,
/// // This field will be moved without calling `relocate`.
/// #[thread_aware(skip)]
/// raw_len: usize,
/// }
///
/// fn demo(a1: Option<Affinity>, a2: Affinity, mut w: Wrapper) {
/// // Move the wrapper from a1 to a2.
/// w.relocate(a1, a2);
/// }
/// ```
pub use ThreadAware;
pub use ;