Nanotrace: Refactore event queue - replace std::mutex with a spinlock

The event queue was previously stored in thread-local storage, which led
to complications when the associated thread became invalid or was no
longer active. In such cases, attempts to acquire a std::mutex lock
failed silently, likely due to the mutex being tied to a thread context
that no longer existed or was in an undefined state.

To address this, we replaced the std::mutex with a spinlock
(std::atomic_flag-based). Spinlocks are not dependent on thread
ownership semantics and provide a lightweight alternative for short
critical sections, especially in scenarios where thread-local state may
be unreliable or transient.

This change ensures more robust and predictable locking behavior in
multi-threaded environments where thread-local resources may be
deallocated or invalidated unexpectedly.

Change-Id: Ife360c09a803c77dfd39b3f49ba89c57ad5bb856
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2025-06-19 16:18:40 +02:00
parent 83a54916e9
commit b63b411f26

View File

@@ -396,9 +396,24 @@ inline bool operator&(IsFlow first, IsFlow second)
struct TraceEventWithoutArguments; struct TraceEventWithoutArguments;
struct TraceEventWithArguments; struct TraceEventWithArguments;
class SpinLock
{
public:
void lock()
{
while (flag.test_and_set(std::memory_order_acquire)) {
}
}
void unlock() { flag.clear(std::memory_order_release); }
private:
std::atomic_flag flag;
};
struct TaskWithArguments struct TaskWithArguments
{ {
TaskWithArguments(std::unique_lock<std::mutex> lock, TaskWithArguments(std::unique_lock<SpinLock> lock,
Utils::span<TraceEventWithArguments> data, Utils::span<TraceEventWithArguments> data,
std::thread::id threadId) std::thread::id threadId)
: lock{std::move(lock)} : lock{std::move(lock)}
@@ -406,14 +421,14 @@ struct TaskWithArguments
, threadId{threadId} , threadId{threadId}
{} {}
std::unique_lock<std::mutex> lock; std::unique_lock<SpinLock> lock;
Utils::span<TraceEventWithArguments> data; Utils::span<TraceEventWithArguments> data;
std::thread::id threadId; std::thread::id threadId;
}; };
struct TaskWithoutArguments struct TaskWithoutArguments
{ {
TaskWithoutArguments(std::unique_lock<std::mutex> lock, TaskWithoutArguments(std::unique_lock<SpinLock> lock,
Utils::span<TraceEventWithoutArguments> data, Utils::span<TraceEventWithoutArguments> data,
std::thread::id threadId) std::thread::id threadId)
: lock{std::move(lock)} : lock{std::move(lock)}
@@ -421,20 +436,20 @@ struct TaskWithoutArguments
, threadId{threadId} , threadId{threadId}
{} {}
std::unique_lock<std::mutex> lock; std::unique_lock<SpinLock> lock;
Utils::span<TraceEventWithoutArguments> data; Utils::span<TraceEventWithoutArguments> data;
std::thread::id threadId; std::thread::id threadId;
}; };
struct MetaData struct MetaData
{ {
MetaData(std::unique_lock<std::mutex> lock, std::string key, std::string value) MetaData(std::unique_lock<SpinLock> lock, std::string key, std::string value)
: lock{std::move(lock)} : lock{std::move(lock)}
, key{std::move(key)} , key{std::move(key)}
, value{std::move(value)} , value{std::move(value)}
{} {}
std::unique_lock<std::mutex> lock; std::unique_lock<SpinLock> lock;
std::string key; std::string key;
std::string value; std::string value;
}; };
@@ -646,7 +661,7 @@ public:
TraceEventsSpan currentEvents; TraceEventsSpan currentEvents;
std::size_t eventsIndex = 0; std::size_t eventsIndex = 0;
IsEnabled isEnabled = IsEnabled::Yes; IsEnabled isEnabled = IsEnabled::Yes;
std::mutex mutex; SpinLock mutex;
std::thread::id threadId; std::thread::id threadId;
}; };