-
Notifications
You must be signed in to change notification settings - Fork 60
Fix runtime data races, memory leak, and shutdown safety #1429
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?
Changes from all commits
a783517
28cf17d
a355ec5
de46cb2
706a01f
0b27717
2cdf817
95519ef
11820ae
68f4dd0
4a8cc9d
5638972
05bd377
2c559d0
b0ad7d8
2241c38
eb3bfff
a111e11
42cfa76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,8 @@ | |
| #include "pal/WorkerThread.hpp" | ||
| #include "pal/PAL.hpp" | ||
|
|
||
| #include <system_error> | ||
|
|
||
| #if defined(MATSDK_PAL_CPP11) || defined(MATSDK_PAL_WIN32) | ||
|
|
||
| /* Maximum scheduler interval for SDK is 1 hour required for clamping in case of monotonic clock drift */ | ||
|
|
@@ -35,7 +37,7 @@ namespace PAL_NS_BEGIN { | |
| std::list<MAT::Task*> m_timerQueue; | ||
| Event m_event; | ||
| MAT::Task* m_itemInProgress; | ||
| int count = 0; | ||
| bool m_shuttingDown = false; | ||
|
|
||
| public: | ||
|
|
||
|
|
@@ -53,32 +55,65 @@ namespace PAL_NS_BEGIN { | |
|
|
||
| void Join() final | ||
| { | ||
| auto item = new WorkerThreadShutdownItem(); | ||
| Queue(item); | ||
| std::thread::id this_id = std::this_thread::get_id(); | ||
| bool joined = false; | ||
| { | ||
| LOCKGUARD(m_lock); | ||
| if (!m_shuttingDown) { | ||
| m_shuttingDown = true; | ||
| m_queue.push_back(new WorkerThreadShutdownItem()); | ||
| m_event.post(); | ||
| } | ||
| } | ||
| try { | ||
| if (m_hThread.joinable() && (m_hThread.get_id() != this_id)) | ||
| if (!m_hThread.joinable()) { | ||
| return; | ||
| } | ||
| if (m_hThread.get_id() != this_id) { | ||
| m_hThread.join(); | ||
| else | ||
| joined = true; | ||
| } else { | ||
| m_hThread.detach(); | ||
| } | ||
| } | ||
| catch (const std::system_error& e) { | ||
| LOG_ERROR("Thread join/detach failed: [%d] %s", e.code().value(), e.what()); | ||
| } | ||
| catch (const std::exception& e) { | ||
| LOG_ERROR("Thread join/detach failed: %s", e.what()); | ||
| } | ||
| catch (...) {}; | ||
|
|
||
| // TODO: [MG] - investigate if we ever drop work items on shutdown. | ||
| if (!m_queue.empty()) | ||
| { | ||
| LOG_WARN("m_queue is not empty!"); | ||
| // Log pending work in both paths so operators can see if | ||
| // shutdown is dropping tasks. | ||
| LOCKGUARD(m_lock); | ||
| if (!m_queue.empty()) { | ||
| LOG_WARN("Shutdown with %zu queued task(s) pending", m_queue.size()); | ||
| } | ||
| if (!m_timerQueue.empty()) | ||
| { | ||
| LOG_WARN("m_timerQueue is not empty!"); | ||
| if (!m_timerQueue.empty()) { | ||
| LOG_WARN("Shutdown with %zu timer(s) pending", m_timerQueue.size()); | ||
| } | ||
|
|
||
| // Clean up any tasks remaining in the queues after shutdown. | ||
| // Only safe after join() — the thread has fully exited. | ||
| // After detach(), the thread still needs the shutdown item | ||
| // and may still be accessing the queues. | ||
| if (joined) { | ||
| for (auto task : m_queue) { delete task; } | ||
| m_queue.clear(); | ||
| for (auto task : m_timerQueue) { delete task; } | ||
| m_timerQueue.clear(); | ||
| } | ||
| } | ||
|
|
||
| void Queue(MAT::Task* item) final | ||
| { | ||
| LOG_INFO("queue item=%p", &item); | ||
| LOG_INFO("queue item=%p", static_cast<void*>(item)); | ||
| LOCKGUARD(m_lock); | ||
| if (m_shuttingDown) { | ||
| LOG_WARN("Dropping queued task %p during shutdown", static_cast<void*>(item)); | ||
| delete item; | ||
| return; | ||
|
Comment on lines
+112
to
+115
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pointer is only used for checking the identity of the task or queue removal, not for accessing the actual task
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if |
||
| } | ||
| if (item->Type == MAT::Task::TimedCall) { | ||
| auto it = m_timerQueue.begin(); | ||
| while (it != m_timerQueue.end() && (*it)->TargetTime < item->TargetTime) { | ||
|
|
@@ -89,7 +124,6 @@ namespace PAL_NS_BEGIN { | |
| else { | ||
| m_queue.push_back(item); | ||
| } | ||
| count++; | ||
| m_event.post(); | ||
| } | ||
|
|
||
|
|
@@ -261,4 +295,3 @@ namespace PAL_NS_BEGIN { | |
| } PAL_NS_END | ||
|
|
||
| #endif | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.