Changeset 864d3475 in rtems


Ignore:
Timestamp:
Dec 17, 2014, 2:11:00 PM (5 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, master
Children:
8ce00eaf
Parents:
481054e0
git-author:
Sebastian Huber <sebastian.huber@…> (12/17/14 14:11:00)
git-committer:
Sebastian Huber <sebastian.huber@…> (12/18/14 07:33:29)
Message:

smp: Fix timeout for MrsP semaphores

The previous timeout handling was flawed. In case a waiting thread
helped out the owner could use the scheduler node indefinitely long.
Update the resource tree in _MRSP_Timeout() to avoid this issue.

Bug reported by Luca Bonato.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • cpukit/score/include/rtems/score/mrsp.h

    r481054e0 r864d3475  
    2020#if defined(RTEMS_SMP)
    2121
    22 #include <rtems/score/atomic.h>
    2322#include <rtems/score/chain.h>
     23#include <rtems/score/scheduler.h>
    2424#include <rtems/score/thread.h>
    2525
     
    6767  MRSP_INVALID_PRIORITY = 19,
    6868  MRSP_NOT_OWNER_OF_RESOURCE = 23,
    69   MRSP_NO_MEMORY = 26
     69  MRSP_NO_MEMORY = 26,
     70
     71  /**
     72   * @brief Internal state used for MRSP_Rival::status to indicate that this
     73   * rival waits for resource ownership.
     74   */
     75  MRSP_WAIT_FOR_OWNERSHIP = 255
    7076} MRSP_Status;
    7177
     
    8086   * @brief The node for registration in the MRSP rival chain.
    8187   *
     88   * The chain operations are protected by the Giant lock and disabled
     89   * interrupts.
     90   *
    8291   * @see MRSP_Control::Rivals.
    8392   */
     
    9099
    91100  /**
    92    * @brief The rival state.
     101   * @brief The initial priority of the thread at the begin of the resource
     102   * obtain sequence.
    93103   *
    94    * Initially no state bits are set (MRSP_RIVAL_STATE_WAITING).  The rival
    95    * will busy wait until a state change happens.  This can be
    96    * MRSP_RIVAL_STATE_NEW_OWNER or MRSP_RIVAL_STATE_TIMEOUT.
     104   * Used to restore the priority after a release of this resource or timeout.
    97105   */
    98   Atomic_Uint state;
     106  Priority_Control initial_priority;
     107
     108  /**
     109   * @brief The initial help state of the thread at the begin of the resource
     110   * obtain sequence.
     111   *
     112   * Used to restore this state after a timeout.
     113   */
     114  Scheduler_Help_state initial_help_state;
     115
     116  /**
     117   * @brief The rival status.
     118   *
     119   * Initially the status is set to MRSP_WAIT_FOR_OWNERSHIP.  The rival will
     120   * busy wait until a status change happens.  This can be MRSP_SUCCESSFUL or
     121   * MRSP_TIMEOUT.  State changes are protected by the Giant lock and disabled
     122   * interrupts.
     123   */
     124  volatile MRSP_Status status;
    99125} MRSP_Rival;
    100126
  • cpukit/score/include/rtems/score/mrspimpl.h

    r481054e0 r864d3475  
    3737 */
    3838
    39 #define MRSP_RIVAL_STATE_WAITING 0x0U
    40 
    41 #define MRSP_RIVAL_STATE_NEW_OWNER 0x1U
    42 
    43 #define MRSP_RIVAL_STATE_TIMEOUT 0x2U
    44 
    4539RTEMS_INLINE_ROUTINE void _MRSP_Elevate_priority(
    4640  MRSP_Control     *mrsp,
     
    5347
    5448RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority(
    55   const MRSP_Control *mrsp,
    56   Thread_Control     *thread,
    57   Priority_Control    initial_priority
     49  Thread_Control   *thread,
     50  Priority_Control  initial_priority
    5851)
    5952{
     
    135128}
    136129
    137 RTEMS_INLINE_ROUTINE void _MRSP_Add_state(
    138   MRSP_Rival   *rival,
    139   unsigned int  state
    140 )
    141 {
    142   _Atomic_Fetch_or_uint( &rival->state, state, ATOMIC_ORDER_RELEASE );
    143 }
    144 
    145130RTEMS_INLINE_ROUTINE void _MRSP_Timeout(
    146131  Objects_Id  id,
     
    149134{
    150135  MRSP_Rival *rival = arg;
     136  Thread_Control *thread = rival->thread;
     137  ISR_Level level;
    151138
    152139  (void) id;
    153140
    154   _MRSP_Add_state( rival, MRSP_RIVAL_STATE_TIMEOUT );
     141  _ISR_Disable( level );
     142
     143  if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
     144    _Chain_Extract_unprotected( &rival->Node );
     145
     146    _ISR_Enable( level );
     147
     148    rival->status = MRSP_TIMEOUT;
     149
     150    _Resource_Node_extract( &thread->Resource_node );
     151    _Resource_Node_set_dependency( &thread->Resource_node, NULL );
     152    _Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
     153    _Scheduler_Thread_change_resource_root( thread, thread );
     154    _MRSP_Restore_priority( thread, rival->initial_priority );
     155  } else {
     156    _ISR_Enable( level );
     157  }
    155158}
    156159
     
    166169  MRSP_Status status;
    167170  MRSP_Rival rival;
    168   bool previous_life_protection;
    169   unsigned int state;
    170   Scheduler_Help_state previous_help_state;
     171  bool initial_life_protection;
     172  ISR_Level level;
     173
     174  rival.thread = executing;
     175  rival.initial_priority = initial_priority;
     176  rival.initial_help_state =
     177    _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
     178  rival.status = MRSP_WAIT_FOR_OWNERSHIP;
    171179
    172180  _MRSP_Elevate_priority( mrsp, executing, ceiling_priority );
    173181
    174   rival.thread = executing;
    175   _Atomic_Init_uint( &rival.state, MRSP_RIVAL_STATE_WAITING );
     182  _ISR_Disable( level );
    176183  _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
     184  _ISR_Enable( level );
     185
    177186  _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
    178187  _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
    179   previous_help_state =
    180     _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
    181188
    182189  _Scheduler_Thread_change_resource_root(
     
    195202  }
    196203
    197   previous_life_protection = _Thread_Set_life_protection( true );
     204  initial_life_protection = _Thread_Set_life_protection( true );
    198205  _Thread_Enable_dispatch();
    199206
    200207  _Assert( _Debug_Is_thread_dispatching_allowed() );
    201208
    202   while (
    203     _Atomic_Load_uint( &rival.state, ATOMIC_ORDER_ACQUIRE )
    204       == MRSP_RIVAL_STATE_WAITING
    205   ) {
    206     /* Wait for state change */
    207   }
     209  /* Wait for state change */
     210  do {
     211    status = rival.status;
     212  } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
    208213
    209214  _Thread_Disable_dispatch();
    210   _Thread_Set_life_protection( previous_life_protection );
     215  _Thread_Set_life_protection( initial_life_protection );
    211216
    212217  if ( timeout > 0 ) {
    213218    _Watchdog_Remove( &executing->Timer );
    214   }
    215 
    216   _Chain_Extract_unprotected( &rival.Node );
    217   state = _Atomic_Load_uint( &rival.state, ATOMIC_ORDER_RELAXED );
    218 
    219   if ( ( state & MRSP_RIVAL_STATE_NEW_OWNER ) != 0 ) {
    220     mrsp->initial_priority_of_owner = initial_priority;
    221     status = MRSP_SUCCESSFUL;
    222   } else {
    223     _Resource_Node_extract( &executing->Resource_node );
    224     _Resource_Node_set_dependency( &executing->Resource_node, NULL );
    225     _Scheduler_Thread_change_help_state( executing, previous_help_state );
    226     _Scheduler_Thread_change_resource_root( executing, executing );
    227     _MRSP_Restore_priority( mrsp, executing, initial_priority );
    228 
    229     status = MRSP_TIMEOUT;
    230219  }
    231220
     
    290279)
    291280{
     281  ISR_Level level;
     282
    292283  if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
    293284    return MRSP_NOT_OWNER_OF_RESOURCE;
     
    304295
    305296  _Resource_Extract( &mrsp->Resource );
    306   _MRSP_Restore_priority( mrsp, executing, mrsp->initial_priority_of_owner );
     297  _MRSP_Restore_priority( executing, mrsp->initial_priority_of_owner );
     298
     299  _ISR_Disable( level );
    307300
    308301  if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
     302    _ISR_Enable( level );
     303
    309304    _Resource_Set_owner( &mrsp->Resource, NULL );
    310305  } else {
    311     MRSP_Rival *rival = (MRSP_Rival *) _Chain_First( &mrsp->Rivals );
    312     Thread_Control *new_owner = rival->thread;
    313 
     306    MRSP_Rival *rival = (MRSP_Rival *)
     307      _Chain_Get_first_unprotected( &mrsp->Rivals );
     308    Thread_Control *new_owner;
     309
     310    /*
     311     * This must be inside the critical section since the status prevents a
     312     * potential double extraction in _MRSP_Timeout().
     313     */
     314    rival->status = MRSP_SUCCESSFUL;
     315
     316    _ISR_Enable( level );
     317
     318    new_owner = rival->thread;
     319    mrsp->initial_priority_of_owner = rival->initial_priority;
    314320    _Resource_Node_extract( &new_owner->Resource_node );
    315321    _Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
     
    318324    _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
    319325    _Scheduler_Thread_change_resource_root( new_owner, new_owner );
    320     _MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER );
    321326  }
    322327
  • testsuites/smptests/smpmrsp01/init.c

    r481054e0 r864d3475  
    209209}
    210210
     211static void run_task(rtems_task_argument arg)
     212{
     213  volatile bool *run = (volatile bool *) arg;
     214
     215  while (true) {
     216    *run = true;
     217  }
     218}
     219
    211220static void obtain_and_release_worker(rtems_task_argument arg)
    212221{
     
    217226  ctx->worker_task = _Thread_Get_executing();
    218227
    219   assert_prio(RTEMS_SELF, 3);
     228  assert_prio(RTEMS_SELF, 4);
    220229
    221230  /* Obtain with timeout (A) */
     
    225234  rtems_test_assert(sc == RTEMS_TIMEOUT);
    226235
    227   assert_prio(RTEMS_SELF, 3);
     236  assert_prio(RTEMS_SELF, 4);
    228237
    229238  /* Obtain with priority change and timeout (B) */
     
    233242  rtems_test_assert(sc == RTEMS_TIMEOUT);
    234243
    235   assert_prio(RTEMS_SELF, 1);
     244  assert_prio(RTEMS_SELF, 2);
    236245
    237246  /* Restore priority (C) */
     
    244253  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    245254
    246   assert_prio(RTEMS_SELF, 2);
     255  assert_prio(RTEMS_SELF, 3);
    247256
    248257  sc = rtems_semaphore_release(ctx->mrsp_ids[0]);
    249258  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    250259
    251   assert_prio(RTEMS_SELF, 3);
    252 
    253   /* Worker done (E) */
     260  assert_prio(RTEMS_SELF, 4);
     261
     262  /* Obtain and help with timeout (E) */
     263  barrier(ctx, &barrier_state);
     264
     265  sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, 4);
     266  rtems_test_assert(sc == RTEMS_TIMEOUT);
     267
     268  assert_prio(RTEMS_SELF, 4);
     269
     270  sc = rtems_task_suspend(ctx->high_task_id[0]);
     271  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     272
     273  /* Worker done (H) */
    254274  barrier(ctx, &barrier_state);
    255275
     
    267287  puts("test MrsP obtain and release");
    268288
    269   change_prio(RTEMS_SELF, 2);
     289  change_prio(RTEMS_SELF, 3);
     290
     291  reset_switch_events(ctx);
     292
     293  ctx->high_run[0] = false;
     294
     295  sc = rtems_task_create(
     296    rtems_build_name('H', 'I', 'G', '0'),
     297    1,
     298    RTEMS_MINIMUM_STACK_SIZE,
     299    RTEMS_DEFAULT_MODES,
     300    RTEMS_DEFAULT_ATTRIBUTES,
     301    &ctx->high_task_id[0]
     302  );
     303  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    270304
    271305  /* Check executing task parameters */
     
    283317    RTEMS_MULTIPROCESSOR_RESOURCE_SHARING
    284318      | RTEMS_BINARY_SEMAPHORE,
    285     1,
     319    2,
    286320    &ctx->mrsp_ids[0]
    287321  );
    288322  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    289323
     324  assert_prio(RTEMS_SELF, 3);
     325
     326  sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     327  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     328
    290329  assert_prio(RTEMS_SELF, 2);
    291 
    292   sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    293   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    294 
    295   assert_prio(RTEMS_SELF, 1);
    296330
    297331  /*
     
    308342  );
    309343  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    310   rtems_test_assert(prio == 1);
     344  rtems_test_assert(prio == 2);
    311345
    312346  /* Check the old value and set a new ceiling priority for scheduler B */
    313347
    314   prio = 2;
     348  prio = 3;
    315349  sc = rtems_semaphore_set_priority(
    316350    ctx->mrsp_ids[0],
     
    320354  );
    321355  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    322   rtems_test_assert(prio == 1);
     356  rtems_test_assert(prio == 2);
    323357
    324358  /* Check the ceiling priority values */
     
    332366  );
    333367  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    334   rtems_test_assert(prio == 1);
     368  rtems_test_assert(prio == 2);
    335369
    336370  prio = RTEMS_CURRENT_PRIORITY;
     
    342376  );
    343377  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    344   rtems_test_assert(prio == 2);
     378  rtems_test_assert(prio == 3);
    345379
    346380  /* Check that a thread waiting to get ownership remains executing */
     
    348382  sc = rtems_task_create(
    349383    rtems_build_name('W', 'O', 'R', 'K'),
    350     3,
     384    4,
    351385    RTEMS_MINIMUM_STACK_SIZE,
    352386    RTEMS_DEFAULT_MODES,
     
    365399  barrier_and_delay(ctx, &barrier_state);
    366400
    367   assert_prio(ctx->worker_ids[0], 2);
     401  assert_prio(ctx->worker_ids[0], 3);
    368402  assert_executing_worker(ctx);
    369403
     
    371405  barrier_and_delay(ctx, &barrier_state);
    372406
    373   assert_prio(ctx->worker_ids[0], 2);
    374   change_prio(ctx->worker_ids[0], 1);
     407  assert_prio(ctx->worker_ids[0], 3);
     408  change_prio(ctx->worker_ids[0], 2);
    375409  assert_executing_worker(ctx);
    376410
     
    378412  barrier(ctx, &barrier_state);
    379413
    380   assert_prio(ctx->worker_ids[0], 1);
    381   change_prio(ctx->worker_ids[0], 3);
     414  assert_prio(ctx->worker_ids[0], 2);
     415  change_prio(ctx->worker_ids[0], 4);
    382416
    383417  /* Obtain without timeout (D) */
    384418  barrier_and_delay(ctx, &barrier_state);
    385419
    386   assert_prio(ctx->worker_ids[0], 2);
     420  assert_prio(ctx->worker_ids[0], 3);
    387421  assert_executing_worker(ctx);
    388422
     
    390424  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    391425
    392   /* Worker done (E) */
     426  /* Check that a timeout works in case the waiting thread actually helps */
     427
     428  sc = rtems_semaphore_obtain(ctx->mrsp_ids[0], RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     429  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     430
     431  /* Obtain and help with timeout (E) */
     432  barrier_and_delay(ctx, &barrier_state);
     433
     434  sc = rtems_task_start(
     435    ctx->high_task_id[0],
     436    run_task,
     437    (rtems_task_argument) &ctx->high_run[0]
     438  );
     439  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     440
     441  rtems_test_assert(rtems_get_current_processor() == 1);
     442
     443  while (rtems_get_current_processor() != 0) {
     444    /* Wait */
     445  }
     446
     447  rtems_test_assert(ctx->high_run[0]);
     448
     449  sc = rtems_semaphore_release(ctx->mrsp_ids[0]);
     450  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     451
     452  print_switch_events(ctx);
     453
     454  /* Worker done (H) */
    393455  barrier(ctx, &barrier_state);
    394456
    395457  sc = rtems_task_delete(ctx->worker_ids[0]);
     458  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     459
     460  sc = rtems_task_delete(ctx->high_task_id[0]);
    396461  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    397462
     
    726791  sc = rtems_semaphore_delete(sem_c_id);
    727792  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    728 }
    729 
    730 static void run_task(rtems_task_argument arg)
    731 {
    732   volatile bool *run = (volatile bool *) arg;
    733 
    734   while (true) {
    735     *run = true;
    736   }
    737793}
    738794
  • testsuites/smptests/smpmrsp01/smpmrsp01.scn

    r481054e0 r864d3475  
    4646[1] MAIN -> HELP (prio   2, node HELP)
    4747test MrsP obtain and release
     48[1] IDLE -> WORK (prio   4, node WORK)
     49[1] WORK -> MAIN (prio   3, node WORK)
     50[0] MAIN -> HIG0 (prio   1, node HIG0)
     51[1] MAIN -> WORK (prio   4, node WORK)
     52[0] HIG0 -> MAIN (prio   2, node MAIN)
    4853test MrsP load
    4954worker[0]
Note: See TracChangeset for help on using the changeset viewer.