Changeset 72857659 in rtems


Ignore:
Timestamp:
11/10/15 16:23:12 (8 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11
Children:
2d7aad73
Parents:
0c9bf40b
git-author:
Sebastian Huber <sebastian.huber@…> (11/10/15 16:23:12)
git-committer:
Sebastian Huber <sebastian.huber@…> (11/17/15 06:47:48)
Message:

score: Fix race condition on SMP

We must ensure that the Thread_Control::Wait information update is
visible to the target thread before we update its wait flags, otherwise
we may return out of date events or a wrong status.

Close #2471.

Location:
cpukit
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • cpukit/rtems/src/eventseize.c

    r0c9bf40b r72857659  
    101101  _Thread_Set_state( executing, block_state );
    102102
     103  /*
     104   * See _Event_Surrender() and _Thread_Timeout(), corresponding atomic
     105   * variable is Thread_Control::Wait::flags.
     106   */
     107  _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );
     108
    103109  success = _Thread_Wait_flags_try_change(
    104110    executing,
  • cpukit/rtems/src/eventsurrender.c

    r0c9bf40b r72857659  
    3535}
    3636
     37static bool _Event_Is_blocking_on_event(
     38  const Thread_Control *the_thread,
     39  Thread_Wait_flags     wait_class
     40)
     41{
     42  Thread_Wait_flags wait_flags;
     43  Thread_Wait_flags wait_mask;
     44
     45  wait_flags = _Thread_Wait_flags_get( the_thread );
     46  wait_mask = THREAD_WAIT_CLASS_MASK | THREAD_WAIT_STATE_READY_AGAIN;
     47
     48  return ( wait_flags & wait_mask ) == wait_class;
     49}
     50
    3751static bool _Event_Is_satisfied(
    3852  const Thread_Control *the_thread,
     
    6074)
    6175{
    62   rtems_event_set   pending_events;
    63   rtems_event_set   seized_events;
    64   Thread_Wait_flags wait_flags;
    65   bool              unblock;
     76  rtems_event_set pending_events;
     77  rtems_event_set seized_events;
     78  bool            unblock;
    6679
    6780  _Thread_Lock_acquire_default_critical( the_thread, lock_context );
     
    7083  pending_events = event->pending_events;
    7184
    72   wait_flags = _Thread_Wait_flags_get( the_thread );
    73 
    7485  if (
    75     ( wait_flags & THREAD_WAIT_CLASS_MASK ) == wait_class
     86    _Event_Is_blocking_on_event( the_thread, wait_class )
    7687      && _Event_Is_satisfied( the_thread, pending_events, &seized_events )
    7788  ) {
    78     Thread_Wait_flags intend_to_block;
    79     Thread_Wait_flags blocked;
    80     bool success;
     89    Thread_Wait_flags ready_again;
     90    bool              success;
    8191
    82     intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK;
    83     blocked = wait_class | THREAD_WAIT_STATE_BLOCKED;
     92    _Event_Satisfy( the_thread, event, pending_events, seized_events );
    8493
     94    /* See _Event_Seize() */
     95    _Atomic_Fence( ATOMIC_ORDER_RELEASE );
     96
     97    ready_again = wait_class | THREAD_WAIT_STATE_READY_AGAIN;
    8598    success = _Thread_Wait_flags_try_change_critical(
    8699      the_thread,
    87       intend_to_block,
    88       wait_class | THREAD_WAIT_STATE_READY_AGAIN
     100      wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK,
     101      ready_again
    89102    );
     103
    90104    if ( success ) {
    91       _Event_Satisfy( the_thread, event, pending_events, seized_events );
    92105      unblock = false;
    93     } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) {
    94       _Event_Satisfy( the_thread, event, pending_events, seized_events );
    95       _Thread_Wait_flags_set(
    96         the_thread,
    97         wait_class | THREAD_WAIT_STATE_READY_AGAIN
     106    } else {
     107      _Assert(
     108        _Thread_Wait_flags_get( the_thread )
     109          == wait_class | THREAD_WAIT_STATE_BLOCKED
    98110      );
     111      _Thread_Wait_flags_set( the_thread, ready_again );
    99112      unblock = true;
    100     } else {
    101       unblock = false;
    102113    }
    103114  } else {
  • cpukit/score/src/threadtimeout.c

    r0c9bf40b r72857659  
    4040  ISR_lock_Context   lock_context;
    4141  Thread_Wait_flags  wait_flags;
    42   Thread_Wait_flags  wait_class;
    43   Thread_Wait_flags  intend_to_block;
    44   Thread_Wait_flags  blocked;
    45   bool               success;
    4642  bool               unblock;
    4743
     
    5046
    5147  wait_flags = _Thread_Wait_flags_get( the_thread );
    52   wait_class = wait_flags & THREAD_WAIT_CLASS_MASK;
    53   intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK;
    54   blocked = wait_class | THREAD_WAIT_STATE_BLOCKED;
    55   success = _Thread_Wait_flags_try_change_critical(
    56     the_thread,
    57     intend_to_block,
    58     wait_class | THREAD_WAIT_STATE_READY_AGAIN
    59   );
    6048
    61   if ( success ) {
     49  if ( ( wait_flags & THREAD_WAIT_STATE_READY_AGAIN ) == 0 ) {
     50    Thread_Wait_flags wait_class;
     51    Thread_Wait_flags ready_again;
     52    bool              success;
     53
    6254    _Thread_Do_timeout( the_thread );
    63     unblock = false;
    64   } else if ( _Thread_Wait_flags_get( the_thread ) == blocked ) {
    65     _Thread_Wait_flags_set(
     55
     56    /*
     57     * This fence is only necessary for the events, see _Event_Seize().  The
     58     * thread queues use the thread lock for synchronization.
     59     */
     60    _Atomic_Fence( ATOMIC_ORDER_RELEASE );
     61
     62    wait_class = wait_flags & THREAD_WAIT_CLASS_MASK;
     63    ready_again = wait_class | THREAD_WAIT_STATE_READY_AGAIN;
     64    success = _Thread_Wait_flags_try_change_critical(
    6665      the_thread,
    67       wait_class | THREAD_WAIT_STATE_READY_AGAIN
     66      wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK,
     67      ready_again
    6868    );
    69     _Thread_Do_timeout( the_thread );
    70     unblock = true;
     69
     70    if ( success ) {
     71      unblock = false;
     72    } else {
     73      _Assert(
     74        _Thread_Wait_flags_get( the_thread )
     75          == wait_class | THREAD_WAIT_STATE_BLOCKED
     76      );
     77      _Thread_Wait_flags_set( the_thread, ready_again );
     78      unblock = true;
     79    }
    7180  } else {
    7281    unblock = false;
Note: See TracChangeset for help on using the changeset viewer.