-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
thread_num / thread_num_dynamic are never decremented in CMSIS v2 thread.c #23062
Comments
That won't work, thread_num is used to select the thread object in cv2_thread_pool. Decrementing it when a thread exits will not do what you expect, at worst it will cause thread objects to be used twice and crash the kernel. We need something like The code is seriously incorrect anyway, it tries to manage concurrency with respect to thread/stack IDs with atomic variables but is full of race windows where it falls over. |
Converting this to use k_mem_slab() wasn't bad and I have a patch ready for that. The problem lies with race conditions with re-using these thread objects. The CMSISv2 wrapper code doesn't seem to handle thread exits very robustly:
What I need is some kind of centralized hook that gets invoked when a CMSIS thread exits (regardless of method), where it is completely safe to release the k_thread and associated stack back to the pool. And I can't seem to safely to this in the context of the exiting thread itself. This seems a more fundamental race, as the core kernel has a similar problem with |
In order to get this and #23063 fixed robustly I think I need the following:
This is currently falling over for threads that self-abort because the relevant logic in The same guarantees must also hold if the target thread, instead of being the current thread, is instead running on some other CPU. I think we need to defer this stuff until we have swapped to a different thread's context. For CONFIG_SWITCH architectures I am eyeing doing this work in the latter half of do_swap(). If this approach pans out I'll have to hook swap-based arches as well. This probably should also result in some kind of torture test to hammer all CPUs with multiple threads being created, aborted, joining with each other, etc. |
#26486 is most of what's needed to fix this -- if all the |
This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time. |
Fixes races where threads on another CPU are joining the exiting thread, since it could still be running when the joiners wake up on a different CPU. Fixes problems where the thread object is still being used by the kernel when the fn_abort() function is called, preventing the thread object from being recycled or freed back to a slab pool. Precedent for doing this comes from FreeRTOS, which also performs final thread cleanup in the idle thread. Add some extra comments and log messages to the meta-irq test case. Some logic in z_thread_single_abort() rearranged such that when we release sched_spinlock, the thread object pointer is never dereferenced by the kernel again; join waiters or fn_abort() logic may free it immediately. An assertion added to z_thread_single_abort() to ensure it never gets called with thread == _current outside of an ISR. This requires an increase of the idle thread stack size. This was already necessary for a lot of applications that have any kind of power management since PM infrastructure gets invoked from the idle thread. Some logic has been added to ensure z_thread_single_abort() tasks don't run more than once. Fixes: zephyrproject-rtos#26486 Related to: zephyrproject-rtos#23063 zephyrproject-rtos#23062 Signed-off-by: Andrew Boie <[email protected]>
Fixes races where threads on another CPU are joining the exiting thread, since it could still be running when the joiners wake up on a different CPU. Fixes problems where the thread object is still being used by the kernel when the fn_abort() function is called, preventing the thread object from being recycled or freed back to a slab pool. Fixes a race where a thread is aborted from one CPU while it self-aborts on another CPU, that was currently worked around with a busy-wait. Precedent for doing this comes from FreeRTOS, which also performs final thread cleanup in the idle thread. Some logic in z_thread_single_abort() rearranged such that when we release sched_spinlock, the thread object pointer is never dereferenced by the kernel again; join waiters or fn_abort() logic may free it immediately. An assertion added to z_thread_single_abort() to ensure it never gets called with thread == _current outside of an ISR. Some logic has been added to ensure z_thread_single_abort() tasks don't run more than once. Fixes: zephyrproject-rtos#26486 Related to: zephyrproject-rtos#23063 zephyrproject-rtos#23062 Signed-off-by: Andrew Boie <[email protected]>
WIP branch still debugging stuff, https://github.com/andrewboie/zephyr/tree/cmsis-thread-slabs |
Fixes races where threads on another CPU are joining the exiting thread, since it could still be running when the joiners wake up on a different CPU. Fixes problems where the thread object is still being used by the kernel when the fn_abort() function is called, preventing the thread object from being recycled or freed back to a slab pool. Fixes a race where a thread is aborted from one CPU while it self-aborts on another CPU, that was currently worked around with a busy-wait. Precedent for doing this comes from FreeRTOS, which also performs final thread cleanup in the idle thread. Some logic in z_thread_single_abort() rearranged such that when we release sched_spinlock, the thread object pointer is never dereferenced by the kernel again; join waiters or fn_abort() logic may free it immediately. An assertion added to z_thread_single_abort() to ensure it never gets called with thread == _current outside of an ISR. Some logic has been added to ensure z_thread_single_abort() tasks don't run more than once. Fixes: zephyrproject-rtos#26486 Related to: zephyrproject-rtos#23063 zephyrproject-rtos#23062 Signed-off-by: Andrew Boie <[email protected]>
Fixes races where threads on another CPU are joining the exiting thread, since it could still be running when the joiners wake up on a different CPU. Fixes problems where the thread object is still being used by the kernel when the fn_abort() function is called, preventing the thread object from being recycled or freed back to a slab pool. Fixes a race where a thread is aborted from one CPU while it self-aborts on another CPU, that was currently worked around with a busy-wait. Precedent for doing this comes from FreeRTOS, which also performs final thread cleanup in the idle thread. Some logic in z_thread_single_abort() rearranged such that when we release sched_spinlock, the thread object pointer is never dereferenced by the kernel again; join waiters or fn_abort() logic may free it immediately. An assertion added to z_thread_single_abort() to ensure it never gets called with thread == _current outside of an ISR. Some logic has been added to ensure z_thread_single_abort() tasks don't run more than once. Fixes: #26486 Related to: #23063 #23062 Signed-off-by: Andrew Boie <[email protected]>
This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time. |
Terminating threads through CMSIS v2 APIs does not free up resources allocated to the threads by the CMSISv2 API. Upon inspection, it is easy to spot that the thread_num and thread_num_dynamic variables are only ever incremented, though they should also be decremented when osThreadExit is called by the thread or osThreadTerminate is called elsewhere. Simply decrementing thread_num in the correct place should be enough for statically allocated threads, however thread_num_dynamic needs some additional handling as the value is used for choosing the stack for the next dynamic thread.
The text was updated successfully, but these errors were encountered: