Skip to content

Commit d40b8ce

Browse files
pabigotcarlescufi
authored andcommitted
sys: dlist: Add sys_dnode_is_linked
The original implementation allows a list to be corrupted by list operations on the removed node. Existing code attempts to avoid this by using external state to determine whether a node is in a list, but this is fragile and fails when the state that holds the flag value is changed after the node is removed, e.g. in preparation for re-using the node. Follow Linux in invalidating the link pointers in a removed node. Add API so that detection of particpation in a list is available at the node abstraction. This solution relies on the following steady-state invariants: * A node (as opposed to a list) will never be adjacent to itself in a list; * The next and prev pointers of a node are always either both null or both non-null. Signed-off-by: Peter A. Bigot <[email protected]>
1 parent 692e103 commit d40b8ce

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

include/misc/dlist.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ typedef struct _dnode sys_dnode_t;
181181
__cns = SYS_DLIST_PEEK_NEXT_CONTAINER(__dl, __cn, __n))
182182

183183
/**
184-
* @brief initialize list
184+
* @brief initialize list to its empty state
185185
*
186186
* @param list the doubly-linked list
187187
*
@@ -196,6 +196,33 @@ static inline void sys_dlist_init(sys_dlist_t *list)
196196

197197
#define SYS_DLIST_STATIC_INIT(ptr_to_list) { {(ptr_to_list)}, {(ptr_to_list)} }
198198

199+
/**
200+
* @brief initialize node to its state when not in a list
201+
*
202+
* @param node the node
203+
*
204+
* @return N/A
205+
*/
206+
207+
static inline void sys_dnode_init(sys_dnode_t *node)
208+
{
209+
node->next = NULL;
210+
node->prev = NULL;
211+
}
212+
213+
/**
214+
* @brief check if a node is a member of any list
215+
*
216+
* @param node the node
217+
*
218+
* @return true if node is linked into a list, false if it is not
219+
*/
220+
221+
static inline bool sys_dnode_is_linked(const sys_dnode_t *node)
222+
{
223+
return node->next != NULL;
224+
}
225+
199226
/**
200227
* @brief check if a node is the list's head
201228
*
@@ -500,6 +527,7 @@ static inline void sys_dlist_remove(sys_dnode_t *node)
500527
{
501528
node->prev->next = node->next;
502529
node->next->prev = node->prev;
530+
sys_dnode_init(node);
503531
}
504532

505533
/**

tests/kernel/common/src/dlist.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,13 @@ void test_dlist(void)
189189
"test_list head/tail are wrong");
190190

191191
/* Finding and removing node 1 */
192+
zassert_true(sys_dnode_is_linked(&test_node_1.node),
193+
"node1 is not linked");
192194
sys_dlist_remove(&test_node_1.node);
193195
zassert_true((verify_emptyness(&test_list)),
194196
"test_list should be empty");
197+
zassert_false(sys_dnode_is_linked(&test_node_1.node),
198+
"node1 is still linked");
195199

196200
/* Prepending node 1 */
197201
sys_dlist_prepend(&test_list, &test_node_1.node);

0 commit comments

Comments
 (0)