RTEMS  5.0.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
mrspimpl.h
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>
26 #include <rtems/score/wkspace.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif /* __cplusplus */
31 
38 #define MRSP_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
39 
40 RTEMS_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 
48 RTEMS_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 
56 RTEMS_INLINE_ROUTINE Thread_Control *_MRSP_Get_owner(
57  const MRSP_Control *mrsp
58 )
59 {
60  return mrsp->Wait_queue.Queue.owner;
61 }
62 
63 RTEMS_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 
71 RTEMS_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 
82 RTEMS_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 
94 RTEMS_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 
129 RTEMS_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 
143 RTEMS_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 );
153  thread,
154  ceiling_priority,
155  &mrsp->Ceiling_priority
156  );
157  _Thread_Wait_release_default( thread, &lock_context );
158 }
159 
160 RTEMS_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_queue_Dispatch_disable( queue_context );
183  _MRSP_Release( mrsp, queue_context );
184  _Thread_Priority_and_sticky_update( executing, 1 );
185  _Thread_Dispatch_enable( cpu_self );
186  return STATUS_SUCCESSFUL;
187 }
188 
189 RTEMS_INLINE_ROUTINE Status_Control _MRSP_Initialize(
190  MRSP_Control *mrsp,
191  const Scheduler_Control *scheduler,
192  Priority_Control ceiling_priority,
193  Thread_Control *executing,
194  bool initially_locked
195 )
196 {
197  uint32_t scheduler_count = _Scheduler_Count;
198  uint32_t i;
199 
200  if ( initially_locked ) {
201  return STATUS_INVALID_NUMBER;
202  }
203 
204  mrsp->ceiling_priorities = _Workspace_Allocate(
205  sizeof( *mrsp->ceiling_priorities ) * scheduler_count
206  );
207  if ( mrsp->ceiling_priorities == NULL ) {
208  return STATUS_NO_MEMORY;
209  }
210 
211  for ( i = 0 ; i < scheduler_count ; ++i ) {
212  const Scheduler_Control *scheduler_of_index;
213 
214  scheduler_of_index = &_Scheduler_Table[ i ];
215 
216  if ( scheduler != scheduler_of_index ) {
217  mrsp->ceiling_priorities[ i ] =
218  _Scheduler_Map_priority( scheduler_of_index, 0 );
219  } else {
220  mrsp->ceiling_priorities[ i ] = ceiling_priority;
221  }
222  }
223 
224  _Thread_queue_Object_initialize( &mrsp->Wait_queue );
225  return STATUS_SUCCESSFUL;
226 }
227 
228 RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
229  MRSP_Control *mrsp,
230  Thread_Control *executing,
231  Thread_queue_Context *queue_context
232 )
233 {
234  Status_Control status;
235  Priority_Node ceiling_priority;
236 
237  status = _MRSP_Raise_priority(
238  mrsp,
239  executing,
240  &ceiling_priority,
241  queue_context
242  );
243 
244  if ( status != STATUS_SUCCESSFUL ) {
245  _MRSP_Release( mrsp, queue_context );
246  return status;
247  }
248 
250  queue_context,
252  );
253  status = _Thread_queue_Enqueue_sticky(
254  &mrsp->Wait_queue.Queue,
255  MRSP_TQ_OPERATIONS,
256  executing,
257  queue_context
258  );
259 
260  if ( status == STATUS_SUCCESSFUL ) {
261  _MRSP_Replace_priority( mrsp, executing, &ceiling_priority );
262  } else {
263  Thread_queue_Context queue_context;
264  Per_CPU_Control *cpu_self;
265  int sticky_level_change;
266 
267  if ( status != STATUS_DEADLOCK ) {
268  sticky_level_change = -1;
269  } else {
270  sticky_level_change = 0;
271  }
272 
274  _MRSP_Remove_priority( executing, &ceiling_priority, &queue_context );
276  &queue_context.Lock_context.Lock_context
277  );
279  _Thread_Priority_and_sticky_update( executing, sticky_level_change );
280  _Thread_Dispatch_enable( cpu_self );
281  }
282 
283  return status;
284 }
285 
286 RTEMS_INLINE_ROUTINE Status_Control _MRSP_Seize(
287  MRSP_Control *mrsp,
288  Thread_Control *executing,
289  bool wait,
290  Thread_queue_Context *queue_context
291 )
292 {
293  Status_Control status;
294  Thread_Control *owner;
295 
296  _MRSP_Acquire_critical( mrsp, queue_context );
297 
298  owner = _MRSP_Get_owner( mrsp );
299 
300  if ( owner == NULL ) {
301  status = _MRSP_Claim_ownership( mrsp, executing, queue_context );
302  } else if ( owner == executing ) {
303  _MRSP_Release( mrsp, queue_context );
304  status = STATUS_UNAVAILABLE;
305  } else if ( wait ) {
306  status = _MRSP_Wait_for_ownership( mrsp, executing, queue_context );
307  } else {
308  _MRSP_Release( mrsp, queue_context );
309  status = STATUS_UNAVAILABLE;
310  }
311 
312  return status;
313 }
314 
315 RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
316  MRSP_Control *mrsp,
317  Thread_Control *executing,
318  Thread_queue_Context *queue_context
319 )
320 {
321  Thread_queue_Heads *heads;
322 
323  if ( _MRSP_Get_owner( mrsp ) != executing ) {
325  return STATUS_NOT_OWNER;
326  }
327 
328  _MRSP_Acquire_critical( mrsp, queue_context );
329 
330  _MRSP_Set_owner( mrsp, NULL );
331  _MRSP_Remove_priority( executing, &mrsp->Ceiling_priority, queue_context );
332 
333  heads = mrsp->Wait_queue.Queue.heads;
334 
335  if ( heads == NULL ) {
336  Per_CPU_Control *cpu_self;
337 
339  &queue_context->Lock_context.Lock_context
340  );
341  _MRSP_Release( mrsp, queue_context );
342  _Thread_Priority_and_sticky_update( executing, -1 );
343  _Thread_Dispatch_enable( cpu_self );
344  return STATUS_SUCCESSFUL;
345  }
346 
347  _Thread_queue_Surrender_sticky(
348  &mrsp->Wait_queue.Queue,
349  heads,
350  executing,
351  queue_context,
352  MRSP_TQ_OPERATIONS
353  );
354  return STATUS_SUCCESSFUL;
355 }
356 
357 RTEMS_INLINE_ROUTINE Status_Control _MRSP_Can_destroy( MRSP_Control *mrsp )
358 {
359  if ( _MRSP_Get_owner( mrsp ) != NULL ) {
360  return STATUS_RESOURCE_IN_USE;
361  }
362 
363  return STATUS_SUCCESSFUL;
364 }
365 
366 RTEMS_INLINE_ROUTINE void _MRSP_Destroy(
367  MRSP_Control *mrsp,
368  Thread_queue_Context *queue_context
369 )
370 {
371  _MRSP_Release( mrsp, queue_context );
372  _Thread_queue_Destroy( &mrsp->Wait_queue );
373  _Workspace_Free( mrsp->ceiling_priorities );
374 }
375 
378 #ifdef __cplusplus
379 }
380 #endif /* __cplusplus */
381 
382 #endif /* RTEMS_SMP */
383 
384 #endif /* _RTEMS_SCORE_MRSPIMPL_H */
void _Thread_queue_Object_initialize(Thread_queue_Control *the_thread_queue)
Initializes a thread queue embedded in an object with identifier.
Definition: threadq.c:148
Thread queue context for the thread queue methods.
Definition: threadq.h:193
The priority node to build up a priority aggregation.
Definition: priority.h:94
void _Thread_Priority_add(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Adds the specified thread priority node to the corresponding thread priority aggregation.
Definition: threadchangepriority.c:277
Inlined Routines in the Watchdog Handler.
#define RTEMS_INLINE_ROUTINE
Definition: basedefs.h:65
void _Thread_Priority_replace(Thread_Control *the_thread, Priority_Node *victim_node, Priority_Node *replacement_node)
Replaces the victim priority node with the replacement priority node in the corresponding thread prio...
Definition: threadchangepriority.c:323
RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Map_priority(const Scheduler_Control *scheduler, Priority_Control priority)
Maps a thread priority from the user domain to the scheduler domain.
Definition: schedulerimpl.h:448
RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Releases the thread wait default lock and restores the previous interrupt status. ...
Definition: threadimpl.h:1236
RTEMS_INLINE_ROUTINE void _Thread_queue_Context_set_deadlock_callout(Thread_queue_Context *queue_context, Thread_queue_Deadlock_callout deadlock_callout)
Sets the deadlock callout in the thread queue context.
Definition: threadqimpl.h:280
uint64_t Priority_Control
The thread priority control.
Definition: priority.h:66
Thread queue heads.
Definition: threadq.h:355
void _Thread_Priority_remove(Thread_Control *the_thread, Priority_Node *priority_node, Thread_queue_Context *queue_context)
Removes the specified thread priority node from the corresponding thread priority aggregation...
Definition: threadchangepriority.c:292
#define _ISR_lock_ISR_disable(_context)
Disables interrupts and saves the previous interrupt state in the ISR lock context.
Definition: isrlock.h:383
RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Acquires the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1160
Definition: thread.h:728
#define _ISR_lock_ISR_enable(_context)
Restores the saved interrupt state of the ISR lock context.
Definition: isrlock.h:404
Per CPU Core Structure.
Definition: percpu.h:290
RTEMS_INLINE_ROUTINE void _Thread_Wait_acquire_default(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Acquires the thread wait default lock and disables interrupts.
Definition: threadimpl.h:1201
Information Related to the RAM Workspace.
Thread_queue_Lock_context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:198
struct Scheduler_Node::@3976 Wait
Thread wait support block.
void _Workspace_Free(void *block)
Free memory to the workspace.
Definition: wkspace.c:259
Scheduler control.
Definition: scheduler.h:266
Scheduler node for per-thread data.
Definition: schedulernode.h:65
const Scheduler_Control _Scheduler_Table[]
Registered schedulers.
RTEMS_INLINE_ROUTINE Per_CPU_Control * _Thread_Dispatch_disable_critical(const ISR_lock_Context *lock_context)
Disables thread dispatching inside a critical section (interrupts disabled).
Definition: threaddispatch.h:175
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
ISR_lock_Context Lock_context
The lock context for the thread queue acquire and release operations.
Definition: threadq.h:125
void _Thread_queue_Deadlock_status(Thread_Control *the_thread)
Sets the thread wait return code to STATUS_DEADLOCK.
Definition: threadqenqueue.c:369
void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
Definition: threaddispatch.c:353
void * _Workspace_Allocate(size_t size)
Allocate memory from workspace.
Definition: wkspace.c:232
RTEMS_INLINE_ROUTINE void _Thread_Wait_release_default_critical(Thread_Control *the_thread, ISR_lock_Context *lock_context)
Releases the thread wait default lock inside a critical section (interrupts disabled).
Definition: threadimpl.h:1220
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77
#define _Scheduler_Count
Count of registered schedulers.
Definition: scheduler.h:314