source: rtems/cpukit/include/rtems/score/chainimpl.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: 29.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSScoreChain
7 *
8 * @brief This header file provides interfaces of the
9 *   @ref RTEMSScoreChain which are only used by the implementation.
10 */
11
12/*
13 *  Copyright (c) 2010 embedded brains GmbH.
14 *
15 *  COPYRIGHT (c) 1989-2014.
16 *  On-Line Applications Research Corporation (OAR).
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#ifndef _RTEMS_SCORE_CHAINIMPL_H
41#define _RTEMS_SCORE_CHAINIMPL_H
42
43#include <rtems/score/chain.h>
44#include <rtems/score/assert.h>
45
46#ifdef __cplusplus
47extern "C" {
48#endif
49
50/**
51 * @addtogroup RTEMSScoreChain
52 *
53 * @{
54 */
55
56/**
57 *  @brief Chain initializer for an empty chain with designator @a name.
58 */
59#define CHAIN_INITIALIZER_EMPTY(name) \
60  { { { &(name).Tail.Node, NULL }, &(name).Head.Node } }
61
62/**
63 *  @brief Chain initializer for a chain with one @a node.
64 *
65 *  @see CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN().
66 */
67#define CHAIN_INITIALIZER_ONE_NODE( node ) \
68  { { { (node), NULL }, (node) } }
69
70/**
71 *  @brief Chain node initializer for a @a chain containing exactly this node.
72 *
73 *  @see CHAIN_INITIALIZER_ONE_NODE().
74 */
75#define CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( chain ) \
76  { &(chain)->Tail.Node, &(chain)->Head.Node }
77
78/**
79 *  @brief Chain definition for an empty chain with designator @a name.
80 */
81#define CHAIN_DEFINE_EMPTY(name) \
82  Chain_Control name = CHAIN_INITIALIZER_EMPTY(name)
83
84/**
85 *  @brief Initializes a chain header.
86 *
87 *  This routine initializes @a the_chain structure to manage the
88 *  contiguous array of @a number_nodes nodes which starts at
89 *  @a starting_address.  Each node is of @a node_size bytes.
90 *
91 *  @param[out] the_chain Specifies the chain to initialize.
92 *  @param starting_address The starting address of the array
93 *         of elements.
94 *  @param number_nodes The number of nodes that will be in the chain.
95 *  @param node_size The size of each node.
96 */
97void _Chain_Initialize(
98  Chain_Control *the_chain,
99  void          *starting_address,
100  size_t         number_nodes,
101  size_t         node_size
102);
103
104/**
105 * @brief Returns the node count of the chain.
106 *
107 * @param chain The chain to return the node count from.
108 *
109 * @note It does NOT disable interrupts to ensure the atomicity of the
110 * operation.
111 *
112 * @return The node count of the chain.
113 */
114size_t _Chain_Node_count_unprotected( const Chain_Control *chain );
115
116/**
117 * @brief Sets off chain.
118 *
119 * This function sets the next field of the @a node to NULL indicating the @a
120 * node is not part of a chain.
121 *
122 * @param[out] node The node to set off chain.
123 */
124static inline void _Chain_Set_off_chain(
125  Chain_Node *node
126)
127{
128  node->next = NULL;
129#if defined(RTEMS_DEBUG)
130  node->previous = NULL;
131#endif
132}
133
134/**
135 * @brief Initializes a chain node.
136 *
137 * In debug configurations, the node is set off chain.  In all other
138 * configurations, this function does nothing.
139 *
140 * @param[out] the_node The chain node to initialize.
141 */
142static inline void _Chain_Initialize_node( Chain_Node *the_node )
143{
144#if defined(RTEMS_DEBUG)
145  _Chain_Set_off_chain( the_node );
146#else
147  (void) the_node;
148#endif
149}
150
151/**
152 * @brief Checks if the node is off chain.
153 *
154 * This function returns true if the @a node is not on a chain.  A @a node is
155 * off chain if the next field is set to NULL.
156 *
157 * @param node The node to check if it is off chain.
158 *
159 * @retval true The @a node is off chain.
160 * @retval false The @a node is not off chain.
161 */
162static inline bool _Chain_Is_node_off_chain(
163  const Chain_Node *node
164)
165{
166  return node->next == NULL;
167}
168
169/**
170 * @brief Checks if two nodes are equal.
171 *
172 * This function returns true if @a left and @a right are equal,
173 * and false otherwise.
174 *
175 * @param left The node on the left hand side of the comparison.
176 * @param right The node on the right hand side of the comparison.
177 *
178 * @retval true @a left and @a right are equal.
179 * @retval false @a left and @a right are not equal.
180 */
181static inline bool _Chain_Are_nodes_equal(
182  const Chain_Node *left,
183  const Chain_Node *right
184)
185{
186  return left == right;
187}
188
189/**
190 * @brief Returns pointer to chain head.
191 *
192 * This function returns a pointer to the head node on the chain.
193 *
194 * @param[in] the_chain The chain to be operated upon.
195 *
196 * @return This method returns the permanent head node of the chain.
197 */
198static inline Chain_Node *_Chain_Head(
199  Chain_Control *the_chain
200)
201{
202  return &the_chain->Head.Node;
203}
204
205/**
206 * @brief Returns pointer to immutable chain head.
207 *
208 * This function returns a pointer to the head node on the chain.
209 *
210 * @param the_chain The chain to be operated upon.
211 *
212 * @return This method returns the permanent head node of the chain.
213 */
214static inline const Chain_Node *_Chain_Immutable_head(
215  const Chain_Control *the_chain
216)
217{
218  return &the_chain->Head.Node;
219}
220
221/**
222 * @brief Returns pointer to chain tail.
223 *
224 * This function returns a pointer to the tail node on the chain.
225 *
226 * @param[in] the_chain The chain to be operated upon.
227 *
228 * @return This method returns the permanent tail node of the chain.
229 */
230static inline Chain_Node *_Chain_Tail(
231  Chain_Control *the_chain
232)
233{
234  return &the_chain->Tail.Node;
235}
236
237/**
238 * @brief Returns pointer to immutable chain tail.
239 *
240 * This function returns a pointer to the tail node on the chain.
241 *
242 * @param the_chain The chain to be operated upon.
243 *
244 * @return This method returns the permanent tail node of the chain.
245 */
246static inline const Chain_Node *_Chain_Immutable_tail(
247  const Chain_Control *the_chain
248)
249{
250  return &the_chain->Tail.Node;
251}
252
253/**
254 * @brief Returns pointer to chain's first node.
255 *
256 * This function returns a pointer to the first node on the chain after the
257 * head.
258 *
259 * @param the_chain The chain to be operated upon.
260 *
261 * @return This method returns the first node of the chain.
262 */
263static inline Chain_Node *_Chain_First(
264  const Chain_Control *the_chain
265)
266{
267  return _Chain_Immutable_head( the_chain )->next;
268}
269
270/**
271 * @brief Returns pointer to immutable chain's first node.
272 *
273 * This function returns a pointer to the first node on the chain after the
274 * head.
275 *
276 * @param the_chain The chain to be operated upon.
277 *
278 * @return This method returns the first node of the chain.
279 */
280static inline const Chain_Node *_Chain_Immutable_first(
281  const Chain_Control *the_chain
282)
283{
284  return _Chain_Immutable_head( the_chain )->next;
285}
286
287/**
288 * @brief Returns pointer to chain's last node.
289 *
290 * This function returns a pointer to the last node on the chain just before
291 * the tail.
292 *
293 * @param the_chain The chain to be operated upon.
294 *
295 * @return This method returns the last node of the chain.
296 */
297static inline Chain_Node *_Chain_Last(
298  const Chain_Control *the_chain
299)
300{
301  return _Chain_Immutable_tail( the_chain )->previous;
302}
303
304/**
305 * @brief Returns pointer to immutable chain's last node.
306 *
307 * This function returns a pointer to the last node on the chain just before
308 * the tail.
309 *
310 * @param the_chain The chain to be operated upon.
311 *
312 * @return This method returns the last node of the chain.
313 */
314static inline const Chain_Node *_Chain_Immutable_last(
315  const Chain_Control *the_chain
316)
317{
318  return _Chain_Immutable_tail( the_chain )->previous;
319}
320
321/**
322 * @brief Returns pointer to the next node from this node.
323 *
324 * This function returns a pointer to the next node after this node.
325 *
326 * @param the_node The node to be operated upon.
327 *
328 * @return This method returns the next node on the chain.
329 */
330static inline Chain_Node *_Chain_Next(
331  const Chain_Node *the_node
332)
333{
334  return the_node->next;
335}
336
337/**
338 * @brief Returns pointer to the immutable next node from this node.
339 *
340 * This function returns a pointer to the next node after this node.
341 *
342 * @param the_node The node to be operated upon.
343 *
344 * @return This method returns the next node on the chain.
345 */
346static inline const Chain_Node *_Chain_Immutable_next(
347  const Chain_Node *the_node
348)
349{
350  return the_node->next;
351}
352
353/**
354 * @brief Returns pointer to the previous node from this node.
355 *
356 * This function returns a pointer to the previous node on this chain.
357 *
358 * @param the_node The node to be operated upon.
359 *
360 * @return This method returns the previous node on the chain.
361 */
362static inline Chain_Node *_Chain_Previous(
363  const Chain_Node *the_node
364)
365{
366  return the_node->previous;
367}
368
369/**
370 * @brief Returns pointer to the immutable previous node from this node.
371 *
372 * This function returns a pointer to the previous node on this chain.
373 *
374 * @param the_node The node to be operated upon.
375 *
376 * @return This method returns the previous node on the chain.
377 */
378static inline const Chain_Node *_Chain_Immutable_previous(
379  const Chain_Node *the_node
380)
381{
382  return the_node->previous;
383}
384
385/**
386 * @brief Checks if the chain is empty.
387 *
388 * This function returns true if there are no nodes on @a the_chain and
389 * false otherwise.
390 *
391 * @param the_chain The chain to check if it is empty.
392 *
393 * @retval true There are no nodes on @a the_chain.
394 * @retval false There are nodes on @a the_chain.
395 */
396static inline bool _Chain_Is_empty(
397  const Chain_Control *the_chain
398)
399{
400  return _Chain_Immutable_first( the_chain )
401    == _Chain_Immutable_tail( the_chain );
402}
403
404/**
405 * @brief Checks if this is the first node on the chain.
406 *
407 * This function returns true if the_node is the first node on a chain and
408 * false otherwise.
409 *
410 * @param the_node The node of which the caller wants to know if it is
411 *            the first node on a chain.
412 *
413 * @retval true @a the_node is the first node on a chain.
414 * @retval false @a the_node is not the first node on a chain.
415 */
416static inline bool _Chain_Is_first(
417  const Chain_Node *the_node
418)
419{
420  return (the_node->previous->previous == NULL);
421}
422
423/**
424 * @brief Checks if this is the last node on the chain.
425 *
426 * This function returns true if @a the_node is the last node on a chain and
427 * false otherwise.
428 *
429 * @param the_node The node of which the caller wants to know if it is
430 *            the last node on a chain.
431 *
432 * @retval true @a the_node is the last node on a chain.
433 * @retval false @a the_node is not the last node on a chain.
434 */
435static inline bool _Chain_Is_last(
436  const Chain_Node *the_node
437)
438{
439  return (the_node->next->next == NULL);
440}
441
442/**
443 * @brief Checks if this chain has only one node.
444 *
445 * This function returns true if there is only one node on @a the_chain and
446 * false otherwise.
447 *
448 * @param the_chain is the chain to be operated upon.
449 *
450 * @retval true There is only one node on @a the_chain.
451 * @retval false There is more than one node on @a the_chain.
452 */
453static inline bool _Chain_Has_only_one_node(
454  const Chain_Control *the_chain
455)
456{
457  return _Chain_Immutable_first( the_chain )
458    == _Chain_Immutable_last( the_chain );
459}
460
461/**
462 * @brief Checks if this node is the chain head.
463 *
464 * This function returns true if @a the_node is the head of @a the_chain and
465 * false otherwise.
466 *
467 * @param the_chain The chain to be operated upon.
468 * @param the_node The node to check for being the Chain Head.
469 *
470 * @retval true @a the_node is the head of @a the_chain.
471 * @retval false @a the_node is not the head of @a the_chain.
472 */
473static inline bool _Chain_Is_head(
474  const Chain_Control *the_chain,
475  const Chain_Node    *the_node
476)
477{
478  return (the_node == _Chain_Immutable_head( the_chain ));
479}
480
481/**
482 * @brief Checks if this node is the chain tail.
483 *
484 * This function returns true if @a the_node is the tail of @a the_chain and
485 * false otherwise.
486 *
487 * @param the_chain The chain to be operated upon.
488 * @param the_node The node to check for being the Chain Tail.
489 *
490 * @retval true @a the_node is the tail of @a the_chain.
491 * @retval false @a the_node is not the tail of @a the_chain.
492 */
493static inline bool _Chain_Is_tail(
494  const Chain_Control *the_chain,
495  const Chain_Node    *the_node
496)
497{
498  return (the_node == _Chain_Immutable_tail( the_chain ));
499}
500
501/**
502 * @brief Initializes this chain as empty.
503 *
504 * This routine initializes the specified chain to contain zero nodes.
505 *
506 * @param[out] the_chain The chain to be initialized.
507 */
508static inline void _Chain_Initialize_empty(
509  Chain_Control *the_chain
510)
511{
512  Chain_Node *head;
513  Chain_Node *tail;
514
515  _Assert( the_chain != NULL );
516
517  head = _Chain_Head( the_chain );
518  tail = _Chain_Tail( the_chain );
519
520  head->next = tail;
521  head->previous = NULL;
522  tail->previous = head;
523}
524
525/**
526 * @brief Initializes this chain to contain exactly the specified node.
527 *
528 * @param[out] the_chain The chain to be initialized to contain exactly the specified node.
529 * @param[out] the_node The one and only node of the chain to be initialized.
530 */
531static inline void _Chain_Initialize_one(
532  Chain_Control *the_chain,
533  Chain_Node    *the_node
534)
535{
536  Chain_Node *head;
537  Chain_Node *tail;
538
539  _Assert( _Chain_Is_node_off_chain( the_node ) );
540
541  head = _Chain_Head( the_chain );
542  tail = _Chain_Tail( the_chain );
543
544  the_node->next = tail;
545  the_node->previous = head;
546
547  head->next = the_node;
548  head->previous = NULL;
549  tail->previous = the_node;
550}
551
552/**
553 * @brief Extracts this node (unprotected).
554 *
555 * This routine extracts the_node from the chain on which it resides.
556 * It does NOT disable interrupts to ensure the atomicity of the
557 * extract operation.
558 *
559 * @param[out] the_node The node to be extracted.
560 */
561static inline void _Chain_Extract_unprotected(
562  Chain_Node *the_node
563)
564{
565  Chain_Node *next;
566  Chain_Node *previous;
567
568  _Assert( !_Chain_Is_node_off_chain( the_node ) );
569
570  next           = the_node->next;
571  previous       = the_node->previous;
572  next->previous = previous;
573  previous->next = next;
574
575#if defined(RTEMS_DEBUG)
576  _Chain_Set_off_chain( the_node );
577#endif
578}
579
580/**
581 * @brief Gets the first node (unprotected).
582 *
583 * This function removes the first node from the_chain and returns
584 * a pointer to that node.  It does NOT disable interrupts to ensure
585 * the atomicity of the get operation.
586 *
587 * @param[in, out] the_chain The chain to attempt to get the first node from.
588 *
589 * @return This method returns the first node on the chain even if it is
590 *         the Chain Tail.
591 *
592 * @note This routine assumes that there is at least one node on the chain
593 *       and always returns a node even if it is the Chain Tail.
594 */
595static inline Chain_Node *_Chain_Get_first_unprotected(
596  Chain_Control *the_chain
597)
598{
599  Chain_Node *head;
600  Chain_Node *old_first;
601  Chain_Node *new_first;
602
603  _Assert( !_Chain_Is_empty( the_chain ) );
604
605  head = _Chain_Head( the_chain );
606  old_first = head->next;
607  new_first = old_first->next;
608
609  head->next = new_first;
610  new_first->previous = head;
611
612#if defined(RTEMS_DEBUG)
613  _Chain_Set_off_chain( old_first );
614#endif
615
616  return old_first;
617}
618
619/**
620 * @brief Gets the first node (unprotected).
621 *
622 * This function removes the first node from the_chain and returns
623 * a pointer to that node.  If the_chain is empty, then NULL is returned.
624 *
625 * @param[in, out] the_chain The chain to attempt to get the first node from.
626 *
627 * @retval pointer Pointer to the first node.  The chain contained at least one node.
628 * @retval NULL The chain is empty.
629 *
630 * @note It does NOT disable interrupts to ensure the atomicity of the
631 *       get operation.
632 */
633static inline Chain_Node *_Chain_Get_unprotected(
634  Chain_Control *the_chain
635)
636{
637  if ( !_Chain_Is_empty(the_chain))
638    return _Chain_Get_first_unprotected(the_chain);
639  else
640    return NULL;
641}
642
643/**
644 * @brief Inserts a node (unprotected).
645 *
646 * This routine inserts the_node on a chain immediately following
647 * after_node.
648 *
649 * @param[in, out] after_node The node which will precede @a the_node on the
650 *            chain.
651 * @param[out] the_node The node to be inserted after @a after_node.
652 *
653 * @note It does NOT disable interrupts to ensure the atomicity
654 *       of the extract operation.
655 */
656static inline void _Chain_Insert_unprotected(
657  Chain_Node *after_node,
658  Chain_Node *the_node
659)
660{
661  Chain_Node *before_node;
662
663  _Assert( _Chain_Is_node_off_chain( the_node ) );
664
665  the_node->previous    = after_node;
666  before_node           = after_node->next;
667  after_node->next      = the_node;
668  the_node->next        = before_node;
669  before_node->previous = the_node;
670}
671
672/**
673 * @brief Appends a node (unprotected).
674 *
675 * This routine appends the_node onto the end of the_chain.
676 *
677 * @param[in, out] the_chain The chain to be operated upon.
678 * @param[out] the_node The node to be appended to the end of @a the_chain.
679 *
680 * @note It does NOT disable interrupts to ensure the atomicity of the
681 *       append operation.
682 */
683static inline void _Chain_Append_unprotected(
684  Chain_Control *the_chain,
685  Chain_Node    *the_node
686)
687{
688  Chain_Node *tail;
689  Chain_Node *old_last;
690
691  _Assert( _Chain_Is_node_off_chain( the_node ) );
692
693  tail = _Chain_Tail( the_chain );
694  old_last = tail->previous;
695
696  the_node->next = tail;
697  tail->previous = the_node;
698  old_last->next = the_node;
699  the_node->previous = old_last;
700}
701
702/**
703 * @brief Appends a node on the end of a chain if the node is in the off chain
704 * state (unprotected).
705 *
706 * @param[in, out] the_chain The chain to be operated upon.
707 * @param[in, out] the_node The node to be appended if it is in the off chain.
708 *
709 * @note It does NOT disable interrupts to ensure the atomicity of the
710 *       append operation.
711 *
712 * @see _Chain_Append_unprotected() and _Chain_Is_node_off_chain().
713 */
714static inline void _Chain_Append_if_is_off_chain_unprotected(
715  Chain_Control *the_chain,
716  Chain_Node    *the_node
717)
718{
719  if ( _Chain_Is_node_off_chain( the_node ) ) {
720    _Chain_Append_unprotected( the_chain, the_node );
721  }
722}
723
724/**
725 * @brief Prepends a node (unprotected).
726 *
727 * This routine prepends the_node onto the front of the_chain.
728 *
729 * @param[in, out] the_chain The chain to be operated upon.
730 * @param[in, out] the_node The node to be prepended to the front of @a the_chain.
731 *
732 * @note It does NOT disable interrupts to ensure the atomicity of the
733 *       prepend operation.
734 */
735static inline void _Chain_Prepend_unprotected(
736  Chain_Control *the_chain,
737  Chain_Node    *the_node
738)
739{
740  _Chain_Insert_unprotected(_Chain_Head(the_chain), the_node);
741}
742
743/**
744 * @brief Appends a node and checks if the chain was empty before (unprotected).
745 *
746 * This routine appends the_node onto the end of the_chain.
747 *
748 * @param[in, out] the_chain The chain to be operated upon.
749 * @param[out] the_node The node to be appended to the end of @a the_chain.
750 *
751 * @note It does NOT disable interrupts to ensure the atomicity of the
752 *       append operation.
753 *
754 * @retval true The chain was empty before.
755 * @retval false The chain contained at least one node before.
756 */
757static inline bool _Chain_Append_with_empty_check_unprotected(
758  Chain_Control *the_chain,
759  Chain_Node    *the_node
760)
761{
762  bool was_empty = _Chain_Is_empty( the_chain );
763
764  _Chain_Append_unprotected( the_chain, the_node );
765
766  return was_empty;
767}
768
769/**
770 * @brief Prepends a node and checks if the chain was empty before (unprotected).
771 *
772 * This routine prepends the_node onto the front of the_chain.
773 *
774 * @param[in, out] the_chain The chain to be operated upon.
775 * @param[out] the_node The node to be prepended to the front of @a the_chain.
776 *
777 * @note It does NOT disable interrupts to ensure the atomicity of the
778 *       prepend operation.
779 *
780 * @retval true The chain was empty before.
781 * @retval false The chain contained at least one node before.
782 */
783static inline bool _Chain_Prepend_with_empty_check_unprotected(
784  Chain_Control *the_chain,
785  Chain_Node    *the_node
786)
787{
788  bool was_empty = _Chain_Is_empty( the_chain );
789
790  _Chain_Prepend_unprotected( the_chain, the_node );
791
792  return was_empty;
793}
794
795/**
796 * @brief Gets the first node and checks if the chain is empty afterwards
797 * (unprotected).
798 *
799 * This function removes the first node from the_chain and returns
800 * a pointer to that node in @a the_node.  If the_chain is empty, then NULL is
801 * returned.
802 *
803 * @param[in, out] the_chain The chain to attempt to get the first node from.
804 * @param[out] the_node The first node on the chain or NULL if the chain is
805 * empty.
806 *
807 * @note It does NOT disable interrupts to ensure the atomicity of the
808 *       get operation.
809 *
810 * @retval true The chain is empty now.
811 * @retval false The chain contains at least one node now.
812 */
813static inline bool _Chain_Get_with_empty_check_unprotected(
814  Chain_Control *the_chain,
815  Chain_Node **the_node
816)
817{
818  bool is_empty_now = true;
819  Chain_Node *head = _Chain_Head( the_chain );
820  Chain_Node *tail = _Chain_Tail( the_chain );
821  Chain_Node *old_first = head->next;
822
823  if ( old_first != tail ) {
824    Chain_Node *new_first = old_first->next;
825
826    head->next = new_first;
827    new_first->previous = head;
828
829    *the_node = old_first;
830
831    is_empty_now = new_first == tail;
832  } else
833    *the_node = NULL;
834
835  return is_empty_now;
836}
837
838/**
839 * @brief Chain node order.
840 *
841 * @param left The left hand side.
842 * @param right The right hand side.
843 *
844 * @retval true According to the order the left node precedes the right node.
845 * @retval false Otherwise.
846 */
847typedef bool ( *Chain_Node_order )(
848  const void       *key,
849  const Chain_Node *left,
850  const Chain_Node *right
851);
852
853/**
854 * @brief Inserts a node into the chain according to the order relation.
855 *
856 * After the operation the chain contains the node to insert and the order
857 * relation holds for all nodes from the head up to the inserted node.  Nodes
858 * after the inserted node are not moved.
859 *
860 * @param[in, out] the_chain The chain to be operated upon.
861 * @param[out] to_insert The node to insert.
862 * @param left The left hand side passed to the order relation.  It must
863 *   correspond to the node to insert.  The separate left hand side parameter
864 *   may help the compiler to generate better code if it is stored in a local
865 *   variable.
866 * @param order The order relation.
867 */
868static inline void _Chain_Insert_ordered_unprotected(
869  Chain_Control    *the_chain,
870  Chain_Node       *to_insert,
871  const void       *key,
872  Chain_Node_order  order
873)
874{
875  const Chain_Node *tail = _Chain_Immutable_tail( the_chain );
876  Chain_Node *previous = _Chain_Head( the_chain );
877  Chain_Node *next = _Chain_First( the_chain );
878
879  while ( next != tail && !( *order )( key, to_insert, next ) ) {
880    previous = next;
881    next = _Chain_Next( next );
882  }
883
884  _Chain_Insert_unprotected( previous, to_insert );
885}
886
887/**
888 * @brief The chain iterator direction.
889 */
890typedef enum {
891  /**
892   * @brief Iteration from head to tail.
893   */
894  CHAIN_ITERATOR_FORWARD,
895
896  /**
897   * @brief Iteration from tail to head.
898   */
899  CHAIN_ITERATOR_BACKWARD
900} Chain_Iterator_direction;
901
902/**
903 * @brief A chain iterator which is updated during node extraction if it is
904 * properly registered.
905 *
906 * @see _Chain_Iterator_initialize().
907 */
908typedef struct {
909  /**
910   * @brief Node for registration.
911   *
912   * Used during _Chain_Iterator_initialize() and _Chain_Iterator_destroy().
913   */
914  Chain_Node Registry_node;
915
916  /**
917   * @brief The direction of this iterator.
918   *
919   * Immutable after initialization via _Chain_Iterator_initialize().
920   */
921  Chain_Iterator_direction  direction;
922
923  /**
924   * @brief The current position of this iterator.
925   *
926   * The position is initialized via _Chain_Iterator_initialize().  It must be
927   * explicitly set after one valid iteration step, e.g. in case a next node in
928   * the iterator direction existed.  It is updated through the registration in
929   * case a node is extracted via _Chain_Iterator_registry_update().
930   */
931  Chain_Node *position;
932} Chain_Iterator;
933
934/**
935 * @brief A registry for chain iterators.
936 *
937 * Should be attached to a chain control to enable safe iteration through a
938 * chain in case of concurrent node extractions.
939 */
940typedef struct {
941  Chain_Control Iterators;
942} Chain_Iterator_registry;
943
944/**
945 * @brief Chain iterator registry initializer for static initialization.
946 *
947 * @param name The designator of the chain iterator registry.
948 */
949#define CHAIN_ITERATOR_REGISTRY_INITIALIZER( name ) \
950  { CHAIN_INITIALIZER_EMPTY( name.Iterators ) }
951
952/**
953 * @brief Initializes a chain iterator registry.
954 *
955 * @param[out] the_registry The chain iterator registry to be initialized.
956 */
957static inline void _Chain_Iterator_registry_initialize(
958  Chain_Iterator_registry *the_registry
959)
960{
961  _Chain_Initialize_empty( &the_registry->Iterators );
962}
963
964/**
965 * @brief Updates all iterators present in the chain iterator registry in case
966 * of a node extraction.
967 *
968 * Must be called before _Chain_Extract_unprotected().
969 *
970 * @warning This function will look at all registered chain iterators to
971 *   determine if an update is necessary.
972 *
973 * @param[in, out] the_registry the chain iterator registry.
974 * @param[out] the_node_to_extract The node that will be extracted.
975 */
976static inline void _Chain_Iterator_registry_update(
977  Chain_Iterator_registry *the_registry,
978  Chain_Node              *the_node_to_extract
979)
980{
981  Chain_Node *iter_node;
982  Chain_Node *iter_tail;
983
984  iter_node = _Chain_Head( &the_registry->Iterators );
985  iter_tail = _Chain_Tail( &the_registry->Iterators );
986
987  while ( ( iter_node = _Chain_Next( iter_node ) ) != iter_tail ) {
988    Chain_Iterator *iter;
989
990    iter = (Chain_Iterator *) iter_node;
991
992    if ( iter->position == the_node_to_extract ) {
993      if ( iter->direction == CHAIN_ITERATOR_FORWARD ) {
994        iter->position = _Chain_Previous( the_node_to_extract );
995      } else {
996        iter->position = _Chain_Next( the_node_to_extract );
997      }
998    }
999  }
1000}
1001
1002/**
1003 * @brief Initializes the chain iterator.
1004 *
1005 * In the following example nodes inserted during the iteration are visited in
1006 * case they are inserted after the current position in iteration order.
1007 *
1008 * @code
1009 * #include <rtems/score/chainimpl.h>
1010 * #include <rtems/score/isrlock.h>
1011 *
1012 * typedef struct {
1013 *   Chain_Control           Chain;
1014 *   Chain_Iterator_registry Iterators;
1015 *   ISR_LOCK_MEMBER(        Lock )
1016 * } Some_Control;
1017 *
1018 * void iterate(
1019 *   Some_Control   *the_some,
1020 *   void         ( *visitor )( Chain_Node * )
1021 * )
1022 * {
1023 *   ISR_lock_Context  lock_context;
1024 *   Chain_Iterator    iter;
1025 *   Chain_Node       *node;
1026 *   const Chain_Node *end;
1027 *
1028 *   end = _Chain_Immutable_tail( &the_some->Chain );
1029 *
1030 *   _ISR_lock_ISR_disable_and_acquire( &the_some->Lock, &lock_context );
1031 *
1032 *   _Chain_Iterator_initialize(
1033 *     &the_some->Chain,
1034 *     &the_some->Iterators,
1035 *     &iter,
1036 *     CHAIN_ITERATOR_FORWARD
1037 *   );
1038 *
1039 *   while ( ( node = _Chain_Iterator_next( &iter ) ) != end ) {
1040 *     _Chain_Iterator_set_position( &iter, node );
1041 *     _ISR_lock_Release_and_ISR_enable( &the_some->Lock, &lock_context );
1042 *     ( *visitor )( node );
1043 *     _ISR_lock_ISR_disable_and_acquire( &the_some->Lock, &lock_context );
1044 *   }
1045 *
1046 *   _Chain_Iterator_destroy( &iter );
1047 *   _ISR_lock_Release_and_ISR_enable( &the_some->Lock, &lock_context );
1048 * }
1049 * @endcode
1050 *
1051 * @param[out] the_chain The chain to iterate.
1052 * @param[in, out] the_registry The registry for the chain iterator.
1053 * @param[out] the_iterator The chain iterator to initialize.
1054 * @param[out] direction The iteration direction.
1055 *
1056 * @see _Chain_Iterator_next(), _Chain_Iterator_set_position() and
1057 * Chain_Iterator_destroy().
1058 *
1059 * @warning Think twice before you use a chain iterator.  Its current
1060 *   implementation is unfit for use in performance relevant components, due to
1061 *   the linear time complexity in _Chain_Iterator_registry_update().
1062 */
1063static inline void _Chain_Iterator_initialize(
1064  Chain_Control            *the_chain,
1065  Chain_Iterator_registry  *the_registry,
1066  Chain_Iterator           *the_iterator,
1067  Chain_Iterator_direction  direction
1068)
1069{
1070  _Chain_Initialize_node( &the_iterator->Registry_node );
1071  _Chain_Append_unprotected(
1072    &the_registry->Iterators,
1073    &the_iterator->Registry_node
1074  );
1075
1076  the_iterator->direction = direction;
1077
1078  if ( direction == CHAIN_ITERATOR_FORWARD ) {
1079    the_iterator->position = _Chain_Head( the_chain );
1080  } else {
1081    the_iterator->position = _Chain_Tail( the_chain );
1082  }
1083}
1084
1085/**
1086 * @brief Returns the next node in the iterator direction.
1087 *
1088 * In case a next node exists, then the iterator should be updated via
1089 * _Chain_Iterator_set_position() to continue with the next iteration step.
1090 *
1091 * @param[in, out] the_iterator The chain iterator.
1092 *
1093 * @return The next node in the iterator direction
1094 */
1095static inline Chain_Node *_Chain_Iterator_next(
1096  const Chain_Iterator *the_iterator
1097)
1098{
1099  if ( the_iterator->direction == CHAIN_ITERATOR_FORWARD ) {
1100    return _Chain_Next( the_iterator->position );
1101  } else {
1102    return _Chain_Previous( the_iterator->position );
1103  }
1104}
1105
1106/**
1107 * @brief Sets the iterator position.
1108 *
1109 * @param[out] the_iterator The chain iterator.
1110 * @param[out] the_node The new iterator position.
1111 */
1112static inline void _Chain_Iterator_set_position(
1113  Chain_Iterator *the_iterator,
1114  Chain_Node     *the_node
1115)
1116{
1117  the_iterator->position = the_node;
1118}
1119
1120/**
1121 * @brief Destroys the iterator.
1122 *
1123 * Removes the iterator from its registry.
1124 *
1125 * @param[out] the_iterator The chain iterator.
1126 */
1127static inline void _Chain_Iterator_destroy(
1128  Chain_Iterator *the_iterator
1129)
1130{
1131  _Chain_Extract_unprotected( &the_iterator->Registry_node );
1132}
1133
1134/** @} */
1135
1136#ifdef __cplusplus
1137}
1138#endif
1139
1140#endif
1141/* end of include file */
Note: See TracBrowser for help on using the repository browser.