mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 17:36:15 +08:00
score: Avoid atomic fences for thread wait flags
The use of atomic fences is brittle and may break due to changes in different areas which is hard to manage.
This commit is contained in:
@@ -91,13 +91,7 @@ rtems_status_code _Event_Seize(
|
||||
|
||||
_Thread_Set_state( executing, block_state );
|
||||
|
||||
/*
|
||||
* See _Event_Surrender() and _Thread_Timeout(), corresponding atomic
|
||||
* variable is Thread_Control::Wait::flags.
|
||||
*/
|
||||
_Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
|
||||
|
||||
success = _Thread_Wait_flags_try_change(
|
||||
success = _Thread_Wait_flags_try_change_acquire(
|
||||
executing,
|
||||
intend_to_block,
|
||||
wait_class | THREAD_WAIT_STATE_BLOCKED
|
||||
|
||||
@@ -91,11 +91,8 @@ rtems_status_code _Event_Surrender(
|
||||
|
||||
_Event_Satisfy( the_thread, event, pending_events, seized_events );
|
||||
|
||||
/* See _Event_Seize() */
|
||||
_Atomic_Fence( ATOMIC_ORDER_RELEASE );
|
||||
|
||||
ready_again = wait_class | THREAD_WAIT_STATE_READY_AGAIN;
|
||||
success = _Thread_Wait_flags_try_change_critical(
|
||||
success = _Thread_Wait_flags_try_change_release(
|
||||
the_thread,
|
||||
wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK,
|
||||
ready_again
|
||||
|
||||
@@ -221,7 +221,7 @@ static rtems_status_code _Rate_monotonic_Block_while_active(
|
||||
|
||||
_Thread_Set_state( executing, STATES_WAITING_FOR_PERIOD );
|
||||
|
||||
success = _Thread_Wait_flags_try_change(
|
||||
success = _Thread_Wait_flags_try_change_acquire(
|
||||
executing,
|
||||
RATE_MONOTONIC_INTEND_TO_BLOCK,
|
||||
RATE_MONOTONIC_BLOCKED
|
||||
|
||||
@@ -43,7 +43,7 @@ void _Rate_monotonic_Timeout( Watchdog_Control *the_watchdog )
|
||||
|
||||
owner->Wait.return_argument = NULL;
|
||||
|
||||
success = _Thread_Wait_flags_try_change_critical(
|
||||
success = _Thread_Wait_flags_try_change_release(
|
||||
owner,
|
||||
RATE_MONOTONIC_INTEND_TO_BLOCK,
|
||||
RATE_MONOTONIC_READY_AGAIN
|
||||
|
||||
@@ -1311,8 +1311,10 @@ RTEMS_INLINE_ROUTINE Thread_Wait_flags _Thread_Wait_flags_get(
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to change the thread wait flags inside a critical section
|
||||
* (interrupts disabled).
|
||||
* @brief Tries to change the thread wait flags with release semantics in case
|
||||
* of success.
|
||||
*
|
||||
* Must be called inside a critical section (interrupts disabled).
|
||||
*
|
||||
* In case the wait flags are equal to the expected wait flags, then the wait
|
||||
* flags are set to the desired wait flags.
|
||||
@@ -1324,22 +1326,24 @@ RTEMS_INLINE_ROUTINE Thread_Wait_flags _Thread_Wait_flags_get(
|
||||
* @retval true The wait flags were equal to the expected wait flags.
|
||||
* @retval false Otherwise.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_critical(
|
||||
RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_release(
|
||||
Thread_Control *the_thread,
|
||||
Thread_Wait_flags expected_flags,
|
||||
Thread_Wait_flags desired_flags
|
||||
)
|
||||
{
|
||||
_Assert( _ISR_Get_level() != 0 );
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
return _Atomic_Compare_exchange_uint(
|
||||
&the_thread->Wait.flags,
|
||||
&expected_flags,
|
||||
desired_flags,
|
||||
ATOMIC_ORDER_RELAXED,
|
||||
ATOMIC_ORDER_RELEASE,
|
||||
ATOMIC_ORDER_RELAXED
|
||||
);
|
||||
#else
|
||||
bool success = the_thread->Wait.flags == expected_flags;
|
||||
bool success = ( the_thread->Wait.flags == expected_flags );
|
||||
|
||||
if ( success ) {
|
||||
the_thread->Wait.flags = desired_flags;
|
||||
@@ -1350,30 +1354,44 @@ RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_critical(
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to change the thread wait flags.
|
||||
* @brief Tries to change the thread wait flags with acquire semantics.
|
||||
*
|
||||
* @see _Thread_Wait_flags_try_change_critical().
|
||||
* In case the wait flags are equal to the expected wait flags, then the wait
|
||||
* flags are set to the desired wait flags.
|
||||
*
|
||||
* @param[in] the_thread The thread.
|
||||
* @param[in] expected_flags The expected wait flags.
|
||||
* @param[in] desired_flags The desired wait flags.
|
||||
*
|
||||
* @retval true The wait flags were equal to the expected wait flags.
|
||||
* @retval false Otherwise.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change(
|
||||
RTEMS_INLINE_ROUTINE bool _Thread_Wait_flags_try_change_acquire(
|
||||
Thread_Control *the_thread,
|
||||
Thread_Wait_flags expected_flags,
|
||||
Thread_Wait_flags desired_flags
|
||||
)
|
||||
{
|
||||
bool success;
|
||||
#if !defined(RTEMS_SMP)
|
||||
#if defined(RTEMS_SMP)
|
||||
return _Atomic_Compare_exchange_uint(
|
||||
&the_thread->Wait.flags,
|
||||
&expected_flags,
|
||||
desired_flags,
|
||||
ATOMIC_ORDER_ACQUIRE,
|
||||
ATOMIC_ORDER_ACQUIRE
|
||||
);
|
||||
#else
|
||||
ISR_Level level;
|
||||
|
||||
_ISR_Local_disable( level );
|
||||
#endif
|
||||
|
||||
success = _Thread_Wait_flags_try_change_critical(
|
||||
success = _Thread_Wait_flags_try_change_release(
|
||||
the_thread,
|
||||
expected_flags,
|
||||
desired_flags
|
||||
);
|
||||
|
||||
#if !defined(RTEMS_SMP)
|
||||
_ISR_Local_enable( level );
|
||||
#endif
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ void _Thread_queue_Enqueue_critical(
|
||||
* as long as we are in the THREAD_QUEUE_INTEND_TO_BLOCK thread wait state,
|
||||
* thus we have to cancel the blocking operation ourself if necessary.
|
||||
*/
|
||||
success = _Thread_Wait_flags_try_change(
|
||||
success = _Thread_Wait_flags_try_change_acquire(
|
||||
the_thread,
|
||||
THREAD_QUEUE_INTEND_TO_BLOCK,
|
||||
THREAD_QUEUE_BLOCKED
|
||||
@@ -144,7 +144,7 @@ bool _Thread_queue_Do_extract_locked(
|
||||
* We must update the wait flags under protection of the current thread lock,
|
||||
* otherwise a _Thread_Timeout() running on another processor may interfere.
|
||||
*/
|
||||
success = _Thread_Wait_flags_try_change_critical(
|
||||
success = _Thread_Wait_flags_try_change_release(
|
||||
the_thread,
|
||||
THREAD_QUEUE_INTEND_TO_BLOCK,
|
||||
THREAD_QUEUE_READY_AGAIN
|
||||
|
||||
@@ -54,15 +54,9 @@ void _Thread_Timeout( Watchdog_Control *watchdog )
|
||||
|
||||
_Thread_Do_timeout( the_thread );
|
||||
|
||||
/*
|
||||
* This fence is only necessary for the events, see _Event_Seize(). The
|
||||
* thread queues use the thread lock for synchronization.
|
||||
*/
|
||||
_Atomic_Fence( ATOMIC_ORDER_RELEASE );
|
||||
|
||||
wait_class = wait_flags & THREAD_WAIT_CLASS_MASK;
|
||||
ready_again = wait_class | THREAD_WAIT_STATE_READY_AGAIN;
|
||||
success = _Thread_Wait_flags_try_change_critical(
|
||||
success = _Thread_Wait_flags_try_change_release(
|
||||
the_thread,
|
||||
wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK,
|
||||
ready_again
|
||||
|
||||
Reference in New Issue
Block a user