Skip to main content

hirun/channel/
token.rs

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}