F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Clist.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title Clist.cpp
3 // \brief CFDP circular list definition source file
4 //
5 // This file is a port of the cf_clist.c file from the
6 // NASA Core Flight System (cFS) CFDP (CF) Application,
7 // version 3.0.0, adapted for use within the F-Prime (F') framework.
8 //
9 // This is a circular doubly-linked list implementation. It is used for
10 // multiple data structures in CFDP.
11 //
12 // ======================================================================
13 //
14 // NASA Docket No. GSC-18,447-1
15 //
16 // Copyright (c) 2019 United States Government as represented by the
17 // Administrator of the National Aeronautics and Space Administration.
18 // All Rights Reserved.
19 //
20 // Licensed under the Apache License, Version 2.0 (the "License"); you may
21 // not use this file except in compliance with the License. You may obtain
22 // a copy of the License at
23 //
24 // http://www.apache.org/licenses/LICENSE-2.0
25 //
26 // Unless required by applicable law or agreed to in writing, software
27 // distributed under the License is distributed on an "AS IS" BASIS,
28 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 // See the License for the specific language governing permissions and
30 // limitations under the License.
31 //
32 // ======================================================================
33 
35 #include <config/CfdpCfg.hpp>
36 
37 #include <Fw/Types/Assert.hpp>
38 
39 namespace Svc {
40 namespace Ccsds {
41 namespace Cfdp {
42 
44  node->next = node;
45  node->prev = node;
46 }
47 
49  CListNode* last;
50 
51  FW_ASSERT(head);
52  FW_ASSERT(node);
53  FW_ASSERT(node->next == node);
54  FW_ASSERT(node->prev == node);
55 
56  if (*head) {
57  last = (*head)->prev;
58 
59  node->next = *head;
60  node->prev = last;
61 
62  last->next = node;
63  (*head)->prev = node;
64  }
65 
66  *head = node;
67 }
68 
70  CListNode* last;
71 
72  FW_ASSERT(head);
73  FW_ASSERT(node);
74  FW_ASSERT(node->next == node);
75  FW_ASSERT(node->prev == node);
76 
77  if (!*head) {
78  *head = node;
79  } else {
80  last = (*head)->prev;
81 
82  node->next = *head;
83  (*head)->prev = node;
84  node->prev = last;
85  last->next = node;
86  }
87 }
88 
90  CListNode* ret;
91 
92  FW_ASSERT(head);
93 
94  ret = *head;
95  if (ret) {
96  CfdpCListRemove(head, ret);
97  }
98 
99  return ret;
100 }
101 
102 void CfdpCListRemove(CListNode** head, CListNode* node) {
103  FW_ASSERT(head);
104  FW_ASSERT(node);
105  FW_ASSERT(*head);
106 
107  if (node->next == node) {
108  /* only node in the list, so this one is easy */
109  FW_ASSERT(node == *head); /* sanity check */
110  *head = nullptr;
111  } else if (*head == node) {
112  /* removing the first node in the list, so make the second node in the list the first */
113  (*head)->prev->next = node->next;
114  *head = node->next;
115 
116  (*head)->prev = node->prev;
117  } else {
118  node->next->prev = node->prev;
119  node->prev->next = node->next;
120  }
121 
122  CfdpCListInitNode(node);
123 }
124 
125 void CfdpCListInsertAfter(CListNode** head, CListNode* start, CListNode* after) {
126  /* calling insert_after with nothing to insert after (no head) makes no sense */
127  FW_ASSERT(head);
128  FW_ASSERT(*head);
129  FW_ASSERT(start);
130  FW_ASSERT(start != after);
131 
132  /* knowing that head is not empty, and knowing that start is non-zero, this is an easy operation */
133  after->next = start->next;
134  start->next = after;
135  after->prev = start;
136  after->next->prev = after;
137 }
138 
139 void CfdpCListTraverse(CListNode* start, CListFunc fn, void* context) {
140  CListNode* node = start;
141  CListNode* node_next;
142  bool last = false;
143  // Safety bound: maximum possible list size based on transaction pool configuration
144  // Prevents infinite loop if list becomes corrupted
145  constexpr U32 maxIterations = MaxSimultaneousRx + MaxCommandedPlaybackFilesPerChan +
148 
149  if (node) {
150  U32 i;
151  for (i = 0; i < maxIterations && !last; ++i) {
152  /* set node_next in case callback removes this node from the list */
153  node_next = node->next;
154  if (node_next == start) {
155  last = true;
156  }
157  if (!CfdpCListTraverseStatusIsContinue(fn(node, context))) {
158  break;
159  }
160  /* list traversal is robust against an item deleting itself during traversal,
161  * but there is a special case if that item is the starting node. Since this is
162  * a circular list, start is remembered so we know when to stop. Must set start
163  * to the next node in this case. */
164  if ((start == node) && (node->next != node_next)) {
165  start = node_next;
166  }
167  node = node_next;
168  }
169  FW_ASSERT(last, static_cast<FwAssertArgType>(i));
170  }
171 }
172 
173 void CfdpCListTraverseR(CListNode* end, CListFunc fn, void* context) {
174  if (end) {
175  CListNode* node = end->prev;
176  CListNode* node_next;
177  bool last = false;
178  // Safety bound: maximum possible list size based on transaction pool configuration
179  // Prevents infinite loop if list becomes corrupted
180  constexpr U32 maxIterations = MaxSimultaneousRx + MaxCommandedPlaybackFilesPerChan +
183 
184  if (node) {
185  end = node;
186  U32 i;
187 
188  for (i = 0; i < maxIterations && !last; ++i) {
189  /* set node_next in case callback removes this node from the list */
190  node_next = node->prev;
191  if (node_next == end) {
192  last = true;
193  }
194 
195  if (!CfdpCListTraverseStatusIsContinue(fn(node, context))) {
196  break;
197  }
198 
199  /* list traversal is robust against an item deleting itself during traversal,
200  * but there is a special case if that item is the starting node. Since this is
201  * a circular list, "end" is remembered so we know when to stop. Must set "end"
202  * to the next node in this case. */
203  if ((end == node) && (node->prev != node_next)) {
204  end = node_next;
205  }
206  node = node_next;
207  }
208  FW_ASSERT(last, static_cast<FwAssertArgType>(i));
209  }
210  }
211 }
212 
213 } // namespace Cfdp
214 } // namespace Ccsds
215 } // namespace Svc
struct CListNode * prev
Pointer to previous node.
Definition: Clist.hpp:68
void CfdpCListInsertAfter(CListNode **head, CListNode *start, CListNode *after)
Insert the given node into the last after the given start node.
Definition: Clist.cpp:125
struct CListNode * next
Pointer to next node.
Definition: Clist.hpp:67
void CfdpCListInsertFront(CListNode **head, CListNode *node)
Insert the given node into the front of a list.
Definition: Clist.cpp:48
CListTraverseStatus(*)(CListNode *, void *) CListFunc
Callback function type for use with CfdpCListTraverse()
Definition: Clist.hpp:95
void CfdpCListTraverse(CListNode *start, CListFunc fn, void *context)
Traverse the entire list, calling the given function on all nodes.
Definition: Clist.cpp:139
CListNode * CfdpCListPop(CListNode **head)
Remove the first node from a list and return it.
Definition: Clist.cpp:89
void CfdpCListInsertBack(CListNode **head, CListNode *node)
Insert the given node into the back of a list.
Definition: Clist.cpp:69
static bool CfdpCListTraverseStatusIsContinue(CListTraverseStatus stat)
Definition: Clist.hpp:59
void CfdpCListRemove(CListNode **head, CListNode *node)
Remove the given node from the list.
Definition: Clist.cpp:102
Circular linked list node structure.
Definition: Clist.hpp:66
RateGroupDivider component implementation.
void CfdpCListTraverseR(CListNode *end, CListFunc fn, void *context)
Reverse list traversal, starting from end, calling given function on all nodes.
Definition: Clist.cpp:173
#define FW_ASSERT(...)
Definition: Assert.hpp:14
void CfdpCListInitNode(CListNode *node)
Initialize a clist node.
Definition: Clist.cpp:43