source: rtems/cpukit/include/rtems/score/mrspimpl.h @ 255fe43

Last change on this file since 255fe43 was 255fe43, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 20:40:44

cpukit/: Scripted embedded brains header file clean up

Updates #4625.

  • Property mode set to 100644
File size: 15.8 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreMRSP
7 *
8 * @brief This header file provides interfaces of the
9 *   @ref RTEMSScoreMRSP which are only used by the implementation.
10 */
11
12/*
13 * Copyright (c) 2014, 2019 embedded brains GmbH.  All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#ifndef _RTEMS_SCORE_MRSPIMPL_H
38#define _RTEMS_SCORE_MRSPIMPL_H
39
40#include <rtems/score/mrsp.h>
41
42#if defined(RTEMS_SMP)
43
44#include <rtems/score/assert.h>
45#include <rtems/score/status.h>
46#include <rtems/score/threadqimpl.h>
47#include <rtems/score/watchdogimpl.h>
48
49#ifdef __cplusplus
50extern "C" {
51#endif /* __cplusplus */
52
53/**
54 * @addtogroup RTEMSScoreMRSP
55 *
56 * @{
57 */
58
59#define MRSP_TQ_OPERATIONS &_Thread_queue_Operations_priority_inherit
60
61/**
62 * @brief Acquires critical accordingt to MrsP.
63 *
64 * @param mrsp The MrsP control for the operation.
65 * @param queue_context The thread queue context.
66 */
67RTEMS_INLINE_ROUTINE void _MRSP_Acquire_critical(
68  MRSP_Control         *mrsp,
69  Thread_queue_Context *queue_context
70)
71{
72  _Thread_queue_Acquire_critical( &mrsp->Wait_queue, queue_context );
73}
74
75/**
76 * @brief Releases according to MrsP.
77 *
78 * @param mrsp The MrsP control for the operation.
79 * @param queue_context The thread queue context.
80 */
81RTEMS_INLINE_ROUTINE void _MRSP_Release(
82  MRSP_Control         *mrsp,
83  Thread_queue_Context *queue_context
84)
85{
86  _Thread_queue_Release( &mrsp->Wait_queue, queue_context );
87}
88
89/**
90 * @brief Gets owner of the MrsP control.
91 *
92 * @param mrsp The MrsP control to get the owner from.
93 *
94 * @return The owner of the Mrsp control.
95 */
96RTEMS_INLINE_ROUTINE Thread_Control *_MRSP_Get_owner(
97  const MRSP_Control *mrsp
98)
99{
100  return mrsp->Wait_queue.Queue.owner;
101}
102
103/**
104 * @brief Sets owner of the MrsP control.
105 *
106 * @param[out] mrsp The MrsP control to set the owner of.
107 * @param owner The desired new owner for @a mrsp.
108 */
109RTEMS_INLINE_ROUTINE void _MRSP_Set_owner(
110  MRSP_Control   *mrsp,
111  Thread_Control *owner
112)
113{
114  mrsp->Wait_queue.Queue.owner = owner;
115}
116
117/**
118 * @brief Gets priority of the MrsP control.
119 *
120 * @param mrsp The mrsp to get the priority from.
121 * @param scheduler The corresponding scheduler.
122 *
123 * @return The priority of the MrsP control.
124 */
125RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_priority(
126  const MRSP_Control      *mrsp,
127  const Scheduler_Control *scheduler
128)
129{
130  uint32_t scheduler_index;
131
132  scheduler_index = _Scheduler_Get_index( scheduler );
133  return mrsp->ceiling_priorities[ scheduler_index ];
134}
135
136/**
137 * @brief Sets priority of the MrsP control
138 *
139 * @param[out] mrsp The MrsP control to set the priority of.
140 * @param schedulger The corresponding scheduler.
141 * @param new_priority The new priority for the MrsP control
142 */
143RTEMS_INLINE_ROUTINE void _MRSP_Set_priority(
144  MRSP_Control            *mrsp,
145  const Scheduler_Control *scheduler,
146  Priority_Control         new_priority
147)
148{
149  uint32_t scheduler_index;
150
151  scheduler_index = _Scheduler_Get_index( scheduler );
152  mrsp->ceiling_priorities[ scheduler_index ] = new_priority;
153}
154
155/**
156 * @brief Adds the priority to the given thread.
157 *
158 * @param mrsp The MrsP control for the operation.
159 * @param[in, out] thread The thread to add the priority node to.
160 * @param[out] priority_node The priority node to initialize and add to
161 *      the thread.
162 * @param queue_context The thread queue context.
163 *
164 * @retval STATUS_SUCCESSFUL The operation succeeded.
165 * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the thread
166 *      exceeds the ceiling priority.
167 */
168RTEMS_INLINE_ROUTINE Status_Control _MRSP_Raise_priority(
169  MRSP_Control         *mrsp,
170  Thread_Control       *thread,
171  Priority_Node        *priority_node,
172  Thread_queue_Context *queue_context
173)
174{
175  Status_Control           status;
176  ISR_lock_Context         lock_context;
177  const Scheduler_Control *scheduler;
178  Priority_Control         ceiling_priority;
179  Scheduler_Node          *scheduler_node;
180
181  _Thread_queue_Context_clear_priority_updates( queue_context );
182  _Thread_Wait_acquire_default_critical( thread, &lock_context );
183
184  scheduler = _Thread_Scheduler_get_home( thread );
185  scheduler_node = _Thread_Scheduler_get_home_node( thread );
186  ceiling_priority = _MRSP_Get_priority( mrsp, scheduler );
187
188  if (
189    ceiling_priority
190      <= _Priority_Get_priority( &scheduler_node->Wait.Priority )
191  ) {
192    _Priority_Node_initialize( priority_node, ceiling_priority );
193    _Thread_Priority_add( thread, priority_node, queue_context );
194    status = STATUS_SUCCESSFUL;
195  } else {
196    status = STATUS_MUTEX_CEILING_VIOLATED;
197  }
198
199  _Thread_Wait_release_default_critical( thread, &lock_context );
200  return status;
201}
202
203/**
204 * @brief Removes the priority from the given thread.
205 *
206 * @param[in, out] The thread to remove the priority from.
207 * @param priority_node The priority node to remove from the thread
208 * @param queue_context The thread queue context.
209 */
210RTEMS_INLINE_ROUTINE void _MRSP_Remove_priority(
211  Thread_Control       *thread,
212  Priority_Node        *priority_node,
213  Thread_queue_Context *queue_context
214)
215{
216  ISR_lock_Context lock_context;
217
218  _Thread_queue_Context_clear_priority_updates( queue_context );
219  _Thread_Wait_acquire_default_critical( thread, &lock_context );
220  _Thread_Priority_remove( thread, priority_node, queue_context );
221  _Thread_Wait_release_default_critical( thread, &lock_context );
222}
223
224/**
225 * @brief Replaces the given priority node with the ceiling priority of
226 *      the MrsP control.
227 *
228 * @param mrsp The mrsp control for the operation.
229 * @param[out] thread The thread to replace the priorities.
230 * @param ceiling_priority The node to be replaced.
231 */
232RTEMS_INLINE_ROUTINE void _MRSP_Replace_priority(
233  MRSP_Control   *mrsp,
234  Thread_Control *thread,
235  Priority_Node  *ceiling_priority
236)
237{
238  ISR_lock_Context lock_context;
239
240  _Thread_Wait_acquire_default( thread, &lock_context );
241  _Thread_Priority_replace(
242    thread,
243    ceiling_priority,
244    &mrsp->Ceiling_priority
245  );
246  _Thread_Wait_release_default( thread, &lock_context );
247}
248
249/**
250 * @brief Claims ownership of the MrsP control.
251 *
252 * @param mrsp The MrsP control to claim the ownership of.
253 * @param[in, out] executing The currently executing thread.
254 * @param queue_context The thread queue context.
255 *
256 * @retval STATUS_SUCCESSFUL The operation succeeded.
257 * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the executing
258 *      thread exceeds the ceiling priority.
259 */
260RTEMS_INLINE_ROUTINE Status_Control _MRSP_Claim_ownership(
261  MRSP_Control         *mrsp,
262  Thread_Control       *executing,
263  Thread_queue_Context *queue_context
264)
265{
266  Status_Control   status;
267  Per_CPU_Control *cpu_self;
268
269  status = _MRSP_Raise_priority(
270    mrsp,
271    executing,
272    &mrsp->Ceiling_priority,
273    queue_context
274  );
275
276  if ( status != STATUS_SUCCESSFUL ) {
277    _MRSP_Release( mrsp, queue_context );
278    return status;
279  }
280
281  _MRSP_Set_owner( mrsp, executing );
282  cpu_self = _Thread_queue_Dispatch_disable( queue_context );
283  _MRSP_Release( mrsp, queue_context );
284  _Thread_Priority_update_and_make_sticky( executing );
285  _Thread_Dispatch_enable( cpu_self );
286  return STATUS_SUCCESSFUL;
287}
288
289/**
290 * @brief Initializes a MrsP control.
291 *
292 * @param[out] mrsp The MrsP control that is initialized.
293 * @param scheduler The scheduler for the operation.
294 * @param ceiling_priority
295 * @param executing The currently executing thread.  Ignored in this method.
296 * @param initially_locked Indicates whether the MrsP control shall be initally
297 *      locked. If it is initially locked, this method returns STATUS_INVALID_NUMBER.
298 *
299 * @retval STATUS_SUCCESSFUL The operation succeeded.
300 * @retval STATUS_INVALID_NUMBER The MrsP control is initially locked.
301 * @retval STATUS_NO_MEMORY There is not enough memory to allocate.
302 */
303RTEMS_INLINE_ROUTINE Status_Control _MRSP_Initialize(
304  MRSP_Control            *mrsp,
305  const Scheduler_Control *scheduler,
306  Priority_Control         ceiling_priority,
307  Thread_Control          *executing,
308  bool                     initially_locked
309)
310{
311  Thread_queue_Context queue_context;
312  ISR_Level            level;
313  size_t               scheduler_count;
314  size_t               i;
315  Status_Control       status;
316
317  scheduler_count = _Scheduler_Count;
318
319  for ( i = 0 ; i < scheduler_count ; ++i ) {
320    const Scheduler_Control *scheduler_of_index;
321
322    scheduler_of_index = &_Scheduler_Table[ i ];
323
324    if ( scheduler != scheduler_of_index ) {
325      mrsp->ceiling_priorities[ i ] =
326        _Scheduler_Map_priority( scheduler_of_index, 0 );
327    } else {
328      mrsp->ceiling_priorities[ i ] = ceiling_priority;
329    }
330  }
331
332  _Thread_queue_Object_initialize( &mrsp->Wait_queue );
333
334  if ( !initially_locked ) {
335    return STATUS_SUCCESSFUL;
336  }
337
338  _Thread_queue_Context_initialize( &queue_context );
339  _Thread_queue_Context_ISR_disable( &queue_context, level );
340  _Thread_queue_Context_set_ISR_level( &queue_context, level );
341  _MRSP_Acquire_critical( mrsp, &queue_context );
342  status = _MRSP_Claim_ownership( mrsp, executing, &queue_context );
343
344  if ( status != STATUS_SUCCESSFUL ) {
345    _Thread_queue_Destroy( &mrsp->Wait_queue );
346  }
347
348  return status;
349}
350
351/**
352 * @brief Waits for the ownership of the MrsP control.
353 *
354 * @param[in, out] mrsp The MrsP control to get the ownership of.
355 * @param[in, out] executing The currently executing thread.
356 * @param queue_context the thread queue context.
357 *
358 * @retval STATUS_SUCCESSFUL The operation succeeded.
359 * @retval STATUS_MUTEX_CEILING_VIOLATED The wait priority of the
360 *      currently executing thread exceeds the ceiling priority.
361 * @retval STATUS_DEADLOCK A deadlock occurred.
362 * @retval STATUS_TIMEOUT A timeout occurred.
363 */
364RTEMS_INLINE_ROUTINE Status_Control _MRSP_Wait_for_ownership(
365  MRSP_Control         *mrsp,
366  Thread_Control       *executing,
367  Thread_queue_Context *queue_context
368)
369{
370  Status_Control status;
371  Priority_Node  ceiling_priority;
372
373  status = _MRSP_Raise_priority(
374    mrsp,
375    executing,
376    &ceiling_priority,
377    queue_context
378  );
379
380  if ( status != STATUS_SUCCESSFUL ) {
381    _MRSP_Release( mrsp, queue_context );
382    return status;
383  }
384
385  _Thread_queue_Context_set_deadlock_callout(
386    queue_context,
387    _Thread_queue_Deadlock_status
388  );
389  status = _Thread_queue_Enqueue_sticky(
390    &mrsp->Wait_queue.Queue,
391    MRSP_TQ_OPERATIONS,
392    executing,
393    queue_context
394  );
395
396  if ( status == STATUS_SUCCESSFUL ) {
397    _MRSP_Replace_priority( mrsp, executing, &ceiling_priority );
398  } else {
399    Per_CPU_Control *cpu_self;
400
401    _ISR_lock_ISR_disable( &queue_context->Lock_context.Lock_context );
402    _MRSP_Remove_priority( executing, &ceiling_priority, queue_context );
403    cpu_self = _Thread_Dispatch_disable_critical(
404      &queue_context->Lock_context.Lock_context
405    );
406    _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
407
408    if ( status != STATUS_DEADLOCK ) {
409      _Thread_Priority_update_and_clean_sticky( executing );
410    } else {
411      _Thread_Priority_update_ignore_sticky( executing );
412    }
413
414    _Thread_Dispatch_enable( cpu_self );
415  }
416
417  return status;
418}
419
420/**
421 * @brief Seizes the MrsP mutex.
422 *
423 * @param[in, out] mrsp is the MrsP mutex to seize.
424 *
425 * @param[in, out] executing is the currently executing thread.
426 *
427 * @param wait shall be true, if the executing thread is willing to wait,
428 *   otherwise it shall be false.
429 *
430 * @param[in, out] queue_context is the thread queue context.
431 *
432 * @retval STATUS_SUCCESSFUL The requested operation was successful.
433 *
434 * @retval STATUS_UNAVAILABLE Seizing the mutex was not immmediately possible.
435 *
436 * @retval STATUS_DEADLOCK The executing thread was already the owner of
437 *   the mutex.
438 *
439 * @retval STATUS_MUTEX_CEILING_VIOLATED The current priority of the executing
440 *   thread exceeds the ceiling priority of the mutex.
441 */
442RTEMS_INLINE_ROUTINE Status_Control _MRSP_Seize(
443  MRSP_Control         *mrsp,
444  Thread_Control       *executing,
445  bool                  wait,
446  Thread_queue_Context *queue_context
447)
448{
449  Status_Control  status;
450  Thread_Control *owner;
451
452  _MRSP_Acquire_critical( mrsp, queue_context );
453
454  owner = _MRSP_Get_owner( mrsp );
455
456  if ( owner == NULL ) {
457    status = _MRSP_Claim_ownership( mrsp, executing, queue_context );
458  } else if ( owner == executing ) {
459    _MRSP_Release( mrsp, queue_context );
460    status = STATUS_DEADLOCK;
461  } else if ( wait ) {
462    status = _MRSP_Wait_for_ownership( mrsp, executing, queue_context );
463  } else {
464    _MRSP_Release( mrsp, queue_context );
465    status = STATUS_UNAVAILABLE;
466  }
467
468  return status;
469}
470
471/**
472 * @brief Surrenders the MrsP control.
473 *
474 * @param[in, out] mrsp The MrsP control to surrender the control of.
475 * @param[in, out] executing The currently executing thread.
476 * @param queue_context The thread queue context.
477 *
478 * @retval STATUS_SUCCESSFUL The operation succeeded.
479 * @retval STATUS_NOT_OWNER The executing thread does not own the MrsP control.
480 */
481RTEMS_INLINE_ROUTINE Status_Control _MRSP_Surrender(
482  MRSP_Control         *mrsp,
483  Thread_Control       *executing,
484  Thread_queue_Context *queue_context
485)
486{
487  Thread_queue_Heads *heads;
488
489  if ( _MRSP_Get_owner( mrsp ) != executing ) {
490    _ISR_lock_ISR_enable( &queue_context->Lock_context.Lock_context );
491    return STATUS_NOT_OWNER;
492  }
493
494  _MRSP_Acquire_critical( mrsp, queue_context );
495
496  _MRSP_Set_owner( mrsp, NULL );
497  _MRSP_Remove_priority( executing, &mrsp->Ceiling_priority, queue_context );
498
499  heads = mrsp->Wait_queue.Queue.heads;
500
501  if ( heads == NULL ) {
502    Per_CPU_Control *cpu_self;
503
504    cpu_self = _Thread_Dispatch_disable_critical(
505      &queue_context->Lock_context.Lock_context
506    );
507    _MRSP_Release( mrsp, queue_context );
508    _Thread_Priority_update_and_clean_sticky( executing );
509    _Thread_Dispatch_enable( cpu_self );
510    return STATUS_SUCCESSFUL;
511  }
512
513  _Thread_queue_Surrender_sticky(
514    &mrsp->Wait_queue.Queue,
515    heads,
516    executing,
517    queue_context,
518    MRSP_TQ_OPERATIONS
519  );
520  return STATUS_SUCCESSFUL;
521}
522
523/**
524 * @brief Checks if the MrsP control can be destroyed.
525 *
526 * @param mrsp The MrsP control for the operation.
527 *
528 * @retval STATUS_SUCCESSFUL The MrsP is currently not used
529 *      and can be destroyed.
530 * @retval STATUS_RESOURCE_IN_USE The MrsP control is in use,
531 *      it cannot be destroyed.
532 */
533RTEMS_INLINE_ROUTINE Status_Control _MRSP_Can_destroy( MRSP_Control *mrsp )
534{
535  if ( _MRSP_Get_owner( mrsp ) != NULL ) {
536    return STATUS_RESOURCE_IN_USE;
537  }
538
539  return STATUS_SUCCESSFUL;
540}
541
542/**
543 * @brief Destroys the MrsP control
544 *
545 * @param[in, out] The mrsp that is about to be destroyed.
546 * @param queue_context The thread queue context.
547 */
548RTEMS_INLINE_ROUTINE void _MRSP_Destroy(
549  MRSP_Control         *mrsp,
550  Thread_queue_Context *queue_context
551)
552{
553  _MRSP_Release( mrsp, queue_context );
554  _Thread_queue_Destroy( &mrsp->Wait_queue );
555}
556
557/** @} */
558
559#ifdef __cplusplus
560}
561#endif /* __cplusplus */
562
563#endif /* RTEMS_SMP */
564
565#endif /* _RTEMS_SCORE_MRSPIMPL_H */
Note: See TracBrowser for help on using the repository browser.