![]() |
|
|||
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 */
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |