source: rtems/cpukit/score/include/rtems/score/mrspimpl.h @ e366f77

5
Last change on this file since e366f77 was e366f77, checked in by Sebastian Huber <sebastian.huber@…>, on 01/31/17 at 07:08:24

score: Add _Thread_queue_Object_name

Add the special thread queue name _Thread_queue_Object_name to mark
thread queues embedded in an object with identifier. Using the special
thread state STATES_THREAD_QUEUE_WITH_IDENTIFIER is not reliable for
this purpose since the thread wait information and thread state are
protected by different SMP locks in separate critical sections. Remove
STATES_THREAD_QUEUE_WITH_IDENTIFIER.

Add and use _Thread_queue_Object_initialize().

Update #2858.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2014, 2016 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#ifndef _RTEMS_SCORE_MRSPIMPL_H
16#define _RTEMS_SCORE_MRSPIMPL_H
17
18#include <rtems/score/mrsp.h>
19
20#if defined(RTEMS_SMP)
21
22#include <rtems/score/assert.h>
23#include <rtems/score/status.h>
24#include <rtems/score/threadqimpl.h>
25#include <rtems/score/watchdogimpl.h>
26#include <rtems/score/wkspace.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif /* __cplusplus */
31
32/**
33 * @addtogroup ScoreMRSP
34 *
35 * @{
36 */
37
38#define MRSP_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
39
40RTEMS_INLINE_ROUTINE void _MRSP_Acquire_critical(
41  MRSP_Control         *mrsp,
42  Thread_queue_Context *queue_context
43)
44{
45  _Thread_queue_Acquire_critical( &mrsp->Wait_queue, queue_context );
46}
47
48RTEMS_INLINE_ROUTINE void _MRSP_Release(
49  MRSP_Control         *mrsp,
50  Thread_queue_Context *queue_context
51)
52{
53  _Thread_queue_Release( &mrsp->Wait_queue, queue_context );
54}
55
56RTEMS_INLINE_ROUTINE Thread_Control *_MRSP_Get_owner(
57  const MRSP_Control *mrsp
58)
59{
60  return mrsp->Wait_queue.Queue.owner;
61}
62
63RTEMS_INLINE_ROUTINE void _MRSP_Set_owner(
64  MRSP_Control   *mrsp,
65  Thread_Control *owner
66)
67{
68  mrsp->Wait_queue.Queue.owner = owner;
69}
70
71RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_priority(
72  const MRSP_Control      *mrsp,
73  const Scheduler_Control *scheduler
74)
75{
76  uint32_t scheduler_index;
77
78  scheduler_index = _Scheduler_Get_index( scheduler );
79  return mrsp->ceiling_priorities[ scheduler_index ];
80}
81
82RTEMS_INLINE_ROUTINE void _MRSP_Set_priority(
83  MRSP_Control            *mrsp,
84  const Scheduler_Control *scheduler,
85  Priority_Control         new_priority
86)
87{
88  uint32_t scheduler_index;
89
90  scheduler_index = _Scheduler_Get_index( scheduler );
91  mrsp->ceiling_priorities[ scheduler_index ] = new_priority;
92}
93
94RTEMS_INLINE_ROUTINE Status_Control _MRSP_Raise_priority(
95  MRSP_Control         *mrsp,
96  Thread_Control       *thread,
97  Priority_Node        *priority_node,
98  Thread_queue_Context *queue_context
99)
100{
101  Status_Control           status;
102  ISR_lock_Context         lock_context;
103  const Scheduler_Control *scheduler;
104  Priority_Control         ceiling_priority;
105  Scheduler_Node          *scheduler_node;
106
107  _Thread_queue_Context_clear_priority_updates( queue_context );
108  _Thread_Wait_acquire_default_critical( thread, &lock_context );
109
110  scheduler = _Thread_Scheduler_get_home( thread );
111  scheduler_node = _Thread_Scheduler_get_home_node( thread );
112  ceiling_priority = _MRSP_Get_priority( mrsp, scheduler );
113
114  if (
115    ceiling_priority
116      <= _Priority_Get_priority( &scheduler_node->Wait.Priority )
117  ) {
118    _Priority_Node_initialize( priority_node, ceiling_priority );
119    _Thread_Priority_add( thread, priority_node, queue_context );
120    status = STATUS_SUCCESSFUL;
121  } else {
122    status = STATUS_MUTEX_CEILING_VIOLATED;
123  }
124
125  _Thread_Wait_release_default_critical( thread, &lock_context );
126  return status;
127}
128
129RTEMS_INLINE_ROUTINE void _MRSP_Remove_priority(
130  Thread_Control       *thread,
131  Priority_Node        *priority_node,
132  Thread_queue_Context *queue_context
133)
134{
135  ISR_lock_Context lock_context;
136
137  _Thread_queue_Context_clear_priority_updates( queue_context );
138  _Thread_Wait_acquire_default_critical( thread, &lock_context );
139  _Thread_Priority_remove( thread, priority_node, queue_context );
140  _Thread_Wait_release_default_critical( thread, &lock_context );
141}
142
143RTEMS_INLINE_ROUTINE void _MRSP_Replace_priority(
144  MRSP_Control   *mrsp,
145  Thread_Control *thread,
146  Priority_Node  *ceiling_priority
147)
148{
149  ISR_lock_Context lock_context;
150
151  _Thread_Wait_acquire_default( thread, &lock_context );
152  _Thread_Priority_replace(
153    thread,
154    ceiling_priority,
155    &mrsp->Ceiling_priority
156  );
157  _Thread_Wait_release_default( thread, &lock_context );
158}
159
160RTEMS_INLINE_ROUTINE Status_Control _MRSP_Claim_ownership(
161  MRSP_Control         *mrsp,
162  Thread_Control       *executing,
163  Thread_queue_Context *queue_context
164)
165{
166  Status_Control   status;
167  Per_CPU_Control *cpu_self;
168
169  status = _MRSP_Raise_priority(
170    mrsp,
171    executing,
172    &mrsp->Ceiling_priority,
173    queue_context
174  );
175
176  if ( status != STATUS_SUCCESSFUL ) {
177    _MRSP_Release( mrsp, queue_context );
178    return status;
179  }
180
181  _MRSP_Set_owner( mrsp, executing );
182  cpu_self = _Thread_Dispatch_disable_critical(
183    &queue_context->Lock_context.Lock_context
184  );
185  _MRSP_Release( mrsp, queue_context );
186  _Thread_Priority_and_sticky_update( executing, 1 );
187  _Thread_Dispatch_enable( cpu_self );
188  return STATUS_SUCCESSFUL;
189}
190
191RTEMS_INLINE_ROUTINE Status_Control _MRSP_Initialize(
192  MRSP_Control            *mrsp,
193  const Scheduler_Control *scheduler,
194  Priority_Control         ceiling_priority,
195  Thread_Control          *executing,
196  bool                     initially_locked
197)
198{
199  uint32_t scheduler_count = _Scheduler_Count;
200  uint32_t i;
201
202  if ( initially_locked ) {
203    return STATUS_INVALID_NUMBER;
204  }
205
206  mrsp->ceiling_priorities = _Workspace_Allocate(
207    sizeof( *mrsp->ceiling_priorities ) * scheduler_count
208  );
209  if ( mrsp->ceiling_priorities == NULL ) {
210    return STATUS_NO_MEMORY;
211  }
212
213  for ( i = 0 ; i < scheduler_count ; ++i ) {
214    const Scheduler_Control *scheduler_of_index;
215
216    scheduler_of_index = &_Scheduler_Table[ i ];
217
218    if ( scheduler != scheduler_of_index ) {
219      mrsp->ceiling_priorities[ i ] =
220        _Scheduler_Map_priority( scheduler_of_index, 0 );
221    } else {
222      mrsp->ceiling_priorities[ i ] = ceiling_priority;
223    }
224  }
225
226  _Thread_queue_Object_initialize( &mrsp->Wait_queue );
227  return STATUS_SUCCESSFUL;
228}
229
230RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
231  MRSP_Control         *mrsp,
232  Thread_Control       *executing,
233  Thread_queue_Context *queue_context
234)
235{
236  Status_Control status;
237  Priority_Node  ceiling_priority;
238
239  status = _MRSP_Raise_priority(
240    mrsp,
241    executing,
242    &ceiling_priority,
243    queue_context
244  );
245
246  if ( status != STATUS_SUCCESSFUL ) {
247    _MRSP_Release( mrsp, queue_context );
248    return status;
249  }
250
251  _Thread_queue_Context_set_deadlock_callout(
252    queue_context,
253    _Thread_queue_Deadlock_status
254  );
255  status = _Thread_queue_Enqueue_sticky(
256    &mrsp->Wait_queue.Queue,
257    MRSP_TQ_OPERATIONS,
258    executing,
259    queue_context
260  );
261
262  if ( status == STATUS_SUCCESSFUL ) {
263    _MRSP_Replace_priority( mrsp, executing, &ceiling_priority );
264  } else {
265    Thread_queue_Context  queue_context;
266    Per_CPU_Control      *cpu_self;
267    int                   sticky_level_change;
268
269    if ( status != STATUS_DEADLOCK ) {
270      sticky_level_change = -1;
271    } else {
272      sticky_level_change = 0;
273    }
274
275    _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context );
276    _MRSP_Remove_priority( executing, &ceiling_priority, &queue_context );
277    cpu_self = _Thread_Dispatch_disable_critical(
278      &queue_context.Lock_context.Lock_context
279    );
280    _ISR_lock_ISR_enable( &queue_context.Lock_context.Lock_context );
281    _Thread_Priority_and_sticky_update( executing, sticky_level_change );
282    _Thread_Dispatch_enable( cpu_self );
283  }
284
285  return status;
286}
287
288RTEMS_INLINE_ROUTINE Status_Control _MRSP_Seize(
289  MRSP_Control         *mrsp,
290  Thread_Control       *executing,
291  bool                  wait,
292  Thread_queue_Context *queue_context
293)
294{
295  Status_Control  status;
296  Thread_Control *owner;
297
298  _MRSP_Acquire_critical( mrsp, queue_context );
299
300  owner = _MRSP_Get_owner( mrsp );
301
302  if ( owner == NULL ) {
303    status = _MRSP_Claim_ownership( mrsp, executing, queue_context );
304  } else if ( owner == executing ) {
305    _MRSP_Release( mrsp, queue_context );
306    status = STATUS_UNAVAILABLE;
307  } else if ( wait ) {
308    status = _MRSP_Wait_for_ownership( mrsp, executing, queue_context );
309  } else {
310    _MRSP_Release( mrsp, queue_context );
311    status = STATUS_UNAVAILABLE;
312  }
313
314  return status;
315}
316
317RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
318  MRSP_Control         *mrsp,
319  Thread_Control       *executing,
320  Thread_queue_Context *queue_context
321)
322{
323  Thread_queue_Heads *heads;
324
325  if ( _MRSP_Get_owner( mrsp ) != executing ) {
326    _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
327    return STATUS_NOT_OWNER;
328  }
329
330  _MRSP_Acquire_critical( mrsp, queue_context );
331
332  _MRSP_Set_owner( mrsp, NULL );
333  _MRSP_Remove_priority( executing, &mrsp->Ceiling_priority, queue_context );
334
335  heads = mrsp->Wait_queue.Queue.heads;
336
337  if ( heads == NULL ) {
338    Per_CPU_Control *cpu_self;
339
340    cpu_self = _Thread_Dispatch_disable_critical(
341      &queue_context->Lock_context.Lock_context
342    );
343    _MRSP_Release( mrsp, queue_context );
344    _Thread_Priority_and_sticky_update( executing, -1 );
345    _Thread_Dispatch_enable( cpu_self );
346    return STATUS_SUCCESSFUL;
347  }
348
349  _Thread_queue_Surrender_sticky(
350    &mrsp->Wait_queue.Queue,
351    heads,
352    executing,
353    queue_context,
354    MRSP_TQ_OPERATIONS
355  );
356  return STATUS_SUCCESSFUL;
357}
358
359RTEMS_INLINE_ROUTINE Status_Control _MRSP_Can_destroy( MRSP_Control *mrsp )
360{
361  if ( _MRSP_Get_owner( mrsp ) != NULL ) {
362    return STATUS_RESOURCE_IN_USE;
363  }
364
365  return STATUS_SUCCESSFUL;
366}
367
368RTEMS_INLINE_ROUTINE void _MRSP_Destroy(
369  MRSP_Control         *mrsp,
370  Thread_queue_Context *queue_context
371)
372{
373  _MRSP_Release( mrsp, queue_context );
374  _Thread_queue_Destroy( &mrsp->Wait_queue );
375  _Workspace_Free( mrsp->ceiling_priorities );
376}
377
378/** @} */
379
380#ifdef __cplusplus
381}
382#endif /* __cplusplus */
383
384#endif /* RTEMS_SMP */
385
386#endif /* _RTEMS_SCORE_MRSPIMPL_H */
Note: See TracBrowser for help on using the repository browser.