source: rtems/cpukit/include/rtems/score/priorityimpl.h @ a660e9dc

Last change on this file since a660e9dc was a660e9dc, checked in by Sebastian Huber <sebastian.huber@…>, on 09/08/22 at 08:37:05

Do not use RTEMS_INLINE_ROUTINE

Directly use "static inline" which is available in C99 and later. This brings
the RTEMS implementation closer to standard C.

Close #3935.

  • Property mode set to 100644
File size: 21.2 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScorePriority
7 *
8 * @brief This header file provides interfaces of the
9 *   @ref RTEMSScorePriority which are only used by the implementation.
10 */
11
12/*
13 * Copyright (c) 2016 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_PRIORITYIMPL_H
38#define _RTEMS_SCORE_PRIORITYIMPL_H
39
40#include <rtems/score/priority.h>
41#include <rtems/score/scheduler.h>
42
43#ifdef __cplusplus
44extern "C" {
45#endif /* __cplusplus */
46
47/**
48 * @addtogroup RTEMSScorePriority
49 *
50 * @{
51 */
52
53 /**
54  * @brief The priority group order determines if a priority node is inserted
55  *   as the first or last node into its priority group.
56  *
57  * The values of the enumerators matter.  The least significant bit of a
58  * ::Priority_Control value is not used for the actual priority of a node.
59  * During insertion the least significant bit is used to determine the
60  * ordering within a priority group based on the enumerator values.
61  */
62typedef enum {
63  /**
64   * @brief Priority group first option requests that the priority node is
65   *   inserted as the first node into its priority group.
66   */
67  PRIORITY_GROUP_FIRST = 0,
68
69  /**
70   * @brief Priority group last option requests that the priority node is
71   *   inserted as the last node into its priority group.
72   */
73  PRIORITY_GROUP_LAST = 1
74} Priority_Group_order;
75
76/**
77 * @brief Initializes the priority actions empty.
78 *
79 * @param[out] actions The actions to be initialized empty.
80 */
81static inline void _Priority_Actions_initialize_empty(
82  Priority_Actions *actions
83)
84{
85  actions->actions = NULL;
86}
87
88/**
89 * @brief Initializes the priority actions with the given information.
90 *
91 * @param[out] actions The actions to be initialized.
92 * @param aggregation The aggregation for the @a actions to be initialized.
93 * @param node The action node for the @a actions to be initialized.
94 * @param type The action type for the @a actions to be initialized.
95 */
96static inline void _Priority_Actions_initialize_one(
97  Priority_Actions     *actions,
98  Priority_Aggregation *aggregation,
99  Priority_Node        *node,
100  Priority_Action_type  type
101)
102{
103#if defined(RTEMS_SMP)
104  aggregation->Action.next = NULL;
105#endif
106  aggregation->Action.node = node;
107  aggregation->Action.type = type;
108
109  actions->actions = aggregation;
110}
111
112/**
113 * @brief Checks if the priority actions is empty.
114 *
115 * @param actions The priority actions to check if it is empty.
116 *
117 * @retval true The priority actions @a actions is empty.
118 * @retval false The priority actions @a actions is empty.
119 */
120static inline bool _Priority_Actions_is_empty(
121  const Priority_Actions *actions
122)
123{
124  return actions->actions == NULL;
125}
126
127/**
128 * @brief Moves the priority actions' actions.
129 *
130 * @param[in, out] actions The priority actions to move the actions away from.
131 *
132 * @return The former actions of @a actions that were moved.
133 */
134static inline Priority_Aggregation *_Priority_Actions_move(
135  Priority_Actions *actions
136)
137{
138  Priority_Aggregation *aggregation;
139
140  aggregation = actions->actions;
141  actions->actions = NULL;
142
143  return aggregation;
144}
145
146/**
147 * @brief Adds actions to the priority actions' actions.
148 *
149 * @param[in, out] actions The priority actions to add actions to.
150 * @param[out] aggregation The actions to add to @a actions.
151 */
152static inline void _Priority_Actions_add(
153  Priority_Actions     *actions,
154  Priority_Aggregation *aggregation
155)
156{
157#if defined(RTEMS_SMP)
158  /*
159   * Priority aggregations are only added to action lists, so do not care about
160   * the current next pointer value.
161   */
162  aggregation->Action.next = actions->actions;
163#endif
164  actions->actions = aggregation;
165}
166
167/**
168 * @brief Initializes the priority node to the given priority.
169 *
170 * @param[out] node The priority node to be initialized.
171 * @param priority The priority to initialize @a node to.
172 */
173static inline void _Priority_Node_initialize(
174  Priority_Node    *node,
175  Priority_Control  priority
176)
177{
178  node->priority = priority;
179  _RBTree_Initialize_node( &node->Node.RBTree );
180}
181
182/**
183 * @brief Sets the priority of the priority node to the given priority.
184 *
185 * @param[out] node The priority node to set the priority of.
186 * @param priority The new priority for @a node.
187 */
188static inline void _Priority_Node_set_priority(
189  Priority_Node    *node,
190  Priority_Control  priority
191)
192{
193  node->priority = priority;
194}
195
196/**
197 * @brief Sets the priority node inactive.
198 *
199 * @param[in, out] node The priority node to set inactive.
200 */
201static inline void _Priority_Node_set_inactive(
202  Priority_Node *node
203)
204{
205  _RBTree_Set_off_tree( &node->Node.RBTree );
206}
207
208/**
209 * @brief Checks if the priority node is active.
210 *
211 * @param node The priority node that shall be verified if it is active.
212 *
213 * @retval true The priority node is active.
214 * @retval false The priority node is inactive.
215 */
216static inline bool _Priority_Node_is_active(
217  const Priority_Node *node
218)
219{
220  return !_RBTree_Is_node_off_tree( &node->Node.RBTree );
221}
222
223/**
224 * @brief Initializes the priority aggregation empty.
225 *
226 * @param[out] aggregation The priority aggregaton to initialize empty.
227 */
228static inline void _Priority_Initialize_empty(
229  Priority_Aggregation *aggregation
230)
231{
232#if defined(RTEMS_DEBUG)
233#if defined(RTEMS_SMP)
234  aggregation->Action.next = NULL;
235#endif
236  aggregation->Action.node = NULL;
237  aggregation->Action.type = PRIORITY_ACTION_INVALID;
238#endif
239  _RBTree_Initialize_node( &aggregation->Node.Node.RBTree );
240  _RBTree_Initialize_empty( &aggregation->Contributors );
241}
242
243/**
244 * @brief Initializes the priority aggregation with the given information.
245 *
246 * @param[out] aggregation The priority aggregaton to initialize.
247 * @param node The priority node to initialize @a aggregation with.
248 */
249static inline void _Priority_Initialize_one(
250  Priority_Aggregation *aggregation,
251  Priority_Node        *node
252)
253{
254#if defined(RTEMS_DEBUG)
255#if defined(RTEMS_SMP)
256  aggregation->Action.next = NULL;
257#endif
258  aggregation->Action.node = NULL;
259  aggregation->Action.type = PRIORITY_ACTION_INVALID;
260#endif
261  _Priority_Node_initialize( &aggregation->Node, node->priority );
262  _RBTree_Initialize_one( &aggregation->Contributors, &node->Node.RBTree );
263}
264
265/**
266 * @brief Checks if the priority aggregation is empty.
267 *
268 * @param aggregation The priority aggregation that shall be verified if it is empty.
269 *
270 * @retval true The priority aggregation is empty.
271 * @retval false The priority aggregation is not empty.
272 */
273static inline bool _Priority_Is_empty(
274  const Priority_Aggregation *aggregation
275)
276{
277  return _RBTree_Is_empty( &aggregation->Contributors );
278}
279
280/**
281 * @brief Gets the priority aggregation's priority.
282 *
283 * @param aggregation The priority aggregation to get the priority from.
284 *
285 * @return The priority of @a aggregation.
286 */
287static inline Priority_Control _Priority_Get_priority(
288  const Priority_Aggregation *aggregation
289)
290{
291  return aggregation->Node.priority;
292}
293
294/**
295 * @brief Gets the priority aggregation's scheduler.
296 *
297 * @param aggregation The priority aggregation to get the scheduler from.
298 *
299 * @return The scheduler of @a aggregation.
300 */
301static inline const Scheduler_Control *_Priority_Get_scheduler(
302  const Priority_Aggregation *aggregation
303)
304{
305#if defined(RTEMS_SMP)
306  return aggregation->scheduler;
307#else
308  return &_Scheduler_Table[ 0 ];
309#endif
310}
311
312/**
313 * @brief Gets the minimum node of the priority aggregation
314 *
315 * @param aggregation The priority aggregation to get the minimum node from.
316 *
317 * @return The minimum node of @a aggregation
318 */
319static inline Priority_Node *_Priority_Get_minimum_node(
320  const Priority_Aggregation *aggregation
321)
322{
323  return (Priority_Node *) _RBTree_Minimum( &aggregation->Contributors );
324}
325
326/**
327 * @brief Sets the action node of the priority aggregation.
328 *
329 * @param[out] aggregation The priority aggregation to set the action node of.
330 * @param node The new priority node for @a aggregation.
331 */
332static inline void _Priority_Set_action_node(
333  Priority_Aggregation *aggregation,
334  Priority_Node        *node
335)
336{
337  aggregation->Action.node = node;
338}
339
340/**
341 * @brief Sets the action type of the priority aggregation.
342 *
343 * @param[out] aggregation The priority aggregation to set the action type of.
344 * @param type The new action type for @a aggregation.
345 */
346static inline void _Priority_Set_action_type(
347  Priority_Aggregation *aggregation,
348  Priority_Action_type  type
349)
350{
351  aggregation->Action.type = type;
352}
353
354/**
355 * @brief Sets the action type and action node of the priority aggregation.
356 *
357 * @param[out] aggregation The priority aggregation to set the action type
358 *      and action node of.
359 * @param node The new action node for @a aggregation.
360 * @param type The new action type for @a aggregation.
361 */
362static inline void _Priority_Set_action(
363  Priority_Aggregation *aggregation,
364  Priority_Node        *node,
365  Priority_Action_type  type
366)
367{
368  aggregation->Action.node = node;
369  aggregation->Action.type = type;
370}
371
372#if defined(RTEMS_SMP)
373/**
374 * @brief Gets the next action of the priority aggregation.
375 *
376 * @param aggregation is the priority aggregation to get the next action of.
377 *
378 * @return Returns the next action of the priority aggregation or NULL if there
379 *   is no next action.
380 */
381static inline Priority_Aggregation *_Priority_Get_next_action(
382  const Priority_Aggregation *aggregation
383)
384{
385  return aggregation->Action.next;
386}
387#endif
388
389/**
390 * @brief Compares two priorities.
391 *
392 * @param left The priority control on the left hand side of the comparison.
393 * @param right THe RBTree_Node to get the priority for the comparison from.
394 *
395 * @retval true The priority on the left hand side of the comparison is smaller.
396 * @retval false The priority on the left hand side of the comparison is greater of equal.
397 */
398static inline bool _Priority_Less(
399  const void        *left,
400  const RBTree_Node *right
401)
402{
403  const Priority_Control *the_left;
404  const Priority_Node    *the_right;
405
406  the_left = (const Priority_Control *) left;
407  the_right = RTEMS_CONTAINER_OF( right, Priority_Node, Node.RBTree );
408
409  return *the_left < the_right->priority;
410}
411
412/**
413 * @brief Inserts the node with the given priority into the
414 *      priority aggregation's contributors.
415 *
416 * This method does not handle the case that @a node was the minimal node.
417 *
418 * @param[in, out] aggregation The aggregation to insert the node in its contributors.
419 * @param[in] node The node to insert in the contributors.
420 * @param priority The priority control for the inserted node.
421 *
422 * @retval true The inserted node with its priority is the minimum of the RBTree.
423 * @retval false The inserted node with its priority is not the minimum of the RBTree.
424 */
425static inline bool _Priority_Plain_insert(
426  Priority_Aggregation *aggregation,
427  Priority_Node        *node,
428  Priority_Control      priority
429)
430{
431  return _RBTree_Insert_inline(
432    &aggregation->Contributors,
433    &node->Node.RBTree,
434    &priority,
435    _Priority_Less
436  );
437}
438
439/**
440 * @brief Extracts the priority node from the aggregation.
441 *
442 * This method does not handle the case that @a node was the minimal node.
443 *
444 * @param[in,  out] aggregation The aggregation to extract the node from.
445 * @param node The node to be extracted.
446 */
447static inline void _Priority_Plain_extract(
448  Priority_Aggregation *aggregation,
449  Priority_Node        *node
450)
451{
452  _RBTree_Extract( &aggregation->Contributors, &node->Node.RBTree );
453}
454
455/**
456 * @brief Updates the priority of the node in the aggregation.
457 *
458 * It first extracts the node and inserts it again, with the new @a node priority as key.
459 *   This method does not handle the case that @a node was the minimal node.
460 *
461 * @param[in, out] aggregation The aggregation to change the node in.
462 * @param node The node that has a new priority and will be reinserted in the aggregation.
463 */
464static inline void _Priority_Plain_changed(
465  Priority_Aggregation *aggregation,
466  Priority_Node        *node
467)
468{
469  _Priority_Plain_extract( aggregation, node );
470  _Priority_Plain_insert( aggregation, node, node->priority );
471}
472
473typedef void ( *Priority_Add_handler )(
474  Priority_Aggregation *aggregation,
475  Priority_Actions     *actions,
476  void                 *arg
477);
478
479typedef void ( *Priority_Change_handler )(
480  Priority_Aggregation *aggregation,
481  Priority_Group_order  group_order,
482  Priority_Actions     *actions,
483  void                 *arg
484);
485
486typedef void ( *Priority_Remove_handler )(
487  Priority_Aggregation *aggregation,
488  Priority_Actions     *actions,
489  void                 *arg
490);
491
492/**
493 * @brief Does nothing.
494 *
495 * This method does nothing.
496 *
497 * @param aggregation Is ignored by the method.
498 * @param group_order Is ignored by the method.
499 * @param actions Is ignored by the method.
500 * @param arg Is ignored by the method.
501 */
502static inline void _Priority_Change_nothing(
503  Priority_Aggregation *aggregation,
504  Priority_Group_order  group_order,
505  Priority_Actions     *actions,
506  void                 *arg
507)
508{
509  (void) aggregation;
510  (void) group_order;
511  (void) actions;
512  (void) arg;
513}
514
515/**
516 * @brief Does nothing.
517 *
518 * This method does nothing.
519 *
520 * @param aggregation Is ignored by the method.
521 * @param actions Is ignored by the method.
522 * @param arg Is ignored by the method.
523 */
524static inline void _Priority_Remove_nothing(
525  Priority_Aggregation *aggregation,
526  Priority_Actions     *actions,
527  void                 *arg
528)
529{
530  (void) aggregation;
531  (void) actions;
532  (void) arg;
533}
534
535/**
536 * @brief Inserts the node in a nonempty aggregation and handles change if
537 *      the node is the new minimum.
538 *
539 * @param[in, out] aggregation The aggregation to insert the node into.
540 * @param node The node to be inserted.  The node's priority is used as a key.
541 * @param actions Parameter for @a change that is used if the node is the new
542 *      minimum.
543 * @param change The priority change handler that is called in the case that
544 *      the new node is the minimum of the aggregation.
545 * @param arg Arguments for @a change that is used if the node is the new
546 *      minimum.
547 */
548static inline void _Priority_Non_empty_insert(
549  Priority_Aggregation    *aggregation,
550  Priority_Node           *node,
551  Priority_Actions        *actions,
552  Priority_Change_handler  change,
553  void                    *arg
554)
555{
556  bool is_new_minimum;
557
558  _Assert( !_Priority_Is_empty( aggregation ) );
559  is_new_minimum = _Priority_Plain_insert( aggregation, node, node->priority );
560
561  if ( is_new_minimum ) {
562    aggregation->Node.priority = node->priority;
563    ( *change )( aggregation, PRIORITY_GROUP_LAST, actions, arg );
564  }
565}
566
567/**
568 * @brief
569 *
570 * @param[in, out] aggregation The aggregation to insert the node in.
571 * @param node The node to be inserted.  The node's priority is used as key.
572 * @param actions Priority actions for the case that the aggregation was empty before
573 *      the insert or the node is the new minimum.
574 * @param add Is called in the case that @a aggregation was empty before the insert.
575 * @param change Is called in the case that @a aggregation was nonempty before the
576 *      insert and @a node is the new minimum of the aggregation.
577 * @param arg The arguments for @a change.
578 */
579static inline void _Priority_Insert(
580  Priority_Aggregation    *aggregation,
581  Priority_Node           *node,
582  Priority_Actions        *actions,
583  Priority_Add_handler     add,
584  Priority_Change_handler  change,
585  void                    *arg
586)
587{
588  if ( _Priority_Is_empty( aggregation ) ) {
589    _Priority_Initialize_one( aggregation, node );
590    ( *add )( aggregation, actions, arg );
591  } else {
592    _Priority_Non_empty_insert( aggregation, node, actions, change, arg );
593  }
594}
595
596/**
597 * @brief Extracts the node from the aggregation.
598 *
599 * This method extracts the node from the aggregation and handles the
600 * cases that @a aggregation is empty after the extraction, or that
601 * @a node was the minimal node in @a aggregation by calling remove (if
602 * empty) or change (if @a node was the minimal node).
603 *
604 * @param[in, out] aggregation The aggregation to extract the @a node from.
605 * @param node The node to extract from @a aggregation.
606 * @param actions The actions for the cases that the aggregation is empty
607 *      after the extraction, or the minimal node was extracted.
608 * @param remove Is called in the case that the aggregation is empty after
609 *      the extraction.
610 * @param change Is called in the case that the minimal node was extracted.
611 * @param arg The arguments for @a remove and @a change.
612 */
613static inline void _Priority_Extract(
614  Priority_Aggregation    *aggregation,
615  Priority_Node           *node,
616  Priority_Actions        *actions,
617  Priority_Remove_handler  remove,
618  Priority_Change_handler  change,
619  void                    *arg
620)
621{
622  _Priority_Plain_extract( aggregation, node );
623
624  if ( _Priority_Is_empty( aggregation ) ) {
625    ( *remove )( aggregation, actions, arg );
626  } else {
627    Priority_Node *min;
628
629    /* The aggregation is non-empty, so the minimum node exists. */
630    min = _Priority_Get_minimum_node( aggregation );
631    _Assert( min != NULL );
632
633    if ( node->priority < min->priority ) {
634      aggregation->Node.priority = min->priority;
635      ( *change )( aggregation, PRIORITY_GROUP_FIRST, actions, arg );
636    }
637  }
638}
639
640/**
641 * @brief Extracts the node from the aggregation.
642 *
643 * This method extracts the node from the aggregation and handles the
644 * case that @a node was the minimal node in @a aggregation by calling
645 * change (if @a node was the minimal node).
646 *
647 * @param[in, out] aggregation The aggregation to extract the @a node from.
648 * @param node The node to extract from @a aggregation.
649 * @param actions The actions for the case that the minimal node was extracted.
650 * @param change Is called in the case that the minimal node was extracted.
651 * @param arg The arguments for @a change.
652 */
653static inline void _Priority_Extract_non_empty(
654  Priority_Aggregation    *aggregation,
655  Priority_Node           *node,
656  Priority_Actions        *actions,
657  Priority_Change_handler  change,
658  void                    *arg
659)
660{
661  Priority_Node *min;
662
663  _Priority_Plain_extract( aggregation, node );
664  _Assert( !_Priority_Is_empty( aggregation ) );
665
666  min = _Priority_Get_minimum_node( aggregation );
667
668  if ( node->priority < min->priority ) {
669    aggregation->Node.priority = min->priority;
670    ( *change )( aggregation, PRIORITY_GROUP_FIRST, actions, arg );
671  }
672}
673
674/**
675 * @brief Updates the priority of the node in the aggregation.
676 *
677 * This method handles the case that @a node was the minimal node in
678 * @a aggregation.
679 *
680 * @param[in, out] aggregation The aggregation to change the node in.
681 * @param node The node that has a new priority and will be reinserted in the aggregation.
682 * @param group_order The priority group order which may be used by @ change.
683 * @param actions The actions for the case that the minimal priority is incorrectly set
684 *      after the change.
685 * @param change Is called if the minimal priority is incorrectly set after the change.
686 * @param arg The arguments for @a change.
687 */
688static inline void _Priority_Changed(
689  Priority_Aggregation    *aggregation,
690  Priority_Node           *node,
691  Priority_Group_order     group_order,
692  Priority_Actions        *actions,
693  Priority_Change_handler  change,
694  void                    *arg
695)
696{
697  Priority_Node *min;
698
699  _Priority_Plain_changed( aggregation, node );
700
701  /*
702   * There is at least the changed node in the aggregation, so the minimum node
703   * exists.
704   */
705  min = _Priority_Get_minimum_node( aggregation );
706  _Assert( min != NULL );
707
708  if ( min->priority != aggregation->Node.priority ) {
709    aggregation->Node.priority = min->priority;
710    ( *change )( aggregation, group_order, actions, arg );
711  }
712}
713
714/**
715 * @brief Replaces one node by another.
716 *
717 * The new node has the priority of the old node.
718 *
719 * @param[in, out] aggregation The aggregation to replace @a victim by @a replacement in.
720 * @param victim The node that will be replaced.
721 * @param[out] replacement The node that replaces @a victim.  It obtains its priority
722 *      from @a victim.
723 */
724static inline void _Priority_Replace(
725  Priority_Aggregation *aggregation,
726  Priority_Node        *victim,
727  Priority_Node        *replacement
728)
729{
730  replacement->priority = victim->priority;
731  _RBTree_Replace_node(
732    &aggregation->Contributors,
733    &victim->Node.RBTree,
734    &replacement->Node.RBTree
735  );
736}
737
738/** @} */
739
740#ifdef __cplusplus
741}
742#endif /* __cplusplus */
743
744#endif /* _RTEMS_SCORE_PRIORITYIMPL_H */
Note: See TracBrowser for help on using the repository browser.