mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-24 22:02:39 +02:00
wait: Fix a race
This commit is contained in:
parent
eb01ccd097
commit
b38983c1b7
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user