GCC Code Coverage Report


Directory: ./
File: Svc/Ccsds/CfdpManager/Clist.cpp
Date: 2026-10-14 21:15:02
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 117469 void CfdpCListInitNode(CListNode* node) {
44 117469 node->next = node;
45 117469 node->prev = node;
46 117469 }
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 117140 void CfdpCListInsertBack(CListNode** head, CListNode* node) {
70 CListNode* last;
71
72 117140 FW_ASSERT(head);
73 117140 FW_ASSERT(node);
74 117140 FW_ASSERT(node->next == node);
75 117140 FW_ASSERT(node->prev == node);
76
77
2/2
✓ Branch 1 taken 1258 times.
✓ Branch 2 taken 115882 times.
117140 if (!*head) {
78 1258 *head = node;
79 } else {
80 115882 last = (*head)->prev;
81
82 115882 node->next = *head;
83 115882 (*head)->prev = node;
84 115882 node->prev = last;
85 115882 last->next = node;
86 }
87 117140 }
88
89 145 CListNode* CfdpCListPop(CListNode** head) {
90 CListNode* ret;
91
92 145 FW_ASSERT(head);
93
94 145 ret = *head;
95
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 1 times.
145 if (ret) {
96 144 CfdpCListRemove(head, ret);
97 }
98
99 145 return ret;
100 }
101
102 394 void CfdpCListRemove(CListNode** head, CListNode* node) {
103 394 FW_ASSERT(head);
104 394 FW_ASSERT(node);
105 394 FW_ASSERT(*head);
106
107
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 338 times.
394 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 337 times.
✓ Branch 2 taken 1 times.
338 } else if (*head == node) {
112 /* removing the first node in the list, so make the second node in the list the first */
113 337 (*head)->prev->next = node->next;
114 337 *head = node->next;
115
116 337 (*head)->prev = node->prev;
117 } else {
118 1 node->next->prev = node->prev;
119 1 node->prev->next = node->next;
120 }
121
122 394 CfdpCListInitNode(node);
123 394 }
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 16091 void CfdpCListTraverse(CListNode* start, CListFunc fn, void* context) {
140 16091 CListNode* node = start;
141 CListNode* node_next;
142 16091 bool last = false;
143 // Safety bound: maximum possible list size based on transaction pool configuration
144 // Prevents infinite loop if list becomes corrupted
145 16091 constexpr U32 maxIterations = MaxSimultaneousRx + MaxCommandedPlaybackFilesPerChan +
146 (MaxCommandedPlaybackDirectoriesPerChan * NumTransactionsPerPlayback) +
147 (MaxPollingDirPerChan * NumTransactionsPerPlayback);
148
149
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 15754 times.
16091 if (node) {
150 U32 i;
151
4/4
✓ Branch 0 taken 1817 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1564 times.
✓ Branch 3 taken 253 times.
1818 for (i = 0; i < maxIterations && !last; ++i) {
152 /* set node_next in case callback removes this node from the list */
153 1564 node_next = node->next;
154
2/2
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 1227 times.
1564 if (node_next == start) {
155 337 last = true;
156 }
157
2/2
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 1481 times.
1564 if (!CfdpCListTraverseStatusIsContinue(fn(node, context))) {
158 83 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 254 times.
✓ Branch 1 taken 1227 times.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 232 times.
1481 if ((start == node) && (node->next != node_next)) {
165 22 start = node_next;
166 }
167 1481 node = node_next;
168 }
169 337 FW_ASSERT(last || (i < maxIterations), static_cast<FwAssertArgType>(i));
170 }
171 16091 }
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