Skip to content
3 changes: 2 additions & 1 deletion lib/api/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ namespace MAT_NS_BEGIN

Logger::~Logger() noexcept
{
LOG_TRACE("%p: Destroyed", this);
// Intentionally empty — logging here triggers a static-destruction-order
// crash on iOS simulator (recursive_mutex used after teardown).
}

ISemanticContext* Logger::GetSemanticContext() const
Expand Down
9 changes: 8 additions & 1 deletion lib/http/HttpClientManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,15 @@ namespace MAT_NS_BEGIN {
void HttpClientManager::cancelAllRequests()
{
cancelAllRequestsAsync();
while (!m_httpCallbacks.empty())
while (true)
{
{
LOCKGUARD(m_httpCallbacksMtx);
if (m_httpCallbacks.empty())
break;
}
std::this_thread::yield();
}
Comment thread
bmehta001 marked this conversation as resolved.
}

// start async cancellation
Expand Down
24 changes: 6 additions & 18 deletions lib/http/HttpClient_Apple.mm
Original file line number Diff line number Diff line change
Expand Up @@ -132,23 +132,6 @@ void HandleResponse(NSData* data, NSURLResponse* response, NSError* error)
void Cancel()
{
[m_dataTask cancel];
[session getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks)
{
for (NSURLSessionTask* _task in dataTasks)
{
[_task cancel];
}

for (NSURLSessionTask* _task in downloadTasks)
{
[_task cancel];
}

for (NSURLSessionTask* _task in uploadTasks)
{
[_task cancel];
}
}];
}

private:
Expand Down Expand Up @@ -214,8 +197,13 @@ void Cancel()
for (const auto &id : ids)
CancelRequestAsync(id);

while (!m_requests.empty())
while (true)
{
{
std::lock_guard<std::mutex> lock(m_requestsMtx);
if (m_requests.empty())
break;
}
PAL::sleep(100);
std::this_thread::yield();
}
Expand Down
4 changes: 0 additions & 4 deletions lib/http/HttpResponseDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,11 @@ namespace MAT_NS_BEGIN {
break;

case HttpResult_Aborted:
ctx->httpResponse = nullptr;
outcome = Abort;
break;

case HttpResult_LocalFailure:
case HttpResult_NetworkFailure:
ctx->httpResponse = nullptr;
outcome = RetryNetwork;
break;
}
Expand Down Expand Up @@ -129,7 +127,6 @@ namespace MAT_NS_BEGIN {
evt.param1 = 0; // response.GetStatusCode();
DispatchEvent(evt);
}
ctx->httpResponse = nullptr;
// eventsRejected(ctx); // FIXME: [MG] - investigate why ctx gets corrupt after eventsRejected
requestAborted(ctx);
break;
Expand Down Expand Up @@ -253,4 +250,3 @@ namespace MAT_NS_BEGIN {
}

} MAT_NS_END

61 changes: 49 additions & 12 deletions lib/pal/WorkerThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -35,6 +37,7 @@ namespace PAL_NS_BEGIN {
std::list<MAT::Task*> m_timerQueue;
Event m_event;
MAT::Task* m_itemInProgress;
bool m_shuttingDown = false;
int count = 0;

public:
Expand All @@ -53,32 +56,66 @@ 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());
count++;
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; }
Comment thread
bmehta001 marked this conversation as resolved.
m_timerQueue.clear();
}
}

void Queue(MAT::Task* item) final
{
LOG_INFO("queue item=%p", &item);
LOCKGUARD(m_lock);
if (m_shuttingDown) {
LOG_WARN("Dropping queued task %p during shutdown", item);
delete item;
return;
Comment thread
bmehta001 marked this conversation as resolved.
}
if (item->Type == MAT::Task::TimedCall) {
auto it = m_timerQueue.begin();
while (it != m_timerQueue.end() && (*it)->TargetTime < item->TargetTime) {
Expand Down
Loading
Loading