1use super::less;
2use core::cell::Cell;
3use core::mem::MaybeUninit;
4use core::ptr;
5use core::sync::atomic::{
6 fence, AtomicU32, AtomicUsize,
7 Ordering::{Acquire, Relaxed, Release},
8};
9
10pub(crate) struct TokenLink(AtomicUsize);
11
12impl TokenLink {
13 pub(crate) const fn new() -> Self {
14 Self(AtomicUsize::new(0))
15 }
16
17 pub(crate) fn lock(&self, token: &Token, last: u16, idx: u16) -> *const Token {
18 debug_assert!(last != idx);
19 let new_status = ((last as u32) << 16) | idx as u32;
20 loop {
21 match token
22 .status
23 .compare_exchange_weak(0, new_status, Relaxed, Relaxed)
24 {
25 Ok(_) => return self.lock_with(token),
26 Err(old) => {
27 if (old as u16) != last && (old >> 16) as u16 != idx {
28 continue;
29 }
30 let current = self.try_lock_update();
31 if current.is_null() {
32 continue;
33 }
34 let status = token.status.load(Relaxed);
35 if status == 0 {
36 token.status.store(new_status, Relaxed);
37 token.set_next(current);
38 return token;
39 } else if (status as u16) == last {
40 token.set_last_and_idx((status >> 16) as u16, idx);
41 return current;
42 } else {
43 token.set_last_and_idx(last, status as u16);
44 return current;
45 }
46 }
47 }
48 }
49 }
50
51 fn try_lock_update(&self) -> *const Token {
52 let old = self.0.load(Relaxed);
53 if old > 0
54 && (old & 1) == 0
55 && self
56 .0
57 .compare_exchange_weak(old, 1, Release, Relaxed)
58 .is_ok()
59 {
60 fence(Acquire);
61 return old as *const Token;
62 }
63 ptr::null()
64 }
65
66 fn lock_with(&self, token: &Token) -> *const Token {
67 let addr = token as *const Token as usize;
68 token.set_next(ptr::null());
69 let mut old = self.0.load(Relaxed);
70 loop {
71 let new = if (old & 1) == 1 {
72 token.set_next((old & !1) as *const Token);
73 addr | 1
74 } else {
75 1
76 };
77 match self.0.compare_exchange_weak(old, new, Release, Relaxed) {
78 Ok(_) => {
79 return if (old & 1) == 0 {
80 fence(Acquire);
81 token.set_next((old & !1) as *const Token);
82 token
83 } else {
84 ptr::null()
85 };
86 }
87 Err(val) => old = val,
88 }
89 }
90 }
91
92 #[inline(always)]
93 fn next_range(old: usize, last: u16) -> bool {
94 debug_assert!(old > 0);
95 if old != 1 {
96 let task = unsafe { &*((old & !1) as *const Token) };
97 return task.find(last);
98 }
99 false
100 }
101
102 #[inline(always)]
103 pub(crate) fn unlock(&self, token: *const Token, last: u16) -> *const Token {
104 if token.is_null() {
105 self.unlock_with_null(last)
106 } else {
107 self.unlock_with_next(unsafe { &*token }, last)
108 }
109 }
110
111 fn unlock_with_null(&self, last: u16) -> *const Token {
112 let mut old = self.0.load(Relaxed);
113 loop {
114 let next_range = Self::next_range(old, last);
115 let new = if !next_range { old & !1 } else { 1 };
116 match self.0.compare_exchange_weak(old, new, Release, Relaxed) {
117 Ok(_) => {
118 return if new == 1 {
119 fence(Acquire);
120 (old & !1) as *const Token
121 } else {
122 ptr::null()
123 };
124 }
125 Err(val) => old = val,
126 }
127 }
128 }
129
130 fn unlock_with_next(&self, token: &Token, last: u16) -> *const Token {
131 let end = token.last();
132 let mut old = self.0.load(Relaxed);
133 loop {
134 let next_range = Self::next_range(old, last);
135 let new = if !next_range {
136 end.set_next((old & !1) as *const Token);
137 token as *const Token as usize
138 } else {
139 1
140 };
141 match self.0.compare_exchange_weak(old, new, Release, Relaxed) {
142 Ok(_) => {
143 return if new == 1 {
144 fence(Acquire);
145 end.set_next((old & !1) as *const Token);
146 token as *const Token
147 } else {
148 ptr::null()
149 };
150 }
151 Err(val) => old = val,
152 }
153 }
154 }
155}
156
157pub trait TokenFactory {
158 fn new() -> Self;
159 fn get(&self) -> &Token;
160}
161
162pub struct NullTokenFactory;
163static NULL_TOKEN: Token = Token::new();
164
165impl TokenFactory for NullTokenFactory {
166 fn new() -> Self {
167 NullTokenFactory
168 }
169 fn get(&self) -> &Token {
170 &NULL_TOKEN
171 }
172}
173
174pub type TokenArray = Tokens<2>;
175
176#[repr(C)]
177pub struct Tokens<const CNT: usize> {
178 idx: Cell<usize>,
179 tokens: MaybeUninit<[Token; CNT]>,
180}
181
182impl<const CNT: usize> TokenFactory for Tokens<CNT> {
183 fn new() -> Self {
184 debug_assert!((CNT & (CNT - 1)) == 0);
185 Self {
186 tokens: MaybeUninit::zeroed(),
187 idx: Cell::new(0),
188 }
189 }
190
191 fn get(&self) -> &Token {
192 let idx = self.idx.get();
193 self.idx.set((idx + 1) & (CNT - 1));
194 unsafe { self.tokens.assume_init_ref().get_unchecked(idx) }
195 }
196}
197
198#[repr(C)]
199pub struct Token {
200 status: AtomicU32,
201 next: Cell<*const Token>,
202}
203
204unsafe impl Send for Token {}
205unsafe impl Sync for Token {}
206
207impl Token {
208 pub(crate) const fn new() -> Self {
209 Self {
210 status: AtomicU32::new(0),
211 next: Cell::new(ptr::null()),
212 }
213 }
214
215 pub(crate) fn find(&self, last: u16) -> bool {
216 let mut token = self;
217 loop {
218 let (expected, _) = token.last_and_idx();
219 if expected == last {
220 return true;
221 }
222 let next = token.next();
223 if next.is_null() {
224 return false;
225 }
226 token = unsafe { &*next };
227 }
228 }
229
230 pub(crate) fn unlock(&self) -> *const Token {
231 let next = self.next.replace(ptr::null());
232 self.status.store(0, Release);
233 next
234 }
235
236 pub(crate) fn last_and_idx(&self) -> (u16, u16) {
237 let status = self.status.load(Relaxed);
238 ((status >> 16) as u16, status as u16)
239 }
240
241 pub(crate) fn set_last_and_idx(&self, last: u16, idx: u16) {
242 let new_status = ((last as u32) << 16) | idx as u32;
243 self.status.store(new_status, Relaxed);
244 }
245
246 fn try_merge_next(&self, idx: u16) -> u16 {
247 let next = self.next();
248 if next.is_null() {
249 return idx;
250 }
251 let next = unsafe { &*next };
252 let (next_last, next_idx) = next.last_and_idx();
253 if idx == next_last {
254 self.set_next(next.unlock());
255 next_idx
256 } else {
257 idx
258 }
259 }
260
261 pub(crate) fn next(&self) -> *const Token {
262 self.next.get()
263 }
264
265 pub(crate) fn set_next(&self, token: *const Token) {
266 self.next.set(token);
267 }
268
269 pub(crate) fn sort(&self) -> &Token {
270 let mut sorted = SortedToken::new();
271 let mut token = self as *const Token;
272 while !token.is_null() {
273 let token_ref = unsafe { &*token };
274 let next = token_ref.next();
275 sorted.insert(token_ref);
276 token = next;
277 }
278 unsafe { &*sorted.token }
279 }
280
281 pub(crate) fn last(&self) -> &Self {
282 let mut last = self;
283 while !last.next().is_null() {
284 last = unsafe { &*last.next() };
285 }
286 last
287 }
288}
289
290struct SortedToken {
291 token: *const Token,
292}
293
294impl SortedToken {
295 fn new() -> Self {
296 Self { token: ptr::null() }
297 }
298 fn insert(&mut self, token: &Token) {
299 token.set_next(ptr::null());
300 if !self.token.is_null() {
301 let (last, idx) = token.last_and_idx();
302 let mut prev = ptr::null::<Token>();
303 let mut pos = self.token;
304 loop {
305 let cur = unsafe { &*pos };
306 let (cur_last, cur_idx) = cur.last_and_idx();
307 if idx == cur_last {
308 cur.set_last_and_idx(last, cur_idx);
309 token.unlock();
310 return;
311 } else if last == cur_idx {
312 let idx = cur.try_merge_next(idx);
313 cur.set_last_and_idx(cur_last, idx);
314 token.unlock();
315 return;
316 } else if less(idx, cur_last) {
317 token.set_next(cur);
318 if prev.is_null() {
319 self.token = token;
320 } else {
321 unsafe { &*prev }.set_next(token);
322 }
323 return;
324 } else if cur.next().is_null() {
325 cur.set_next(token);
326 return;
327 }
328 prev = pos;
329 pos = cur.next();
330 }
331 } else {
332 self.token = token;
333 }
334 }
335}