Changeset f6142c19 in rtems


Ignore:
Timestamp:
Sep 9, 2016, 9:00:06 AM (3 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
4d3c866
Parents:
8123cae8
git-author:
Sebastian Huber <sebastian.huber@…> (09/09/16 09:00:06)
git-committer:
Sebastian Huber <sebastian.huber@…> (09/21/16 06:59:33)
Message:

score: Scheduler node awareness for thread queues

Maintain the priority of a thread for each scheduler instance via the
thread queue enqueue, extract, priority actions and surrender
operations. This replaces the primitive priority boosting.

Update #2556.

Files:
8 edited

Legend:

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

    r8123cae8 rf6142c19  
    210210#endif
    211211
     212#if defined(RTEMS_SMP)
     213#define SCHEDULER_NODE_OF_THREAD_WAIT_NODE( node ) \
     214  RTEMS_CONTAINER_OF( node, Scheduler_Node, Thread.Wait_node )
     215#endif
     216
    212217#ifdef __cplusplus
    213218}
  • cpukit/score/include/rtems/score/threadimpl.h

    r8123cae8 rf6142c19  
    993993#if defined(RTEMS_SMP)
    994994  return the_thread->Scheduler.own_node;
     995#else
     996  return the_thread->Scheduler.nodes;
     997#endif
     998}
     999
     1000RTEMS_INLINE_ROUTINE Scheduler_Node *_Thread_Scheduler_get_home_node(
     1001  const Thread_Control *the_thread
     1002)
     1003{
     1004#if defined(RTEMS_SMP)
     1005  _Assert( !_Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) );
     1006  return SCHEDULER_NODE_OF_THREAD_WAIT_NODE(
     1007    _Chain_First( &the_thread->Scheduler.Wait_nodes )
     1008  );
    9951009#else
    9961010  return the_thread->Scheduler.nodes;
     
    13091323
    13101324/**
    1311  * @brief Claims the thread wait queue and operations.
     1325 * @brief Claims the thread wait queue.
    13121326 *
    13131327 * The caller must not be the owner of the default thread wait lock.  The
    1314  * caller must be the owner of the corresponding thread queue lock.
     1328 * caller must be the owner of the corresponding thread queue lock.  The
     1329 * registration of the corresponding thread queue operations is deferred and
     1330 * done after the deadlock detection.  This is crucial to support timeouts on
     1331 * SMP configurations.
    13151332 *
    13161333 * @param[in] the_thread The thread.
    13171334 * @param[in] queue The new thread queue.
    1318  * @param[in] operations The new thread operations.
    1319  *
    1320  * @see _Thread_Wait_restore_default().
     1335 *
     1336 * @see _Thread_Wait_claim_finalize() and _Thread_Wait_restore_default().
    13211337 */
    13221338RTEMS_INLINE_ROUTINE void _Thread_Wait_claim(
    1323   Thread_Control                *the_thread,
    1324   Thread_queue_Queue            *queue,
    1325   const Thread_queue_Operations *operations
     1339  Thread_Control     *the_thread,
     1340  Thread_queue_Queue *queue
    13261341)
    13271342{
     
    13391354
    13401355  the_thread->Wait.queue = queue;
     1356
     1357  _Thread_Wait_release_default_critical( the_thread, &lock_context );
     1358}
     1359
     1360/**
     1361 * @brief Finalizes the thread wait queue claim via registration of the
     1362 * corresponding thread queue operations.
     1363 *
     1364 * @param[in] the_thread The thread.
     1365 * @param[in] operations The corresponding thread queue operations.
     1366 */
     1367RTEMS_INLINE_ROUTINE void _Thread_Wait_claim_finalize(
     1368  Thread_Control                *the_thread,
     1369  const Thread_queue_Operations *operations
     1370)
     1371{
    13411372  the_thread->Wait.operations = operations;
    1342 
    1343   _Thread_Wait_release_default_critical( the_thread, &lock_context );
    13441373}
    13451374
  • cpukit/score/include/rtems/score/threadq.h

    r8123cae8 rf6142c19  
    217217     */
    218218    Thread_queue_Link Start;
     219
     220    /**
     221     * @brief In case of a deadlock, a link for the first thread on the path
     222     * that tries to enqueue on a thread queue.
     223     */
     224    Thread_queue_Link Deadlock;
    219225  } Path;
    220226#endif
     
    346352#if defined(RTEMS_SMP)
    347353  /**
    348    * @brief Boost priority.
    349    */
    350   Priority_Node Boost_priority;
    351 
    352   /**
    353354   * @brief One priority queue per scheduler instance.
    354355   */
  • cpukit/score/include/rtems/score/threadqimpl.h

    r8123cae8 rf6142c19  
    281281  size_t i;
    282282
    283   _Priority_Node_initialize( &heads->Boost_priority, 0 );
    284   _Priority_Node_set_inactive( &heads->Boost_priority );
    285 
    286283  for ( i = 0; i < _Scheduler_Count; ++i ) {
    287284    _Chain_Initialize_node( &heads->Priority[ i ].Node );
    288285    _Priority_Initialize_empty( &heads->Priority[ i ].Queue );
     286    heads->Priority[ i ].Queue.scheduler = &_Scheduler_Table[ i ];
    289287  }
    290288#endif
     
    956954#endif
    957955
     956#if defined(RTEMS_SMP)
    958957bool _Thread_queue_Path_acquire_critical(
    959958  Thread_queue_Queue   *queue,
     
    965964  Thread_queue_Context *queue_context
    966965);
     966#endif
    967967
    968968/**
  • cpukit/score/src/threadchangepriority.c

    r8123cae8 rf6142c19  
    4545)
    4646{
     47  Scheduler_Node *scheduler_node;
     48  Thread_Control *the_thread;
     49
     50  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
     51  the_thread = arg;
     52
     53  _Chain_Append_unprotected(
     54    &the_thread->Scheduler.Wait_nodes,
     55    &scheduler_node->Thread.Wait_node
     56  );
    4757  _Thread_Set_scheduler_node_priority( priority_aggregation, false );
    4858  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_ADD );
     
    5666)
    5767{
     68  Scheduler_Node *scheduler_node;
     69
     70  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
     71
     72  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
    5873  _Thread_Set_scheduler_node_priority( priority_aggregation, true );
    5974  _Priority_Set_action_type( priority_aggregation, PRIORITY_ACTION_REMOVE );
     
    108123          _Thread_Priority_action_add,
    109124          _Thread_Priority_action_change,
    110           NULL
     125          the_thread
    111126        );
    112127#else
     
    158173  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
    159174    _Thread_queue_Context_add_priority_update( queue_context, the_thread );
     175
    160176    ( *operations->priority_actions )(
    161177      queue,
     
    170186)
    171187{
    172 #if defined(RTEMS_SMP)
    173   Thread_queue_Link *link;
    174 #endif
    175   Thread_Control    *the_thread;
    176   size_t             update_count;
     188  Thread_Control *the_thread;
     189  size_t          update_count;
    177190
    178191  _Assert( start_of_path != NULL );
    179192
    180 #if defined(RTEMS_SMP)
    181   link = &queue_context->Path.Start;
    182 #endif
     193  /*
     194   * This function is tricky on SMP configurations.  Please note that we do not
     195   * use the thread queue path available via the thread queue context.  Instead
     196   * we directly use the thread wait information to traverse the thread queue
     197   * path.  Thus, we do not necessarily acquire all thread queue locks on our
     198   * own.  In case of a deadlock, we use locks acquired by other processors
     199   * along the path.
     200   */
     201
    183202  the_thread = start_of_path;
    184203  update_count = _Thread_queue_Context_save_priority_updates( queue_context );
     
    187206    Thread_queue_Queue *queue;
    188207
    189 #if defined(RTEMS_SMP)
    190     _Assert( link->owner == the_thread );
    191     queue = link->Lock_context.Wait.queue;
    192 #else
    193208    queue = the_thread->Wait.queue;
    194 #endif
    195209
    196210    _Thread_Priority_do_perform_actions(
     
    209223    the_thread = queue->owner;
    210224    _Assert( the_thread != NULL );
    211 
    212 #if defined(RTEMS_SMP)
    213     link = THREAD_QUEUE_LINK_OF_PATH_NODE( _Chain_Next( &link->Path_node ) );
    214 #endif
    215225
    216226    /*
     
    256266
    257267  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     268#if defined(RTEMS_SMP)
    258269    _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
     270#endif
    259271    _Thread_Priority_perform_actions( queue->owner, queue_context );
     272#if defined(RTEMS_SMP)
    260273    _Thread_queue_Path_release_critical( queue_context );
     274#endif
    261275  }
    262276}
  • cpukit/score/src/threadqenqueue.c

    r8123cae8 rf6142c19  
    115115  ISR_lock_Context    lock_context;
    116116
     117  link->source = source;
     118  link->target = target;
     119
    117120  links = &_Thread_queue_Links;
    118121  recursive_target = target;
     
    137140  }
    138141
    139   link->source = source;
    140   link->target = target;
    141142  _RBTree_Insert_inline(
    142143    &links->Links,
     
    163164#endif
    164165
     166#if !defined(RTEMS_SMP)
     167static
     168#endif
    165169void _Thread_queue_Path_release_critical(
    166170  Thread_queue_Context *queue_context
     
    174178  node = _Chain_Last( &queue_context->Path.Links );
    175179
    176   if ( head != node ) {
     180  while ( head != node ) {
    177181    Thread_queue_Link *link;
    178182
    179     /*
    180      * The terminal link may have an owner which does not wait on a thread
    181      * queue.
    182      */
    183 
    184183    link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
    185184
    186     if ( link->Lock_context.Wait.queue == NULL ) {
    187       _Thread_Wait_release_default_critical(
    188         link->owner,
    189         &link->Lock_context.Lock_context
    190       );
    191 
    192       node = _Chain_Previous( node );
    193 #if defined(RTEMS_DEBUG)
    194       _Chain_Set_off_chain( &link->Path_node );
    195 #endif
    196     }
    197 
    198     while ( head != node ) {
    199       /* The other links have an owner which waits on a thread queue */
    200       link = THREAD_QUEUE_LINK_OF_PATH_NODE( node );
    201       _Assert( link->Lock_context.Wait.queue != NULL );
    202 
     185    if ( link->Lock_context.Wait.queue != NULL ) {
    203186      _Thread_queue_Link_remove( link );
    204187      _Thread_Wait_release_queue_critical(
     
    207190      );
    208191      _Thread_Wait_remove_request( link->owner, &link->Lock_context );
    209 
    210       node = _Chain_Previous( node );
     192    } else {
     193      _Thread_Wait_release_default_critical(
     194        link->owner,
     195        &link->Lock_context.Lock_context
     196      );
     197    }
     198
     199    node = _Chain_Previous( node );
    211200#if defined(RTEMS_DEBUG)
    212       _Chain_Set_off_chain( &link->Path_node );
    213 #endif
    214     }
     201    _Chain_Set_off_chain( &link->Path_node );
     202#endif
    215203  }
    216204#else
     
    219207}
    220208
     209#if defined(RTEMS_SMP)
     210static void _Thread_queue_Path_append_deadlock_thread(
     211  Thread_Control       *the_thread,
     212  Thread_queue_Context *queue_context
     213)
     214{
     215  Thread_Control *deadlock;
     216
     217  /*
     218   * In case of a deadlock, we must obtain the thread wait default lock for the
     219   * first thread on the path that tries to enqueue on a thread queue.  This
     220   * thread can be identified by the thread wait operations.  This lock acquire
     221   * is necessary for the timeout and explicit thread priority changes, see
     222   * _Thread_Priority_perform_actions().
     223   */
     224
     225  deadlock = NULL;
     226
     227  while ( the_thread->Wait.operations != &_Thread_queue_Operations_default ) {
     228    the_thread = the_thread->Wait.queue->owner;
     229    deadlock = the_thread;
     230  }
     231
     232  if ( deadlock != NULL ) {
     233    Thread_queue_Link *link;
     234
     235    link = &queue_context->Path.Deadlock;
     236    _Chain_Initialize_node( &link->Path_node );
     237    _Chain_Append_unprotected(
     238      &queue_context->Path.Links,
     239      &link->Path_node
     240    );
     241    link->owner = deadlock;
     242    link->Lock_context.Wait.queue = NULL;
     243    _Thread_Wait_acquire_default_critical(
     244      deadlock,
     245      &link->Lock_context.Lock_context
     246    );
     247  }
     248}
     249#endif
     250
     251#if !defined(RTEMS_SMP)
     252static
     253#endif
    221254bool _Thread_queue_Path_acquire_critical(
    222255  Thread_queue_Queue   *queue,
     
    250283  }
    251284
    252   _RBTree_Initialize_node( &queue_context->Path.Start.Registry_node );
    253   _Chain_Initialize_node( &queue_context->Path.Start.Path_node );
    254285  _Chain_Initialize_node(
    255286    &queue_context->Path.Start.Lock_context.Wait.Gate.Node
    256287  );
    257288  link = &queue_context->Path.Start;
     289  _RBTree_Initialize_node( &link->Registry_node );
     290  _Chain_Initialize_node( &link->Path_node );
    258291
    259292  do {
     
    294327      } else {
    295328        link->Lock_context.Wait.queue = NULL;
     329        _Thread_queue_Path_append_deadlock_thread( owner, queue_context );
    296330        return false;
    297331      }
     
    354388#endif
    355389
    356   _Thread_Wait_claim( the_thread, queue, operations );
     390  _Thread_Wait_claim( the_thread, queue );
    357391
    358392  if ( !_Thread_queue_Path_acquire_critical( queue, the_thread, queue_context ) ) {
     
    366400
    367401  _Thread_queue_Context_clear_priority_updates( queue_context );
     402  _Thread_Wait_claim_finalize( the_thread, operations );
    368403  ( *operations->enqueue )( queue, the_thread, queue_context );
    369404
  • cpukit/score/src/threadqops.c

    r8123cae8 rf6142c19  
    257257}
    258258
     259static size_t _Thread_queue_Scheduler_index(
     260  const Scheduler_Node *scheduler_node
     261)
     262{
     263#if defined(RTEMS_SMP)
     264  const Scheduler_Control *scheduler;
     265
     266  scheduler = _Priority_Get_scheduler( &scheduler_node->Wait.Priority );
     267  return _Scheduler_Get_index( scheduler );
     268#else
     269  (void) scheduler_node;
     270  return 0;
     271#endif
     272}
     273
     274static Thread_queue_Priority_queue *_Thread_queue_Priority_queue_by_index(
     275  Thread_queue_Heads *heads,
     276  size_t              scheduler_index
     277)
     278{
     279#if defined(RTEMS_SMP)
     280  return &heads->Priority[ scheduler_index ];
     281#else
     282  (void) scheduler_index;
     283  return &heads->Heads.Priority;
     284#endif
     285}
     286
    259287static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
    260288  Thread_queue_Heads   *heads,
     
    262290)
    263291{
    264 #if defined(RTEMS_SMP)
    265   const Scheduler_Control *scheduler;
    266 
    267   scheduler = _Priority_Get_scheduler( &scheduler_node->Wait.Priority );
    268   return &heads->Priority[ _Scheduler_Get_index( scheduler ) ];
     292  return _Thread_queue_Priority_queue_by_index(
     293    heads,
     294    _Thread_queue_Scheduler_index( scheduler_node )
     295  );
     296}
     297
     298static Chain_Node *_Thread_queue_Priority_queue_rotation(
     299  Thread_queue_Heads *heads
     300)
     301{
     302  Chain_Node *fifo_node;
     303
     304#if defined(RTEMS_SMP)
     305  /* Ensure FIFO order with respect to the priority queues */
     306  fifo_node = _Chain_First( &heads->Heads.Fifo );
     307  _Chain_Extract_unprotected( fifo_node );
     308  _Chain_Append_unprotected( &heads->Heads.Fifo, fifo_node );
    269309#else
    270   (void) scheduler_node;
    271   return &heads->Heads.Priority;
    272 #endif
    273 }
     310  (void) heads;
     311  fifo_node = NULL;
     312#endif
     313
     314  return fifo_node;
     315}
     316
     317#if defined(RTEMS_SMP)
     318static void _Thread_queue_Priority_queue_extract(
     319  Priority_Aggregation *priority_aggregation,
     320  Priority_Actions     *priority_actions,
     321  void                 *arg
     322)
     323{
     324  Thread_queue_Priority_queue *priority_queue;
     325
     326  (void) priority_actions;
     327  (void) arg;
     328
     329  priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
     330    priority_aggregation
     331  );
     332
     333  _Chain_Extract_unprotected( &priority_queue->Node );
     334}
     335#endif
    274336
    275337static void _Thread_queue_Priority_priority_actions(
     
    290352    Scheduler_Node              *scheduler_node;
    291353    Thread_queue_Priority_queue *priority_queue;
     354    Priority_Action_type         priority_action_type;
    292355
    293356    scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
    294357    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    295 
    296     _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
    297     _Priority_Plain_changed(
    298       &priority_queue->Queue,
    299       &scheduler_node->Wait.Priority.Node
    300     );
     358    priority_action_type = priority_aggregation->Action.type;
     359
     360    switch ( priority_action_type ) {
     361#if defined(RTEMS_SMP)
     362      case PRIORITY_ACTION_ADD:
     363        _Priority_Plain_insert(
     364          &priority_queue->Queue,
     365          &scheduler_node->Wait.Priority.Node,
     366          _Priority_Get_priority( &scheduler_node->Wait.Priority )
     367        );
     368        break;
     369      case PRIORITY_ACTION_REMOVE:
     370        _Priority_Plain_extract(
     371          &priority_queue->Queue,
     372          &scheduler_node->Wait.Priority.Node
     373        );
     374        break;
     375#endif
     376      default:
     377        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
     378        _Priority_Plain_changed(
     379          &priority_queue->Queue,
     380          &scheduler_node->Wait.Priority.Node
     381        );
     382        break;
     383    }
    301384
    302385    priority_aggregation = _Priority_Get_next_action( priority_aggregation );
     
    313396  Scheduler_Node              *scheduler_node;
    314397  Thread_queue_Priority_queue *priority_queue;
    315 
    316   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
     398#if defined(RTEMS_SMP)
     399  Chain_Node                  *wait_node;
     400  const Chain_Node            *wait_tail;
     401#endif
     402
     403  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
    317404  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    318 
    319 #if defined(RTEMS_SMP)
    320   _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
    321 #endif
    322405
    323406  _Priority_Initialize_one(
     
    325408    &scheduler_node->Wait.Priority.Node
    326409  );
     410
     411#if defined(RTEMS_SMP)
     412  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
     413
     414  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     415  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     416
     417  while ( wait_node != wait_tail ) {
     418    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     419    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
     420
     421    _Priority_Initialize_one(
     422      &priority_queue->Queue,
     423      &scheduler_node->Wait.Priority.Node
     424    );
     425    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
     426
     427    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     428  }
     429#endif
    327430}
    328431
     
    334437)
    335438{
     439#if defined(RTEMS_SMP)
     440  Chain_Node       *wait_node;
     441  const Chain_Node *wait_tail;
     442
     443  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
     444  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     445
     446  do {
     447    Scheduler_Node              *scheduler_node;
     448    Thread_queue_Priority_queue *priority_queue;
     449
     450    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     451    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
     452
     453    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
     454      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
     455      _Priority_Initialize_one(
     456        &priority_queue->Queue,
     457        &scheduler_node->Wait.Priority.Node
     458      );
     459    } else {
     460      _Priority_Plain_insert(
     461        &priority_queue->Queue,
     462        &scheduler_node->Wait.Priority.Node,
     463        _Priority_Get_priority( &scheduler_node->Wait.Priority )
     464      );
     465    }
     466
     467    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     468  } while ( wait_node != wait_tail );
     469#else
    336470  Scheduler_Node              *scheduler_node;
    337471  Thread_queue_Priority_queue *priority_queue;
    338472
    339   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
     473  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
    340474  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    341 
    342 #if defined(RTEMS_SMP)
    343   if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
    344     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
    345     _Priority_Initialize_one(
    346       &priority_queue->Queue,
    347       &scheduler_node->Wait.Priority.Node
    348     );
    349     return;
    350   }
    351 #endif
    352475
    353476  _Priority_Plain_insert(
     
    356479    _Priority_Get_priority( &scheduler_node->Wait.Priority )
    357480  );
     481#endif
    358482}
    359483
     
    366490)
    367491{
     492#if defined(RTEMS_SMP)
     493  Chain_Node       *wait_node;
     494  const Chain_Node *wait_tail;
     495
     496  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
     497  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     498
     499  do {
     500    Scheduler_Node              *scheduler_node;
     501    Thread_queue_Priority_queue *priority_queue;
     502
     503    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     504    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
     505
     506    _Priority_Plain_extract(
     507      &priority_queue->Queue,
     508      &scheduler_node->Wait.Priority.Node
     509    );
     510
     511    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
     512      _Chain_Extract_unprotected( &priority_queue->Node );
     513    }
     514
     515    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     516  } while ( wait_node != wait_tail );
     517#else
    368518  Scheduler_Node              *scheduler_node;
    369519  Thread_queue_Priority_queue *priority_queue;
    370520
    371   (void) current_or_previous_owner;
    372   (void) queue_context;
    373 
    374   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
     521  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
    375522  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    376523
     
    379526    &scheduler_node->Wait.Priority.Node
    380527  );
    381 
    382 #if defined(RTEMS_SMP)
    383   _Chain_Extract_unprotected( &priority_queue->Node );
    384 
    385   if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
    386     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
    387   }
    388 #endif
     528#endif
     529
     530  (void) current_or_previous_owner;
     531  (void) queue_context;
     532}
     533
     534static void _Thread_queue_Priority_do_surrender(
     535  Thread_queue_Queue   *queue,
     536  Thread_queue_Heads   *heads,
     537  Thread_Control       *current_or_previous_owner,
     538  Thread_queue_Context *queue_context,
     539  Thread_Control       *the_thread
     540)
     541{
     542  _Thread_queue_Priority_queue_rotation( heads );
     543  _Thread_queue_Priority_do_extract(
     544    queue,
     545    heads,
     546    current_or_previous_owner,
     547    queue_context,
     548    the_thread
     549  );
    389550}
    390551
     
    459620    queue_context,
    460621    first,
    461     _Thread_queue_Priority_do_extract
     622    _Thread_queue_Priority_do_surrender
    462623  );
    463624
     
    465626}
    466627
    467 static void _Thread_queue_Priority_inherit_do_actions_change(
     628static void _Thread_queue_Priority_inherit_do_priority_actions_action(
     629  Priority_Aggregation *priority_aggregation,
     630  Priority_Actions     *priority_actions,
     631  Scheduler_Node       *scheduler_node_of_owner,
     632  Priority_Action_type  priority_action_type
     633)
     634{
     635  _Priority_Set_action(
     636    &scheduler_node_of_owner->Wait.Priority,
     637    &priority_aggregation->Node,
     638    priority_action_type
     639  );
     640  _Priority_Actions_add(
     641    priority_actions,
     642    &scheduler_node_of_owner->Wait.Priority
     643  );
     644}
     645
     646#if defined(RTEMS_SMP)
     647static void _Thread_queue_Priority_inherit_do_priority_actions_add(
     648  Priority_Aggregation *priority_aggregation,
     649  Priority_Actions     *priority_actions,
     650  void                 *arg
     651)
     652{
     653  _Thread_queue_Priority_inherit_do_priority_actions_action(
     654    priority_aggregation,
     655    priority_actions,
     656    arg,
     657    PRIORITY_ACTION_ADD
     658  );
     659}
     660
     661static void _Thread_queue_Priority_inherit_do_priority_actions_remove(
     662  Priority_Aggregation *priority_aggregation,
     663  Priority_Actions     *priority_actions,
     664  void                 *arg
     665)
     666{
     667  _Thread_queue_Priority_queue_extract(
     668    priority_aggregation,
     669    priority_actions,
     670    arg
     671  );
     672  _Thread_queue_Priority_inherit_do_priority_actions_action(
     673    priority_aggregation,
     674    priority_actions,
     675    arg,
     676    PRIORITY_ACTION_REMOVE
     677  );
     678}
     679#endif
     680
     681static void _Thread_queue_Priority_inherit_do_priority_actions_change(
    468682  Priority_Aggregation *priority_aggregation,
    469683  bool                  prepend_it,
     
    472686)
    473687{
    474   Thread_queue_Priority_queue *priority_queue;
    475   Scheduler_Node              *scheduler_node;
    476 
    477   priority_queue = THREAD_QUEUE_PRIORITY_QUEUE_OF_PRIORITY_AGGREGATION(
    478     priority_aggregation
    479   );
    480   scheduler_node = priority_queue->scheduler_node;
    481 
    482   _Priority_Set_action(
    483     &scheduler_node->Wait.Priority,
    484     &priority_aggregation->Node,
     688  _Thread_queue_Priority_inherit_do_priority_actions_action(
     689    priority_aggregation,
     690    priority_actions,
     691    arg,
    485692    PRIORITY_ACTION_CHANGE
    486693  );
    487   _Priority_Actions_add( priority_actions, &scheduler_node->Wait.Priority );
    488694}
    489695
     
    494700{
    495701  Thread_queue_Heads   *heads;
     702  Thread_Control       *owner;
    496703  Priority_Aggregation *priority_aggregation;
    497704
    498705  heads = queue->heads;
    499706  _Assert( heads != NULL );
     707
     708  owner = queue->owner;
     709  _Assert( owner != NULL );
    500710
    501711  _Assert( !_Priority_Actions_is_empty( priority_actions ) );
     
    505715    Priority_Aggregation        *next_aggregation;
    506716    Scheduler_Node              *scheduler_node;
     717    size_t                       scheduler_index;
    507718    Thread_queue_Priority_queue *priority_queue;
     719    Scheduler_Node              *scheduler_node_of_owner;
     720    Priority_Action_type         priority_action_type;
    508721
    509722    next_aggregation = _Priority_Get_next_action( priority_aggregation );
    510723
    511724    scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
    512     priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    513 
    514     _Assert( priority_aggregation->Action.type == PRIORITY_ACTION_CHANGE );
    515     _Priority_Changed(
    516       &priority_queue->Queue,
    517       &scheduler_node->Wait.Priority.Node,
    518       false,
    519       priority_actions,
    520       _Thread_queue_Priority_inherit_do_actions_change,
    521       NULL
    522     );
     725    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
     726    priority_queue = _Thread_queue_Priority_queue_by_index(
     727      heads,
     728      scheduler_index
     729    );
     730    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
     731      owner,
     732      scheduler_index
     733    );
     734    priority_action_type = priority_aggregation->Action.type;
     735
     736    switch ( priority_action_type ) {
     737#if defined(RTEMS_SMP)
     738      case PRIORITY_ACTION_ADD:
     739        if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
     740          _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
     741          priority_queue->scheduler_node = scheduler_node_of_owner;
     742        }
     743
     744        _Priority_Insert(
     745          &priority_queue->Queue,
     746          &scheduler_node->Wait.Priority.Node,
     747          priority_actions,
     748          _Thread_queue_Priority_inherit_do_priority_actions_add,
     749          _Thread_queue_Priority_inherit_do_priority_actions_change,
     750          scheduler_node_of_owner
     751        );
     752        break;
     753      case PRIORITY_ACTION_REMOVE:
     754        _Priority_Extract(
     755          &priority_queue->Queue,
     756          &scheduler_node->Wait.Priority.Node,
     757          priority_actions,
     758          _Thread_queue_Priority_inherit_do_priority_actions_remove,
     759          _Thread_queue_Priority_inherit_do_priority_actions_change,
     760          scheduler_node_of_owner
     761        );
     762
     763        break;
     764#endif
     765      default:
     766        _Assert( priority_action_type == PRIORITY_ACTION_CHANGE );
     767        _Priority_Changed(
     768          &priority_queue->Queue,
     769          &scheduler_node->Wait.Priority.Node,
     770          false,
     771          priority_actions,
     772          _Thread_queue_Priority_inherit_do_priority_actions_change,
     773          scheduler_node_of_owner
     774        );
     775        break;
     776    }
    523777
    524778    priority_aggregation = next_aggregation;
    525779  } while ( _Priority_Actions_is_valid( priority_aggregation ) );
    526 }
    527 
    528 static void _Thread_queue_Boost_priority(
    529   Thread_queue_Heads   *heads,
    530   Thread_Control       *the_thread,
    531   Thread_Control       *owner,
    532   Thread_queue_Context *queue_context
    533 )
    534 {
    535 #if defined(RTEMS_SMP)
    536   const Scheduler_Control *scheduler;
    537   const Scheduler_Control *scheduler_of_owner;
    538   Scheduler_Node          *scheduler_node_of_owner;
    539   Priority_Control         boost_priority;
    540 
    541   if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
    542     return;
    543   }
    544 
    545   scheduler = _Scheduler_Get_own( the_thread );
    546   scheduler_of_owner = _Scheduler_Get_own( owner );
    547 
    548   if ( scheduler == scheduler_of_owner ) {
    549     return;
    550   }
    551 
    552   scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
    553 
    554   boost_priority = _Scheduler_Map_priority(
    555     scheduler_of_owner,
    556     PRIORITY_PSEUDO_ISR
    557   );
    558 
    559   _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
    560   _Priority_Actions_initialize_one(
    561     &queue_context->Priority.Actions,
    562     &scheduler_node_of_owner->Wait.Priority,
    563     &heads->Boost_priority,
    564     PRIORITY_ACTION_ADD
    565   );
    566   _Thread_Priority_perform_actions( owner, queue_context );
    567 #else
    568   (void) heads;
    569   (void) the_thread;
    570   (void) owner;
    571   (void) queue_context;
    572 #endif
    573780}
    574781
     
    581788{
    582789  Scheduler_Node              *scheduler_node;
     790  size_t                       scheduler_index;
    583791  Thread_queue_Priority_queue *priority_queue;
    584792  Thread_Control              *owner;
    585793  Scheduler_Node              *scheduler_node_of_owner;
    586 
    587   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
    588   priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    589 
    590 #if defined(RTEMS_SMP)
    591   _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
    592 #endif
    593 
     794#if defined(RTEMS_SMP)
     795  Chain_Node                  *wait_node;
     796  const Chain_Node            *wait_tail;
     797#endif
     798
     799  owner = queue->owner;
     800
     801  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
     802  scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
     803  priority_queue = _Thread_queue_Priority_queue_by_index(
     804    heads,
     805    scheduler_index
     806  );
     807  scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
     808    owner,
     809    scheduler_index
     810  );
     811
     812  priority_queue->scheduler_node = scheduler_node_of_owner;
    594813  _Priority_Initialize_one(
    595814    &priority_queue->Queue,
    596815    &scheduler_node->Wait.Priority.Node
    597816  );
    598 
    599   owner = queue->owner;
    600   scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
    601   priority_queue->scheduler_node = scheduler_node_of_owner;
    602 
    603817  _Priority_Actions_initialize_one(
    604818    &queue_context->Priority.Actions,
     
    607821    PRIORITY_ACTION_ADD
    608822  );
     823
     824#if defined(RTEMS_SMP)
     825  _Chain_Initialize_one( &heads->Heads.Fifo, &priority_queue->Node );
     826
     827  wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     828  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     829
     830  while ( wait_node != wait_tail ) {
     831    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     832    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
     833    priority_queue = _Thread_queue_Priority_queue_by_index(
     834      heads,
     835      scheduler_index
     836    );
     837    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
     838      owner,
     839      scheduler_index
     840    );
     841
     842    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
     843    priority_queue->scheduler_node = scheduler_node_of_owner;
     844    _Priority_Initialize_one(
     845      &priority_queue->Queue,
     846      &scheduler_node->Wait.Priority.Node
     847    );
     848    _Priority_Set_action(
     849      &scheduler_node_of_owner->Wait.Priority,
     850      &priority_queue->Queue.Node,
     851      PRIORITY_ACTION_ADD
     852    );
     853    _Priority_Actions_add(
     854      &queue_context->Priority.Actions,
     855      &scheduler_node_of_owner->Wait.Priority
     856    );
     857
     858    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     859  }
     860#endif
     861
    609862  _Thread_Priority_perform_actions( owner, queue_context );
    610   _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
    611863}
    612864
     
    618870)
    619871{
     872#if defined(RTEMS_SMP)
     873  Scheduler_Node *scheduler_node_of_owner;
     874
     875  scheduler_node_of_owner = arg;
     876
     877  _Priority_Set_action(
     878    &scheduler_node_of_owner->Wait.Priority,
     879    &priority_aggregation->Node,
     880    PRIORITY_ACTION_CHANGE
     881  );
     882  _Priority_Actions_add(
     883    priority_actions,
     884    &scheduler_node_of_owner->Wait.Priority
     885  );
     886#else
    620887  Thread_queue_Queue   *queue;
    621888  Thread_Control       *owner;
     
    635902  );
    636903  _Thread_Priority_perform_actions( owner, queue_context );
     904#endif
    637905}
    638906
     
    644912)
    645913{
     914#if defined(RTEMS_SMP)
     915  Thread_Control   *owner;
     916  Chain_Node       *wait_node;
     917  const Chain_Node *wait_tail;
     918
     919  owner = queue->owner;
     920  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
     921  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     922
     923  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
     924
     925  do {
     926    Scheduler_Node              *scheduler_node;
     927    size_t                       scheduler_index;
     928    Thread_queue_Priority_queue *priority_queue;
     929    Scheduler_Node              *scheduler_node_of_owner;
     930
     931    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     932    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
     933    priority_queue = _Thread_queue_Priority_queue_by_index(
     934      heads,
     935      scheduler_index
     936    );
     937    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
     938      owner,
     939      scheduler_index
     940    );
     941
     942    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
     943      _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
     944      priority_queue->scheduler_node = scheduler_node_of_owner;
     945      _Priority_Initialize_one(
     946        &priority_queue->Queue,
     947        &scheduler_node->Wait.Priority.Node
     948      );
     949      _Priority_Set_action(
     950        &scheduler_node_of_owner->Wait.Priority,
     951        &priority_queue->Queue.Node,
     952        PRIORITY_ACTION_ADD
     953      );
     954      _Priority_Actions_add(
     955        &queue_context->Priority.Actions,
     956        &scheduler_node_of_owner->Wait.Priority
     957      );
     958    } else {
     959      _Priority_Non_empty_insert(
     960        &priority_queue->Queue,
     961        &scheduler_node->Wait.Priority.Node,
     962        &queue_context->Priority.Actions,
     963        _Thread_queue_Priority_inherit_do_enqueue_change,
     964        scheduler_node_of_owner
     965      );
     966    }
     967
     968    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     969  } while ( wait_node != wait_tail );
     970
     971  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     972    _Thread_Priority_perform_actions( owner, queue_context );
     973  }
     974#else
    646975  Scheduler_Node              *scheduler_node;
    647976  Thread_queue_Priority_queue *priority_queue;
    648977
    649   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
     978  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
    650979  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    651 
    652 #if defined(RTEMS_SMP)
    653   if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
    654     Thread_Control *owner;
    655     Scheduler_Node *scheduler_node_of_owner;
    656 
    657     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
    658     _Priority_Initialize_one(
    659       &priority_queue->Queue,
    660       &scheduler_node->Wait.Priority.Node
    661     );
    662 
    663     owner = queue->owner;
    664     scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
    665     priority_queue->scheduler_node = scheduler_node_of_owner;
    666 
    667     _Priority_Actions_initialize_one(
    668       &queue_context->Priority.Actions,
    669       &scheduler_node_of_owner->Wait.Priority,
    670       &priority_queue->Queue.Node,
    671       PRIORITY_ACTION_ADD
    672     );
    673     _Thread_Priority_perform_actions( owner, queue_context );
    674     _Thread_queue_Boost_priority( heads, the_thread, owner, queue_context );
    675     return;
    676   }
    677 #endif
    678980
    679981  _Priority_Non_empty_insert(
     
    684986    queue
    685987  );
    686   _Thread_queue_Boost_priority(
    687     heads,
    688     the_thread,
    689     queue->owner,
    690     queue_context
    691   );
     988#endif
    692989}
    693990
     
    7091006static void _Thread_queue_Priority_inherit_do_extract_action(
    7101007  Priority_Actions     *priority_actions,
    711   Thread_Control       *owner,
    712   Priority_Node        *priority_action_node,
     1008  void                 *arg,
     1009  Priority_Aggregation *priority_aggregation,
    7131010  Priority_Action_type  priority_action_type
    7141011)
    7151012{
     1013#if defined(RTEMS_SMP)
     1014  Scheduler_Node *scheduler_node_of_owner;
     1015
     1016  scheduler_node_of_owner = arg;
     1017
     1018  _Priority_Set_action(
     1019    &scheduler_node_of_owner->Wait.Priority,
     1020    &priority_aggregation->Node,
     1021    priority_action_type
     1022  );
     1023  _Priority_Actions_add(
     1024    priority_actions,
     1025    &scheduler_node_of_owner->Wait.Priority
     1026  );
     1027#else
    7161028  Thread_queue_Context *queue_context;
     1029  Thread_Control       *owner;
    7171030  Scheduler_Node       *scheduler_node_of_owner;
    7181031
    7191032  queue_context = THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions );
    720   scheduler_node_of_owner = _Thread_Scheduler_get_own_node( owner );
     1033  owner = arg;
     1034  scheduler_node_of_owner = _Thread_Scheduler_get_home_node( owner );
    7211035
    7221036  _Priority_Actions_initialize_one(
    7231037    &queue_context->Priority.Actions,
    7241038    &scheduler_node_of_owner->Wait.Priority,
    725     priority_action_node,
     1039    &priority_aggregation->Node,
    7261040    priority_action_type
    7271041  );
    728   _Thread_Priority_perform_actions( owner, queue_context );
     1042  _Thread_Priority_perform_actions( arg, queue_context );
     1043#endif
    7291044}
    7301045
     
    7381053    priority_actions,
    7391054    arg,
    740     &priority_aggregation->Node,
     1055    priority_aggregation,
    7411056    PRIORITY_ACTION_REMOVE
    7421057  );
     
    7531068    priority_actions,
    7541069    arg,
    755     &priority_aggregation->Node,
     1070    priority_aggregation,
    7561071    PRIORITY_ACTION_CHANGE
    7571072  );
     
    7661081)
    7671082{
     1083#if defined(RTEMS_SMP)
     1084  Chain_Node                  *wait_node;
     1085  const Chain_Node            *wait_tail;
     1086#endif
    7681087  Scheduler_Node              *scheduler_node;
    7691088  Thread_queue_Priority_queue *priority_queue;
    7701089
    771   scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
     1090#if defined(RTEMS_SMP)
     1091  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
     1092  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     1093
     1094  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
     1095
     1096  do {
     1097    size_t          scheduler_index;
     1098    Scheduler_Node *scheduler_node_of_owner;
     1099
     1100    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     1101    scheduler_index = _Thread_queue_Scheduler_index( scheduler_node );
     1102    priority_queue = _Thread_queue_Priority_queue_by_index(
     1103      heads,
     1104      scheduler_index
     1105    );
     1106    scheduler_node_of_owner = _Thread_Scheduler_get_node_by_index(
     1107      owner,
     1108      scheduler_index
     1109    );
     1110
     1111    _Priority_Extract(
     1112      &priority_queue->Queue,
     1113      &scheduler_node->Wait.Priority.Node,
     1114      &queue_context->Priority.Actions,
     1115      _Thread_queue_Priority_inherit_do_extract_remove,
     1116      _Thread_queue_Priority_inherit_do_extract_change,
     1117      scheduler_node_of_owner
     1118    );
     1119
     1120    if ( _Priority_Is_empty( &priority_queue->Queue ) ) {
     1121      _Chain_Extract_unprotected( &priority_queue->Node );
     1122    }
     1123
     1124    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     1125  } while ( wait_node != wait_tail );
     1126
     1127  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     1128    _Thread_Priority_perform_actions( owner, queue_context );
     1129  }
     1130#else
     1131  scheduler_node = _Thread_Scheduler_get_home_node( the_thread );
    7721132  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    773 
    774   _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
    7751133
    7761134  _Priority_Extract(
     
    7821140    owner
    7831141  );
    784 
    785 #if defined(RTEMS_SMP)
    786   _Chain_Extract_unprotected( &priority_queue->Node );
    787 
    788   if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
    789     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
    790   }
    791 
    792   if (
    793     _Priority_Node_is_active( &heads->Boost_priority )
    794       && ( _Chain_Is_empty( &heads->Heads.Fifo )
    795         || _Chain_Has_only_one_node( &heads->Heads.Fifo ) )
    796   ) {
    797     _Thread_queue_Priority_inherit_do_extract_action(
    798       &queue_context->Priority.Actions,
    799       owner,
    800       &heads->Boost_priority,
    801       PRIORITY_ACTION_REMOVE
    802     );
    803     _Priority_Node_set_inactive( &heads->Boost_priority );
    804   }
    805 #endif
    806 
    807   _Thread_queue_Path_release_critical( queue_context );
     1142#endif
    8081143}
    8091144
     
    8141149)
    8151150{
     1151#if defined(RTEMS_SMP)
     1152  /*
     1153   * We must lock the thread wait path for the complete extract operation
     1154   * including the thread queue head management.  Consider the following
     1155   * scenario on three processors.  Thread T0 owns thread queue A, thread T1
     1156   * owns thread queue B and thread T2 owns thread queue C.  Thread T0 waits
     1157   * for B and thread T1 waits for C.
     1158   *
     1159   * A <-------------------------\
     1160   *  \                          |
     1161   *   > T0 -> B                 |
     1162   *            \                |
     1163   *             > T1 -> C       |
     1164   *                      \      |
     1165   *                       > T2 -/
     1166   *
     1167   * Now three things happen at the same time
     1168   *  - thread T0 times out,
     1169   *  - thread T1 times out,
     1170   *  - thread T2 tries to enqueue on a thread queue A.
     1171   *
     1172   * Thread T1 acquires thread queue lock C and waits for thread queue lock A.
     1173   * Thread T2 acquires thread queue lock A and waits for thread queue lock B.
     1174   * Thread T0 acquires thread queue lock B and detects a potential deadlock.
     1175   * Thread T0 carries out the thread queue extraction due to the timeout and
     1176   * uses the thread wait path segments acquired by thread T1 and T2.  This
     1177   * resolves the deadlock.  Thread T1 and T2 can the complete their
     1178   * operations.
     1179   */
     1180  _Thread_queue_Path_acquire_critical( queue, the_thread, queue_context );
     1181#endif
     1182
    8161183  _Thread_queue_Queue_extract(
    8171184    queue,
     
    8221189    _Thread_queue_Priority_inherit_do_extract
    8231190  );
    824 }
     1191
     1192#if defined(RTEMS_SMP)
     1193  _Thread_queue_Path_release_critical( queue_context );
     1194#endif
     1195}
     1196
     1197#if defined(RTEMS_SMP)
     1198static void _Thread_queue_Priority_inherit_do_surrender_add(
     1199  Priority_Aggregation *priority_aggregation,
     1200  Priority_Actions     *priority_actions,
     1201  void                 *arg
     1202)
     1203{
     1204  Scheduler_Node *scheduler_node;
     1205  Thread_Control *the_thread;
     1206
     1207  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
     1208  the_thread = arg;
     1209
     1210  _Chain_Append_unprotected(
     1211    &the_thread->Scheduler.Wait_nodes,
     1212    &scheduler_node->Thread.Wait_node
     1213  );
     1214  _Scheduler_Node_set_priority(
     1215    scheduler_node,
     1216    _Priority_Get_priority( priority_aggregation ),
     1217    false
     1218  );
     1219}
     1220
     1221static void _Thread_queue_Priority_inherit_do_surrender_remove(
     1222  Priority_Aggregation *priority_aggregation,
     1223  Priority_Actions     *priority_actions,
     1224  void                 *arg
     1225)
     1226{
     1227  Scheduler_Node *scheduler_node;
     1228
     1229  scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation );
     1230
     1231  _Priority_Actions_add( priority_actions, priority_aggregation );
     1232  _Chain_Extract_unprotected( &scheduler_node->Thread.Wait_node );
     1233}
     1234#endif
    8251235
    8261236static void _Thread_queue_Priority_inherit_do_surrender_change(
     
    8311241)
    8321242{
     1243#if defined(RTEMS_SMP)
     1244  _Priority_Actions_add( priority_actions, priority_aggregation );
     1245#else
    8331246  _Thread_queue_Context_add_priority_update(
    8341247    THREAD_QUEUE_CONTEXT_OF_PRIORITY_ACTIONS( priority_actions ),
    8351248    arg
    8361249  );
     1250#endif
    8371251  _Scheduler_Node_set_priority(
    8381252    SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
     
    8421256}
    8431257
    844 static void _Thread_queue_Priority_add(
    845   Thread_Control       *the_thread,
     1258static void _Thread_queue_Priority_inherit_do_surrender_change_2(
    8461259  Priority_Aggregation *priority_aggregation,
    847   Priority_Node        *priority_node,
    848   Thread_queue_Context *queue_context
    849 )
    850 {
    851   _Priority_Non_empty_insert(
    852     priority_aggregation,
    853     priority_node,
    854     &queue_context->Priority.Actions,
    855     _Thread_queue_Priority_inherit_do_surrender_change,
    856     the_thread
    857   );
    858 }
    859 
    860 static void _Thread_queue_Priority_remove(
    861   Thread_Control       *the_thread,
    862   Scheduler_Node       *scheduler_node,
    863   Priority_Node        *priority_node,
    864   Thread_queue_Context *queue_context
    865 )
    866 {
    867   _Priority_Extract_non_empty(
    868     &scheduler_node->Wait.Priority,
    869     priority_node,
    870     &queue_context->Priority.Actions,
    871     _Thread_queue_Priority_inherit_do_surrender_change,
    872     the_thread
     1260  bool                  prepend_it,
     1261  Priority_Actions     *priority_actions,
     1262  void                 *arg
     1263)
     1264{
     1265  _Scheduler_Node_set_priority(
     1266    SCHEDULER_NODE_OF_WAIT_PRIORITY( priority_aggregation ),
     1267    _Priority_Get_priority( priority_aggregation ),
     1268    prepend_it
    8731269  );
    8741270}
     
    8821278)
    8831279{
     1280#if defined(RTEMS_SMP)
     1281  Chain_Node                  *fifo_node;
     1282  const Chain_Node            *fifo_head;
     1283  const Chain_Node            *fifo_tail;
     1284  Chain_Node                  *wait_node;
     1285  const Chain_Node            *wait_tail;
     1286  ISR_lock_Context             lock_context;
     1287#endif
    8841288  Scheduler_Node              *scheduler_node;
    8851289  Thread_queue_Priority_queue *priority_queue;
    886   ISR_lock_Context             lock_context;
    887 
     1290  Scheduler_Node              *scheduler_node_of_owner;
     1291
     1292#if defined(RTEMS_SMP)
     1293  /*
     1294   * Remove the priority node of each priority queue from the previous owner.
     1295   * If a priority changes due to this, then register it for a priority update.
     1296   */
     1297
     1298  fifo_node = _Thread_queue_Priority_queue_rotation( heads );
     1299  fifo_head = _Chain_Immutable_head( &heads->Heads.Fifo );
     1300
     1301  _Priority_Actions_initialize_empty( &queue_context->Priority.Actions );
     1302
     1303  _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
     1304
     1305  do {
     1306    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
     1307    scheduler_node_of_owner = priority_queue->scheduler_node;
     1308
     1309    _Assert( scheduler_node_of_owner->owner == previous_owner );
     1310
     1311    _Priority_Extract(
     1312      &scheduler_node_of_owner->Wait.Priority,
     1313      &priority_queue->Queue.Node,
     1314      &queue_context->Priority.Actions,
     1315      _Thread_queue_Priority_inherit_do_surrender_remove,
     1316      _Thread_queue_Priority_inherit_do_surrender_change,
     1317      NULL
     1318    );
     1319
     1320    fifo_node = _Chain_Previous( fifo_node );
     1321  } while ( fifo_node != fifo_head );
     1322
     1323  if ( !_Priority_Actions_is_empty( &queue_context->Priority.Actions ) ) {
     1324    /*
     1325     * The previous owner performs this surrender operation.  So, it is
     1326     * definitely not enqueued on a thread queue.  It is sufficient to notify
     1327     * the scheduler about a priority update.  There is no need for a
     1328     * _Thread_Priority_perform_actions().
     1329     */
     1330    _Thread_queue_Context_add_priority_update( queue_context, previous_owner );
     1331  }
     1332
     1333  _Thread_Wait_release_default_critical( previous_owner, &lock_context );
     1334
     1335  /*
     1336   * Remove the wait node of the new owner from the corresponding priority
     1337   * queue.
     1338   */
     1339
     1340  wait_node = _Chain_First( &the_thread->Scheduler.Wait_nodes );
     1341  wait_tail = _Chain_Immutable_tail( &the_thread->Scheduler.Wait_nodes );
     1342
     1343  do {
     1344    scheduler_node = SCHEDULER_NODE_OF_THREAD_WAIT_NODE( wait_node );
     1345    priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
     1346
     1347    _Priority_Extract(
     1348      &priority_queue->Queue,
     1349      &scheduler_node->Wait.Priority.Node,
     1350      NULL,
     1351      _Thread_queue_Priority_queue_extract,
     1352      _Priority_Change_nothing,
     1353      NULL
     1354    );
     1355
     1356    wait_node = _Chain_Next( &scheduler_node->Thread.Wait_node );
     1357  } while ( wait_node != wait_tail );
     1358
     1359  /* Add the priority node of the remaining priority queues to the new owner */
     1360
     1361  fifo_node = _Chain_First( &heads->Heads.Fifo );
     1362  fifo_tail = _Chain_Immutable_tail( &heads->Heads.Fifo );
     1363
     1364  while ( fifo_node != fifo_tail ) {
     1365    const Scheduler_Control *scheduler;
     1366
     1367    priority_queue = (Thread_queue_Priority_queue *) fifo_node;
     1368    scheduler = _Priority_Get_scheduler( &priority_queue->Queue );
     1369    scheduler_node = _Thread_Scheduler_get_node_by_index(
     1370      the_thread,
     1371      _Scheduler_Get_index( scheduler )
     1372    );
     1373
     1374    priority_queue->scheduler_node = scheduler_node;
     1375    _Priority_Insert(
     1376      &scheduler_node->Wait.Priority,
     1377      &priority_queue->Queue.Node,
     1378      &queue_context->Priority.Actions,
     1379      _Thread_queue_Priority_inherit_do_surrender_add,
     1380      _Thread_queue_Priority_inherit_do_surrender_change_2,
     1381      the_thread
     1382    );
     1383
     1384    fifo_node = _Chain_Next( fifo_node );
     1385  }
     1386#else
    8881387  scheduler_node = _Thread_Scheduler_get_own_node( the_thread );
    8891388  priority_queue = _Thread_queue_Priority_queue( heads, scheduler_node );
    890 
    891   _Thread_Wait_acquire_default_critical( previous_owner, &lock_context );
    892 
    893 #if defined(RTEMS_SMP)
    894   if ( _Priority_Node_is_active( &heads->Boost_priority ) ) {
    895     _Thread_queue_Priority_remove(
    896       previous_owner,
    897       _Thread_Scheduler_get_own_node( previous_owner ),
    898       &heads->Boost_priority,
    899       queue_context
    900     );
    901     _Priority_Node_set_inactive( &heads->Boost_priority );
    902   }
    903 #endif
    904 
    905   _Thread_queue_Priority_remove(
    906     previous_owner,
    907     priority_queue->scheduler_node,
     1389  scheduler_node_of_owner = priority_queue->scheduler_node;
     1390
     1391  _Priority_Extract_non_empty(
     1392    &scheduler_node_of_owner->Wait.Priority,
    9081393    &priority_queue->Queue.Node,
    909     queue_context
    910   );
    911 
    912   _Thread_Wait_release_default_critical( previous_owner, &lock_context );
    913 
     1394    &queue_context->Priority.Actions,
     1395    _Thread_queue_Priority_inherit_do_surrender_change,
     1396    previous_owner
     1397  );
    9141398  _Priority_Extract(
    9151399    &priority_queue->Queue,
     
    9181402    _Priority_Remove_nothing,
    9191403    _Priority_Change_nothing,
    920     previous_owner
     1404    NULL
    9211405  );
    9221406
    9231407  if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
    9241408    priority_queue->scheduler_node = scheduler_node;
    925     _Thread_queue_Priority_add(
    926       the_thread,
     1409    _Priority_Non_empty_insert(
    9271410      &scheduler_node->Wait.Priority,
    9281411      &priority_queue->Queue.Node,
    929       queue_context
    930     );
    931   }
    932 
    933 #if defined(RTEMS_SMP)
    934   _Chain_Extract_unprotected( &priority_queue->Node );
    935 
    936   if ( !_Priority_Is_empty( &priority_queue->Queue ) ) {
    937     _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
    938   }
    939 
    940   if (
    941     !_Chain_Is_empty( &heads->Heads.Fifo)
    942       && !_Chain_Has_only_one_node( &heads->Heads.Fifo)
    943   ) {
    944     Priority_Control boost_priority;
    945 
    946     boost_priority = _Scheduler_Map_priority(
    947       _Scheduler_Get_own( the_thread ),
    948       PRIORITY_PSEUDO_ISR
    949     );
    950     _Priority_Node_initialize( &heads->Boost_priority, boost_priority );
    951     _Thread_queue_Priority_add(
    952       the_thread,
    953       &scheduler_node->Wait.Priority,
    954       &heads->Boost_priority,
    955       queue_context
     1412      &queue_context->Priority.Actions,
     1413      _Thread_queue_Priority_inherit_do_surrender_change,
     1414      the_thread
    9561415    );
    9571416  }
  • testsuites/smptests/smpmutex01/init.c

    r8123cae8 rf6142c19  
    11/*
    2  * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
     2 * Copyright (c) 2015, 2016 embedded brains GmbH.  All rights reserved.
    33 *
    44 *  embedded brains GmbH
     
    2929#define TASK_COUNT 9
    3030
     31#define PRIO_NONE 0
     32
     33/* Value choosen for Qemu, 2 would be sufficient for real targets */
     34#define TIMEOUT_IN_TICKS 10
     35
    3136typedef enum {
    3237  REQ_WAKE_UP_MASTER = RTEMS_EVENT_0,
    3338  REQ_WAKE_UP_HELPER = RTEMS_EVENT_1,
    3439  REQ_MTX_OBTAIN = RTEMS_EVENT_2,
    35   REQ_MTX_RELEASE = RTEMS_EVENT_3
     40  REQ_MTX_OBTAIN_TIMEOUT = RTEMS_EVENT_3,
     41  REQ_MTX_RELEASE = RTEMS_EVENT_4,
     42  REQ_MTX_2_OBTAIN = RTEMS_EVENT_5,
     43  REQ_MTX_2_RELEASE = RTEMS_EVENT_6,
     44  REQ_SEM_OBTAIN_RELEASE = RTEMS_EVENT_7,
     45  REQ_SEM_RELEASE = RTEMS_EVENT_8
    3646} request_id;
    3747
     
    5161typedef struct {
    5262  rtems_id mtx;
     63  rtems_id mtx_2;
     64  rtems_id sem;
    5365  rtems_id tasks[TASK_COUNT];
    5466  int generation[TASK_COUNT];
     
    157169}
    158170
     171static void obtain_timeout(test_context *ctx)
     172{
     173  rtems_status_code sc;
     174
     175  sc = rtems_semaphore_obtain(ctx->mtx, RTEMS_WAIT, TIMEOUT_IN_TICKS);
     176  rtems_test_assert(sc == RTEMS_TIMEOUT);
     177}
     178
    159179static void release(test_context *ctx)
    160180{
     
    162182
    163183  sc = rtems_semaphore_release(ctx->mtx);
     184  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     185}
     186
     187static void obtain_2(test_context *ctx)
     188{
     189  rtems_status_code sc;
     190
     191  sc = rtems_semaphore_obtain(ctx->mtx_2, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     192  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     193}
     194
     195static void release_2(test_context *ctx)
     196{
     197  rtems_status_code sc;
     198
     199  sc = rtems_semaphore_release(ctx->mtx_2);
     200  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     201}
     202
     203static void sem_obtain(test_context *ctx)
     204{
     205  rtems_status_code sc;
     206
     207  sc = rtems_semaphore_obtain(ctx->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     208  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     209}
     210
     211static void sem_release(test_context *ctx)
     212{
     213  rtems_status_code sc;
     214
     215  sc = rtems_semaphore_release(ctx->sem);
     216  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     217}
     218
     219static void wait(void)
     220{
     221  rtems_status_code sc;
     222
     223  sc = rtems_task_wake_after(TIMEOUT_IN_TICKS + 1);
    164224  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    165225}
     
    200260}
    201261
     262static void assert_prio_by_scheduler(
     263  test_context *ctx,
     264  task_id id,
     265  rtems_name scheduler,
     266  rtems_task_priority expected
     267)
     268{
     269  rtems_task_priority actual;
     270  rtems_status_code sc;
     271  rtems_id scheduler_id;
     272
     273  sc = rtems_scheduler_ident(scheduler, &scheduler_id);
     274  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     275
     276  actual = PRIO_NONE;
     277  sc = rtems_task_get_priority(
     278    ctx->tasks[id],
     279    scheduler_id,
     280    &actual
     281  );
     282
     283  if (expected == PRIO_NONE) {
     284    rtems_test_assert(sc == RTEMS_NOT_DEFINED);
     285  } else {
     286    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     287  }
     288
     289  rtems_test_assert(actual == expected);
     290}
     291
    202292static void helper(rtems_task_argument arg)
    203293{
     
    206296  while (true) {
    207297    rtems_event_set events = wait_for_events();
    208     rtems_test_assert(events == REQ_WAKE_UP_HELPER);
    209     send_event(ctx, M, REQ_WAKE_UP_MASTER);
     298
     299    if ((events & REQ_WAKE_UP_HELPER) != 0) {
     300      send_event(ctx, M, REQ_WAKE_UP_MASTER);
     301    }
     302
     303    if ((events & REQ_SEM_RELEASE) != 0) {
     304      sem_release(ctx);
     305    }
    210306  }
    211307}
     
    224320    }
    225321
     322    if ((events & REQ_MTX_OBTAIN_TIMEOUT) != 0) {
     323      obtain_timeout(ctx);
     324      ++ctx->generation[id];
     325    }
     326
    226327    if ((events & REQ_MTX_RELEASE) != 0) {
    227328      release(ctx);
    228329      ++ctx->generation[id];
     330    }
     331
     332    if ((events & REQ_MTX_2_OBTAIN) != 0) {
     333      obtain_2(ctx);
     334      ++ctx->generation[id];
     335    }
     336
     337    if ((events & REQ_MTX_2_RELEASE) != 0) {
     338      release_2(ctx);
     339      ++ctx->generation[id];
     340    }
     341
     342    if ((events & REQ_SEM_OBTAIN_RELEASE) != 0) {
     343      sem_obtain(ctx);
     344      ++ctx->generation[id];
     345      sem_release(ctx);
    229346    }
    230347  }
     
    246363
    247364  sc = rtems_semaphore_create(
    248     rtems_build_name(' ', 'M', 'T', 'X'),
     365    rtems_build_name('M', 'T', 'X', '1'),
    249366    1,
    250367    RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
    251368    0,
    252369    &ctx->mtx
     370  );
     371  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     372
     373  sc = rtems_semaphore_create(
     374    rtems_build_name('M', 'T', 'X', '2'),
     375    1,
     376    RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
     377    0,
     378    &ctx->mtx_2
     379  );
     380  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     381
     382  sc = rtems_semaphore_create(
     383    rtems_build_name(' ', 'S', 'E', 'M'),
     384    0,
     385    RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,
     386    0,
     387    &ctx->sem
    253388  );
    254389  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     
    288423}
    289424
    290 static void test_simple_boosting(test_context *ctx)
     425static void test_mixed_queue_two_scheduler_instances(test_context *ctx)
    291426{
    292427  obtain(ctx);
     428  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     429  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     430
     431  request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
     432  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     433  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     434  check_generations(ctx, NONE, NONE);
     435  wait();
     436  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     437  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     438  check_generations(ctx, B_4, NONE);
     439
     440  request(ctx, B_4, REQ_MTX_OBTAIN);
     441  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     442  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     443  check_generations(ctx, NONE, NONE);
     444
     445  request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
     446  send_event(ctx, H_A, REQ_SEM_RELEASE);
     447  check_generations(ctx, NONE, NONE);
     448
     449  /*
     450   * We are in scheduler instance A.  Task B_5_0 of scheduler instance B issued
     451   * the counting semaphore obtain before us.  However, we inherited the
     452   * priority of B_4, so we get the semaphore before B_5_0 (priority order
     453   * within scheduler instance B).
     454   */
     455  sem_obtain(ctx);
     456  check_generations(ctx, NONE, NONE);
     457
     458  release(ctx);
     459  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     460  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     461  sync_with_helper(ctx);
     462  check_generations(ctx, B_4, NONE);
     463
     464  request(ctx, B_4, REQ_MTX_RELEASE);
     465  check_generations(ctx, B_4, NONE);
     466
     467  sem_release(ctx);
     468  sync_with_helper(ctx);
     469  check_generations(ctx, B_5_0, NONE);
     470
     471  sem_obtain(ctx);
     472}
     473
     474static void test_mixed_queue_two_scheduler_instances_sem_only(test_context *ctx)
     475{
     476  request(ctx, B_5_0, REQ_SEM_OBTAIN_RELEASE);
     477  send_event(ctx, H_A, REQ_SEM_RELEASE);
     478  check_generations(ctx, NONE, NONE);
     479
     480  /*
     481   * We are in scheduler instance A.  Task B_5_0 of scheduler instance B issued
     482   * the counting semaphore obtain before us.  No priority inheritance is
     483   * involved, so task B_5_0 gets the counting semaphore first.
     484   */
     485  sem_obtain(ctx);
     486  check_generations(ctx, B_5_0, NONE);
     487
     488  sem_release(ctx);
     489}
     490
     491static void test_simple_inheritance_two_scheduler_instances(test_context *ctx)
     492{
     493  obtain(ctx);
     494  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     495  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     496
    293497  request(ctx, B_5_0, REQ_MTX_OBTAIN);
     498  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     499  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
     500
    294501  request(ctx, B_4, REQ_MTX_OBTAIN);
     502  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     503  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     504
    295505  request(ctx, B_5_1, REQ_MTX_OBTAIN);
    296   check_generations(ctx, NONE, NONE);
    297   assert_prio(ctx, M, 0);
     506  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     507  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     508  check_generations(ctx, NONE, NONE);
     509
     510  release(ctx);
     511  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     512  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     513  sync_with_helper(ctx);
     514  check_generations(ctx, B_4, NONE);
     515
     516  request(ctx, B_4, REQ_MTX_RELEASE);
     517  check_generations(ctx, B_4, B_5_0);
     518
     519  request(ctx, B_5_0, REQ_MTX_RELEASE);
     520  check_generations(ctx, B_5_0, B_5_1);
     521
     522  request(ctx, B_5_1, REQ_MTX_RELEASE);
     523  check_generations(ctx, B_5_1, NONE);
     524}
     525
     526static void test_nested_inheritance_two_scheduler_instances(test_context *ctx)
     527{
     528  obtain_2(ctx);
     529  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     530  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     531
     532  request(ctx, B_5_0, REQ_MTX_OBTAIN);
     533  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     534  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     535  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     536  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     537  check_generations(ctx, B_5_0, NONE);
     538
     539  request(ctx, B_5_0, REQ_MTX_2_OBTAIN);
     540  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     541  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
     542  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     543  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     544
     545  request(ctx, B_4, REQ_MTX_OBTAIN_TIMEOUT);
     546  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     547  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     548  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     549  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
     550  wait();
     551  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     552  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
     553  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     554  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     555  check_generations(ctx, B_4, NONE);
     556
     557  request(ctx, B_4, REQ_MTX_OBTAIN);
     558  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     559  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     560  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     561  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
     562
     563  request(ctx, B_5_1, REQ_MTX_2_OBTAIN);
     564  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     565  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     566  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     567  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
     568  check_generations(ctx, NONE, NONE);
     569
     570  release_2(ctx);
     571  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     572  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     573  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     574  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 4);
     575  sync_with_helper(ctx);
     576  check_generations(ctx, B_5_0, NONE);
     577
     578  request(ctx, B_5_0, REQ_MTX_RELEASE);
     579  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     580  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     581  check_generations(ctx, B_4, B_5_0);
     582
     583  request(ctx, B_4, REQ_MTX_RELEASE);
     584  check_generations(ctx, B_4, NONE);
     585
     586  request(ctx, B_5_0, REQ_MTX_2_RELEASE);
     587  check_generations(ctx, B_5_0, B_5_1);
     588
     589  request(ctx, B_5_1, REQ_MTX_2_RELEASE);
     590  check_generations(ctx, B_5_1, NONE);
     591}
     592
     593static void test_dequeue_order_two_scheduler_instances(test_context *ctx)
     594{
     595  obtain(ctx);
     596  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     597  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     598
     599  request(ctx, A_2_0, REQ_MTX_OBTAIN);
     600  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
     601  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     602  check_generations(ctx, NONE, NONE);
     603
     604  request(ctx, B_5_0, REQ_MTX_OBTAIN);
     605  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
     606  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
     607  check_generations(ctx, NONE, NONE);
     608
     609  request(ctx, B_5_1, REQ_MTX_OBTAIN);
     610  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
     611  assert_prio_by_scheduler(ctx, M, SCHED_B, 5);
     612
     613  request(ctx, B_4, REQ_MTX_OBTAIN);
     614  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
     615  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     616
     617  request(ctx, A_2_1, REQ_MTX_OBTAIN);
     618  assert_prio_by_scheduler(ctx, M, SCHED_A, 2);
     619  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     620
     621  request(ctx, A_1, REQ_MTX_OBTAIN);
     622  assert_prio_by_scheduler(ctx, M, SCHED_A, 1);
     623  assert_prio_by_scheduler(ctx, M, SCHED_B, 4);
     624  check_generations(ctx, NONE, NONE);
     625
    298626  release(ctx);
    299627  sync_with_helper(ctx);
    300   assert_prio(ctx, M, 3);
    301   check_generations(ctx, B_4, NONE);
     628  assert_prio_by_scheduler(ctx, M, SCHED_A, 3);
     629  assert_prio_by_scheduler(ctx, M, SCHED_B, PRIO_NONE);
     630  assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
     631  assert_prio_by_scheduler(ctx, A_1, SCHED_B, 4);
     632  check_generations(ctx, A_1, NONE);
     633
     634  request(ctx, A_1, REQ_MTX_RELEASE);
     635  assert_prio_by_scheduler(ctx, A_1, SCHED_A, 1);
     636  assert_prio_by_scheduler(ctx, A_1, SCHED_B, PRIO_NONE);
     637  assert_prio_by_scheduler(ctx, B_4, SCHED_A, 2);
     638  assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
     639  check_generations(ctx, A_1, B_4);
     640
    302641  request(ctx, B_4, REQ_MTX_RELEASE);
    303   check_generations(ctx, B_4, B_5_0);
     642  assert_prio_by_scheduler(ctx, B_4, SCHED_A, PRIO_NONE);
     643  assert_prio_by_scheduler(ctx, B_4, SCHED_B, 4);
     644  assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
     645  assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, 5);
     646  check_generations(ctx, B_4, A_2_0);
     647
     648  request(ctx, A_2_0, REQ_MTX_RELEASE);
     649  assert_prio_by_scheduler(ctx, A_2_0, SCHED_A, 2);
     650  assert_prio_by_scheduler(ctx, A_2_0, SCHED_B, PRIO_NONE);
     651  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, 2);
     652  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     653  check_generations(ctx, A_2_0, B_5_0);
     654
    304655  request(ctx, B_5_0, REQ_MTX_RELEASE);
    305   check_generations(ctx, B_5_0, B_5_1);
     656  assert_prio_by_scheduler(ctx, B_5_0, SCHED_A, PRIO_NONE);
     657  assert_prio_by_scheduler(ctx, B_5_0, SCHED_B, 5);
     658  assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
     659  assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, 5);
     660  check_generations(ctx, B_5_0, A_2_1);
     661
     662  request(ctx, A_2_1, REQ_MTX_RELEASE);
     663  assert_prio_by_scheduler(ctx, A_2_1, SCHED_A, 2);
     664  assert_prio_by_scheduler(ctx, A_2_1, SCHED_B, PRIO_NONE);
     665  assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
     666  assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
     667  check_generations(ctx, A_2_1, B_5_1);
     668
    306669  request(ctx, B_5_1, REQ_MTX_RELEASE);
     670  assert_prio_by_scheduler(ctx, B_5_1, SCHED_A, PRIO_NONE);
     671  assert_prio_by_scheduler(ctx, B_5_1, SCHED_B, 5);
    307672  check_generations(ctx, B_5_1, NONE);
    308 }
    309 
    310 static void test_dequeue_order_two_scheduler_instances(test_context *ctx)
    311 {
    312   obtain(ctx);
    313   request(ctx, A_2_0, REQ_MTX_OBTAIN);
    314   check_generations(ctx, NONE, NONE);
    315   assert_prio(ctx, M, 2);
    316   request(ctx, B_5_0, REQ_MTX_OBTAIN);
    317   check_generations(ctx, NONE, NONE);
    318   assert_prio(ctx, M, 0);
    319   request(ctx, B_5_1, REQ_MTX_OBTAIN);
    320   request(ctx, B_4, REQ_MTX_OBTAIN);
    321   request(ctx, A_2_1, REQ_MTX_OBTAIN);
    322   request(ctx, A_1, REQ_MTX_OBTAIN);
    323   check_generations(ctx, NONE, NONE);
    324   release(ctx);
    325   sync_with_helper(ctx);
    326   check_generations(ctx, A_1, NONE);
    327   assert_prio(ctx, M, 3);
    328   assert_prio(ctx, A_1, 0);
    329   request(ctx, A_1, REQ_MTX_RELEASE);
    330   check_generations(ctx, A_1, B_4);
    331   assert_prio(ctx, A_1, 1);
    332   assert_prio(ctx, B_4, 0);
    333   request(ctx, B_4, REQ_MTX_RELEASE);
    334   check_generations(ctx, B_4, A_2_0);
    335   assert_prio(ctx, B_4, 4);
    336   assert_prio(ctx, A_2_0, 0);
    337   request(ctx, A_2_0, REQ_MTX_RELEASE);
    338   check_generations(ctx, A_2_0, B_5_0);
    339   assert_prio(ctx, A_2_0, 2);
    340   assert_prio(ctx, B_5_0, 0);
    341   request(ctx, B_5_0, REQ_MTX_RELEASE);
    342   check_generations(ctx, B_5_0, A_2_1);
    343   assert_prio(ctx, B_5_0, 5);
    344   assert_prio(ctx, A_2_1, 2);
    345   request(ctx, A_2_1, REQ_MTX_RELEASE);
    346   check_generations(ctx, A_2_1, B_5_1);
    347   assert_prio(ctx, B_5_1, 5);
    348   request(ctx, B_5_1, REQ_MTX_RELEASE);
    349   check_generations(ctx, B_5_1, NONE);
    350   assert_prio(ctx, B_5_1, 5);
    351673}
    352674
     
    359681  test_simple_inheritance(ctx);
    360682  test_dequeue_order_one_scheduler_instance(ctx);
    361   test_simple_boosting(ctx);
     683  test_mixed_queue_two_scheduler_instances(ctx);
     684  test_mixed_queue_two_scheduler_instances_sem_only(ctx);
     685  test_simple_inheritance_two_scheduler_instances(ctx);
     686  test_nested_inheritance_two_scheduler_instances(ctx);
    362687  test_dequeue_order_two_scheduler_instances(ctx);
    363688}
     
    400725#define CONFIGURE_MAXIMUM_TASKS TASK_COUNT
    401726
    402 #define CONFIGURE_MAXIMUM_SEMAPHORES 1
     727#define CONFIGURE_MAXIMUM_SEMAPHORES 3
    403728
    404729#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
Note: See TracChangeset for help on using the changeset viewer.