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

5
Last change on this file since d7665823 was d7665823, checked in by Sebastian Huber <sebastian.huber@…>, on 06/24/15 at 13:43:19

score: Introduce Thread_queue_Heads

Move the storage for the thread queue heads to the threads. Each thread
provides a set of thread queue heads allocated from a dedicated memory
pool. In case a thread blocks on a queue, then it lends its heads to
the queue. In case the thread unblocks, then it takes a free set of
threads from the queue. Since a thread can block on at most one queue
this works. This mechanism is used in FreeBSD. The motivation for this
change is to reduce the memory demands of the synchronization objects.
On a 32-bit uni-processor configuration the Thread_queue_Control size is
now 8 bytes, compared to 64 bytes in RTEMS 4.10 (other changes reduced
the size as well).

  • Property mode set to 100644
File size: 5.8 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
24static void _Thread_queue_Do_nothing_priority_change(
25  Thread_Control     *the_thread,
26  Priority_Control    new_priority,
27  Thread_queue_Queue *queue
28)
29{
30  /* Do nothing */
31}
32
33static void _Thread_queue_Do_nothing_extract(
34  Thread_queue_Queue *queue,
35  Thread_Control    *the_thread
36)
37{
38  /* Do nothing */
39}
40
41static void _Thread_queue_Queue_enqueue(
42  Thread_queue_Queue *queue,
43  Thread_Control     *the_thread,
44  void             ( *initialize )( Thread_queue_Heads * ),
45  void             ( *enqueue )( Thread_queue_Heads *, Thread_Control * )
46)
47{
48  Thread_queue_Heads *heads = queue->heads;
49  Thread_queue_Heads *spare_heads = the_thread->Wait.spare_heads;
50
51  the_thread->Wait.spare_heads = NULL;
52
53  if ( heads == NULL ) {
54    _Assert( spare_heads != NULL );
55    _Assert( _Chain_Is_empty( &spare_heads->Free_chain ) );
56    heads = spare_heads;
57    queue->heads = heads;
58    ( *initialize )( heads );
59  }
60
61  _Chain_Prepend_unprotected( &heads->Free_chain, &spare_heads->Free_node );
62
63  ( *enqueue )( heads, the_thread );
64}
65
66static void _Thread_queue_Queue_extract(
67  Thread_queue_Queue *queue,
68  Thread_Control     *the_thread,
69  void             ( *extract )( Thread_queue_Heads *, Thread_Control * )
70)
71{
72  Thread_queue_Heads *heads = queue->heads;
73
74  _Assert( heads != NULL );
75
76  the_thread->Wait.spare_heads = RTEMS_CONTAINER_OF(
77    _Chain_Get_first_unprotected( &heads->Free_chain ),
78    Thread_queue_Heads,
79    Free_node
80  );
81
82  if ( _Chain_Is_empty( &heads->Free_chain ) ) {
83    queue->heads = NULL;
84  }
85
86  ( *extract )( heads, the_thread );
87}
88
89static void _Thread_queue_FIFO_do_initialize(
90  Thread_queue_Heads *heads
91)
92{
93  _Chain_Initialize_empty( &heads->Heads.Fifo );
94}
95
96static void _Thread_queue_FIFO_do_enqueue(
97  Thread_queue_Heads *heads,
98  Thread_Control     *the_thread
99)
100{
101  _Chain_Append_unprotected(
102    &heads->Heads.Fifo,
103    &the_thread->Wait.Node.Chain
104  );
105}
106
107static void _Thread_queue_FIFO_do_extract(
108  Thread_queue_Heads *heads,
109  Thread_Control     *the_thread
110)
111{
112  _Chain_Extract_unprotected( &the_thread->Wait.Node.Chain );
113}
114
115static void _Thread_queue_FIFO_enqueue(
116  Thread_queue_Queue *queue,
117  Thread_Control     *the_thread
118)
119{
120  _Thread_queue_Queue_enqueue(
121    queue,
122    the_thread,
123    _Thread_queue_FIFO_do_initialize,
124    _Thread_queue_FIFO_do_enqueue
125  );
126}
127
128static void _Thread_queue_FIFO_extract(
129  Thread_queue_Queue *queue,
130  Thread_Control     *the_thread
131)
132{
133  _Thread_queue_Queue_extract(
134    queue,
135    the_thread,
136    _Thread_queue_FIFO_do_extract
137  );
138}
139
140static Thread_Control *_Thread_queue_FIFO_first(
141  Thread_queue_Heads *heads
142)
143{
144  Chain_Control *fifo = &heads->Heads.Fifo;
145
146  return _Chain_Is_empty( fifo ) ?
147    NULL : THREAD_CHAIN_NODE_TO_THREAD( _Chain_First( fifo ) );
148}
149
150static void _Thread_queue_Priority_priority_change(
151  Thread_Control     *the_thread,
152  Priority_Control    new_priority,
153  Thread_queue_Queue *queue
154)
155{
156  Thread_queue_Heads *heads = queue->heads;
157
158  _Assert( heads != NULL );
159
160  _RBTree_Extract(
161    &heads->Heads.Priority,
162    &the_thread->Wait.Node.RBTree
163  );
164  _RBTree_Insert(
165    &heads->Heads.Priority,
166    &the_thread->Wait.Node.RBTree,
167    _Thread_queue_Compare_priority,
168    false
169  );
170}
171
172static void _Thread_queue_Priority_do_initialize(
173  Thread_queue_Heads *heads
174)
175{
176  _RBTree_Initialize_empty( &heads->Heads.Priority );
177}
178
179static void _Thread_queue_Priority_do_enqueue(
180  Thread_queue_Heads *heads,
181  Thread_Control     *the_thread
182)
183{
184  _RBTree_Insert(
185    &heads->Heads.Priority,
186    &the_thread->Wait.Node.RBTree,
187    _Thread_queue_Compare_priority,
188    false
189  );
190}
191
192static void _Thread_queue_Priority_do_extract(
193  Thread_queue_Heads *heads,
194  Thread_Control     *the_thread
195)
196{
197  _RBTree_Extract(
198    &heads->Heads.Priority,
199    &the_thread->Wait.Node.RBTree
200  );
201}
202
203static void _Thread_queue_Priority_enqueue(
204  Thread_queue_Queue *queue,
205  Thread_Control     *the_thread
206)
207{
208  _Thread_queue_Queue_enqueue(
209    queue,
210    the_thread,
211    _Thread_queue_Priority_do_initialize,
212    _Thread_queue_Priority_do_enqueue
213  );
214}
215
216static void _Thread_queue_Priority_extract(
217  Thread_queue_Queue *queue,
218  Thread_Control     *the_thread
219)
220{
221  _Thread_queue_Queue_extract(
222    queue,
223    the_thread,
224    _Thread_queue_Priority_do_extract
225  );
226}
227
228static Thread_Control *_Thread_queue_Priority_first(
229  Thread_queue_Heads *heads
230)
231{
232  RBTree_Node *first;
233
234  first = _RBTree_First( &heads->Heads.Priority, RBT_LEFT );
235
236  return first != NULL ? THREAD_RBTREE_NODE_TO_THREAD( first ) : NULL;
237}
238
239const Thread_queue_Operations _Thread_queue_Operations_default = {
240  .priority_change = _Thread_queue_Do_nothing_priority_change,
241  .extract = _Thread_queue_Do_nothing_extract
242  /*
243   * The default operations are only used in _Thread_Change_priority() and
244   * _Thread_Timeout() and don't have a thread queue associated with them, so
245   * the enqueue and first operations are superfluous.
246   */
247};
248
249const Thread_queue_Operations _Thread_queue_Operations_FIFO = {
250  .priority_change = _Thread_queue_Do_nothing_priority_change,
251  .enqueue = _Thread_queue_FIFO_enqueue,
252  .extract = _Thread_queue_FIFO_extract,
253  .first = _Thread_queue_FIFO_first
254};
255
256const Thread_queue_Operations _Thread_queue_Operations_priority = {
257  .priority_change = _Thread_queue_Priority_priority_change,
258  .enqueue = _Thread_queue_Priority_enqueue,
259  .extract = _Thread_queue_Priority_extract,
260  .first = _Thread_queue_Priority_first
261};
Note: See TracBrowser for help on using the repository browser.