RTEMS CPU Kit with SuperCore  4.11.2
mrspimpl.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-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 #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/chainimpl.h>
27 #include <rtems/score/wkspace.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif /* __cplusplus */
32 
39 /*
40  * FIXME: Operations with the resource dependency tree are protected by the
41  * global scheduler lock. Since the scheduler lock should be scheduler
42  * instance specific in the future this will only work temporarily. A more
43  * sophisticated locking strategy is necessary.
44  */
45 
46 RTEMS_INLINE_ROUTINE void _MRSP_Giant_acquire( ISR_lock_Context *lock_context )
47 {
48  _ISR_lock_Acquire( &_Scheduler_Lock, lock_context );
49 }
50 
51 RTEMS_INLINE_ROUTINE void _MRSP_Giant_release( ISR_lock_Context *lock_context )
52 {
53  _ISR_lock_Release( &_Scheduler_Lock, lock_context );
54 }
55 
56 RTEMS_INLINE_ROUTINE bool _MRSP_Restore_priority_filter(
57  Thread_Control *thread,
58  Priority_Control *new_priority,
59  void *arg
60 )
61 {
62  *new_priority = _Thread_Priority_highest(
63  thread->real_priority,
64  *new_priority
65  );
66 
67  return *new_priority != thread->current_priority;
68 }
69 
70 RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority(
71  Thread_Control *thread,
72  Priority_Control initial_priority
73 )
74 {
75  /*
76  * The Thread_Control::resource_count is used by the normal priority ceiling
77  * or priority inheritance semaphores.
78  */
79  if ( thread->resource_count == 0 ) {
81  thread,
82  initial_priority,
83  NULL,
84  _MRSP_Restore_priority_filter,
85  true
86  );
87  }
88 }
89 
90 RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership(
91  MRSP_Control *mrsp,
92  Thread_Control *new_owner,
93  Priority_Control initial_priority,
94  Priority_Control ceiling_priority,
95  ISR_lock_Context *lock_context
96 )
97 {
98  Per_CPU_Control *cpu_self;
99 
100  _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
101  _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
102  mrsp->initial_priority_of_owner = initial_priority;
103  _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
104 
105  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
106  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
107 
108  _Thread_Raise_priority( new_owner, ceiling_priority );
109 
110  _Thread_Dispatch_enable( cpu_self );
111 }
112 
113 RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize(
114  MRSP_Control *mrsp,
115  Priority_Control ceiling_priority,
116  Thread_Control *executing,
117  bool initially_locked
118 )
119 {
120  uint32_t scheduler_count = _Scheduler_Count;
121  uint32_t i;
122 
123  if ( initially_locked ) {
124  return MRSP_INVALID_NUMBER;
125  }
126 
127  mrsp->ceiling_priorities = _Workspace_Allocate(
128  sizeof( *mrsp->ceiling_priorities ) * scheduler_count
129  );
130  if ( mrsp->ceiling_priorities == NULL ) {
131  return MRSP_NO_MEMORY;
132  }
133 
134  for ( i = 0 ; i < scheduler_count ; ++i ) {
135  mrsp->ceiling_priorities[ i ] = ceiling_priority;
136  }
137 
138  _Resource_Initialize( &mrsp->Resource );
139  _Chain_Initialize_empty( &mrsp->Rivals );
140  _ISR_lock_Initialize( &mrsp->Lock, "MrsP" );
141 
142  return MRSP_SUCCESSFUL;
143 }
144 
145 RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_ceiling_priority(
146  MRSP_Control *mrsp,
147  uint32_t scheduler_index
148 )
149 {
150  return mrsp->ceiling_priorities[ scheduler_index ];
151 }
152 
153 RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority(
154  MRSP_Control *mrsp,
155  uint32_t scheduler_index,
156  Priority_Control ceiling_priority
157 )
158 {
159  mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority;
160 }
161 
162 RTEMS_INLINE_ROUTINE void _MRSP_Timeout(
163  Objects_Id id,
164  void *arg
165 )
166 {
167  MRSP_Rival *rival = arg;
168  MRSP_Control *mrsp = rival->resource;
169  Thread_Control *thread = rival->thread;
170  ISR_lock_Context lock_context;
171 
172  (void) id;
173 
174  _ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context );
175 
176  if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) {
177  ISR_lock_Context giant_lock_context;
178 
179  _MRSP_Giant_acquire( &giant_lock_context );
180 
181  _Chain_Extract_unprotected( &rival->Node );
182  _Resource_Node_extract( &thread->Resource_node );
183  _Resource_Node_set_dependency( &thread->Resource_node, NULL );
184  _Scheduler_Thread_change_help_state( thread, rival->initial_help_state );
185  _Scheduler_Thread_change_resource_root( thread, thread );
186 
187  _MRSP_Giant_release( &giant_lock_context );
188 
189  rival->status = MRSP_TIMEOUT;
190 
191  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
192  } else {
193  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, &lock_context );
194  }
195 }
196 
197 RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership(
198  MRSP_Control *mrsp,
199  Resource_Node *owner,
200  Thread_Control *executing,
201  Priority_Control initial_priority,
202  Priority_Control ceiling_priority,
203  Watchdog_Interval timeout,
204  ISR_lock_Context *lock_context
205 )
206 {
207  MRSP_Status status;
208  MRSP_Rival rival;
209  bool initial_life_protection;
210  Per_CPU_Control *cpu_self;
211  ISR_lock_Context giant_lock_context;
212 
213  rival.thread = executing;
214  rival.resource = mrsp;
215  rival.initial_priority = initial_priority;
216 
217  _MRSP_Giant_acquire( &giant_lock_context );
218 
219  rival.initial_help_state =
220  _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_ACTIVE_RIVAL );
221  rival.status = MRSP_WAIT_FOR_OWNERSHIP;
222 
223  _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node );
224  _Resource_Add_rival( &mrsp->Resource, &executing->Resource_node );
225  _Resource_Node_set_dependency( &executing->Resource_node, &mrsp->Resource );
226  _Scheduler_Thread_change_resource_root(
227  executing,
228  THREAD_RESOURCE_NODE_TO_THREAD( _Resource_Node_get_root( owner ) )
229  );
230 
231  _MRSP_Giant_release( &giant_lock_context );
232 
233  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
234  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
235 
236  _Thread_Raise_priority( executing, ceiling_priority );
237 
238  if ( timeout > 0 ) {
240  &executing->Timer,
241  _MRSP_Timeout,
242  0,
243  &rival
244  );
245  _Watchdog_Insert_ticks( &executing->Timer, timeout );
246  }
247 
248  initial_life_protection = _Thread_Set_life_protection( true );
249  _Thread_Dispatch_enable( cpu_self );
250 
251  _Assert( _Debug_Is_thread_dispatching_allowed() );
252 
253  /* Wait for state change */
254  do {
255  status = rival.status;
256  } while ( status == MRSP_WAIT_FOR_OWNERSHIP );
257 
258  _Thread_Set_life_protection( initial_life_protection );
259 
260  if ( timeout > 0 ) {
261  _Watchdog_Remove_ticks( &executing->Timer );
262 
263  if ( status == MRSP_TIMEOUT ) {
264  _MRSP_Restore_priority( executing, initial_priority );
265  }
266  }
267 
268  return status;
269 }
270 
271 RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain(
272  MRSP_Control *mrsp,
273  Thread_Control *executing,
274  bool wait,
275  Watchdog_Interval timeout,
276  ISR_lock_Context *lock_context
277 )
278 {
279  MRSP_Status status;
280  const Scheduler_Control *scheduler = _Scheduler_Get_own( executing );
281  uint32_t scheduler_index = _Scheduler_Get_index( scheduler );
282  Priority_Control initial_priority = executing->current_priority;
283  Priority_Control ceiling_priority =
284  _MRSP_Get_ceiling_priority( mrsp, scheduler_index );
285  bool priority_ok = !_Thread_Priority_less_than(
286  ceiling_priority,
287  initial_priority
288  );
289  Resource_Node *owner;
290 
291  if ( !priority_ok) {
292  _ISR_lock_ISR_enable( lock_context );
293  return MRSP_INVALID_PRIORITY;
294  }
295 
296  _ISR_lock_Acquire( &mrsp->Lock, lock_context );
297  owner = _Resource_Get_owner( &mrsp->Resource );
298  if ( owner == NULL ) {
299  _MRSP_Claim_ownership(
300  mrsp,
301  executing,
302  initial_priority,
303  ceiling_priority,
304  lock_context
305  );
306  status = MRSP_SUCCESSFUL;
307  } else if (
308  wait
309  && _Resource_Node_get_root( owner ) != &executing->Resource_node
310  ) {
311  status = _MRSP_Wait_for_ownership(
312  mrsp,
313  owner,
314  executing,
315  initial_priority,
316  ceiling_priority,
317  timeout,
318  lock_context
319  );
320  } else {
321  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
322  /* Not available, nested access or deadlock */
323  status = MRSP_UNSATISFIED;
324  }
325 
326  return status;
327 }
328 
329 RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release(
330  MRSP_Control *mrsp,
331  Thread_Control *executing,
332  ISR_lock_Context *lock_context
333 )
334 {
335  Priority_Control initial_priority;
336  Per_CPU_Control *cpu_self;
337  ISR_lock_Context giant_lock_context;
338 
339  if ( _Resource_Get_owner( &mrsp->Resource ) != &executing->Resource_node ) {
340  _ISR_lock_ISR_enable( lock_context );
341  return MRSP_NOT_OWNER_OF_RESOURCE;
342  }
343 
344  if (
346  &mrsp->Resource,
347  &executing->Resource_node
348  )
349  ) {
350  _ISR_lock_ISR_enable( lock_context );
351  return MRSP_INCORRECT_STATE;
352  }
353 
354  initial_priority = mrsp->initial_priority_of_owner;
355 
356  _ISR_lock_Acquire( &mrsp->Lock, lock_context );
357 
358  _MRSP_Giant_acquire( &giant_lock_context );
359 
360  _Resource_Extract( &mrsp->Resource );
361 
362  if ( _Chain_Is_empty( &mrsp->Rivals ) ) {
363  _Resource_Set_owner( &mrsp->Resource, NULL );
364  } else {
365  MRSP_Rival *rival = (MRSP_Rival *)
366  _Chain_Get_first_unprotected( &mrsp->Rivals );
367  Thread_Control *new_owner;
368 
369  /*
370  * This must be inside the critical section since the status prevents a
371  * potential double extraction in _MRSP_Timeout().
372  */
373  rival->status = MRSP_SUCCESSFUL;
374 
375  new_owner = rival->thread;
376  mrsp->initial_priority_of_owner = rival->initial_priority;
377  _Resource_Node_extract( &new_owner->Resource_node );
378  _Resource_Node_set_dependency( &new_owner->Resource_node, NULL );
379  _Resource_Node_add_resource( &new_owner->Resource_node, &mrsp->Resource );
380  _Resource_Set_owner( &mrsp->Resource, &new_owner->Resource_node );
381  _Scheduler_Thread_change_help_state( new_owner, SCHEDULER_HELP_ACTIVE_OWNER );
382  _Scheduler_Thread_change_resource_root( new_owner, new_owner );
383  }
384 
385  if ( !_Resource_Node_owns_resources( &executing->Resource_node ) ) {
386  _Scheduler_Thread_change_help_state( executing, SCHEDULER_HELP_YOURSELF );
387  }
388 
389  _MRSP_Giant_release( &giant_lock_context );
390 
391  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
392  _ISR_lock_Release_and_ISR_enable( &mrsp->Lock, lock_context );
393 
394  _MRSP_Restore_priority( executing, initial_priority );
395 
396  _Thread_Dispatch_enable( cpu_self );
397 
398  return MRSP_SUCCESSFUL;
399 }
400 
401 RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp )
402 {
403  if ( _Resource_Get_owner( &mrsp->Resource ) != NULL ) {
404  return MRSP_RESOUCE_IN_USE;
405  }
406 
407  _ISR_lock_Destroy( &mrsp->Lock );
408  _Workspace_Free( mrsp->ceiling_priorities );
409 
410  return MRSP_SUCCESSFUL;
411 }
412 
415 #ifdef __cplusplus
416 }
417 #endif /* __cplusplus */
418 
419 #endif /* RTEMS_SMP */
420 
421 #endif /* _RTEMS_SCORE_MRSPIMPL_H */
RTEMS_INLINE_ROUTINE Priority_Control _Thread_Priority_highest(Priority_Control left, Priority_Control right)
Returns the highest priority of the left and right thread priorities in the intuitive sense of priori...
Definition: threadimpl.h:351
RTEMS_INLINE_ROUTINE void _Chain_Append_unprotected(Chain_Control *the_chain, Chain_Node *the_node)
Append a node (unprotected).
Definition: chainimpl.h:743
Scheduler control.
Definition: scheduler.h:192
Priority_Control current_priority
This field is the current priority state of this thread.
Definition: thread.h:683
#define _ISR_lock_ISR_disable_and_acquire(_lock, _context)
Acquires an ISR lock.
Definition: isrlock.h:205
#define _ISR_lock_Acquire(_lock, _context)
Acquires an ISR lock inside an ISR disabled section.
Definition: isrlock.h:257
Inlined Routines in the Watchdog Handler.
#define RTEMS_INLINE_ROUTINE
The following (in conjunction with compiler arguments) are used to choose between the use of static i...
Definition: basedefs.h:135
RTEMS_INLINE_ROUTINE void _Thread_Dispatch_enable(Per_CPU_Control *cpu_self)
Enables thread dispatching.
Definition: threaddispatch.h:304
Inlined Routines Associated with the Manipulation of the Scheduler.
#define _ISR_lock_Initialize(_lock, _name)
Initializes an ISR lock.
Definition: isrlock.h:167
RTEMS_INLINE_ROUTINE void _Chain_Extract_unprotected(Chain_Node *the_node)
Extract this node (unprotected).
Definition: chainimpl.h:639
void _Thread_Raise_priority(Thread_Control *the_thread, Priority_Control new_priority)
Raises the priority of a thread.
Definition: threadchangepriority.c:99
RTEMS_INLINE_ROUTINE void _Chain_Initialize_empty(Chain_Control *the_chain)
Initialize this chain as empty.
Definition: chainimpl.h:613
Resource node to reflect ownership of resources and a dependency on a resource.
Definition: resource.h:150
uint32_t Priority_Control
The following type defines the control block used to manage thread priorities.
Definition: priority.h:56
RTEMS_INLINE_ROUTINE bool _Chain_Is_empty(const Chain_Control *the_chain)
Is the chain empty.
Definition: chainimpl.h:499
RTEMS_INLINE_ROUTINE bool _Resource_Is_most_recently_obtained(const Resource_Control *resource, const Resource_Node *node)
Returns true if this is the most recently obtained resource of the node, and false otherwise...
Definition: resourceimpl.h:150
This structure defines the Thread Control Block (TCB).
Definition: thread.h:671
#define _ISR_lock_ISR_enable(_context)
Restores the saved interrupt state of the ISR lock context.
Definition: isrlock.h:358
Per CPU Core Structure.
Definition: percpu.h:233
#define _ISR_lock_Release(_lock, _context)
Releases an ISR lock inside an ISR disabled section.
Definition: isrlock.h:279
Information Related to the RAM Workspace.
uint32_t resource_count
This field is the number of mutexes currently held by this thread.
Definition: thread.h:713
#define _ISR_lock_Release_and_ISR_enable(_lock, _context)
Releases an ISR lock.
Definition: isrlock.h:230
Priority_Control real_priority
This field is the base priority of this thread.
Definition: thread.h:691
#define _Assert(_e)
Assertion similar to assert() controlled via RTEMS_DEBUG instead of NDEBUG.
Definition: assert.h:83
Chain Handler API.
RTEMS_INLINE_ROUTINE bool _Thread_Priority_less_than(Priority_Control left, Priority_Control right)
Returns true if the left thread priority is less than the right thread priority in the intuitive sens...
Definition: threadimpl.h:339
RTEMS_INLINE_ROUTINE void _Watchdog_Initialize(Watchdog_Control *the_watchdog, Watchdog_Service_routine_entry routine, Objects_Id id, void *user_data)
This routine initializes the specified watchdog.
Definition: watchdogimpl.h:299
uint32_t Watchdog_Interval
Type is used to specify the length of intervals.
Definition: watchdog.h:47
void _Workspace_Free(void *block)
Free memory to the workspace.
Definition: wkspace.c:172
Watchdog_Control Timer
This field is the Watchdog used to manage thread delays and timeouts.
Definition: thread.h:717
void _Thread_Change_priority(Thread_Control *the_thread, Priority_Control new_priority, void *arg, Thread_Change_priority_filter filter, bool prepend_it)
Changes the priority of a thread if allowed by the filter function.
Definition: threadchangepriority.c:25
RTEMS_INLINE_ROUTINE Chain_Node * _Chain_Get_first_unprotected(Chain_Control *the_chain)
Get the first node (unprotected).
Definition: chainimpl.h:667
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:251
Local ISR lock context for acquire and release pairs.
Definition: isrlock.h:65
uint32_t Objects_Id
The following type defines the control block used to manage object IDs.
Definition: object.h:122
void * _Workspace_Allocate(size_t size)
Allocate memory from workspace.
Definition: wkspace.c:145
#define _ISR_lock_Destroy(_lock)
Destroys an ISR lock.
Definition: isrlock.h:181
RTEMS_INLINE_ROUTINE void _Watchdog_Insert_ticks(Watchdog_Control *the_watchdog, Watchdog_Interval units)
This routine inserts THE_WATCHDOG into the ticks watchdog chain for a time of UNITS ticks...
Definition: watchdogimpl.h:371
#define _Scheduler_Count
Count of registered schedulers.
Definition: scheduler.h:352