From b38983c1b7afe9f791dc67a33627069cce245e7e Mon Sep 17 00:00:00 2001 From: plutooo Date: Thu, 13 Dec 2018 01:01:42 +0100 Subject: [PATCH] wait: Fix a race --- nx/source/kernel/uevent.c | 2 +- nx/source/kernel/utimer.c | 2 +- nx/source/kernel/wait.h | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/nx/source/kernel/uevent.c b/nx/source/kernel/uevent.c index 8c96ae8c..9ac277ed 100644 --- a/nx/source/kernel/uevent.c +++ b/nx/source/kernel/uevent.c @@ -39,7 +39,7 @@ void _ueventTryAutoClear(UsermodeEvent* e) bool _ueventAddListener(UsermodeEvent* e, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread) { - _waiterNodeInitialize(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out); + _waiterNodeCreate(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out); mutexLock(&e->waitable.mutex); diff --git a/nx/source/kernel/utimer.c b/nx/source/kernel/utimer.c index 998ab506..eddacca5 100644 --- a/nx/source/kernel/utimer.c +++ b/nx/source/kernel/utimer.c @@ -73,7 +73,7 @@ u64 _utimerGetNextTick(UsermodeTimer* t) void _utimerAddListener(UsermodeTimer* t, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread) { - _waiterNodeInitialize(w, WaiterNodeType_Timer, &t->waitable, thread, idx, idx_out); + _waiterNodeCreate(w, WaiterNodeType_Timer, &t->waitable, thread, idx, idx_out); mutexLock(&t->waitable.mutex); _waiterNodeAddToWaitable(w, &t->waitable); diff --git a/nx/source/kernel/wait.h b/nx/source/kernel/wait.h index 4a000b3c..abe2734b 100644 --- a/nx/source/kernel/wait.h +++ b/nx/source/kernel/wait.h @@ -20,12 +20,19 @@ static inline void _waitableSignalAllListeners(Waitable* ww) node = node->next; WaiterNode* w = (WaiterNode*) node; - *w->idx_out = w->idx; - svcCancelSynchronization(w->thread); + // Try to swap -1 => idx on the waiter thread. + // If another waitable signals simultaneously only one will win the race and insert its own idx. + size_t minus_one = -1; + bool sent_idx = __atomic_compare_exchange_n( + w->idx_out, &minus_one, w->idx, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + + if (sent_idx) { + svcCancelSynchronization(w->thread); + } } } -static inline void _waiterNodeInitialize( +static inline void _waiterNodeCreate( WaiterNode* w, WaiterNodeType type, Waitable* parent, Handle thread, size_t idx, size_t* idx_out) {