mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-23 21:32:39 +02:00
waitN: Fix index bug when there are handles before UEvents in the array
This commit is contained in:
parent
3c9a84fe68
commit
2e76b2b150
@ -35,8 +35,8 @@ typedef struct {
|
|||||||
UEvent* parent_event;
|
UEvent* parent_event;
|
||||||
UTimer* parent_timer;
|
UTimer* parent_timer;
|
||||||
};
|
};
|
||||||
size_t idx;
|
s32 idx;
|
||||||
size_t* idx_out;
|
s32* idx_out;
|
||||||
} WaiterNode;
|
} WaiterNode;
|
||||||
|
|
||||||
struct Waitable {
|
struct Waitable {
|
||||||
|
@ -36,10 +36,8 @@ void _ueventTryAutoClear(UEvent* e)
|
|||||||
mutexUnlock(&e->waitable.mutex);
|
mutexUnlock(&e->waitable.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _ueventAddListener(UEvent* e, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread)
|
bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread)
|
||||||
{
|
{
|
||||||
_waiterNodeCreate(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out);
|
|
||||||
|
|
||||||
mutexLock(&e->waitable.mutex);
|
mutexLock(&e->waitable.mutex);
|
||||||
|
|
||||||
bool signalled = e->signal;
|
bool signalled = e->signal;
|
||||||
@ -47,8 +45,10 @@ bool _ueventAddListener(UEvent* e, WaiterNode* w, size_t idx, size_t* idx_out, H
|
|||||||
if (signalled) {
|
if (signalled) {
|
||||||
if (e->auto_clear)
|
if (e->auto_clear)
|
||||||
e->signal = false;
|
e->signal = false;
|
||||||
} else
|
} else {
|
||||||
|
_waiterNodeCreate(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out);
|
||||||
_waiterNodeAddToWaitable(w, &e->waitable);
|
_waiterNodeAddToWaitable(w, &e->waitable);
|
||||||
|
}
|
||||||
|
|
||||||
mutexUnlock(&e->waitable.mutex);
|
mutexUnlock(&e->waitable.mutex);
|
||||||
return !signalled;
|
return !signalled;
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
#include "kernel/uevent.h"
|
#include "kernel/uevent.h"
|
||||||
|
|
||||||
void _ueventTryAutoClear(UEvent* e);
|
void _ueventTryAutoClear(UEvent* e);
|
||||||
bool _ueventAddListener(UEvent* e, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread);
|
bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread);
|
||||||
|
@ -75,7 +75,7 @@ u64 _utimerGetNextTick(UTimer* t)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _utimerAddListener(UTimer* t, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread)
|
void _utimerAddListener(UTimer* t, WaiterNode* w, s32 idx, s32* idx_out, Handle thread)
|
||||||
{
|
{
|
||||||
_waiterNodeCreate(w, WaiterNodeType_Timer, &t->waitable, thread, idx, idx_out);
|
_waiterNodeCreate(w, WaiterNodeType_Timer, &t->waitable, thread, idx, idx_out);
|
||||||
|
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
void _utimerRecalculate(UTimer* t, u64 old_tick);
|
void _utimerRecalculate(UTimer* t, u64 old_tick);
|
||||||
u64 _utimerGetNextTick(UTimer* t);
|
u64 _utimerGetNextTick(UTimer* t);
|
||||||
void _utimerAddListener(UTimer* t, WaiterNode* w, size_t idx, size_t* idx_out, Handle thread);
|
void _utimerAddListener(UTimer* t, WaiterNode* w, s32 idx, s32* idx_out, Handle thread);
|
||||||
|
@ -26,8 +26,8 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
|||||||
Handle handles[num_objects];
|
Handle handles[num_objects];
|
||||||
u64 cur_tick = armGetSystemTick();
|
u64 cur_tick = armGetSystemTick();
|
||||||
|
|
||||||
size_t triggered_idx = -1;
|
s32 triggered_idx = -1;
|
||||||
size_t num_waiters = 0;
|
u64 waiters_added = 0;
|
||||||
WaiterNode waiters[num_objects];
|
WaiterNode waiters[num_objects];
|
||||||
|
|
||||||
u64 end_tick = UINT64_MAX;
|
u64 end_tick = UINT64_MAX;
|
||||||
@ -67,16 +67,16 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
|||||||
// Always add a listener on the timer,
|
// Always add a listener on the timer,
|
||||||
// If the timer is started/stopped we want to detect that.
|
// If the timer is started/stopped we want to detect that.
|
||||||
_utimerAddListener(
|
_utimerAddListener(
|
||||||
obj->timer, &waiters[num_waiters], num_waiters, &triggered_idx,
|
obj->timer, &waiters[i], i, &triggered_idx,
|
||||||
own_thread_handle);
|
own_thread_handle);
|
||||||
|
|
||||||
num_waiters++;
|
waiters_added |= 1ULL << i;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WaiterType_UEvent:
|
case WaiterType_UEvent:
|
||||||
// Try to add a listener to the event, if it hasn't already signalled.
|
// Try to add a listener to the event, if it hasn't already signalled.
|
||||||
added = _ueventAddListener(
|
added = _ueventAddListener(
|
||||||
obj->event, &waiters[num_waiters], num_waiters, &triggered_idx,
|
obj->event, &waiters[i], i, &triggered_idx,
|
||||||
own_thread_handle);
|
own_thread_handle);
|
||||||
|
|
||||||
// If the event already happened, we're done.
|
// If the event already happened, we're done.
|
||||||
@ -87,7 +87,7 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the event hasn't signalled, we added a listener.
|
// If the event hasn't signalled, we added a listener.
|
||||||
num_waiters++;
|
waiters_added |= 1ULL << i;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WaiterType_Handle:
|
case WaiterType_Handle:
|
||||||
@ -138,8 +138,9 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
|||||||
|
|
||||||
clean_up:
|
clean_up:
|
||||||
// Remove listeners.
|
// Remove listeners.
|
||||||
for (i = 0; i < num_waiters; i ++)
|
for (i = 0; i < num_objects; i ++)
|
||||||
_waiterNodeFree(&waiters[i]);
|
if (waiters_added & (1ULL << i))
|
||||||
|
_waiterNodeFree(&waiters[i]);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
|
|||||||
|
|
||||||
// Try to swap -1 => idx on the waiter 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.
|
// If another waitable signals simultaneously only one will win the race and insert its own idx.
|
||||||
size_t minus_one = -1;
|
s32 minus_one = -1;
|
||||||
bool sent_idx = __atomic_compare_exchange_n(
|
bool sent_idx = __atomic_compare_exchange_n(
|
||||||
w->idx_out, &minus_one, w->idx, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
w->idx_out, &minus_one, w->idx, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
|
|||||||
|
|
||||||
static inline void _waiterNodeCreate(
|
static inline void _waiterNodeCreate(
|
||||||
WaiterNode* w, WaiterNodeType type, Waitable* parent, Handle thread,
|
WaiterNode* w, WaiterNodeType type, Waitable* parent, Handle thread,
|
||||||
size_t idx, size_t* idx_out)
|
s32 idx, s32* idx_out)
|
||||||
{
|
{
|
||||||
w->type = type;
|
w->type = type;
|
||||||
w->parent = parent;
|
w->parent = parent;
|
||||||
|
Loading…
Reference in New Issue
Block a user