@@ -518,11 +518,16 @@ pid_t Thread::currentId()
*/
EventDispatcher *Thread::eventDispatcher()
{
- if (!data_->dispatcher_.load(std::memory_order_relaxed))
- data_->dispatcher_.store(new EventDispatcherPoll(),
- std::memory_order_release);
+ if (EventDispatcher *dispatcher = data_->dispatcher_.load(std::memory_order_acquire))
+ return dispatcher;
- return data_->dispatcher_.load(std::memory_order_relaxed);
+ auto dispatcher = std::make_unique<EventDispatcherPoll>();
+ EventDispatcher *expected = nullptr;
+
+ if (data_->dispatcher_.compare_exchange_strong(expected, dispatcher.get(), std::memory_order_acq_rel))
+ return dispatcher.release();
+
+ return expected;
}
/**
Use an appropriate compare-and-exchange atomic instruction to set the event dispatcher pointer. This ensures that there is only ever a single event dispatcher associated with a given thread. Consider e.g. the following series of events: 1. thread 0 :: if (!data_->dispatcher_.load(std::memory_order_relaxed)) // reads nullptr and proceeds into the `if`'s block 2. thread 1 :: if (!data_->dispatcher_.load(std::memory_order_relaxed)) // reads nullptr and proceeds into the `if`'s block 3. thread 0 :: data_->dispatcher_.store(new EventDispatcherPoll(), std::memory_order_release); // creates dispatcher and sets pointer 4. thread 1 :: data_->dispatcher_.store(new EventDispatcherPoll(), std::memory_order_release); // creates dispatcher and sets pointer At the end, one of the event dispatchers is leaked, and furthermore the `eventDispatcher()` calls might return different values in the calling threads. Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com> --- src/libcamera/base/thread.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) -- 2.48.1