waitN: Fix index bug when there are handles before UEvents in the array

This commit is contained in:
fincs 2018-12-14 17:44:35 +01:00 committed by fincs
parent 3c9a84fe68
commit 2e76b2b150
7 changed files with 20 additions and 19 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
} }

View File

@ -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;