Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fd76552
std: use an event flag based thread parker on SOLID
joboet May 18, 2022
3b6ae15
std: fix deadlock in `Parker`
joboet May 19, 2022
b9660de
std: solve priority issue for Parker
joboet Jun 4, 2022
5823d7b
Partial stabilization of "nonzero_unchecked_ops".
iago-lito May 30, 2022
69e8e7e
Stabilize NonZero* checked operations constness.
iago-lito Jun 9, 2022
caff723
std: relax memory orderings in `Parker`
joboet Jun 7, 2022
cc4f804
Move help popup into a pocket menu as well
GuillaumeGomez Jun 20, 2022
3eb9e1a
Add/update GUI tests for help pocket menu
GuillaumeGomez Jun 20, 2022
e4b2b41
Merge all popover hide functions into one
GuillaumeGomez Jun 22, 2022
99bc979
macros: use typed identifiers in diag derive
davidtwco Jun 23, 2022
abd3467
macros: use typed identifiers in subdiag derive
davidtwco Jun 23, 2022
dc90d1d
errors: remove diagnostic message ctors
davidtwco Jun 23, 2022
7475867
[rustc_parse] Forbid lets in certain places
c410-f3r Jun 25, 2022
dc2cc10
make const_err show up in future breakage reports
RalfJung Jun 4, 2022
af58692
bless remaining tests
RalfJung Jun 4, 2022
24b66da
Support setting file accessed/modified timestamps
joshtriplett Jun 19, 2022
e2b5729
Add alias `File::set_modified` as shorthand
joshtriplett Jun 20, 2022
3899914
bless after rebase
RalfJung Jun 25, 2022
1d32fed
Return an error if trying to set a file timestamp to 0 on Windows
joshtriplett Jun 25, 2022
2339bb2
Update `since` to 1.64 (since we're after 1.63)
scottmcm Jun 26, 2022
0398aa8
Add regression test for #92859
GuillaumeGomez Jun 26, 2022
03edb85
Rollup merge of #97140 - joboet:solid_parker, r=m-ou-se
matthiaskrgr Jun 26, 2022
8df0f4a
Rollup merge of #97295 - c410-f3r:yet-another-let-chain, r=compiler-e…
matthiaskrgr Jun 26, 2022
3fb4a87
Rollup merge of #97743 - RalfJung:const-err-future-breakage, r=estebank
matthiaskrgr Jun 26, 2022
f8e3771
Rollup merge of #97908 - iago-lito:stabilize_nonzero_checked_ops_cons…
matthiaskrgr Jun 26, 2022
b843ac5
Rollup merge of #98246 - joshtriplett:times, r=m-ou-se
matthiaskrgr Jun 26, 2022
4b59173
Rollup merge of #98297 - GuillaumeGomez:help-pocket-menu, r=notriddle
matthiaskrgr Jun 26, 2022
14859a5
Rollup merge of #98428 - davidtwco:translation-derive-typed-identifie…
matthiaskrgr Jun 26, 2022
45f9740
Rollup merge of #98535 - GuillaumeGomez:regression-test-92859, r=lcnr
matthiaskrgr Jun 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions library/std/src/sys/itron/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,32 @@ pub type ER = int_t;
/// Error code type, `ID` on success
pub type ER_ID = int_t;

/// Service call operational mode
pub type MODE = uint_t;

/// OR waiting condition for an eventflag
pub const TWF_ORW: MODE = 0x01;

/// Object attributes
pub type ATR = uint_t;

/// FIFO wait order
pub const TA_FIFO: ATR = 0;
/// Only one task is allowed to be in the waiting state for the eventflag
pub const TA_WSGL: ATR = 0;
/// The eventflag’s bit pattern is cleared when a task is released from the
/// waiting state for that eventflag.
pub const TA_CLR: ATR = 0x04;

/// Bit pattern of an eventflag
pub type FLGPTN = uint_t;

/// Task or interrupt priority
pub type PRI = int_t;

/// The special value of `PRI` representing the current task's priority.
pub const TPRI_SELF: PRI = 0;

/// Object attributes
pub type ATR = uint_t;

/// Use the priority inheritance protocol
#[cfg(target_os = "solid_asp3")]
pub const TA_INHERIT: ATR = 0x02;
Expand Down Expand Up @@ -90,6 +107,13 @@ pub struct T_CSEM {
pub maxsem: uint_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct T_CFLG {
pub flgatr: ATR,
pub iflgptn: FLGPTN,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct T_CMTX {
Expand Down Expand Up @@ -139,6 +163,24 @@ extern "C" {
pub fn sns_dsp() -> bool_t;
#[link_name = "__asp3_get_tim"]
pub fn get_tim(p_systim: *mut SYSTIM) -> ER;
#[link_name = "__asp3_acre_flg"]
pub fn acre_flg(pk_cflg: *const T_CFLG) -> ER_ID;
#[link_name = "__asp3_del_flg"]
pub fn del_flg(flgid: ID) -> ER;
#[link_name = "__asp3_set_flg"]
pub fn set_flg(flgid: ID, setptn: FLGPTN) -> ER;
#[link_name = "__asp3_clr_flg"]
pub fn clr_flg(flgid: ID, clrptn: FLGPTN) -> ER;
#[link_name = "__asp3_wai_flg"]
pub fn wai_flg(flgid: ID, waiptn: FLGPTN, wfmode: MODE, p_flgptn: *mut FLGPTN) -> ER;
#[link_name = "__asp3_twai_flg"]
pub fn twai_flg(
flgid: ID,
waiptn: FLGPTN,
wfmode: MODE,
p_flgptn: *mut FLGPTN,
tmout: TMO,
) -> ER;
#[link_name = "__asp3_acre_mtx"]
pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID;
#[link_name = "__asp3_del_mtx"]
Expand Down
72 changes: 72 additions & 0 deletions library/std/src/sys/itron/wait_flag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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");
}
}
2 changes: 2 additions & 0 deletions library/std/src/sys/solid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod itron {
pub mod thread;
pub(super) mod time;
use super::unsupported;
pub mod wait_flag;
}

pub mod alloc;
Expand Down Expand Up @@ -43,6 +44,7 @@ pub mod memchr;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;
pub use self::itron::wait_flag;

mod rwlock;

Expand Down
7 changes: 4 additions & 3 deletions library/std/src/sys_common/thread_parker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ cfg_if::cfg_if! {
))] {
mod futex;
pub use futex::Parker;
} else if #[cfg(windows)] {
pub use crate::sys::thread_parker::Parker;
} else if #[cfg(target_family = "unix")] {
} else if #[cfg(target_os = "solid_asp3")] {
mod wait_flag;
pub use wait_flag::Parker;
} else if #[cfg(any(windows, target_family = "unix"))] {
pub use crate::sys::thread_parker::Parker;
} else {
mod generic;
Expand Down
102 changes: 102 additions & 0 deletions library/std/src/sys_common/thread_parker/wait_flag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! A wait-flag-based thread parker.
//!
//! Some operating systems provide low-level parking primitives like wait counts,
//! event flags or semaphores which are not susceptible to race conditions (meaning
//! the wakeup can occur before the wait operation). To implement the `std` thread
//! parker on top of these primitives, we only have to ensure that parking is fast
//! when the thread token is available, the atomic ordering guarantees are maintained
//! and spurious wakeups are minimized.
//!
//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`,
//! `PARKED` and `NOTIFIED`:
//! * `EMPTY` means the token has not been made available, but the thread is not
//! currently waiting on it.
//! * `PARKED` means the token is not available and the thread is parked.
//! * `NOTIFIED` means the token is available.
//!
//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from
//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and
//! execution can continue without calling into the OS. If the state was `EMPTY`,
//! the token is not available and the thread waits on the primitive (here called
//! "wait flag").
//!
//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread
//! is or will be sleeping on the wait flag, so we raise it.

use crate::pin::Pin;
use crate::sync::atomic::AtomicI8;
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use crate::sys::wait_flag::WaitFlag;
use crate::time::Duration;

const EMPTY: i8 = 0;
const PARKED: i8 = -1;
const NOTIFIED: i8 = 1;

pub struct Parker {
state: AtomicI8,
wait_flag: WaitFlag,
}

impl Parker {
/// Construct a parker for the current thread. The UNIX parker
/// implementation requires this to happen in-place.
pub unsafe fn new(parker: *mut Parker) {
parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() })
}

// This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
pub unsafe fn park(self: Pin<&Self>) {
match self.state.fetch_sub(1, Acquire) {
// NOTIFIED => EMPTY
NOTIFIED => return,
// EMPTY => PARKED
EMPTY => (),
_ => panic!("inconsistent park state"),
}

// Avoid waking up from spurious wakeups (these are quite likely, see below).
loop {
self.wait_flag.wait();

match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
Ok(_) => return,
Err(PARKED) => (),
Err(_) => panic!("inconsistent park state"),
}
}
}

// This implementation doesn't require `unsafe` and `Pin`, but other implementations do.
pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) {
match self.state.fetch_sub(1, Acquire) {
NOTIFIED => return,
EMPTY => (),
_ => panic!("inconsistent park state"),
}

self.wait_flag.wait_timeout(dur);

// Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be
// a race condition when `unpark` is performed between receiving the timeout and
// resetting the state, resulting in the eventflag being set unnecessarily. `park`
// is protected against this by looping until the token is actually given, but
// here we cannot easily tell.

// Use `swap` to provide acquire ordering.
match self.state.swap(EMPTY, Acquire) {
NOTIFIED => (),
PARKED => (),
_ => panic!("inconsistent park state"),
}
}

// This implementation doesn't require `Pin`, but other implementations do.
pub fn unpark(self: Pin<&Self>) {
let state = self.state.swap(NOTIFIED, Release);

if state == PARKED {
self.wait_flag.raise();
}
}
}