source: rtems/cpukit/score/src/threadqenqueue.c @ 469dc47

5
Last change on this file since 469dc47 was 8f96581, checked in by Sebastian Huber <sebastian.huber@…>, on 04/01/16 at 09:38:47

score: Rework MP thread queue callout support

The thread queue implementation was heavily reworked to support SMP.
This broke the multiprocessing support of the thread queues. This is
fixed by this patch.

A thread proxy is unblocked due to three reasons

1) timeout,
2) request satisfaction, and
3) extraction.

In case 1) no MPCI message must be sent. This is ensured via the
_Thread_queue_MP_callout_do_nothing() callout set during
_Thread_MP_Allocate_proxy().

In case 2) and 3) an MPCI message must be sent. In case we interrupt
the blocking operation during _Thread_queue_Enqueue_critical(), then
this message must be sent by the blocking thread. For this the new
fields Thread_Proxy_control::thread_queue_callout and
Thread_Proxy_control::thread_queue_id are used.

Delete the individual API MP callout types and use
Thread_queue_MP_callout throughout. This type is only defined in
multiprocessing configurations. Prefix the multiprocessing parameters
with mp_ to ease code review. Multiprocessing specific parameters are
optional due to use of a similar macro pattern. There is no overhead
for non-multiprocessing configurations.

  • Property mode set to 100644
File size: 7.1 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/assert.h>
23#include <rtems/score/threaddispatch.h>
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/watchdogimpl.h>
26
27#define THREAD_QUEUE_INTEND_TO_BLOCK \
28  (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_INTEND_TO_BLOCK)
29
30#define THREAD_QUEUE_BLOCKED \
31  (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_BLOCKED)
32
33#define THREAD_QUEUE_READY_AGAIN \
34  (THREAD_WAIT_CLASS_OBJECT | THREAD_WAIT_STATE_READY_AGAIN)
35
36void _Thread_queue_Enqueue_critical(
37  Thread_queue_Queue            *queue,
38  const Thread_queue_Operations *operations,
39  Thread_Control                *the_thread,
40  States_Control                 state,
41  Watchdog_Interval              timeout,
42  uint32_t                       timeout_code,
43  ISR_lock_Context              *lock_context
44)
45{
46  Per_CPU_Control *cpu_self;
47  bool             success;
48
49#if defined(RTEMS_MULTIPROCESSING)
50  if ( _Thread_MP_Is_receive( the_thread ) && the_thread->receive_packet ) {
51    the_thread = _Thread_MP_Allocate_proxy( state );
52  }
53#endif
54
55  _Thread_Lock_set( the_thread, &queue->Lock );
56
57  _Thread_Wait_set_queue( the_thread, queue );
58  _Thread_Wait_set_operations( the_thread, operations );
59
60  ( *operations->enqueue )( queue, the_thread );
61
62  _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_INTEND_TO_BLOCK );
63  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
64  _Thread_queue_Queue_release( queue, lock_context );
65
66  /*
67   *  Set the blocking state for this thread queue in the thread.
68   */
69  _Thread_Set_state( the_thread, state );
70
71  /*
72   *  If the thread wants to timeout, then schedule its timer.
73   */
74  if ( timeout != WATCHDOG_NO_TIMEOUT ) {
75    _Thread_Wait_set_timeout_code( the_thread, timeout_code );
76    _Thread_Timer_insert_relative(
77      the_thread,
78      cpu_self,
79      _Thread_Timeout,
80      timeout
81    );
82  }
83
84  success = _Thread_Wait_flags_try_change(
85    the_thread,
86    THREAD_QUEUE_INTEND_TO_BLOCK,
87    THREAD_QUEUE_BLOCKED
88  );
89  if ( !success ) {
90    _Thread_Timer_remove( the_thread );
91
92#if defined(RTEMS_MULTIPROCESSING)
93    if ( _Objects_Is_local_id( the_thread->Object.id ) ) {
94      _Thread_Unblock( the_thread );
95    } else {
96      Thread_Proxy_control *the_proxy;
97
98      the_proxy = (Thread_Proxy_control *) the_thread;
99      ( *the_proxy->thread_queue_callout )(
100        the_thread,
101        the_proxy->thread_queue_id
102      );
103
104      _Thread_MP_Free_proxy( the_thread );
105    }
106#else
107    _Thread_Unblock( the_thread );
108#endif
109  }
110
111  _Thread_Dispatch_enable( cpu_self );
112}
113
114bool _Thread_queue_Do_extract_locked(
115  Thread_queue_Queue            *queue,
116  const Thread_queue_Operations *operations,
117  Thread_Control                *the_thread
118#if defined(RTEMS_MULTIPROCESSING)
119  ,
120  Thread_queue_MP_callout        mp_callout,
121  Objects_Id                     mp_id
122#endif
123)
124{
125  bool success;
126  bool unblock;
127
128#if defined(RTEMS_MULTIPROCESSING)
129  if ( !_Objects_Is_local_id( the_thread->Object.id ) ) {
130    Thread_Proxy_control *the_proxy;
131
132    _Assert( mp_callout != NULL );
133
134    the_proxy = (Thread_Proxy_control *) the_thread;
135    the_proxy->thread_queue_callout = mp_callout;
136    the_proxy->thread_queue_id = mp_id;
137  }
138#endif
139
140  ( *operations->extract )( queue, the_thread );
141
142  /*
143   * We must update the wait flags under protection of the current thread lock,
144   * otherwise a _Thread_Timeout() running on another processor may interfere.
145   */
146  success = _Thread_Wait_flags_try_change_critical(
147    the_thread,
148    THREAD_QUEUE_INTEND_TO_BLOCK,
149    THREAD_QUEUE_READY_AGAIN
150  );
151  if ( success ) {
152    unblock = false;
153  } else {
154    _Assert( _Thread_Wait_flags_get( the_thread ) == THREAD_QUEUE_BLOCKED );
155    _Thread_Wait_flags_set( the_thread, THREAD_QUEUE_READY_AGAIN );
156    unblock = true;
157  }
158
159  _Thread_Wait_set_queue( the_thread, NULL );
160  _Thread_Wait_restore_default_operations( the_thread );
161  _Thread_Lock_restore_default( the_thread );
162
163  return unblock;
164}
165
166void _Thread_queue_Do_unblock_critical(
167  bool                     unblock,
168  Thread_queue_Queue      *queue,
169  Thread_Control          *the_thread,
170#if defined(RTEMS_MULTIPROCESSING)
171  Thread_queue_MP_callout  mp_callout,
172  Objects_Id               mp_id,
173#endif
174  ISR_lock_Context        *lock_context
175)
176{
177  if ( unblock ) {
178    Per_CPU_Control *cpu_self;
179
180    cpu_self = _Thread_Dispatch_disable_critical( lock_context );
181    _Thread_queue_Queue_release( queue, lock_context );
182
183    _Thread_Timer_remove( the_thread );
184
185#if defined(RTEMS_MULTIPROCESSING)
186    if ( _Objects_Is_local_id( the_thread->Object.id ) ) {
187      _Thread_Unblock( the_thread );
188    } else {
189      ( *mp_callout )( the_thread, mp_id );
190      _Thread_MP_Free_proxy( the_thread );
191    }
192#else
193    _Thread_Unblock( the_thread );
194#endif
195
196    _Thread_Dispatch_enable( cpu_self );
197  } else {
198    _Thread_queue_Queue_release( queue, lock_context );
199  }
200}
201
202void _Thread_queue_Do_extract_critical(
203  Thread_queue_Queue            *queue,
204  const Thread_queue_Operations *operations,
205  Thread_Control                *the_thread,
206#if defined(RTEMS_MULTIPROCESSING)
207  Thread_queue_MP_callout        mp_callout,
208  Objects_Id                     mp_id,
209#endif
210  ISR_lock_Context              *lock_context
211)
212{
213  bool unblock;
214
215  unblock = _Thread_queue_Extract_locked(
216    queue,
217    operations,
218    the_thread,
219    mp_callout,
220    mp_id
221  );
222
223  _Thread_queue_Unblock_critical(
224    unblock,
225    queue,
226    the_thread,
227    mp_callout,
228    mp_id,
229    lock_context
230  );
231}
232
233void _Thread_queue_Extract( Thread_Control *the_thread )
234{
235  ISR_lock_Context    lock_context;
236  void               *lock;
237  Thread_queue_Queue *queue;
238
239  lock = _Thread_Lock_acquire( the_thread, &lock_context );
240
241  queue = the_thread->Wait.queue;
242
243  if ( queue != NULL ) {
244    _SMP_Assert( lock == &queue->Lock );
245
246    _Thread_queue_Extract_critical(
247      queue,
248      the_thread->Wait.operations,
249      the_thread,
250      _Thread_queue_MP_callout_do_nothing,
251      0,
252      &lock_context
253    );
254  } else {
255    _Thread_Lock_release( lock, &lock_context );
256  }
257}
258
259Thread_Control *_Thread_queue_Do_dequeue(
260  Thread_queue_Control          *the_thread_queue,
261  const Thread_queue_Operations *operations
262#if defined(RTEMS_MULTIPROCESSING)
263  ,
264  Thread_queue_MP_callout        mp_callout,
265  Objects_Id                     mp_id
266#endif
267)
268{
269  ISR_lock_Context  lock_context;
270  Thread_Control   *the_thread;
271
272  _Thread_queue_Acquire( the_thread_queue, &lock_context );
273
274  the_thread = _Thread_queue_First_locked( the_thread_queue, operations );
275
276  if ( the_thread != NULL ) {
277    _SMP_Assert( the_thread->Lock.current == &the_thread_queue->Queue.Lock );
278
279    _Thread_queue_Extract_critical(
280      &the_thread_queue->Queue,
281      operations,
282      the_thread,
283      mp_callout,
284      mp_id,
285      &lock_context
286    );
287  } else {
288    _Thread_queue_Release( the_thread_queue, &lock_context );
289  }
290
291  return the_thread;
292}
Note: See TracBrowser for help on using the repository browser.