GCC Code Coverage Report


Directory: ./
File: Svc/Ccsds/CfdpManager/Clist.cpp
Date: 2026-09-03 21:13:48
Exec Total Coverage
Lines: 94 95 98.9%
Functions: 8 8 100.0%
Branches: 37 40 92.5%

Line Branch Exec Source
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
34 #include <Svc/Ccsds/CfdpManager/Clist.hpp>
35 #include <config/CfdpCfg.hpp>
36
37 #include <Fw/Types/Assert.hpp>
38
39 namespace Svc {
40 namespace Ccsds {
41 namespace Cfdp {
42
43 106905 void CfdpCListInitNode(CListNode* node) {
44 106905 node->next = node;
45 106905 node->prev = node;
46 106905 }
47
48 2 void CfdpCListInsertFront(CListNode** head, CListNode* node) {
49 CListNode* last;
50
51 2 FW_ASSERT(head);
52 2 FW_ASSERT(node);
53 2 FW_ASSERT(node->next == node);
54 2 FW_ASSERT(node->prev == node);
55
56
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (*head) {
57 1 last = (*head)->prev;
58
59 1 node->next = *head;
60 1 node->prev = last;
61
62 1 last->next = node;
63 1 (*head)->prev = node;
64 }
65
66 2 *head = node;
67 2 }
68
69 106582 void CfdpCListInsertBack(CListNode** head, CListNode* node) {
70 CListNode* last;
71
72 106582 FW_ASSERT(head);
73 106582 FW_ASSERT(node);
74 106582 FW_ASSERT(node->next == node);
75 106582 FW_ASSERT(node->prev == node);
76
77
2/2
✓ Branch 1 taken 1152 times.
✓ Branch 2 taken 105430 times.
106582 if (!*head) {
78 1152 *head = node;
79 } else {
80 105430 last = (*head)->prev;
81
82 105430 node->next = *head;
83 105430 (*head)->prev = node;
84 105430 node->prev = last;
85 105430 last->next = node;
86 }
87 106582 }
88
89 143 CListNode* CfdpCListPop(CListNode** head) {
90 CListNode* ret;
91
92 143 FW_ASSERT(head);
93
94 143 ret = *head;
95
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 1 times.
143 if (ret) {
96 142 CfdpCListRemove(head, ret);
97 }
98
99 143 return ret;
100 }
101
102 388 void CfdpCListRemove(CListNode** head, CListNode* node) {
103 388 FW_ASSERT(head);
104 388 FW_ASSERT(node);
105 388 FW_ASSERT(*head);
106
107
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 332 times.
388 if (node->next == node) {
108 /* only node in the list, so this one is easy */
109 56 FW_ASSERT(node == *head); /* sanity check */
110 56 *head = nullptr;
111
2/2
✓ Branch 1 taken 331 times.
✓ Branch 2 taken 1 times.
332 } else if (*head == node) {
112 /* removing the first node in the list, so make the second node in the list the first */
113 331 (*head)->prev->next = node->next;
114 331 *head = node->next;
115
116 331 (*head)->prev = node->prev;
117 } else {
118 1 node->next->prev = node->prev;
119 1 node->prev->next = node->next;
120 }
121
122 388 CfdpCListInitNode(node);
123 388 }
124
125 1 void CfdpCListInsertAfter(CListNode** head, CListNode* start, CListNode* after) {
126 /* calling insert_after with nothing to insert after (no head) makes no sense */
127 1 FW_ASSERT(head);
128 1 FW_ASSERT(*head);
129 1 FW_ASSERT(start);
130 1 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 1 after->next = start->next;
134 1 start->next = after;
135 1 after->prev = start;
136 1 after->next->prev = after;
137 1 }
138
139 16065 void CfdpCListTraverse(CListNode* start, CListFunc fn, void* context) {
140 16065 CListNode* node = start;
141 CListNode* node_next;
142 16065 bool last = false;
143 // Safety bound: maximum possible list size based on transaction pool configuration
144 // Prevents infinite loop if list becomes corrupted
145 16065 constexpr U32 maxIterations = MaxSimultaneousRx + MaxCommandedPlaybackFilesPerChan +
146 (MaxCommandedPlaybackDirectoriesPerChan * NumTransactionsPerPlayback) +
147 (MaxPollingDirPerChan * NumTransactionsPerPlayback);
148
149
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 15732 times.
16065 if (node) {
150 U32 i;
151
4/4
✓ Branch 0 taken 1811 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1560 times.
✓ Branch 3 taken 251 times.
1812 for (i = 0; i < maxIterations && !last; ++i) {
152 /* set node_next in case callback removes this node from the list */
153 1560 node_next = node->next;
154
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 1227 times.
1560 if (node_next == start) {
155 333 last = true;
156 }
157
2/2
✓ Branch 2 taken 81 times.
✓ Branch 3 taken 1479 times.
1560 if (!CfdpCListTraverseStatusIsContinue(fn(node, context))) {
158 81 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
4/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 1227 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 230 times.
1479 if ((start == node) && (node->next != node_next)) {
165 22 start = node_next;
166 }
167 1479 node = node_next;
168 }
169 333 FW_ASSERT(last || (i < maxIterations), static_cast<FwAssertArgType>(i));
170 }
171 16065 }
172
173 3 void CfdpCListTraverseR(CListNode* end, CListFunc fn, void* context) {
174
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (end) {
175 2 CListNode* node = end->prev;
176 CListNode* node_next;
177 2 bool last = false;
178 // Safety bound: maximum possible list size based on transaction pool configuration
179 // Prevents infinite loop if list becomes corrupted
180 2 constexpr U32 maxIterations = MaxSimultaneousRx + MaxCommandedPlaybackFilesPerChan +
181 (MaxCommandedPlaybackDirectoriesPerChan * NumTransactionsPerPlayback) +
182 (MaxPollingDirPerChan * NumTransactionsPerPlayback);
183
184
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (node) {
185 2 end = node;
186 U32 i;
187
188
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
5 for (i = 0; i < maxIterations && !last; ++i) {
189 /* set node_next in case callback removes this node from the list */
190 4 node_next = node->prev;
191
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (node_next == end) {
192 2 last = true;
193 }
194
195
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
4 if (!CfdpCListTraverseStatusIsContinue(fn(node, context))) {
196 1 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
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
3 if ((end == node) && (node->prev != node_next)) {
204 end = node_next;
205 }
206 3 node = node_next;
207 }
208 2 FW_ASSERT(last || (i < maxIterations), static_cast<FwAssertArgType>(i));
209 }
210 }
211 3 }
212
213 } // namespace Cfdp
214 } // namespace Ccsds
215 } // namespace Svc
216