Coverage Report

Created: 2026-06-28 08:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/mea-0.6.4/src/internal/countdown.rs
Line
Count
Source
1
// Copyright 2024 tison <wander4096@gmail.com>
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use std::sync::atomic::AtomicU32;
16
use std::sync::atomic::Ordering;
17
use std::task::Context;
18
19
use crate::internal::Mutex;
20
use crate::internal::WaitSet;
21
22
#[derive(Debug)]
23
pub(crate) struct CountdownState {
24
    state: AtomicU32,
25
    waiters: Mutex<WaitSet>,
26
}
27
28
impl CountdownState {
29
0
    pub(crate) const fn new(count: u32) -> Self {
30
0
        Self {
31
0
            state: AtomicU32::new(count),
32
0
            waiters: Mutex::new(WaitSet::new()),
33
0
        }
34
0
    }
35
36
    /// Performs volatile read on `state`.
37
    ///
38
    /// All other writes to `state` should be at least [`Ordering::Release`].
39
0
    pub(crate) fn state(&self) -> u32 {
40
0
        self.state.load(Ordering::Acquire)
41
0
    }
42
43
    /// Performs volatile CAS on `state`.
44
    ///
45
    /// If the comparison succeeds, performs read-modify-write operation with [`Ordering::Relaxed`]
46
    /// for read, and [`Ordering::Release`] for write; if the comparison fails, performs load
47
    /// operation with [`Ordering::Relaxed`].
48
    ///
49
    /// @see https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU32.html#method.compare_exchange_weak
50
    /// @see https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange
51
0
    pub(crate) fn cas_state(&self, current: u32, new: u32) -> Result<(), u32> {
52
0
        self.state
53
0
            .compare_exchange_weak(current, new, Ordering::Release, Ordering::Relaxed)
54
0
            .map(|_| ())
55
0
    }
56
57
    /// Drain and wake up all waiters.
58
0
    pub(crate) fn wake_all(&self) {
59
0
        let mut waiters = self.waiters.lock();
60
0
        waiters.wake_all();
61
0
    }
62
63
    /// Registers a waker to be woken up when the countdown reaches zero.
64
    ///
65
    /// `idx` must be `None` when the waker is not registered, or `Some(key)` where `key` is
66
    /// a value previously returned by this method.
67
0
    pub(crate) fn register_waker(&self, idx: &mut Option<usize>, cx: &mut Context<'_>) {
68
0
        let mut waiters = self.waiters.lock();
69
0
        waiters.register_waker(idx, cx);
70
0
    }
71
72
    /// Returns `Ok(())` if the counter is zero, otherwise returns `Err(s)` where `s` is the current
73
    /// counter value.
74
0
    pub(crate) fn spin_wait(&self, n: usize) -> Result<(), u32> {
75
0
        for _ in 0..n {
76
0
            if self.state() == 0 {
77
0
                return Ok(());
78
0
            }
79
0
            std::hint::spin_loop();
80
        }
81
82
0
        match self.state() {
83
0
            0 => Ok(()),
84
0
            s => Err(s),
85
        }
86
0
    }
87
88
    /// Decrements the counter, and returns whether the caller should wake up all waiters.
89
0
    pub(crate) fn decrement(&self, n: u32) -> bool {
90
0
        let mut cnt = self.state();
91
        loop {
92
0
            if cnt == 0 {
93
                // the one who decrements the counter to zero should wake up all waiters, not this
94
                // one
95
0
                return false;
96
0
            }
97
98
0
            let new_cnt = cnt.saturating_sub(n);
99
0
            match self.cas_state(cnt, new_cnt) {
100
0
                Ok(_) => return new_cnt == 0,
101
0
                Err(x) => cnt = x,
102
            }
103
        }
104
0
    }
105
}