Skip to content

Commit b7cd606

Browse files
LibCore: Protect ThreadData with a mutex in EventLoopImplementationUnix
`register_notifier()` and `unregister_notifier()` could be called from different threads modifying the same `ThreadData`.
1 parent bf0884c commit b7cd606

File tree

1 file changed

+11
-2
lines changed

1 file changed

+11
-2
lines changed

Libraries/LibCore/EventLoopImplementationUnix.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ struct ThreadData {
240240

241241
static ThreadData* for_thread(pthread_t thread_id)
242242
{
243-
Threading::RWLockLocker<Threading::LockMode::Read> locker(s_thread_data_lock);
243+
// NOTE: s_thread_data_lock is supposed to be held by the caller.
244244
return s_thread_data.get(thread_id).value_or(nullptr);
245245
}
246246

@@ -267,6 +267,8 @@ struct ThreadData {
267267
s_thread_data.remove(s_thread_id);
268268
}
269269

270+
Threading::Mutex mutex;
271+
270272
// Each thread has its own timers, notifiers and a wake pipe.
271273
TimeoutSet timeouts;
272274

@@ -328,6 +330,7 @@ void EventLoopImplementationUnix::wake()
328330
void EventLoopManagerUnix::wait_for_events(EventLoopImplementation::PumpMode mode)
329331
{
330332
auto& thread_data = ThreadData::the();
333+
Threading::MutexLocker locker(thread_data.mutex);
331334

332335
retry:
333336
bool has_pending_events = ThreadEventQueue::current().has_pending_events();
@@ -612,6 +615,7 @@ intptr_t EventLoopManagerUnix::register_timer(EventReceiver& object, int millise
612615
{
613616
VERIFY(milliseconds >= 0);
614617
auto& thread_data = ThreadData::the();
618+
Threading::MutexLocker locker(thread_data.mutex);
615619
auto timer = new EventLoopTimer;
616620
timer->owner_thread = s_thread_id;
617621
timer->owner = object;
@@ -625,9 +629,11 @@ intptr_t EventLoopManagerUnix::register_timer(EventReceiver& object, int millise
625629
void EventLoopManagerUnix::unregister_timer(intptr_t timer_id)
626630
{
627631
auto* timer = bit_cast<EventLoopTimer*>(timer_id);
628-
auto thread_data_ptr = ThreadData::for_thread(timer->owner_thread);
632+
Threading::RWLockLocker<Threading::LockMode::Read> locker(s_thread_data_lock);
633+
auto* thread_data_ptr = ThreadData::for_thread(timer->owner_thread);
629634
if (!thread_data_ptr)
630635
return;
636+
Threading::MutexLocker thread_data_content_locker(thread_data_ptr->mutex);
631637
auto& thread_data = *thread_data_ptr;
632638
auto expected = false;
633639
if (timer->is_being_deleted.compare_exchange_strong(expected, true, AK::MemoryOrder::memory_order_acq_rel)) {
@@ -640,6 +646,7 @@ void EventLoopManagerUnix::unregister_timer(intptr_t timer_id)
640646
void EventLoopManagerUnix::register_notifier(Notifier& notifier)
641647
{
642648
auto& thread_data = ThreadData::the();
649+
Threading::MutexLocker locker(thread_data.mutex);
643650

644651
thread_data.notifier_to_index.set(&notifier, thread_data.poll_fds.size());
645652
thread_data.notifiers.append(&notifier);
@@ -652,9 +659,11 @@ void EventLoopManagerUnix::register_notifier(Notifier& notifier)
652659

653660
void EventLoopManagerUnix::unregister_notifier(Notifier& notifier)
654661
{
662+
Threading::RWLockLocker<Threading::LockMode::Read> locker(s_thread_data_lock);
655663
auto* thread_data = ThreadData::for_thread(notifier.owner_thread());
656664
if (!thread_data)
657665
return;
666+
Threading::MutexLocker thread_data_content_locker(thread_data->mutex);
658667

659668
auto notifier_index = thread_data->notifier_to_index.take(&notifier).release_value();
660669

0 commit comments

Comments
 (0)