Introduce syncArbitrateAddress/WithTimeout (replaces __sync_get_arbiter)

This commit is contained in:
fincs 2020-06-12 20:40:47 +02:00
parent 528f8feb0b
commit 9c1c847388
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60
4 changed files with 49 additions and 29 deletions

View File

@ -915,16 +915,7 @@ Result svcCreateAddressArbiter(Handle *arbiter);
* @param addr A pointer to a s32 value.
* @param type Type of action to be performed by the arbiter
* @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison.
*
* This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr.
*
* @code
* s32 val=0;
* // Does *nothing* since val >= 0
* svcCreateAddressArbiter(arbiter,&val,ARBITRATION_WAIT_IF_LESS_THAN,0,0);
* // Thread will wait for a signal or wake up after 10000000 nanoseconds because val < 1.
* svcCreateAddressArbiter(arbiter,&val,ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,1,10000000ULL);
* @endcode
* @warning Please use \ref syncArbitrateAddress or \ref syncArbitrateAddressWithTimeout instead.
*/
Result svcArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds);

View File

@ -126,10 +126,36 @@ static inline bool __strexb(u8* addr, u8 val)
#define AtomicSwap(ptr, value) __atomic_exchange_n((u32*)(ptr), (value), __ATOMIC_SEQ_CST)
/**
* @brief Retrieves the synchronization subsystem's address arbiter handle.
* @return The synchronization subsystem's address arbiter handle.
* @brief Function used to implement user-mode synchronization primitives.
* @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads.
* @param type Type of action to be performed by the arbiter
* @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison.
*
* This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr.
*
* @code
* s32 val=0;
* // Does *nothing* since val >= 0
* syncArbitrateAddress(&val,ARBITRATION_WAIT_IF_LESS_THAN,0);
* @endcode
*/
Handle __sync_get_arbiter(void);
Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value);
/**
* @brief Function used to implement user-mode synchronization primitives (with timeout).
* @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads.
* @param type Type of action to be performed by the arbiter (must use \ref ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT or \ref ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN_TIMEOUT)
* @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison.
*
* This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr.
*
* @code
* s32 val=0;
* // Thread will wait for a signal or wake up after 10000000 nanoseconds because val < 1.
* syncArbitrateAddressWithTimeout(&val,ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,1,10000000LL);
* @endcode
*/
Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns);
/**
* @brief Initializes a light lock.

View File

@ -28,8 +28,6 @@ static vu8* gspEventData;
static void gspEventThreadMain(void *arg);
Handle __sync_get_arbiter(void);
Result gspInit(void)
{
Result res=0;
@ -103,7 +101,7 @@ GSPGPU_Event gspWaitForAnyEvent(void)
}
} while (__strex(&gspLastEvent, -1));
if (x < 0)
svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
syncArbitrateAddress(&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0);
} while (x < 0);
return (GSPGPU_Event)x;
}
@ -177,7 +175,7 @@ void gspEventThreadMain(void *arg)
do
__ldrex(&gspLastEvent);
while (__strex(&gspLastEvent, curEvt));
svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_SIGNAL, 1, 0);
syncArbitrateAddress(&gspLastEvent, ARBITRATION_SIGNAL, 1);
gspEventCounts[curEvt]++;
}
}

View File

@ -16,9 +16,14 @@ void __sync_fini(void)
svcCloseHandle(arbiter);
}
Handle __sync_get_arbiter(void)
Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
{
return arbiter;
return svcArbitrateAddress(arbiter, (u32)addr, type, value, 0);
}
Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
{
return svcArbitrateAddress(arbiter, (u32)addr, type, value, timeout_ns);
}
void LightLock_Init(LightLock* lock)
@ -51,7 +56,7 @@ void LightLock_Lock(LightLock* lock)
while (bAlreadyLocked)
{
// Wait for the lock holder thread to wake us up
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
syncArbitrateAddress(lock, ARBITRATION_WAIT_IF_LESS_THAN, 0);
// Try to lock again
do
@ -97,7 +102,7 @@ void LightLock_Unlock(LightLock* lock)
if (val > 1)
// Wake up exactly one thread
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0);
syncArbitrateAddress(lock, ARBITRATION_SIGNAL, 1);
}
void RecursiveLock_Init(RecursiveLock* lock)
@ -180,9 +185,9 @@ void LightEvent_Clear(LightEvent* event)
void LightEvent_Pulse(LightEvent* event)
{
if (event->state == -2)
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, -1);
else if (event->state == -1)
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1);
else
LightEvent_Clear(event);
}
@ -192,12 +197,12 @@ void LightEvent_Signal(LightEvent* event)
if (event->state == -1)
{
LightEvent_SetState(event, 0);
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0);
syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1);
} else if (event->state == -2)
{
LightLock_Lock(&event->lock);
LightEvent_SetState(event, 1);
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0);
syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, -1);
LightLock_Unlock(&event->lock);
}
}
@ -215,7 +220,7 @@ void LightEvent_Wait(LightEvent* event)
{
if (event->state == -2)
{
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
syncArbitrateAddress(&event->state, ARBITRATION_WAIT_IF_LESS_THAN, 0);
return;
}
if (event->state != -1)
@ -225,7 +230,7 @@ void LightEvent_Wait(LightEvent* event)
if (event->state == 0 && LightEvent_TryReset(event))
return;
}
svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
syncArbitrateAddress(&event->state, ARBITRATION_WAIT_IF_LESS_THAN, 0);
}
}
@ -254,7 +259,7 @@ void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count)
num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq);
while (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq + 1));
svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_WAIT_IF_LESS_THAN, count, 0);
syncArbitrateAddress(&semaphore->current_count, ARBITRATION_WAIT_IF_LESS_THAN, count);
do
num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq);
@ -275,5 +280,5 @@ void LightSemaphore_Release(LightSemaphore* semaphore, s32 count)
} while (__strex(&semaphore->current_count, new_count));
if(old_count <= 0 || semaphore->num_threads_acq > 0)
svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_SIGNAL, count, 0);
syncArbitrateAddress(&semaphore->current_count, ARBITRATION_SIGNAL, count);
}