Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:12

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreChain
0007  *
0008  * @brief This header file provides interfaces of the
0009  *   @ref RTEMSScoreChain which are only used by the implementation.
0010  */
0011 
0012 /*
0013  *  Copyright (c) 2010 embedded brains GmbH & Co. KG
0014  *
0015  *  COPYRIGHT (c) 1989-2014.
0016  *  On-Line Applications Research Corporation (OAR).
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifndef _RTEMS_SCORE_CHAINIMPL_H
0041 #define _RTEMS_SCORE_CHAINIMPL_H
0042 
0043 #include <rtems/score/chain.h>
0044 #include <rtems/score/assert.h>
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif
0049 
0050 /**
0051  * @addtogroup RTEMSScoreChain
0052  *
0053  * @{
0054  */
0055 
0056 /**
0057  *  @brief Chain initializer for an empty chain with designator @a name.
0058  */
0059 #define CHAIN_INITIALIZER_EMPTY(name) \
0060   { { { &(name).Tail.Node, NULL }, &(name).Head.Node } }
0061 
0062 /**
0063  *  @brief Chain initializer for a chain with one @a node.
0064  *
0065  *  @see CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN().
0066  */
0067 #define CHAIN_INITIALIZER_ONE_NODE( node ) \
0068   { { { (node), NULL }, (node) } }
0069 
0070 /**
0071  *  @brief Chain node initializer for a @a chain containing exactly this node.
0072  *
0073  *  @see CHAIN_INITIALIZER_ONE_NODE().
0074  */
0075 #define CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( chain ) \
0076   { &(chain)->Tail.Node, &(chain)->Head.Node }
0077 
0078 /**
0079  *  @brief Chain definition for an empty chain with designator @a name.
0080  */
0081 #define CHAIN_DEFINE_EMPTY(name) \
0082   Chain_Control name = CHAIN_INITIALIZER_EMPTY(name)
0083 
0084 /**
0085  *  @brief Initializes a chain header.
0086  *
0087  *  This routine initializes @a the_chain structure to manage the
0088  *  contiguous array of @a number_nodes nodes which starts at
0089  *  @a starting_address.  Each node is of @a node_size bytes.
0090  *
0091  *  @param[out] the_chain Specifies the chain to initialize.
0092  *  @param starting_address The starting address of the array
0093  *         of elements.
0094  *  @param number_nodes The number of nodes that will be in the chain.
0095  *  @param node_size The size of each node.
0096  */
0097 void _Chain_Initialize(
0098   Chain_Control *the_chain,
0099   void          *starting_address,
0100   size_t         number_nodes,
0101   size_t         node_size
0102 );
0103 
0104 /**
0105  * @brief Returns the node count of the chain.
0106  *
0107  * @param chain The chain to return the node count from.
0108  *
0109  * @note It does NOT disable interrupts to ensure the atomicity of the
0110  * operation.
0111  *
0112  * @return The node count of the chain.
0113  */
0114 size_t _Chain_Node_count_unprotected( const Chain_Control *chain );
0115 
0116 /**
0117  * @brief Sets off chain.
0118  *
0119  * This function sets the next field of the @a node to NULL indicating the @a
0120  * node is not part of a chain.
0121  *
0122  * @param[out] node The node to set off chain.
0123  */
0124 static inline void _Chain_Set_off_chain(
0125   Chain_Node *node
0126 )
0127 {
0128   node->next = NULL;
0129 #if defined(RTEMS_DEBUG)
0130   node->previous = NULL;
0131 #endif
0132 }
0133 
0134 /**
0135  * @brief Initializes a chain node.
0136  *
0137  * In debug configurations, the node is set off chain.  In all other
0138  * configurations, this function does nothing.
0139  *
0140  * @param[out] the_node The chain node to initialize.
0141  */
0142 static inline void _Chain_Initialize_node( Chain_Node *the_node )
0143 {
0144 #if defined(RTEMS_DEBUG)
0145   _Chain_Set_off_chain( the_node );
0146 #else
0147   (void) the_node;
0148 #endif
0149 }
0150 
0151 /**
0152  * @brief Checks if the node is off chain.
0153  *
0154  * This function returns true if the @a node is not on a chain.  A @a node is
0155  * off chain if the next field is set to NULL.
0156  *
0157  * @param node The node to check if it is off chain.
0158  *
0159  * @retval true The @a node is off chain.
0160  * @retval false The @a node is not off chain.
0161  */
0162 static inline bool _Chain_Is_node_off_chain(
0163   const Chain_Node *node
0164 )
0165 {
0166   return node->next == NULL;
0167 }
0168 
0169 /**
0170  * @brief Checks if two nodes are equal.
0171  *
0172  * This function returns true if @a left and @a right are equal,
0173  * and false otherwise.
0174  *
0175  * @param left The node on the left hand side of the comparison.
0176  * @param right The node on the right hand side of the comparison.
0177  *
0178  * @retval true @a left and @a right are equal.
0179  * @retval false @a left and @a right are not equal.
0180  */
0181 static inline bool _Chain_Are_nodes_equal(
0182   const Chain_Node *left,
0183   const Chain_Node *right
0184 )
0185 {
0186   return left == right;
0187 }
0188 
0189 /**
0190  * @brief Returns pointer to chain head.
0191  *
0192  * This function returns a pointer to the head node on the chain.
0193  *
0194  * @param[in] the_chain The chain to be operated upon.
0195  *
0196  * @return This method returns the permanent head node of the chain.
0197  */
0198 static inline Chain_Node *_Chain_Head(
0199   Chain_Control *the_chain
0200 )
0201 {
0202   return &the_chain->Head.Node;
0203 }
0204 
0205 /**
0206  * @brief Returns pointer to immutable chain head.
0207  *
0208  * This function returns a pointer to the head node on the chain.
0209  *
0210  * @param the_chain The chain to be operated upon.
0211  *
0212  * @return This method returns the permanent head node of the chain.
0213  */
0214 static inline const Chain_Node *_Chain_Immutable_head(
0215   const Chain_Control *the_chain
0216 )
0217 {
0218   return &the_chain->Head.Node;
0219 }
0220 
0221 /**
0222  * @brief Returns pointer to chain tail.
0223  *
0224  * This function returns a pointer to the tail node on the chain.
0225  *
0226  * @param[in] the_chain The chain to be operated upon.
0227  *
0228  * @return This method returns the permanent tail node of the chain.
0229  */
0230 static inline Chain_Node *_Chain_Tail(
0231   Chain_Control *the_chain
0232 )
0233 {
0234   return &the_chain->Tail.Node;
0235 }
0236 
0237 /**
0238  * @brief Returns pointer to immutable chain tail.
0239  *
0240  * This function returns a pointer to the tail node on the chain.
0241  *
0242  * @param the_chain The chain to be operated upon.
0243  *
0244  * @return This method returns the permanent tail node of the chain.
0245  */
0246 static inline const Chain_Node *_Chain_Immutable_tail(
0247   const Chain_Control *the_chain
0248 )
0249 {
0250   return &the_chain->Tail.Node;
0251 }
0252 
0253 /**
0254  * @brief Returns pointer to chain's first node.
0255  *
0256  * This function returns a pointer to the first node on the chain after the
0257  * head.
0258  *
0259  * @param the_chain The chain to be operated upon.
0260  *
0261  * @return This method returns the first node of the chain.
0262  */
0263 static inline Chain_Node *_Chain_First(
0264   const Chain_Control *the_chain
0265 )
0266 {
0267   return _Chain_Immutable_head( the_chain )->next;
0268 }
0269 
0270 /**
0271  * @brief Returns pointer to immutable chain's first node.
0272  *
0273  * This function returns a pointer to the first node on the chain after the
0274  * head.
0275  *
0276  * @param the_chain The chain to be operated upon.
0277  *
0278  * @return This method returns the first node of the chain.
0279  */
0280 static inline const Chain_Node *_Chain_Immutable_first(
0281   const Chain_Control *the_chain
0282 )
0283 {
0284   return _Chain_Immutable_head( the_chain )->next;
0285 }
0286 
0287 /**
0288  * @brief Returns pointer to chain's last node.
0289  *
0290  * This function returns a pointer to the last node on the chain just before
0291  * the tail.
0292  *
0293  * @param the_chain The chain to be operated upon.
0294  *
0295  * @return This method returns the last node of the chain.
0296  */
0297 static inline Chain_Node *_Chain_Last(
0298   const Chain_Control *the_chain
0299 )
0300 {
0301   return _Chain_Immutable_tail( the_chain )->previous;
0302 }
0303 
0304 /**
0305  * @brief Returns pointer to immutable chain's last node.
0306  *
0307  * This function returns a pointer to the last node on the chain just before
0308  * the tail.
0309  *
0310  * @param the_chain The chain to be operated upon.
0311  *
0312  * @return This method returns the last node of the chain.
0313  */
0314 static inline const Chain_Node *_Chain_Immutable_last(
0315   const Chain_Control *the_chain
0316 )
0317 {
0318   return _Chain_Immutable_tail( the_chain )->previous;
0319 }
0320 
0321 /**
0322  * @brief Returns pointer to the next node from this node.
0323  *
0324  * This function returns a pointer to the next node after this node.
0325  *
0326  * @param the_node The node to be operated upon.
0327  *
0328  * @return This method returns the next node on the chain.
0329  */
0330 static inline Chain_Node *_Chain_Next(
0331   const Chain_Node *the_node
0332 )
0333 {
0334   return the_node->next;
0335 }
0336 
0337 /**
0338  * @brief Returns pointer to the immutable next node from this node.
0339  *
0340  * This function returns a pointer to the next node after this node.
0341  *
0342  * @param the_node The node to be operated upon.
0343  *
0344  * @return This method returns the next node on the chain.
0345  */
0346 static inline const Chain_Node *_Chain_Immutable_next(
0347   const Chain_Node *the_node
0348 )
0349 {
0350   return the_node->next;
0351 }
0352 
0353 /**
0354  * @brief Returns pointer to the previous node from this node.
0355  *
0356  * This function returns a pointer to the previous node on this chain.
0357  *
0358  * @param the_node The node to be operated upon.
0359  *
0360  * @return This method returns the previous node on the chain.
0361  */
0362 static inline Chain_Node *_Chain_Previous(
0363   const Chain_Node *the_node
0364 )
0365 {
0366   return the_node->previous;
0367 }
0368 
0369 /**
0370  * @brief Returns pointer to the immutable previous node from this node.
0371  *
0372  * This function returns a pointer to the previous node on this chain.
0373  *
0374  * @param the_node The node to be operated upon.
0375  *
0376  * @return This method returns the previous node on the chain.
0377  */
0378 static inline const Chain_Node *_Chain_Immutable_previous(
0379   const Chain_Node *the_node
0380 )
0381 {
0382   return the_node->previous;
0383 }
0384 
0385 /**
0386  * @brief Checks if the chain is empty.
0387  *
0388  * This function returns true if there are no nodes on @a the_chain and
0389  * false otherwise.
0390  *
0391  * @param the_chain The chain to check if it is empty.
0392  *
0393  * @retval true There are no nodes on @a the_chain.
0394  * @retval false There are nodes on @a the_chain.
0395  */
0396 static inline bool _Chain_Is_empty(
0397   const Chain_Control *the_chain
0398 )
0399 {
0400   return _Chain_Immutable_first( the_chain )
0401     == _Chain_Immutable_tail( the_chain );
0402 }
0403 
0404 /**
0405  * @brief Checks if this is the first node on the chain.
0406  *
0407  * This function returns true if the_node is the first node on a chain and
0408  * false otherwise.
0409  *
0410  * @param the_node The node of which the caller wants to know if it is
0411  *            the first node on a chain.
0412  *
0413  * @retval true @a the_node is the first node on a chain.
0414  * @retval false @a the_node is not the first node on a chain.
0415  */
0416 static inline bool _Chain_Is_first(
0417   const Chain_Node *the_node
0418 )
0419 {
0420   return (the_node->previous->previous == NULL);
0421 }
0422 
0423 /**
0424  * @brief Checks if this is the last node on the chain.
0425  *
0426  * This function returns true if @a the_node is the last node on a chain and
0427  * false otherwise.
0428  *
0429  * @param the_node The node of which the caller wants to know if it is
0430  *            the last node on a chain.
0431  *
0432  * @retval true @a the_node is the last node on a chain.
0433  * @retval false @a the_node is not the last node on a chain.
0434  */
0435 static inline bool _Chain_Is_last(
0436   const Chain_Node *the_node
0437 )
0438 {
0439   return (the_node->next->next == NULL);
0440 }
0441 
0442 /**
0443  * @brief Checks if this chain has only one node.
0444  *
0445  * This function returns true if there is only one node on @a the_chain and
0446  * false otherwise.
0447  *
0448  * @param the_chain is the chain to be operated upon.
0449  *
0450  * @retval true There is only one node on @a the_chain.
0451  * @retval false There is more than one node on @a the_chain.
0452  */
0453 static inline bool _Chain_Has_only_one_node(
0454   const Chain_Control *the_chain
0455 )
0456 {
0457   return _Chain_Immutable_first( the_chain )
0458     == _Chain_Immutable_last( the_chain );
0459 }
0460 
0461 /**
0462  * @brief Checks if this node is the chain head.
0463  *
0464  * This function returns true if @a the_node is the head of @a the_chain and
0465  * false otherwise.
0466  *
0467  * @param the_chain The chain to be operated upon.
0468  * @param the_node The node to check for being the Chain Head.
0469  *
0470  * @retval true @a the_node is the head of @a the_chain.
0471  * @retval false @a the_node is not the head of @a the_chain.
0472  */
0473 static inline bool _Chain_Is_head(
0474   const Chain_Control *the_chain,
0475   const Chain_Node    *the_node
0476 )
0477 {
0478   return (the_node == _Chain_Immutable_head( the_chain ));
0479 }
0480 
0481 /**
0482  * @brief Checks if this node is the chain tail.
0483  *
0484  * This function returns true if @a the_node is the tail of @a the_chain and
0485  * false otherwise.
0486  *
0487  * @param the_chain The chain to be operated upon.
0488  * @param the_node The node to check for being the Chain Tail.
0489  *
0490  * @retval true @a the_node is the tail of @a the_chain.
0491  * @retval false @a the_node is not the tail of @a the_chain.
0492  */
0493 static inline bool _Chain_Is_tail(
0494   const Chain_Control *the_chain,
0495   const Chain_Node    *the_node
0496 )
0497 {
0498   return (the_node == _Chain_Immutable_tail( the_chain ));
0499 }
0500 
0501 /**
0502  * @brief Initializes this chain as empty.
0503  *
0504  * This routine initializes the specified chain to contain zero nodes.
0505  *
0506  * @param[out] the_chain The chain to be initialized.
0507  */
0508 static inline void _Chain_Initialize_empty(
0509   Chain_Control *the_chain
0510 )
0511 {
0512   Chain_Node *head;
0513   Chain_Node *tail;
0514 
0515   _Assert( the_chain != NULL );
0516 
0517   head = _Chain_Head( the_chain );
0518   tail = _Chain_Tail( the_chain );
0519 
0520   head->next = tail;
0521   head->previous = NULL;
0522   tail->previous = head;
0523 }
0524 
0525 /**
0526  * @brief Initializes this chain to contain exactly the specified node.
0527  *
0528  * @param[out] the_chain The chain to be initialized to contain exactly the specified node.
0529  * @param[out] the_node The one and only node of the chain to be initialized.
0530  */
0531 static inline void _Chain_Initialize_one(
0532   Chain_Control *the_chain,
0533   Chain_Node    *the_node
0534 )
0535 {
0536   Chain_Node *head;
0537   Chain_Node *tail;
0538 
0539   _Assert( _Chain_Is_node_off_chain( the_node ) );
0540 
0541   head = _Chain_Head( the_chain );
0542   tail = _Chain_Tail( the_chain );
0543 
0544   the_node->next = tail;
0545   the_node->previous = head;
0546 
0547   head->next = the_node;
0548   head->previous = NULL;
0549   tail->previous = the_node;
0550 }
0551 
0552 /**
0553  * @brief Extracts this node (unprotected).
0554  *
0555  * This routine extracts the_node from the chain on which it resides.
0556  * It does NOT disable interrupts to ensure the atomicity of the
0557  * extract operation.
0558  *
0559  * @param[out] the_node The node to be extracted.
0560  */
0561 static inline void _Chain_Extract_unprotected(
0562   Chain_Node *the_node
0563 )
0564 {
0565   Chain_Node *next;
0566   Chain_Node *previous;
0567 
0568   _Assert( !_Chain_Is_node_off_chain( the_node ) );
0569 
0570   next           = the_node->next;
0571   previous       = the_node->previous;
0572   next->previous = previous;
0573   previous->next = next;
0574 
0575 #if defined(RTEMS_DEBUG)
0576   _Chain_Set_off_chain( the_node );
0577 #endif
0578 }
0579 
0580 /**
0581  * @brief Gets the first node (unprotected).
0582  *
0583  * This function removes the first node from the_chain and returns
0584  * a pointer to that node.  It does NOT disable interrupts to ensure
0585  * the atomicity of the get operation.
0586  *
0587  * @param[in, out] the_chain The chain to attempt to get the first node from.
0588  *
0589  * @return This method returns the first node on the chain even if it is
0590  *         the Chain Tail.
0591  *
0592  * @note This routine assumes that there is at least one node on the chain
0593  *       and always returns a node even if it is the Chain Tail.
0594  */
0595 static inline Chain_Node *_Chain_Get_first_unprotected(
0596   Chain_Control *the_chain
0597 )
0598 {
0599   Chain_Node *head;
0600   Chain_Node *old_first;
0601   Chain_Node *new_first;
0602 
0603   _Assert( !_Chain_Is_empty( the_chain ) );
0604 
0605   head = _Chain_Head( the_chain );
0606   old_first = head->next;
0607   new_first = old_first->next;
0608 
0609   head->next = new_first;
0610   new_first->previous = head;
0611 
0612 #if defined(RTEMS_DEBUG)
0613   _Chain_Set_off_chain( old_first );
0614 #endif
0615 
0616   return old_first;
0617 }
0618 
0619 /**
0620  * @brief Gets the first node (unprotected).
0621  *
0622  * This function removes the first node from the_chain and returns
0623  * a pointer to that node.  If the_chain is empty, then NULL is returned.
0624  *
0625  * @param[in, out] the_chain The chain to attempt to get the first node from.
0626  *
0627  * @retval pointer Pointer to the first node.  The chain contained at least one node.
0628  * @retval NULL The chain is empty.
0629  *
0630  * @note It does NOT disable interrupts to ensure the atomicity of the
0631  *       get operation.
0632  */
0633 static inline Chain_Node *_Chain_Get_unprotected(
0634   Chain_Control *the_chain
0635 )
0636 {
0637   if ( !_Chain_Is_empty(the_chain))
0638     return _Chain_Get_first_unprotected(the_chain);
0639   else
0640     return NULL;
0641 }
0642 
0643 /**
0644  * @brief Inserts a node (unprotected).
0645  *
0646  * This routine inserts the_node on a chain immediately following
0647  * after_node.
0648  *
0649  * @param[in, out] after_node The node which will precede @a the_node on the
0650  *            chain.
0651  * @param[out] the_node The node to be inserted after @a after_node.
0652  *
0653  * @note It does NOT disable interrupts to ensure the atomicity
0654  *       of the extract operation.
0655  */
0656 static inline void _Chain_Insert_unprotected(
0657   Chain_Node *after_node,
0658   Chain_Node *the_node
0659 )
0660 {
0661   Chain_Node *before_node;
0662 
0663   _Assert( _Chain_Is_node_off_chain( the_node ) );
0664 
0665   the_node->previous    = after_node;
0666   before_node           = after_node->next;
0667   after_node->next      = the_node;
0668   the_node->next        = before_node;
0669   before_node->previous = the_node;
0670 }
0671 
0672 /**
0673  * @brief Appends a node (unprotected).
0674  *
0675  * This routine appends the_node onto the end of the_chain.
0676  *
0677  * @param[in, out] the_chain The chain to be operated upon.
0678  * @param[out] the_node The node to be appended to the end of @a the_chain.
0679  *
0680  * @note It does NOT disable interrupts to ensure the atomicity of the
0681  *       append operation.
0682  */
0683 static inline void _Chain_Append_unprotected(
0684   Chain_Control *the_chain,
0685   Chain_Node    *the_node
0686 )
0687 {
0688   Chain_Node *tail;
0689   Chain_Node *old_last;
0690 
0691   _Assert( _Chain_Is_node_off_chain( the_node ) );
0692 
0693   tail = _Chain_Tail( the_chain );
0694   old_last = tail->previous;
0695 
0696   the_node->next = tail;
0697   tail->previous = the_node;
0698   old_last->next = the_node;
0699   the_node->previous = old_last;
0700 }
0701 
0702 /**
0703  * @brief Appends a node on the end of a chain if the node is in the off chain
0704  * state (unprotected).
0705  *
0706  * @param[in, out] the_chain The chain to be operated upon.
0707  * @param[in, out] the_node The node to be appended if it is in the off chain.
0708  *
0709  * @note It does NOT disable interrupts to ensure the atomicity of the
0710  *       append operation.
0711  *
0712  * @see _Chain_Append_unprotected() and _Chain_Is_node_off_chain().
0713  */
0714 static inline void _Chain_Append_if_is_off_chain_unprotected(
0715   Chain_Control *the_chain,
0716   Chain_Node    *the_node
0717 )
0718 {
0719   if ( _Chain_Is_node_off_chain( the_node ) ) {
0720     _Chain_Append_unprotected( the_chain, the_node );
0721   }
0722 }
0723 
0724 /**
0725  * @brief Prepends a node (unprotected).
0726  *
0727  * This routine prepends the_node onto the front of the_chain.
0728  *
0729  * @param[in, out] the_chain The chain to be operated upon.
0730  * @param[in, out] the_node The node to be prepended to the front of @a the_chain.
0731  *
0732  * @note It does NOT disable interrupts to ensure the atomicity of the
0733  *       prepend operation.
0734  */
0735 static inline void _Chain_Prepend_unprotected(
0736   Chain_Control *the_chain,
0737   Chain_Node    *the_node
0738 )
0739 {
0740   _Chain_Insert_unprotected(_Chain_Head(the_chain), the_node);
0741 }
0742 
0743 /**
0744  * @brief Appends a node and checks if the chain was empty before (unprotected).
0745  *
0746  * This routine appends the_node onto the end of the_chain.
0747  *
0748  * @param[in, out] the_chain The chain to be operated upon.
0749  * @param[out] the_node The node to be appended to the end of @a the_chain.
0750  *
0751  * @note It does NOT disable interrupts to ensure the atomicity of the
0752  *       append operation.
0753  *
0754  * @retval true The chain was empty before.
0755  * @retval false The chain contained at least one node before.
0756  */
0757 static inline bool _Chain_Append_with_empty_check_unprotected(
0758   Chain_Control *the_chain,
0759   Chain_Node    *the_node
0760 )
0761 {
0762   bool was_empty = _Chain_Is_empty( the_chain );
0763 
0764   _Chain_Append_unprotected( the_chain, the_node );
0765 
0766   return was_empty;
0767 }
0768 
0769 /**
0770  * @brief Prepends a node and checks if the chain was empty before (unprotected).
0771  *
0772  * This routine prepends the_node onto the front of the_chain.
0773  *
0774  * @param[in, out] the_chain The chain to be operated upon.
0775  * @param[out] the_node The node to be prepended to the front of @a the_chain.
0776  *
0777  * @note It does NOT disable interrupts to ensure the atomicity of the
0778  *       prepend operation.
0779  *
0780  * @retval true The chain was empty before.
0781  * @retval false The chain contained at least one node before.
0782  */
0783 static inline bool _Chain_Prepend_with_empty_check_unprotected(
0784   Chain_Control *the_chain,
0785   Chain_Node    *the_node
0786 )
0787 {
0788   bool was_empty = _Chain_Is_empty( the_chain );
0789 
0790   _Chain_Prepend_unprotected( the_chain, the_node );
0791 
0792   return was_empty;
0793 }
0794 
0795 /**
0796  * @brief Gets the first node and checks if the chain is empty afterwards
0797  * (unprotected).
0798  *
0799  * This function removes the first node from the_chain and returns
0800  * a pointer to that node in @a the_node.  If the_chain is empty, then NULL is
0801  * returned.
0802  *
0803  * @param[in, out] the_chain The chain to attempt to get the first node from.
0804  * @param[out] the_node The first node on the chain or NULL if the chain is
0805  * empty.
0806  *
0807  * @note It does NOT disable interrupts to ensure the atomicity of the
0808  *       get operation.
0809  *
0810  * @retval true The chain is empty now.
0811  * @retval false The chain contains at least one node now.
0812  */
0813 static inline bool _Chain_Get_with_empty_check_unprotected(
0814   Chain_Control *the_chain,
0815   Chain_Node **the_node
0816 )
0817 {
0818   bool is_empty_now = true;
0819   Chain_Node *head = _Chain_Head( the_chain );
0820   Chain_Node *tail = _Chain_Tail( the_chain );
0821   Chain_Node *old_first = head->next;
0822 
0823   if ( old_first != tail ) {
0824     Chain_Node *new_first = old_first->next;
0825 
0826     head->next = new_first;
0827     new_first->previous = head;
0828 
0829     *the_node = old_first;
0830 
0831     is_empty_now = new_first == tail;
0832   } else
0833     *the_node = NULL;
0834 
0835   return is_empty_now;
0836 }
0837 
0838 /**
0839  * @brief Chain node order.
0840  *
0841  * @param left The left hand side.
0842  * @param right The right hand side.
0843  *
0844  * @retval true According to the order the left node precedes the right node.
0845  * @retval false Otherwise.
0846  */
0847 typedef bool ( *Chain_Node_order )(
0848   const void       *key,
0849   const Chain_Node *left,
0850   const Chain_Node *right
0851 );
0852 
0853 /**
0854  * @brief Inserts a node into the chain according to the order relation.
0855  *
0856  * After the operation the chain contains the node to insert and the order
0857  * relation holds for all nodes from the head up to the inserted node.  Nodes
0858  * after the inserted node are not moved.
0859  *
0860  * @param[in, out] the_chain The chain to be operated upon.
0861  * @param[out] to_insert The node to insert.
0862  * @param left The left hand side passed to the order relation.  It must
0863  *   correspond to the node to insert.  The separate left hand side parameter
0864  *   may help the compiler to generate better code if it is stored in a local
0865  *   variable.
0866  * @param order The order relation.
0867  */
0868 static inline void _Chain_Insert_ordered_unprotected(
0869   Chain_Control    *the_chain,
0870   Chain_Node       *to_insert,
0871   const void       *key,
0872   Chain_Node_order  order
0873 )
0874 {
0875   const Chain_Node *tail = _Chain_Immutable_tail( the_chain );
0876   Chain_Node *previous = _Chain_Head( the_chain );
0877   Chain_Node *next = _Chain_First( the_chain );
0878 
0879   while ( next != tail && !( *order )( key, to_insert, next ) ) {
0880     previous = next;
0881     next = _Chain_Next( next );
0882   }
0883 
0884   _Chain_Insert_unprotected( previous, to_insert );
0885 }
0886 
0887 /**
0888  * @brief The chain iterator direction.
0889  */
0890 typedef enum {
0891   /**
0892    * @brief Iteration from head to tail.
0893    */
0894   CHAIN_ITERATOR_FORWARD,
0895 
0896   /**
0897    * @brief Iteration from tail to head.
0898    */
0899   CHAIN_ITERATOR_BACKWARD
0900 } Chain_Iterator_direction;
0901 
0902 /**
0903  * @brief A chain iterator which is updated during node extraction if it is
0904  * properly registered.
0905  *
0906  * @see _Chain_Iterator_initialize().
0907  */
0908 typedef struct {
0909   /**
0910    * @brief Node for registration.
0911    *
0912    * Used during _Chain_Iterator_initialize() and _Chain_Iterator_destroy().
0913    */
0914   Chain_Node Registry_node;
0915 
0916   /**
0917    * @brief The direction of this iterator.
0918    *
0919    * Immutable after initialization via _Chain_Iterator_initialize().
0920    */
0921   Chain_Iterator_direction  direction;
0922 
0923   /**
0924    * @brief The current position of this iterator.
0925    *
0926    * The position is initialized via _Chain_Iterator_initialize().  It must be
0927    * explicitly set after one valid iteration step, e.g. in case a next node in
0928    * the iterator direction existed.  It is updated through the registration in
0929    * case a node is extracted via _Chain_Iterator_registry_update().
0930    */
0931   Chain_Node *position;
0932 } Chain_Iterator;
0933 
0934 /**
0935  * @brief A registry for chain iterators.
0936  *
0937  * Should be attached to a chain control to enable safe iteration through a
0938  * chain in case of concurrent node extractions.
0939  */
0940 typedef struct {
0941   Chain_Control Iterators;
0942 } Chain_Iterator_registry;
0943 
0944 /**
0945  * @brief Chain iterator registry initializer for static initialization.
0946  *
0947  * @param name The designator of the chain iterator registry.
0948  */
0949 #define CHAIN_ITERATOR_REGISTRY_INITIALIZER( name ) \
0950   { CHAIN_INITIALIZER_EMPTY( name.Iterators ) }
0951 
0952 /**
0953  * @brief Initializes a chain iterator registry.
0954  *
0955  * @param[out] the_registry The chain iterator registry to be initialized.
0956  */
0957 static inline void _Chain_Iterator_registry_initialize(
0958   Chain_Iterator_registry *the_registry
0959 )
0960 {
0961   _Chain_Initialize_empty( &the_registry->Iterators );
0962 }
0963 
0964 /**
0965  * @brief Updates all iterators present in the chain iterator registry in case
0966  * of a node extraction.
0967  *
0968  * Must be called before _Chain_Extract_unprotected().
0969  *
0970  * @warning This function will look at all registered chain iterators to
0971  *   determine if an update is necessary.
0972  *
0973  * @param[in, out] the_registry the chain iterator registry.
0974  * @param[out] the_node_to_extract The node that will be extracted.
0975  */
0976 static inline void _Chain_Iterator_registry_update(
0977   Chain_Iterator_registry *the_registry,
0978   Chain_Node              *the_node_to_extract
0979 )
0980 {
0981   Chain_Node *iter_node;
0982   Chain_Node *iter_tail;
0983 
0984   iter_node = _Chain_Head( &the_registry->Iterators );
0985   iter_tail = _Chain_Tail( &the_registry->Iterators );
0986 
0987   while ( ( iter_node = _Chain_Next( iter_node ) ) != iter_tail ) {
0988     Chain_Iterator *iter;
0989 
0990     iter = (Chain_Iterator *) iter_node;
0991 
0992     if ( iter->position == the_node_to_extract ) {
0993       if ( iter->direction == CHAIN_ITERATOR_FORWARD ) {
0994         iter->position = _Chain_Previous( the_node_to_extract );
0995       } else {
0996         iter->position = _Chain_Next( the_node_to_extract );
0997       }
0998     }
0999   }
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  * #if ISR_LOCK_NEEDS_OBJECT
1016  *   ISR_lock_Control        Lock;
1017  * #endif
1018  * } Some_Control;
1019  *
1020  * void iterate(
1021  *   Some_Control   *the_some,
1022  *   void         ( *visitor )( Chain_Node * )
1023  * )
1024  * {
1025  *   ISR_lock_Context  lock_context;
1026  *   Chain_Iterator    iter;
1027  *   Chain_Node       *node;
1028  *   const Chain_Node *end;
1029  *
1030  *   end = _Chain_Immutable_tail( &the_some->Chain );
1031  *
1032  *   _ISR_lock_ISR_disable_and_acquire( &the_some->Lock, &lock_context );
1033  *
1034  *   _Chain_Iterator_initialize(
1035  *     &the_some->Chain,
1036  *     &the_some->Iterators,
1037  *     &iter,
1038  *     CHAIN_ITERATOR_FORWARD
1039  *   );
1040  *
1041  *   while ( ( node = _Chain_Iterator_next( &iter ) ) != end ) {
1042  *     _Chain_Iterator_set_position( &iter, node );
1043  *     _ISR_lock_Release_and_ISR_enable( &the_some->Lock, &lock_context );
1044  *     ( *visitor )( node );
1045  *     _ISR_lock_ISR_disable_and_acquire( &the_some->Lock, &lock_context );
1046  *   }
1047  *
1048  *   _Chain_Iterator_destroy( &iter );
1049  *   _ISR_lock_Release_and_ISR_enable( &the_some->Lock, &lock_context );
1050  * }
1051  * @endcode
1052  *
1053  * @param[out] the_chain The chain to iterate.
1054  * @param[in, out] the_registry The registry for the chain iterator.
1055  * @param[out] the_iterator The chain iterator to initialize.
1056  * @param[out] direction The iteration direction.
1057  *
1058  * @see _Chain_Iterator_next(), _Chain_Iterator_set_position() and
1059  * Chain_Iterator_destroy().
1060  *
1061  * @warning Think twice before you use a chain iterator.  Its current
1062  *   implementation is unfit for use in performance relevant components, due to
1063  *   the linear time complexity in _Chain_Iterator_registry_update().
1064  */
1065 static inline void _Chain_Iterator_initialize(
1066   Chain_Control            *the_chain,
1067   Chain_Iterator_registry  *the_registry,
1068   Chain_Iterator           *the_iterator,
1069   Chain_Iterator_direction  direction
1070 )
1071 {
1072   _Chain_Initialize_node( &the_iterator->Registry_node );
1073   _Chain_Append_unprotected(
1074     &the_registry->Iterators,
1075     &the_iterator->Registry_node
1076   );
1077 
1078   the_iterator->direction = direction;
1079 
1080   if ( direction == CHAIN_ITERATOR_FORWARD ) {
1081     the_iterator->position = _Chain_Head( the_chain );
1082   } else {
1083     the_iterator->position = _Chain_Tail( the_chain );
1084   }
1085 }
1086 
1087 /**
1088  * @brief Returns the next node in the iterator direction.
1089  *
1090  * In case a next node exists, then the iterator should be updated via
1091  * _Chain_Iterator_set_position() to continue with the next iteration step.
1092  *
1093  * @param[in, out] the_iterator The chain iterator.
1094  *
1095  * @return The next node in the iterator direction
1096  */
1097 static inline Chain_Node *_Chain_Iterator_next(
1098   const Chain_Iterator *the_iterator
1099 )
1100 {
1101   if ( the_iterator->direction == CHAIN_ITERATOR_FORWARD ) {
1102     return _Chain_Next( the_iterator->position );
1103   } else {
1104     return _Chain_Previous( the_iterator->position );
1105   }
1106 }
1107 
1108 /**
1109  * @brief Sets the iterator position.
1110  *
1111  * @param[out] the_iterator The chain iterator.
1112  * @param[out] the_node The new iterator position.
1113  */
1114 static inline void _Chain_Iterator_set_position(
1115   Chain_Iterator *the_iterator,
1116   Chain_Node     *the_node
1117 )
1118 {
1119   the_iterator->position = the_node;
1120 }
1121 
1122 /**
1123  * @brief Destroys the iterator.
1124  *
1125  * Removes the iterator from its registry.
1126  *
1127  * @param[out] the_iterator The chain iterator.
1128  */
1129 static inline void _Chain_Iterator_destroy(
1130   Chain_Iterator *the_iterator
1131 )
1132 {
1133   _Chain_Extract_unprotected( &the_iterator->Registry_node );
1134 }
1135 
1136 /** @} */
1137 
1138 #ifdef __cplusplus
1139 }
1140 #endif
1141 
1142 #endif
1143 /* end of include file */