source: rtems/cpukit/score/src/threadqops.c @ dafa5d88

Last change on this file since dafa5d88 was dafa5d88, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 3, 2015 at 8:27:16 AM

score: Implement priority boosting

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/*
2 * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
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>
20#include <rtems/score/assert.h>
21#include <rtems/score/chainimpl.h>
22#include <rtems/score/rbtreeimpl.h>
23#include <rtems/score/schedulerimpl.h>
24
25static void _Thread_queue_Do_nothing_priority_change(
26  Thread_Control     *the_thread,
27  Priority_Control    new_priority,
28  Thread_queue_Queue *queue
29)
30{
31  /* Do nothing */
32}
33
34static void _Thread_queue_Do_nothing_extract(
35  Thread_queue_Queue *queue,
36  Thread_Control    *the_thread
37)
38{
39  /* Do nothing */
40}
41
42static void _Thread_queue_Queue_enqueue(
43  Thread_queue_Queue *queue,
44  Thread_Control     *the_thread,
45  void             ( *initialize )( Thread_queue_Heads * ),
46  void             ( *enqueue )( Thread_queue_Heads *, Thread_Control * )
47)
48{
49  Thread_queue_Heads *heads = queue->heads;
50  Thread_queue_Heads *spare_heads = the_thread->Wait.spare_heads;
51
52  the_thread->Wait.spare_heads = NULL;
53
54  if ( heads == NULL ) {
55    _Assert( spare_heads != NULL );
56    _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) );
57    heads = spare_heads;
58    queue->heads = heads;
59    ( *initialize )( heads );
60  }
61
62  _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
63
64  ( *enqueue )( heads, the_thread );
65}
66
67static void _Thread_queue_Queue_extract(
68  Thread_queue_Queue *queue,
69  Thread_Control     *the_thread,
70  void             ( *extract )( Thread_queue_Heads *, Thread_Control * )
71)
72{
73  Thread_queue_Heads *heads = queue->heads;
74
75  _Assert( heads != NULL );
76
77  the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
78    _Chain_Get_first_unprotected( &heads->Free_chain ),
79    Thread_queue_Heads,
80    Free_node
81  );
82
83  if ( _Chain_Is_empty( &heads->Free_chain ) ) {
84    queue->heads = NULL;
85  }
86
87  ( *extract )( heads, the_thread );
88}
89
90static void _Thread_queue_FIFO_do_initialize(
91  Thread_queue_Heads *heads
92)
93{
94  _Chain_Initialize_empty( &heads->Heads.Fifo );
95}
96
97static void _Thread_queue_FIFO_do_enqueue(
98  Thread_queue_Heads *heads,
99  Thread_Control     *the_thread
100)
101{
102  _Chain_Append_unprotected(
103    &heads->Heads.Fifo,
104    &the_thread->Wait.Node.Chain
105  );
106}
107
108static void _Thread_queue_FIFO_do_extract(
109  Thread_queue_Heads *heads,
110  Thread_Control     *the_thread
111)
112{
113  _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain );
114}
115
116static void _Thread_queue_FIFO_enqueue(
117  Thread_queue_Queue *queue,
118  Thread_Control     *the_thread
119)
120{
121  _Thread_queue_Queue_enqueue(
122    queue,
123    the_thread,
124    _Thread_queue_FIFO_do_initialize,
125    _Thread_queue_FIFO_do_enqueue
126  );
127}
128
129static void _Thread_queue_FIFO_extract(
130  Thread_queue_Queue *queue,
131  Thread_Control     *the_thread
132)
133{
134  _Thread_queue_Queue_extract(
135    queue,
136    the_thread,
137    _Thread_queue_FIFO_do_extract
138  );
139}
140
141static Thread_Control *_Thread_queue_FIFO_first(
142  Thread_queue_Heads *heads
143)
144{
145  Chain_Control *fifo = &heads->Heads.Fifo;
146  Chain_Node    *first;
147
148  _Assert( !_Chain_Is_empty( fifo ) );
149  first = _Chain_First( fifo );
150
151  return THREAD_CHAIN_NODE_TO_THREAD( first );
152}
153
154static Thread_queue_Priority_queue *_Thread_queue_Priority_queue(
155  Thread_queue_Heads   *heads,
156  const Thread_Control *the_thread
157)
158{
159#if defined(RTEMS_SMP)
160  return &heads->Priority[
161    _Scheduler_Get_index( _Scheduler_Get_own( the_thread ) )
162  ];
163#else
164  (void) the_thread;
165
166  return &heads->Heads.Priority;
167#endif
168}
169
170static void _Thread_queue_Priority_priority_change(
171  Thread_Control     *the_thread,
172  Priority_Control    new_priority,
173  Thread_queue_Queue *queue
174)
175{
176  Thread_queue_Heads          *heads = queue->heads;
177  Thread_queue_Priority_queue *priority_queue;
178
179  _Assert( heads != NULL );
180
181  priority_queue = _Thread_queue_Priority_queue( heads, the_thread );
182
183  _RBTree_Extract(
184    &priority_queue->Queue,
185    &the_thread->Wait.Node.RBTree
186  );
187  _RBTree_Insert(
188    &priority_queue->Queue,
189    &the_thread->Wait.Node.RBTree,
190    _Thread_queue_Compare_priority,
191    false
192  );
193}
194
195static void _Thread_queue_Priority_do_initialize(
196  Thread_queue_Heads *heads
197)
198{
199#if defined(RTEMS_SMP)
200  _Chain_Initialize_empty( &heads->Heads.Fifo );
201#else
202  _RBTree_Initialize_empty( &heads->Heads.Priority );
203#endif
204}
205
206static void _Thread_queue_Priority_do_enqueue(
207  Thread_queue_Heads *heads,
208  Thread_Control     *the_thread
209)
210{
211  Thread_queue_Priority_queue *priority_queue =
212    _Thread_queue_Priority_queue( heads, the_thread );
213
214#if defined(RTEMS_SMP)
215  if ( _RBTree_Is_empty( &priority_queue->Queue ) ) {
216    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
217  }
218#endif
219
220  _RBTree_Insert(
221    &priority_queue->Queue,
222    &the_thread->Wait.Node.RBTree,
223    _Thread_queue_Compare_priority,
224    false
225  );
226}
227
228static void _Thread_queue_Priority_do_extract(
229  Thread_queue_Heads *heads,
230  Thread_Control     *the_thread
231)
232{
233  Thread_queue_Priority_queue *priority_queue =
234    _Thread_queue_Priority_queue( heads, the_thread );
235
236  _RBTree_Extract(
237    &priority_queue->Queue,
238    &the_thread->Wait.Node.RBTree
239  );
240
241#if defined(RTEMS_SMP)
242  _Chain_Extract_unprotected( &priority_queue->Node );
243
244  if ( !_RBTree_Is_empty( &priority_queue->Queue ) ) {
245    _Chain_Append_unprotected( &heads->Heads.Fifo, &priority_queue->Node );
246  }
247#endif
248}
249
250static void _Thread_queue_Priority_enqueue(
251  Thread_queue_Queue *queue,
252  Thread_Control     *the_thread
253)
254{
255  _Thread_queue_Queue_enqueue(
256    queue,
257    the_thread,
258    _Thread_queue_Priority_do_initialize,
259    _Thread_queue_Priority_do_enqueue
260  );
261}
262
263static void _Thread_queue_Priority_extract(
264  Thread_queue_Queue *queue,
265  Thread_Control     *the_thread
266)
267{
268  _Thread_queue_Queue_extract(
269    queue,
270    the_thread,
271    _Thread_queue_Priority_do_extract
272  );
273}
274
275static Thread_Control *_Thread_queue_Priority_first(
276  Thread_queue_Heads *heads
277)
278{
279  Thread_queue_Priority_queue *priority_queue;
280  RBTree_Node                 *first;
281
282#if defined(RTEMS_SMP)
283  _Assert( !_Chain_Is_empty( &heads->Heads.Fifo ) );
284  priority_queue = (Thread_queue_Priority_queue *)
285    _Chain_First( &heads->Heads.Fifo );
286#else
287  priority_queue = &heads->Heads.Priority;
288#endif
289
290  _Assert( !_RBTree_Is_empty( &priority_queue->Queue ) );
291  first = _RBTree_Minimum( &priority_queue->Queue );
292
293  return THREAD_RBTREE_NODE_TO_THREAD( first );
294}
295
296#if defined(RTEMS_SMP)
297void _Thread_queue_Boost_priority(
298  Thread_queue_Queue *queue,
299  Thread_Control     *the_thread
300)
301{
302  Thread_queue_Heads *heads = queue->heads;
303
304  if (
305    heads != NULL
306      && (
307        !_Chain_Has_only_one_node( &heads->Heads.Fifo )
308          || _RBTree_Is_empty(
309            &_Thread_queue_Priority_queue( heads, the_thread )->Queue
310          )
311      )
312  ) {
313    _Thread_Raise_priority( the_thread, PRIORITY_PSEUDO_ISR );
314  }
315}
316#endif
317
318const Thread_queue_Operations _Thread_queue_Operations_default = {
319  .priority_change = _Thread_queue_Do_nothing_priority_change,
320  .extract = _Thread_queue_Do_nothing_extract
321  /*
322   * The default operations are only used in _Thread_Change_priority() and
323   * _Thread_Timeout() and don't have a thread queue associated with them, so
324   * the enqueue and first operations are superfluous.
325   */
326};
327
328const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
329  .priority_change = _Thread_queue_Do_nothing_priority_change,
330  .enqueue = _Thread_queue_FIFO_enqueue,
331  .extract = _Thread_queue_FIFO_extract,
332  .first = _Thread_queue_FIFO_first
333};
334
335const Thread_queue_Operations _Thread_queue_Operations_priority = {
336  .priority_change = _Thread_queue_Priority_priority_change,
337  .enqueue = _Thread_queue_Priority_enqueue,
338  .extract = _Thread_queue_Priority_extract,
339  .first = _Thread_queue_Priority_first
340};
Note: See TracBrowser for help on using the repository browser.