irox_tools/sync/
flags.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5extern crate alloc;
6use alloc::sync::Arc;
7use std::sync::{Condvar, Mutex};
8
9///
10/// A Synchronous Signal Flag that can be asserted or cleared.
11#[derive(Default, Clone)]
12pub struct SyncFlag {
13    mutex: Arc<Mutex<bool>>,
14    condvar: Arc<Condvar>,
15}
16
17impl SyncFlag {
18    ///
19    /// Creates a new [`SyncFlag`] that can be shared between threads.
20    #[allow(clippy::mutex_atomic)]
21    pub fn new() -> SyncFlag {
22        SyncFlag {
23            mutex: Arc::new(Mutex::new(false)),
24            condvar: Arc::new(Condvar::new()),
25        }
26    }
27
28    /// Asserts the signal flag and notifies any waiters.
29    pub fn set_flag(&self) {
30        if let Ok(mut guard) = self.mutex.lock() {
31            *guard = true;
32        }
33        self.condvar.notify_all();
34    }
35
36    /// Clears the signal flag and notifies any waiters.
37    pub fn clear_flag(&self) {
38        if let Ok(mut guard) = self.mutex.lock() {
39            *guard = false;
40        }
41        self.condvar.notify_all();
42    }
43
44    /// Waits until the flag is notified and returns the current value of the
45    /// signal.
46    pub fn await_flag_notified(&self) -> bool {
47        if let Ok(guard) = self.mutex.lock() {
48            if let Ok(guard) = self.condvar.wait(guard) {
49                return *guard;
50            }
51        };
52        false
53    }
54
55    /// If the flag is set, immediately returns.  Otherwise waits until the flag
56    /// is set and then returns.
57    pub fn await_flag_set(&self) {
58        loop {
59            let Ok(guard) = self.mutex.lock() else {
60                break;
61            };
62            if *guard {
63                return;
64            }
65            let Ok(guard) = self.condvar.wait_while(guard, |v| !*v) else {
66                break;
67            };
68            if *guard {
69                return;
70            }
71        }
72    }
73
74    /// If the flag is cleared, immediately returns.  Otherwise waits until the
75    /// flag is cleared and then returns.
76    pub fn await_flag_unset(&self) {
77        loop {
78            let Ok(guard) = self.mutex.lock() else {
79                break;
80            };
81            if !*guard {
82                return;
83            }
84            let Ok(guard) = self.condvar.wait_while(guard, |v| *v) else {
85                break;
86            };
87            if !*guard {
88                return;
89            }
90        }
91    }
92}