source: rtems/cpukit/score/src/threadqenqueue.c @ 688fbc44

4.115
Last change on this file since 688fbc44 was 688fbc44, checked in by Sebastian Huber <sebastian.huber@…>, on 03/22/15 at 09:43:06

score: Move _Thread_queue_Extract()

Move _Thread_queue_Dequeue(). We need all or no thread queue functions
so it makes no sense to have them in separate modules. One module
enables compiler optimizations without link-time optimization. Make
_Thread_blocking_operation_Finalize() static since it is use now only in
one module.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/**
2 * @file
3 *
4 * @brief Thread Queue Operations
5 * @ingroup ScoreThreadQ
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2014.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/score/threadqimpl.h>
22#include <rtems/score/isrlevel.h>
23#include <rtems/score/rbtreeimpl.h>
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/watchdogimpl.h>
26
27/**
28 *  @brief Finalize a blocking operation.
29 *
30 *  This method is used to finalize a blocking operation that was
31 *  satisfied. It may be used with thread queues or any other synchronization
32 *  object that uses the blocking states and watchdog times for timeout.
33 *
34 *  This method will restore the previous ISR disable level during the cancel
35 *  operation.  Thus it is an implicit _ISR_Enable().
36 *
37 *  @param[in] the_thread is the thread whose blocking is canceled
38 *  @param[in] level is the previous ISR disable level
39 */
40static void _Thread_blocking_operation_Finalize(
41  Thread_Control                   *the_thread,
42  ISR_Level                         level
43)
44{
45  /*
46   * The thread is not waiting on anything after this completes.
47   */
48  the_thread->Wait.queue = NULL;
49
50  /*
51   *  If the sync state is timed out, this is very likely not needed.
52   *  But better safe than sorry when it comes to critical sections.
53   */
54  if ( _Watchdog_Is_active( &the_thread->Timer ) ) {
55    _Watchdog_Deactivate( &the_thread->Timer );
56    _ISR_Enable( level );
57    (void) _Watchdog_Remove( &the_thread->Timer );
58  } else
59    _ISR_Enable( level );
60
61  /*
62   *  Global objects with thread queue's should not be operated on from an
63   *  ISR.  But the sync code still must allow short timeouts to be processed
64   *  correctly.
65   */
66
67  _Thread_Unblock( the_thread );
68
69#if defined(RTEMS_MULTIPROCESSING)
70  if ( !_Objects_Is_local_id( the_thread->Object.id ) )
71    _Thread_MP_Free_proxy( the_thread );
72#endif
73}
74
75/**
76 *  @brief Cancel a blocking operation due to ISR.
77 *
78 *  This method is used to cancel a blocking operation that was
79 *  satisfied from an ISR while the thread executing was in the
80 *  process of blocking.
81 *
82 *  This method will restore the previous ISR disable level during the cancel
83 *  operation.  Thus it is an implicit _ISR_Enable().
84 *
85 *  @param[in] sync_state is the synchronization state
86 *  @param[in] the_thread is the thread whose blocking is canceled
87 *  @param[in] level is the previous ISR disable level
88 *
89 *  @note This is a rare routine in RTEMS.  It is called with
90 *        interrupts disabled and only when an ISR completed
91 *        a blocking condition in process.
92 */
93static void _Thread_blocking_operation_Cancel(
94  Thread_blocking_operation_States  sync_state,
95  Thread_Control                   *the_thread,
96  ISR_Level                         level
97)
98{
99  /*
100   *  Cases that should not happen and why.
101   *
102   *  THREAD_BLOCKING_OPERATION_SYNCHRONIZED:
103   *
104   *  This indicates that someone did not enter a blocking
105   *  operation critical section.
106   *
107   *  THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED:
108   *
109   *  This indicates that there was nothing to cancel so
110   *  we should not have been called.
111   */
112
113  #if defined(RTEMS_DEBUG)
114    if ( (sync_state == THREAD_BLOCKING_OPERATION_SYNCHRONIZED) ||
115         (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) {
116      _Terminate(
117        INTERNAL_ERROR_CORE,
118        true,
119        INTERNAL_ERROR_IMPLEMENTATION_BLOCKING_OPERATION_CANCEL
120      );
121    }
122  #else
123    (void) sync_state;
124  #endif
125
126  _Thread_blocking_operation_Finalize( the_thread, level );
127}
128
129void _Thread_queue_Enqueue_with_handler(
130  Thread_queue_Control         *the_thread_queue,
131  Thread_Control               *the_thread,
132  Watchdog_Interval             timeout,
133  Thread_queue_Timeout_callout  handler
134)
135{
136  ISR_Level                         level;
137  Thread_blocking_operation_States  sync_state;
138
139#if defined(RTEMS_MULTIPROCESSING)
140  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet )
141    the_thread = _Thread_MP_Allocate_proxy( the_thread_queue->state );
142  else
143#endif
144  /*
145   *  Set the blocking state for this thread queue in the thread.
146   */
147  _Thread_Set_state( the_thread, the_thread_queue->state );
148
149  /*
150   *  If the thread wants to timeout, then schedule its timer.
151   */
152  if ( timeout ) {
153    _Watchdog_Initialize(
154       &the_thread->Timer,
155       handler,
156       the_thread->Object.id,
157       NULL
158    );
159
160    _Watchdog_Insert_ticks( &the_thread->Timer, timeout );
161  }
162
163  /*
164   * Now initiate the enqueuing and checking if the blocking operation
165   * should be completed or the thread has had its blocking condition
166   * satisfied before we got here.
167   */
168  _ISR_Disable( level );
169
170  sync_state = the_thread_queue->sync_state;
171  the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;
172
173  if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) {
174    /*
175     * Invoke the discipline specific enqueue method.
176     */
177    if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) {
178      _Chain_Append_unprotected(
179        &the_thread_queue->Queues.Fifo,
180        &the_thread->Object.Node
181      );
182    } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */
183      _RBTree_Insert(
184        &the_thread_queue->Queues.Priority,
185        &the_thread->RBNode,
186        _Thread_queue_Compare_priority,
187        false
188      );
189    }
190
191    the_thread->Wait.queue = the_thread_queue;
192    the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;
193    _ISR_Enable( level );
194    return;
195  } else { /* sync_state != THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) */
196    _Thread_blocking_operation_Cancel( sync_state, the_thread, level );
197  }
198}
199
200void _Thread_queue_Extract_with_return_code(
201  Thread_queue_Control *the_thread_queue,
202  Thread_Control       *the_thread,
203  uint32_t              return_code
204)
205{
206  ISR_Level level;
207
208  _ISR_Disable( level );
209
210  if ( !_States_Is_waiting_on_thread_queue( the_thread->current_state ) ) {
211    _ISR_Enable( level );
212    return;
213  }
214
215  if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) {
216    _Chain_Extract_unprotected( &the_thread->Object.Node );
217  } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */
218    _RBTree_Extract(
219      &the_thread->Wait.queue->Queues.Priority,
220      &the_thread->RBNode
221    );
222  }
223
224  the_thread->Wait.return_code = return_code;
225
226  /*
227   * We found a thread to unblock.
228   *
229   * NOTE: This is invoked with interrupts still disabled.
230   */
231  _Thread_blocking_operation_Finalize( the_thread, level );
232}
233
234void _Thread_queue_Extract(
235  Thread_queue_Control *the_thread_queue,
236  Thread_Control       *the_thread
237)
238{
239  _Thread_queue_Extract_with_return_code(
240    the_thread_queue,
241    the_thread,
242    the_thread->Wait.return_code
243  );
244}
245
246Thread_Control *_Thread_queue_Dequeue(
247  Thread_queue_Control *the_thread_queue
248)
249{
250  Thread_Control *the_thread;
251  ISR_Level       level;
252  Thread_blocking_operation_States  sync_state;
253
254  the_thread = NULL;
255  _ISR_Disable( level );
256
257  /*
258   * Invoke the discipline specific dequeue method.
259   */
260  if ( the_thread_queue->discipline == THREAD_QUEUE_DISCIPLINE_FIFO ) {
261    if ( !_Chain_Is_empty( &the_thread_queue->Queues.Fifo ) ) {
262      the_thread = (Thread_Control *)
263       _Chain_Get_first_unprotected( &the_thread_queue->Queues.Fifo );
264    }
265  } else { /* must be THREAD_QUEUE_DISCIPLINE_PRIORITY */
266    RBTree_Node    *first;
267
268    first = _RBTree_Get( &the_thread_queue->Queues.Priority, RBT_LEFT );
269    if ( first ) {
270      the_thread = THREAD_RBTREE_NODE_TO_THREAD( first );
271    }
272  }
273
274  if ( the_thread == NULL ) {
275    /*
276     * We did not find a thread to unblock in the queue.  Maybe the executing
277     * thread is about to block on this thread queue.
278     */
279    sync_state = the_thread_queue->sync_state;
280    if ( (sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT) ||
281         (sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED) ) {
282      the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SATISFIED;
283      the_thread = _Thread_Executing;
284    } else {
285      _ISR_Enable( level );
286      return NULL;
287    }
288  }
289
290  /*
291   * We found a thread to unblock.
292   *
293   * NOTE: This is invoked with interrupts still disabled.
294   */
295  _Thread_blocking_operation_Finalize( the_thread, level );
296
297  return the_thread;
298}
Note: See TracBrowser for help on using the repository browser.