| use crate::mem::MaybeUninit; |
| use crate::time::Duration; |
| |
| use super::{ |
| abi, |
| error::{expect_success, fail}, |
| time::with_tmos, |
| }; |
| |
| const CLEAR: abi::FLGPTN = 0; |
| const RAISED: abi::FLGPTN = 1; |
| |
| /// A thread parking primitive that is not susceptible to race conditions, |
| /// but provides no atomic ordering guarantees and allows only one `raise` per wait. |
| pub struct WaitFlag { |
| flag: abi::ID, |
| } |
| |
| impl WaitFlag { |
| /// Creates a new wait flag. |
| pub fn new() -> WaitFlag { |
| let flag = expect_success( |
| unsafe { |
| abi::acre_flg(&abi::T_CFLG { |
| flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR, |
| iflgptn: CLEAR, |
| }) |
| }, |
| &"acre_flg", |
| ); |
| |
| WaitFlag { flag } |
| } |
| |
| /// Wait for the wait flag to be raised. |
| pub fn wait(&self) { |
| let mut token = MaybeUninit::uninit(); |
| expect_success( |
| unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) }, |
| &"wai_flg", |
| ); |
| } |
| |
| /// Wait for the wait flag to be raised or the timeout to occur. |
| /// |
| /// Returns whether the flag was raised (`true`) or the operation timed out (`false`). |
| pub fn wait_timeout(&self, dur: Duration) -> bool { |
| let mut token = MaybeUninit::uninit(); |
| let res = with_tmos(dur, |tmout| unsafe { |
| abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout) |
| }); |
| |
| match res { |
| abi::E_OK => true, |
| abi::E_TMOUT => false, |
| error => fail(error, &"twai_flg"), |
| } |
| } |
| |
| /// Raise the wait flag. |
| /// |
| /// Calls to this function should be balanced with the number of successful waits. |
| pub fn raise(&self) { |
| expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg"); |
| } |
| } |
| |
| impl Drop for WaitFlag { |
| fn drop(&mut self) { |
| expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg"); |
| } |
| } |