[RFC,v1] libcamera: thread: Fix event dispatcher creation
diff mbox series

Message ID 20250128130308.509297-2-pobrn@protonmail.com
State New
Headers show
Series
  • [RFC,v1] libcamera: thread: Fix event dispatcher creation
Related show

Commit Message

Barnabás Pőcze Jan. 28, 2025, 1:03 p.m. UTC
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

Patch
diff mbox series

diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp
index de60567f6..93ec7b5a0 100644
--- a/src/libcamera/base/thread.cpp
+++ b/src/libcamera/base/thread.cpp
@@ -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;
 }

 /**