-
Notifications
You must be signed in to change notification settings - Fork 28
Refactor list node for embedded usage #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
e027d81 to
9a49d30
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 3 files
|
Instead of using |
9a49d30 to
1266621
Compare
HeatCrab
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that the original functions and the new helpers share the exact same traversal logic. Would it be better to let the original functions call the new helpers, instead of duplicating the logic?
|
The idea looks good for now. However, in the long run, I wonder if we should consider adopting the Linux kernel approach: embedding the list node within the struct and using container_of(). This would allow us to avoid exposing dual APIs (one with internal allocation and one without). As recent fixes have shown, automatic memory allocation/deallocation can easily lead to oversight and result in memory-related bugs. |
Thanks for your feedback. For this PR, I’ll follow the suggestion from @HeatCrab to consolidate the repetitive API in |
7307a00 to
948d586
Compare
include/lib/list.h
Outdated
| list_remove_node(list, target); | ||
|
|
||
| prev->next = target->next; | ||
| void *data = target->data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only free and return data operations are kept in the below section.
include/lib/list.h
Outdated
|
|
||
| node->data = data; | ||
| node->next = list->tail; | ||
| node->next = NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An initialized node should represent a standalone element; its next pointer must be set to NULL.
You can refine here to consolidate. |
948d586 to
91dc543
Compare
a98c684 to
50fe97c
Compare
| /* Remove a specific node; returns its data */ | ||
| static inline void *list_remove(list_t *list, list_node_t *target) | ||
| /* Remove a specific node form the list */ | ||
| static inline list_node_t *list_remove(list_t *list, list_node_t *target) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value is required for the exception handling when removing the waiter node from the mutex waiting list.
| while (curr && curr != waiters->tail) { | ||
| if (curr->data == self) { | ||
| list_remove(waiters, curr); | ||
| list_node_t *curr_mutex_node = waiters->head->next; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is better aligned with the embedded list node.
Introduce a simple container operation to support embedded node design for the timer and scheduler subsystems This change allows container access from the embedded list node.
bd9cfe7 to
308ae12
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 13 files
Prompt for AI agents (all 5 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="app/test_utils.c">
<violation number="1" location="app/test_utils.c:328">
P2: Incorrect expected value in assertion. After pushing three nodes in order (1, 2, 3), `list->head->next` still points to the first node (val=1), not the third. `list_pushback` adds to the tail, so the head->next remains the first inserted node.</violation>
<violation number="2" location="app/test_utils.c:333">
P2: Incorrect expected value in assertion. After removing the second node, the list is [first, third], so `list->head->next` points to first (val=1), not val=2.</violation>
<violation number="3" location="app/test_utils.c:338">
P2: Incorrect expected length after `list_pop`. The pop operation decrements length, so after popping from a list of 2 elements, length should be 1, not 2.</violation>
</file>
<file name="include/lib/list.h">
<violation number="1" location="include/lib/list.h:108">
P3: Typo in comment: "form" should be "from".</violation>
</file>
<file name="kernel/timer.c">
<violation number="1" location="kernel/timer.c:142">
P0: Wrong `container_of` macro used. This function operates on `kcb->timer_list` (the running timer list) which contains `t_running_node` embedded nodes. Using `timer_from_node` (which offsets from `t_node`) instead of `timer_from_running_node` will compute an incorrect pointer, causing undefined behavior when accessing `deadline_ticks`.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
Remove the data member from list_node to support an embedded-node design. List nodes are now embedded directly into container structures, eliminating the need to manage list node lifecycles during pushback or remove operations. The lifecycle is instead owned by the container itself. This change updates existing list helpers to align with the embedded design and reduces unnecessary memory operations during list manipulation.
Previously, timer management relied on list nodes provided by timer_node_pool. Timer creation and cancellation could trigger allocation or deallocation of timer or list nodes when no pool entries were available. This change pre-allocates timers and embeds list nodes directly within timer structures, reducing memory operations during timer lifecycle transitions and simplifying timer management.
This change introduces helper macros to retrieve timer containers from embedded list nodes. Timer resources are now statically allocated from timer_pool, eliminating dynamic memory operations during timer usage. Timer allocation and release are tracked only via the timer pool bitmask. To avoid ambiguity, the suffix `_running_list` is added to explicitly indicate lists holding active timers.
Timer APIs no longer require memory operations now that timers are statically allocated with embedded list nodes. This change removes redundant allocation paths and uses the timer_from_node() helper to align timer access with the embedded list node design.
Previously, expired timers were placed into the expired_timers array and their list nodes were returned to timer_node_pool. With embedded list nodes, a timer only needs to be removed from the running timer list to stop further handling. This change updates timer handling to operate directly on embedded list nodes, aligning the handler logic with the embedded node design.
The previous non-intrusive list node approach for tcb_t introduced unnecessary memory operations and ambiguity around list node lifecycle management. This change switches task list management to an embedded list node design, aligning task handling with the updated list operation model.
Add unit tests for general list operations using the new embedded-node design. Rename test_libc to test_utils so it can host unit tests for common helpers and consolidate reusable test code.
The condition check is removed because the node is embedded in the tcb, no need to confirm whether tcb is existing anymore. The access of tcb_t is replaced by the marco to align with the embedded node design.
Add timer cancellation APIs to validate timer behavior across different cancellation scenarios, including task destruction, explicit timer cancellation, and one-shot timers. These APIs help ensure cancelled or destroyed timers never fire and that one-shot timers handle tick expiration correctly.
308ae12 to
f58f267
Compare
Previously, the non-intrusive node design made the lifetime of list nodes ambiguous. To clarify the ownership responsibilities between list users and list operations, this change introduces an intrusive (embedded) node
design.
With this approach, list APIs focus solely on manipulating list nodes, while the container owning the node is responsible for its entire lifecycle.
Summary by cubic
Switched lists to an embedded-node design and removed allocations from pushback/remove/pop. Updated tasks, mutexes, and timers to use embedded nodes and a static timer pool to cut malloc/free overhead in hot paths.
New Features
Refactors
Written for commit f58f267. Summary will update automatically on new commits.