source: rtems/cpukit/score/src/threadqops.c @ 424ffe4d

5
Last change on this file since 424ffe4d was 424ffe4d, checked in by Sebastian Huber <sebastian.huber@…>, on 08/11/16 at 08:26:57

score: Introduce thread queue surrender operation

This is an optimization for _Thread_queue_Surrender(). It helps to
encapsulate the priority boosting in the priority inheritance thread
queue operations.

  • Property mode set to 100644
File size: 11.3 KB
RevLine 
[568af83]1/*
[ac8402dd]2 * Copyright (c) 2015, 2016 embedded brains GmbH.  All rights reserved.
[568af83]3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/score/threadimpl.h>
[d7665823]20#include <rtems/score/assert.h>
[383cf42]21#include <rtems/score/chainimpl.h>
[568af83]22#include <rtems/score/rbtreeimpl.h>
[3995e6d]23#include <rtems/score/schedulerimpl.h>
[568af83]24
[ff2e6c64]25static void _Thread_queue_Do_nothing_priority_change(
26  Thread_queue_Queue *queue,
[e2735012]27  Thread_Control     *the_thread,
[ff2e6c64]28  Priority_Control    new_priority
[568af83]29)
30{
[1fcac5ad]31  (void) queue;
[ff2e6c64]32  (void) the_thread;
33  (void) new_priority;
[568af83]34}
35
[383cf42]36static void _Thread_queue_Do_nothing_extract(
[e2735012]37  Thread_queue_Queue *queue,
[ff2e6c64]38  Thread_Control     *the_thread
[1fcac5ad]39)
40{
41  (void) queue;
[ff2e6c64]42  (void) the_thread;
[1fcac5ad]43}
44
[3a58dc8]45static Thread_queue_Heads *_Thread_queue_Queue_enqueue(
[d7665823]46  Thread_queue_Queue *queue,
47  Thread_Control     *the_thread,
48  void             ( *initialize )( Thread_queue_Heads * ),
49  void             ( *enqueue )( Thread_queue_Heads *, Thread_Control * )
[383cf42]50)
51{
[d7665823]52  Thread_queue_Heads *heads = queue->heads;
53  Thread_queue_Heads *spare_heads = the_thread->Wait.spare_heads;
54
55  the_thread->Wait.spare_heads = NULL;
56
57  if ( heads == NULL ) {
58    _Assert( spare_heads != NULL );
59    _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) );
60    heads = spare_heads;
61    queue->heads = heads;
62    ( *initialize )( heads );
63  }
64
65  _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
66
67  ( *enqueue )( heads, the_thread );
[3a58dc8]68
69  return heads;
[383cf42]70}
71
[d7665823]72static void _Thread_queue_Queue_extract(
[e2735012]73  Thread_queue_Queue *queue,
[424ffe4d]74  Thread_queue_Heads *heads,
[d7665823]75  Thread_Control     *the_thread,
76  void             ( *extract )( Thread_queue_Heads *, Thread_Control * )
77)
78{
79  _Assert( heads != NULL );
80
81  the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
82    _Chain_Get_first_unprotected( &heads->Free_chain ),
83    Thread_queue_Heads,
84    Free_node
85  );
86
87  if ( _Chain_Is_empty( &heads->Free_chain ) ) {
88    queue->heads = NULL;
89  }
90
91  ( *extract )( heads, the_thread );
92}
93
94static void _Thread_queue_FIFO_do_initialize(
95  Thread_queue_Heads *heads
96)
97{
98  _Chain_Initialize_empty( &heads->Heads.Fifo );
99}
100
101static void _Thread_queue_FIFO_do_enqueue(
102  Thread_queue_Heads *heads,
[e2735012]103  Thread_Control     *the_thread
[383cf42]104)
105{
[059529e]106  _Chain_Initialize_node( &the_thread->Wait.Node.Chain );
[383cf42]107  _Chain_Append_unprotected(
[d7665823]108    &heads->Heads.Fifo,
[383cf42]109    &the_thread->Wait.Node.Chain
110  );
111}
112
[d7665823]113static void _Thread_queue_FIFO_do_extract(
114  Thread_queue_Heads *heads,
115  Thread_Control     *the_thread
116)
117{
118  _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain );
119}
120
121static void _Thread_queue_FIFO_enqueue(
122  Thread_queue_Queue *queue,
[3a58dc8]123  Thread_Control     *the_thread,
124  Thread_queue_Path  *path
[d7665823]125)
126{
[3a58dc8]127  path->update_priority = NULL;
128
[d7665823]129  _Thread_queue_Queue_enqueue(
130    queue,
131    the_thread,
132    _Thread_queue_FIFO_do_initialize,
133    _Thread_queue_FIFO_do_enqueue
134  );
135}
136
[383cf42]137static void _Thread_queue_FIFO_extract(
[e2735012]138  Thread_queue_Queue *queue,
139  Thread_Control     *the_thread
[383cf42]140)
141{
[d7665823]142  _Thread_queue_Queue_extract(
143    queue,
[424ffe4d]144    queue->heads,
[d7665823]145    the_thread,
146    _Thread_queue_FIFO_do_extract
147  );
[383cf42]148}
149
150static Thread_Control *_Thread_queue_FIFO_first(
[d7665823]151  Thread_queue_Heads *heads
[383cf42]152)
153{
[d7665823]154  Chain_Control *fifo = &heads->Heads.Fifo;
[8c25e04]155  Chain_Node    *first;
[383cf42]156
[8c25e04]157  _Assert( !_Chain_Is_empty( fifo ) );
158  first = _Chain_First( fifo );
159
160  return THREAD_CHAIN_NODE_TO_THREAD( first );
[383cf42]161}
162
[424ffe4d]163static Thread_Control *_Thread_queue_FIFO_surrender(
164  Thread_queue_Queue *queue,
165  Thread_queue_Heads *heads,
166  Thread_Control     *previous_owner
167)
168{
169  Thread_Control *first;
170
171  first = _Thread_queue_FIFO_first( heads );
172  _Thread_queue_Queue_extract(
173    queue,
174    heads,
175    first,
176    _Thread_queue_FIFO_do_extract
177  );
178
179  return first;
180}
181
[3995e6d]182static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
183  Thread_queue_Heads   *heads,
184  const Thread_Control *the_thread
185)
186{
187#if defined(RTEMS_SMP)
188  return &heads->Priority[
189    _Scheduler_Get_index( _Scheduler_Get_own( the_thread ) )
190  ];
191#else
192  (void) the_thread;
193
194  return &heads->Heads.Priority;
195#endif
196}
197
[8a040fe4]198static bool _Thread_queue_Priority_less(
199  const void        *left,
200  const RBTree_Node *right
201)
202{
203  const Priority_Control *the_left;
204  const Thread_Control   *the_right;
205
206  the_left = left;
207  the_right = THREAD_RBTREE_NODE_TO_THREAD( right );
208
209  return *the_left < the_right->current_priority;
210}
211
[568af83]212static void _Thread_queue_Priority_priority_change(
[ff2e6c64]213  Thread_queue_Queue *queue,
[e2735012]214  Thread_Control     *the_thread,
[ff2e6c64]215  Priority_Control    new_priority
[383cf42]216)
217{
[3995e6d]218  Thread_queue_Heads          *heads = queue->heads;
219  Thread_queue_Priority_queue *priority_queue;
[d7665823]220
221  _Assert( heads != NULL );
222
[3995e6d]223  priority_queue = _Thread_queue_Priority_queue( heads, the_thread );
224
[383cf42]225  _RBTree_Extract(
[3995e6d]226    &priority_queue->Queue,
[383cf42]227    &the_thread->Wait.Node.RBTree
228  );
[8a040fe4]229  _RBTree_Insert_inline(
[3995e6d]230    &priority_queue->Queue,
[383cf42]231    &the_thread->Wait.Node.RBTree,
[8a040fe4]232    &new_priority,
233    _Thread_queue_Priority_less
[383cf42]234  );
235}
236
[d7665823]237static void _Thread_queue_Priority_do_initialize(
238  Thread_queue_Heads *heads
[383cf42]239)
240{
[3995e6d]241#if defined(RTEMS_SMP)
242  _Chain_Initialize_empty( &heads->Heads.Fifo );
243#else
[eab538c]244  _RBTree_Initialize_empty( &heads->Heads.Priority.Queue );
[3995e6d]245#endif
[383cf42]246}
247
[d7665823]248static void _Thread_queue_Priority_do_enqueue(
249  Thread_queue_Heads *heads,
[e2735012]250  Thread_Control     *the_thread
[568af83]251)
252{
[3995e6d]253  Thread_queue_Priority_queue *priority_queue =
254    _Thread_queue_Priority_queue( heads, the_thread );
[8a040fe4]255  Priority_Control current_priority;
[3995e6d]256
257#if defined(RTEMS_SMP)
258  if ( _RBTree_Is_empty( &priority_queue->Queue ) ) {
259    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
260  }
261#endif
262
[8a040fe4]263  current_priority = the_thread->current_priority;
[aaaf9610]264  _RBTree_Initialize_node( &the_thread->Wait.Node.RBTree );
[8a040fe4]265  _RBTree_Insert_inline(
[3995e6d]266    &priority_queue->Queue,
[383cf42]267    &the_thread->Wait.Node.RBTree,
[8a040fe4]268    &current_priority,
269    _Thread_queue_Priority_less
[568af83]270  );
271}
272
[d7665823]273static void _Thread_queue_Priority_do_extract(
274  Thread_queue_Heads *heads,
[e2735012]275  Thread_Control     *the_thread
[383cf42]276)
277{
[3995e6d]278  Thread_queue_Priority_queue *priority_queue =
279    _Thread_queue_Priority_queue( heads, the_thread );
280
[383cf42]281  _RBTree_Extract(
[3995e6d]282    &priority_queue->Queue,
[383cf42]283    &the_thread->Wait.Node.RBTree
284  );
[3995e6d]285
286#if defined(RTEMS_SMP)
287  _Chain_Extract_unprotected( &priority_queue->Node );
288
289  if ( !_RBTree_Is_empty( &priority_queue->Queue ) ) {
290    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
291  }
292#endif
[383cf42]293}
294
[d7665823]295static void _Thread_queue_Priority_enqueue(
296  Thread_queue_Queue *queue,
[3a58dc8]297  Thread_Control     *the_thread,
298  Thread_queue_Path  *path
[d7665823]299)
300{
[3a58dc8]301  path->update_priority = NULL;
302
[d7665823]303  _Thread_queue_Queue_enqueue(
304    queue,
305    the_thread,
306    _Thread_queue_Priority_do_initialize,
307    _Thread_queue_Priority_do_enqueue
308  );
309}
310
311static void _Thread_queue_Priority_extract(
312  Thread_queue_Queue *queue,
313  Thread_Control     *the_thread
314)
315{
316  _Thread_queue_Queue_extract(
317    queue,
[424ffe4d]318    queue->heads,
[d7665823]319    the_thread,
320    _Thread_queue_Priority_do_extract
321  );
322}
323
[383cf42]324static Thread_Control *_Thread_queue_Priority_first(
[d7665823]325  Thread_queue_Heads *heads
[383cf42]326)
327{
[3995e6d]328  Thread_queue_Priority_queue *priority_queue;
329  RBTree_Node                 *first;
330
331#if defined(RTEMS_SMP)
332  _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) );
333  priority_queue = (Thread_queue_Priority_queue *)
334    _Chain_First( &heads->Heads.Fifo );
335#else
336  priority_queue = &heads->Heads.Priority;
337#endif
[383cf42]338
[3995e6d]339  _Assert( !_RBTree_Is_empty( &priority_queue->Queue ) );
340  first = _RBTree_Minimum( &priority_queue->Queue );
[383cf42]341
[8c25e04]342  return THREAD_RBTREE_NODE_TO_THREAD( first );
[383cf42]343}
344
[424ffe4d]345static Thread_Control *_Thread_queue_Priority_surrender(
346  Thread_queue_Queue *queue,
347  Thread_queue_Heads *heads,
348  Thread_Control     *previous_owner
349)
350{
351  Thread_Control *first;
352
353  first = _Thread_queue_Priority_first( heads );
354  _Thread_queue_Queue_extract(
355    queue,
356    heads,
357    first,
358    _Thread_queue_Priority_do_extract
359  );
360
361  return first;
362}
363
[3a58dc8]364static void _Thread_queue_Priority_inherit_enqueue(
365  Thread_queue_Queue *queue,
366  Thread_Control     *the_thread,
367  Thread_queue_Path  *path
368)
369{
370  Thread_queue_Heads *heads;
371  Thread_Control     *owner;
372  Priority_Control    priority;
373
374  heads = _Thread_queue_Queue_enqueue(
375    queue,
376    the_thread,
377    _Thread_queue_Priority_do_initialize,
378    _Thread_queue_Priority_do_enqueue
379  );
380
381  owner = queue->owner;
382
383#if defined(RTEMS_SMP)
384  if ( _Chain_Has_only_one_node( &heads->Heads.Fifo ) ) {
385    priority = the_thread->current_priority;
386  } else {
387    priority = _Scheduler_Map_priority(
388      _Scheduler_Get_own( the_thread ),
389      PRIORITY_PSEUDO_ISR
390    );
391  }
392#else
393  (void) heads;
394
395  priority = the_thread->current_priority;
396#endif
397
398  if ( priority < owner->current_priority ) {
399    path->update_priority = owner;
400
401    owner->priority_restore_hint = true;
402    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
403
[ff2e6c64]404    _Scheduler_Thread_set_priority( owner, priority, false );
405
406    ( *owner->Wait.operations->priority_change )(
407      owner->Wait.queue,
[3a58dc8]408      owner,
[ff2e6c64]409      priority
[3a58dc8]410    );
411  } else {
412    path->update_priority = NULL;
413  }
414}
415
[424ffe4d]416static void _Thread_queue_Boost_priority(
417  Thread_queue_Heads *heads,
[dafa5d88]418  Thread_Control     *the_thread
419)
420{
[424ffe4d]421#if defined(RTEMS_SMP)
[ac8402dd]422  if ( !_Chain_Has_only_one_node( &heads->Heads.Fifo ) ) {
423    const Scheduler_Control *scheduler;
424    Priority_Control         boost_priority;
425
426    the_thread->priority_restore_hint = true;
427    _Atomic_Fence( ATOMIC_ORDER_ACQ_REL );
428
429    scheduler = _Scheduler_Get_own( the_thread );
430    boost_priority = _Scheduler_Map_priority( scheduler, PRIORITY_PSEUDO_ISR );
431
[1fcac5ad]432    _Scheduler_Thread_set_priority( the_thread, boost_priority, false );
[dafa5d88]433  }
[424ffe4d]434#else
435  (void) heads;
436  (void) the_thread;
[dafa5d88]437#endif
[424ffe4d]438}
439
440static Thread_Control *_Thread_queue_Priority_inherit_surrender(
441  Thread_queue_Queue *queue,
442  Thread_queue_Heads *heads,
443  Thread_Control     *previous_owner
444)
445{
446  Thread_Control *first;
447
448  first = _Thread_queue_Priority_first( heads );
449  _Thread_queue_Boost_priority( heads, first );
450  _Thread_queue_Queue_extract(
451    queue,
452    heads,
453    first,
454    _Thread_queue_Priority_do_extract
455  );
456
457  return first;
458}
[dafa5d88]459
[568af83]460const Thread_queue_Operations _Thread_queue_Operations_default = {
[ff2e6c64]461  .priority_change = _Thread_queue_Do_nothing_priority_change,
[383cf42]462  .extract = _Thread_queue_Do_nothing_extract
463  /*
464   * The default operations are only used in _Thread_Change_priority() and
465   * _Thread_Timeout() and don't have a thread queue associated with them, so
466   * the enqueue and first operations are superfluous.
467   */
[568af83]468};
469
470const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
[ff2e6c64]471  .priority_change = _Thread_queue_Do_nothing_priority_change,
[383cf42]472  .enqueue = _Thread_queue_FIFO_enqueue,
473  .extract = _Thread_queue_FIFO_extract,
[424ffe4d]474  .surrender = _Thread_queue_FIFO_surrender,
[383cf42]475  .first = _Thread_queue_FIFO_first
[568af83]476};
477
478const Thread_queue_Operations _Thread_queue_Operations_priority = {
[383cf42]479  .priority_change = _Thread_queue_Priority_priority_change,
480  .enqueue = _Thread_queue_Priority_enqueue,
481  .extract = _Thread_queue_Priority_extract,
[424ffe4d]482  .surrender = _Thread_queue_Priority_surrender,
[383cf42]483  .first = _Thread_queue_Priority_first
[568af83]484};
[3a58dc8]485
486const Thread_queue_Operations _Thread_queue_Operations_priority_inherit = {
487  .priority_change = _Thread_queue_Priority_priority_change,
488  .enqueue = _Thread_queue_Priority_inherit_enqueue,
489  .extract = _Thread_queue_Priority_extract,
[424ffe4d]490  .surrender = _Thread_queue_Priority_inherit_surrender,
[3a58dc8]491  .first = _Thread_queue_Priority_first
492};
Note: See TracBrowser for help on using the repository browser.