Convert ticks to 64-bit, added nanosecond precision to the API

Fixes https://github.com/libsdl-org/SDL/issues/5512
Fixes https://github.com/libsdl-org/SDL/issues/6731
This commit is contained in:
Sam Lantinga
2022-12-02 01:17:17 -08:00
parent 764b899a13
commit 8121bbd083
96 changed files with 938 additions and 1243 deletions

View File

@@ -481,4 +481,43 @@ void SDL_DetachThread(SDL_Thread *thread)
}
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeoutNS(sem, SDL_MUTEX_MAXWAIT);
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeoutNS(sem, 0);
}
int SDL_SemWaitTimeout(SDL_sem *sem, Sint32 timeoutMS)
{
Sint64 timeoutNS;
if (timeoutMS >= 0) {
timeoutNS = SDL_MS_TO_NS(timeoutMS);
} else {
timeoutNS = -1;
}
return SDL_SemWaitTimeoutNS(sem, timeoutNS);
}
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeoutNS(cond, mutex, SDL_MUTEX_MAXWAIT);
}
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Sint32 timeoutMS)
{
Sint64 timeoutNS;
if (timeoutMS >= 0) {
timeoutNS = SDL_MS_TO_NS(timeoutMS);
} else {
timeoutNS = -1;
}
return SDL_CondWaitTimeoutNS(cond, mutex, timeoutNS);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -37,8 +37,7 @@
#define SDL_DestroyCond_generic SDL_DestroyCond
#define SDL_CondSignal_generic SDL_CondSignal
#define SDL_CondBroadcast_generic SDL_CondBroadcast
#define SDL_CondWait_generic SDL_CondWait
#define SDL_CondWaitTimeout_generic SDL_CondWaitTimeout
#define SDL_CondWaitTimeoutNS_generic SDL_CondWaitTimeoutNS
#endif
typedef struct SDL_cond_generic
@@ -148,7 +147,7 @@ int SDL_CondBroadcast_generic(SDL_cond *_cond)
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
/* Wait on the condition variable for at most 'timeoutNS' nanoseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
@@ -169,7 +168,7 @@ Thread B:
SDL_CondSignal(cond);
SDL_UnlockMutex(lock);
*/
int SDL_CondWaitTimeout_generic(SDL_cond *_cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS_generic(SDL_cond *_cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
int retval;
@@ -190,11 +189,7 @@ int SDL_CondWaitTimeout_generic(SDL_cond *_cond, SDL_mutex *mutex, Uint32 ms)
SDL_UnlockMutex(mutex);
/* Wait for a signal */
if (ms == SDL_MUTEX_MAXWAIT) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
retval = SDL_SemWaitTimeoutNS(cond->wait_sem, timeoutNS);
/* Let the signaler know we have completed the wait, otherwise
the signaler can race ahead and get the condition semaphore
@@ -223,10 +218,4 @@ int SDL_CondWaitTimeout_generic(SDL_cond *_cond, SDL_mutex *mutex, Uint32 ms)
return retval;
}
/* Wait on the condition variable forever */
int SDL_CondWait_generic(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout_generic(cond, mutex, SDL_MUTEX_MAXWAIT);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -29,9 +29,7 @@ SDL_cond *SDL_CreateCond_generic(void);
void SDL_DestroyCond_generic(SDL_cond *cond);
int SDL_CondSignal_generic(SDL_cond *cond);
int SDL_CondBroadcast_generic(SDL_cond *cond);
int SDL_CondWait_generic(SDL_cond *cond, SDL_mutex *mutex);
int SDL_CondWaitTimeout_generic(SDL_cond *cond,
SDL_mutex *mutex, Uint32 ms);
int SDL_CondWaitTimeoutNS_generic(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS);
#endif /* SDL_THREAD_GENERIC_COND_SUFFIX */

View File

@@ -37,17 +37,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
{
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SetError("SDL not built with thread support");
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
{
return SDL_SetError("SDL not built with thread support");
}
int SDL_SemWait(SDL_sem *sem)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
return SDL_SetError("SDL not built with thread support");
}
@@ -117,26 +107,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
int retval;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
retval = SDL_MUTEX_TIMEDOUT;
SDL_LockMutex(sem->count_lock);
if (sem->count > 0) {
--sem->count;
retval = 0;
}
SDL_UnlockMutex(sem->count_lock);
return retval;
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
int retval;
@@ -145,16 +116,24 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
}
/* A timeout of 0 is an easy case */
if (timeout == 0) {
return SDL_SemTryWait(sem);
if (timeoutNS == 0) {
retval = SDL_MUTEX_TIMEDOUT;
SDL_LockMutex(sem->count_lock);
if (sem->count > 0) {
--sem->count;
retval = 0;
}
SDL_UnlockMutex(sem->count_lock);
return retval;
}
SDL_LockMutex(sem->count_lock);
++sem->waiters_count;
retval = 0;
while ((sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT)) {
retval = SDL_CondWaitTimeout(sem->count_nonzero,
sem->count_lock, timeout);
retval = SDL_CondWaitTimeoutNS(sem->count_nonzero,
sem->count_lock, timeoutNS);
}
--sem->waiters_count;
if (retval == 0) {
@@ -165,11 +144,6 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return retval;
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
Uint32
SDL_SemValue(SDL_sem *sem)
{
@@ -201,4 +175,5 @@ int SDL_SemPost(SDL_sem *sem)
}
#endif /* SDL_THREADS_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -74,7 +74,7 @@ int SDL_CondBroadcast(SDL_cond *cond)
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
/* Wait on the condition variable for at most 'timeoutNS' nanoseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
@@ -95,7 +95,7 @@ Thread B:
SDL_CondSignal(cond);
SDL_UnlockMutex(lock);
*/
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
Result res;
@@ -107,22 +107,15 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
}
res = 0;
if (ms == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
CondVar_Wait(&cond->cond_variable, &mutex->lock.lock);
} else {
res = CondVar_WaitTimeout(&cond->cond_variable, &mutex->lock.lock,
(s64)ms * 1000000LL);
res = CondVar_WaitTimeout(&cond->cond_variable, &mutex->lock.lock, timeoutNS);
}
return R_SUCCEEDED(res) ? 0 : SDL_MUTEX_TIMEDOUT;
}
/* Wait on the condition variable forever */
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
#endif /* SDL_THREAD_N3DS */
/* vi: set sts=4 ts=4 sw=4 expandtab: */

View File

@@ -62,16 +62,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
return SDL_SemWaitTimeout(sem, 0);
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
int retval;
@@ -79,12 +70,15 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return SDL_InvalidParamError("sem");
}
if (timeout == SDL_MUTEX_MAXWAIT) {
if (timeoutNS == SDL_MUTEX_MAXWAIT) {
LightSemaphore_Acquire(&sem->semaphore, 1);
retval = 0;
} else {
int return_code = LightSemaphore_TryAcquire(&sem->semaphore, 1);
if (return_code != 0) {
/* FIXME: Does this code guarantee a wall clock timeout here?
* Can we handle sub-millisecond delays? */
u32 timeout = (u32)SDL_NS_TO_MS(timeoutNS);
for (u32 i = 0; i < timeout; i++) {
svcSleepThread(1000000LL);
return_code = LightSemaphore_TryAcquire(&sem->semaphore, 1);
@@ -99,11 +93,6 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return retval;
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
Uint32
SDL_SemValue(SDL_sem *sem)
{

View File

@@ -100,19 +100,27 @@ void SDL_DestroySemaphore(SDL_sem *sem)
}
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
if (timeout == SDL_MUTEX_MAXWAIT) {
if (timeoutNS == 0) {
if (sem->count > 0) {
--sem->count;
return 0;
}
return SDL_MUTEX_TIMEOUT;
}
if (timeoutNS == SDL_MUTEX_MAXWAIT) {
WaitAll(sem);
return SDL_MUTEX_MAXWAIT;
return 0;
}
RThread thread;
TInfo *info = new (ELeave) TInfo(timeout, sem->handle);
TInfo *info = new (ELeave) TInfo((TInt)SDL_NS_TO_MS(timeoutNS), sem->handle);
TInt status = CreateUnique(NewThread, &thread, info);
if (status != KErrNone) {
@@ -130,23 +138,6 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return info->iVal;
}
int SDL_SemTryWait(SDL_sem *sem)
{
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
if (sem->count > 0) {
sem->count--;
}
return SDL_MUTEX_TIMEOUT;
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
Uint32
SDL_SemValue(SDL_sem *sem)
{

View File

@@ -79,7 +79,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
}
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
int ret;
struct timer_alarm_t alarm;
@@ -89,15 +89,15 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return SDL_InvalidParamError("sem");
}
if (timeout == 0) {
if (timeoutNS == 0) {
if (PollSema(sem->semid) < 0) {
return SDL_MUTEX_TIMEDOUT;
}
return 0;
}
if (timeout != SDL_MUTEX_MAXWAIT) {
SetTimerAlarm(&alarm, MSec2TimerBusClock(timeout), &usercb, (void *)GetThreadId());
if (timeoutNS != SDL_MUTEX_MAXWAIT) {
SetTimerAlarm(&alarm, MSec2TimerBusClock(SDL_NS_TO_MS(timeoutNS)), &usercb, (void *)GetThreadId());
}
ret = WaitSema(sem->semid);
@@ -109,16 +109,6 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return 0; // Wait condition satisfied.
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, 0);
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32 SDL_SemValue(SDL_sem *sem)
{

View File

@@ -132,7 +132,7 @@ int SDL_CondBroadcast(SDL_cond *cond)
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
/* Wait on the condition variable for at most 'timeoutNS' nanoseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
@@ -153,7 +153,7 @@ Thread B:
SDL_CondSignal(cond);
SDL_UnlockMutex(lock);
*/
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
int retval;
@@ -173,11 +173,7 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
SDL_UnlockMutex(mutex);
/* Wait for a signal */
if (ms == SDL_MUTEX_MAXWAIT) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
retval = SDL_SemWaitTimeout(cond->wait_sem, timeoutNS);
/* Let the signaler know we have completed the wait, otherwise
the signaler can race ahead and get the condition semaphore
@@ -206,12 +202,6 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
return retval;
}
/* Wait on the condition variable forever */
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
#endif /* SDL_THREAD_PSP */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -73,16 +73,17 @@ void SDL_DestroySemaphore(SDL_sem *sem)
* If the timeout is 0 then just poll the semaphore; if it's SDL_MUTEX_MAXWAIT, pass
* NULL to sceKernelWaitSema() so that it waits indefinitely; and if the timeout
* is specified, convert it to microseconds. */
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
Uint32 *pTimeout;
SceUInt timeoutUS;
SceUInt *pTimeout;
int res;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
if (timeout == 0) {
if (timeoutNS == 0) {
res = sceKernelPollSema(sem->semid, 1);
if (res < 0) {
return SDL_MUTEX_TIMEDOUT;
@@ -90,14 +91,14 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return 0;
}
if (timeout == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
pTimeout = NULL;
} else {
timeout *= 1000; /* Convert to microseconds. */
pTimeout = &timeout;
timeoutUS = (SceUInt)SDL_NS_TO_US(timeoutNS); /* Convert to microseconds. */
pTimeout = &timeoutUS;
}
res = sceKernelWaitSema(sem->semid, 1, (SceUInt *)pTimeout);
res = sceKernelWaitSema(sem->semid, 1, pTimeout);
switch (res) {
case SCE_KERNEL_ERROR_OK:
return 0;
@@ -108,16 +109,6 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, 0);
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32 SDL_SemValue(SDL_sem *sem)
{

View File

@@ -91,7 +91,7 @@ int SDL_CondBroadcast(SDL_cond *cond)
return retval;
}
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
int retval;
#ifndef HAVE_CLOCK_GETTIME
@@ -103,18 +103,25 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
return SDL_InvalidParamError("cond");
}
if (timeoutNS < 0) {
if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) {
return SDL_SetError("pthread_cond_wait() failed");
}
return 0;
}
#ifdef HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_nsec += (ms % 1000) * 1000000;
abstime.tv_sec += ms / 1000;
abstime.tv_sec += (timeoutNS / SDL_NS_PER_SECOND);
abstime.tv_nsec += (timeoutNS % SDL_NS_PER_SECOND);
#else
gettimeofday(&delta, NULL);
abstime.tv_sec = delta.tv_sec + (ms / 1000);
abstime.tv_nsec = (long)(delta.tv_usec + (ms % 1000) * 1000) * 1000;
abstime.tv_sec = delta.tv_sec + (timeoutNS / SDL_NS_PER_SECOND);
abstime.tv_nsec = SDL_US_TO_NS(delta.tv_usec) + (timeoutNS % SDL_NS_PER_SECOND);
#endif
if (abstime.tv_nsec > 1000000000) {
while (abstime.tv_nsec > 1000000000) {
abstime.tv_sec += 1;
abstime.tv_nsec -= 1000000000;
}
@@ -136,17 +143,4 @@ tryagain:
return retval;
}
/* Wait on the condition variable, unlocking the provided mutex.
The mutex must be locked before entering this function!
*/
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
if (cond == NULL) {
return SDL_InvalidParamError("cond");
} else if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) {
return SDL_SetError("pthread_cond_wait() failed");
}
return 0;
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -63,39 +63,7 @@ void SDL_DestroySemaphore(SDL_sem *sem)
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
int retval;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
retval = SDL_MUTEX_TIMEDOUT;
if (sem_trywait(&sem->sem) == 0) {
retval = 0;
}
return retval;
}
int SDL_SemWait(SDL_sem *sem)
{
int retval;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
do {
retval = sem_wait(&sem->sem);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
retval = SDL_SetError("sem_wait() failed");
}
return retval;
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
int retval;
#ifdef HAVE_SEM_TIMEDWAIT
@@ -104,7 +72,7 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
#endif
struct timespec ts_timeout;
#else
Uint32 end;
Uint64 end;
#endif
if (sem == NULL) {
@@ -112,11 +80,22 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
}
/* Try the easy cases first */
if (timeout == 0) {
return SDL_SemTryWait(sem);
if (timeoutNS == 0) {
retval = SDL_MUTEX_TIMEDOUT;
if (sem_trywait(&sem->sem) == 0) {
retval = 0;
}
return retval;
}
if (timeout == SDL_MUTEX_MAXWAIT) {
return SDL_SemWait(sem);
if (timeoutNS < 0) {
do {
retval = sem_wait(&sem->sem);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
retval = SDL_SetError("sem_wait() failed");
}
return retval;
}
#ifdef HAVE_SEM_TIMEDWAIT
@@ -128,18 +107,18 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
clock_gettime(CLOCK_REALTIME, &ts_timeout);
/* Add our timeout to current time */
ts_timeout.tv_nsec += (timeout % 1000) * 1000000;
ts_timeout.tv_sec += timeout / 1000;
ts_timeout.tv_sec += (timeoutNS / SDL_NS_PER_SECOND);
ts_timeout.tv_nsec += (timeoutNS % SDL_NS_PER_SECOND);
#else
gettimeofday(&now, NULL);
/* Add our timeout to current time */
ts_timeout.tv_sec = now.tv_sec + (timeout / 1000);
ts_timeout.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000;
ts_timeout.tv_sec = now.tv_sec + (timeoutNS / SDL_NS_PER_SECOND);
ts_timeout.tv_nsec = SDL_US_TO_NS(now.tv_usec) + (timeoutNS % SDL_NS_PER_SECOND);
#endif
/* Wrap the second if needed */
if (ts_timeout.tv_nsec > 1000000000) {
while (ts_timeout.tv_nsec > 1000000000) {
ts_timeout.tv_sec += 1;
ts_timeout.tv_nsec -= 1000000000;
}
@@ -157,12 +136,13 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
}
}
#else
end = SDL_GetTicks() + timeout;
while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) {
if (SDL_TICKS_PASSED(SDL_GetTicks(), end)) {
end = SDL_GetTicksNS() + timeoutNS;
while (sem_trywait(&sem->sem) != 0) {
if (SDL_GetTicksNS() >= end) {
retval = SDL_MUTEX_TIMEDOUT;
break;
}
SDL_Delay(1);
SDL_DelayNS(100);
}
#endif /* HAVE_SEM_TIMEDWAIT */

View File

@@ -85,7 +85,7 @@ SDL_CondBroadcast(SDL_cond *cond)
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
/* Wait on the condition variable for at most 'timeoutNS' nanoseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
@@ -107,7 +107,7 @@ Thread B:
SDL_UnlockMutex(lock);
*/
extern "C" int
SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
if (cond == NULL) {
return SDL_InvalidParamError("cond");
@@ -119,7 +119,7 @@ SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
try {
std::unique_lock<std::recursive_mutex> cpp_lock(mutex->cpp_mutex, std::adopt_lock_t());
if (ms == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
cond->cpp_cond.wait(
cpp_lock);
cpp_lock.release();
@@ -127,7 +127,7 @@ SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
} else {
auto wait_result = cond->cpp_cond.wait_for(
cpp_lock,
std::chrono::duration<Uint32, std::milli>(ms));
std::chrono::duration<Sint64, std::nano>(timeoutNS));
cpp_lock.release();
if (wait_result == std::cv_status::timeout) {
return SDL_MUTEX_TIMEDOUT;
@@ -136,15 +136,8 @@ SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
}
}
} catch (std::system_error &ex) {
return SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what());
return SDL_SetError("Unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what());
}
}
/* Wait on the condition variable forever */
extern "C" int
SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -132,7 +132,7 @@ int SDL_CondBroadcast(SDL_cond *cond)
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
/* Wait on the condition variable for at most 'timeoutNS' nanoseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
@@ -153,7 +153,7 @@ Thread B:
SDL_CondSignal(cond);
SDL_UnlockMutex(lock);
*/
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
int retval;
@@ -173,11 +173,7 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
SDL_UnlockMutex(mutex);
/* Wait for a signal */
if (ms == SDL_MUTEX_MAXWAIT) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
retval = SDL_SemWaitTimeoutNS(cond->wait_sem, timeoutNS);
/* Let the signaler know we have completed the wait, otherwise
the signaler can race ahead and get the condition semaphore
@@ -206,12 +202,6 @@ int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
return retval;
}
/* Wait on the condition variable forever */
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
#endif /* SDL_THREAD_VITA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -74,16 +74,17 @@ void SDL_DestroySemaphore(SDL_sem *sem)
* If the timeout is 0 then just poll the semaphore; if it's SDL_MUTEX_MAXWAIT, pass
* NULL to sceKernelWaitSema() so that it waits indefinitely; and if the timeout
* is specified, convert it to microseconds. */
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
Uint32 *pTimeout;
SceUInt timeoutUS;
SceUInt *pTimeout;
int res;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
if (timeout == 0) {
if (timeoutNS == 0) {
res = sceKernelPollSema(sem->semid, 1);
if (res < 0) {
return SDL_MUTEX_TIMEDOUT;
@@ -91,11 +92,11 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
return 0;
}
if (timeout == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
pTimeout = NULL;
} else {
timeout *= 1000; /* Convert to microseconds. */
pTimeout = &timeout;
timeoutUS = (SceUInt)SDL_NS_TO_US(timeoutNS); /* Convert to microseconds. */
pTimeout = &timeoutUS;
}
res = sceKernelWaitSema(sem->semid, 1, pTimeout);
@@ -105,20 +106,10 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
case SCE_KERNEL_ERROR_WAIT_TIMEOUT:
return SDL_MUTEX_TIMEDOUT;
default:
return SDL_SetError("WaitForSingleObject() failed");
return SDL_SetError("sceKernelWaitSema() failed");
}
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, 0);
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32 SDL_SemValue(SDL_sem *sem)
{

View File

@@ -27,8 +27,7 @@ typedef SDL_cond *(*pfnSDL_CreateCond)(void);
typedef void (*pfnSDL_DestroyCond)(SDL_cond *);
typedef int (*pfnSDL_CondSignal)(SDL_cond *);
typedef int (*pfnSDL_CondBroadcast)(SDL_cond *);
typedef int (*pfnSDL_CondWait)(SDL_cond *, SDL_mutex *);
typedef int (*pfnSDL_CondWaitTimeout)(SDL_cond *, SDL_mutex *, Uint32);
typedef int (*pfnSDL_CondWaitTimeoutNS)(SDL_cond *, SDL_mutex *, Sint64);
typedef struct SDL_cond_impl_t
{
@@ -36,8 +35,7 @@ typedef struct SDL_cond_impl_t
pfnSDL_DestroyCond Destroy;
pfnSDL_CondSignal Signal;
pfnSDL_CondBroadcast Broadcast;
pfnSDL_CondWait Wait;
pfnSDL_CondWaitTimeout WaitTimeout;
pfnSDL_CondWaitTimeoutNS WaitTimeoutNS;
} SDL_cond_impl_t;
/* Implementation will be chosen at runtime based on available Kernel features */
@@ -125,7 +123,7 @@ static int SDL_CondBroadcast_cv(SDL_cond *_cond)
return 0;
}
static int SDL_CondWaitTimeout_cv(SDL_cond *_cond, SDL_mutex *_mutex, Uint32 ms)
static int SDL_CondWaitTimeoutNS_cv(SDL_cond *_cond, SDL_mutex *_mutex, Sint64 timeoutNS)
{
SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
DWORD timeout;
@@ -138,10 +136,10 @@ static int SDL_CondWaitTimeout_cv(SDL_cond *_cond, SDL_mutex *_mutex, Uint32 ms)
return SDL_InvalidParamError("mutex");
}
if (ms == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
timeout = INFINITE;
} else {
timeout = (DWORD)ms;
timeout = (DWORD)SDL_NS_TO_MS(timeoutNS);
}
if (SDL_mutex_impl_active.Type == SDL_MUTEX_SRW) {
@@ -188,18 +186,12 @@ static int SDL_CondWaitTimeout_cv(SDL_cond *_cond, SDL_mutex *_mutex, Uint32 ms)
return ret;
}
static int SDL_CondWait_cv(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout_cv(cond, mutex, SDL_MUTEX_MAXWAIT);
}
static const SDL_cond_impl_t SDL_cond_impl_cv = {
&SDL_CreateCond_cv,
&SDL_DestroyCond_cv,
&SDL_CondSignal_cv,
&SDL_CondBroadcast_cv,
&SDL_CondWait_cv,
&SDL_CondWaitTimeout_cv,
&SDL_CondWaitTimeoutNS_cv,
};
/**
@@ -211,8 +203,7 @@ static const SDL_cond_impl_t SDL_cond_impl_generic = {
&SDL_DestroyCond_generic,
&SDL_CondSignal_generic,
&SDL_CondBroadcast_generic,
&SDL_CondWait_generic,
&SDL_CondWaitTimeout_generic,
&SDL_CondWaitTimeoutNS_generic,
};
SDL_cond *
@@ -272,14 +263,9 @@ int SDL_CondBroadcast(SDL_cond *cond)
return SDL_cond_impl_active.Broadcast(cond);
}
int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
int SDL_CondWaitTimeoutNS(SDL_cond *cond, SDL_mutex *mutex, Sint64 timeoutNS)
{
return SDL_cond_impl_active.WaitTimeout(cond, mutex, ms);
}
int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_cond_impl_active.Wait(cond, mutex);
return SDL_cond_impl_active.WaitTimeoutNS(cond, mutex, timeoutNS);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -37,9 +37,7 @@
typedef SDL_sem *(*pfnSDL_CreateSemaphore)(Uint32);
typedef void (*pfnSDL_DestroySemaphore)(SDL_sem *);
typedef int (*pfnSDL_SemWaitTimeout)(SDL_sem *, Uint32);
typedef int (*pfnSDL_SemTryWait)(SDL_sem *);
typedef int (*pfnSDL_SemWait)(SDL_sem *);
typedef int (*pfnSDL_SemWaitTimeoutNS)(SDL_sem *, Sint64);
typedef Uint32 (*pfnSDL_SemValue)(SDL_sem *);
typedef int (*pfnSDL_SemPost)(SDL_sem *);
@@ -47,9 +45,7 @@ typedef struct SDL_semaphore_impl_t
{
pfnSDL_CreateSemaphore Create;
pfnSDL_DestroySemaphore Destroy;
pfnSDL_SemWaitTimeout WaitTimeout;
pfnSDL_SemTryWait TryWait;
pfnSDL_SemWait Wait;
pfnSDL_SemWaitTimeoutNS WaitTimeoutNS;
pfnSDL_SemValue Value;
pfnSDL_SemPost Post;
} SDL_sem_impl_t;
@@ -108,81 +104,60 @@ static void SDL_DestroySemaphore_atom(SDL_sem *sem)
}
}
static int SDL_SemTryWait_atom(SDL_sem *_sem)
static int SDL_SemWaitTimeoutNS_atom(SDL_sem *_sem, Sint64 timeoutNS)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
Uint64 now;
Uint64 deadline;
DWORD timeout_eff;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
count = sem->count;
if (count == 0) {
return SDL_MUTEX_TIMEDOUT;
}
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
return SDL_MUTEX_TIMEDOUT;
}
static int SDL_SemWait_atom(SDL_sem *_sem)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
if (sem == NULL) {
return SDL_InvalidParamError("sem");
}
for (;;) {
if (timeoutNS == 0) {
count = sem->count;
while (count == 0) {
if (pWaitOnAddress(&sem->count, &count, sizeof(sem->count), INFINITE) == FALSE) {
return SDL_SetError("WaitOnAddress() failed");
}
count = sem->count;
if (count == 0) {
return SDL_MUTEX_TIMEDOUT;
}
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
return SDL_MUTEX_TIMEDOUT;
}
}
if (timeoutNS < 0) {
for (;;) {
count = sem->count;
while (count == 0) {
if (pWaitOnAddress(&sem->count, &count, sizeof(sem->count), INFINITE) == FALSE) {
return SDL_SetError("WaitOnAddress() failed");
}
count = sem->count;
}
static int SDL_SemWaitTimeout_atom(SDL_sem *_sem, Uint32 timeout)
{
SDL_sem_atom *sem = (SDL_sem_atom *)_sem;
LONG count;
Uint32 now;
Uint32 deadline;
DWORD timeout_eff;
if (timeout == SDL_MUTEX_MAXWAIT) {
return SDL_SemWait_atom(_sem);
}
if (sem == NULL) {
return SDL_InvalidParamError("sem");
if (InterlockedCompareExchange(&sem->count, count - 1, count) == count) {
return 0;
}
}
}
/**
* WaitOnAddress is subject to spurious and stolen wakeups so we
* need to recalculate the effective timeout before every wait
*/
now = SDL_GetTicks();
deadline = now + (DWORD)timeout;
now = SDL_GetTicksNS();
deadline = now + timeoutNS;
for (;;) {
count = sem->count;
/* If no semaphore is available we need to wait */
while (count == 0) {
now = SDL_GetTicks();
now = SDL_GetTicksNS();
if (deadline > now) {
timeout_eff = deadline - now;
timeout_eff = (DWORD)SDL_NS_TO_MS(deadline - now);
} else {
return SDL_MUTEX_TIMEDOUT;
}
@@ -232,9 +207,7 @@ static int SDL_SemPost_atom(SDL_sem *_sem)
static const SDL_sem_impl_t SDL_sem_impl_atom = {
&SDL_CreateSemaphore_atom,
&SDL_DestroySemaphore_atom,
&SDL_SemWaitTimeout_atom,
&SDL_SemTryWait_atom,
&SDL_SemWait_atom,
&SDL_SemWaitTimeoutNS_atom,
&SDL_SemValue_atom,
&SDL_SemPost_atom,
};
@@ -289,7 +262,7 @@ static void SDL_DestroySemaphore_kern(SDL_sem *_sem)
}
}
static int SDL_SemWaitTimeout_kern(SDL_sem *_sem, Uint32 timeout)
static int SDL_SemWaitTimeoutNS_kern(SDL_sem *_sem, Sint64 timeoutNS)
{
SDL_sem_kern *sem = (SDL_sem_kern *)_sem;
int retval;
@@ -299,10 +272,10 @@ static int SDL_SemWaitTimeout_kern(SDL_sem *_sem, Uint32 timeout)
return SDL_InvalidParamError("sem");
}
if (timeout == SDL_MUTEX_MAXWAIT) {
if (timeoutNS < 0) {
dwMilliseconds = INFINITE;
} else {
dwMilliseconds = (DWORD)timeout;
dwMilliseconds = (DWORD)SDL_NS_TO_MS(timeoutNS);
}
switch (WaitForSingleObjectEx(sem->id, dwMilliseconds, FALSE)) {
case WAIT_OBJECT_0:
@@ -319,16 +292,6 @@ static int SDL_SemWaitTimeout_kern(SDL_sem *_sem, Uint32 timeout)
return retval;
}
static int SDL_SemTryWait_kern(SDL_sem *sem)
{
return SDL_SemWaitTimeout_kern(sem, 0);
}
static int SDL_SemWait_kern(SDL_sem *sem)
{
return SDL_SemWaitTimeout_kern(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
static Uint32 SDL_SemValue_kern(SDL_sem *_sem)
{
@@ -362,9 +325,7 @@ static int SDL_SemPost_kern(SDL_sem *_sem)
static const SDL_sem_impl_t SDL_sem_impl_kern = {
&SDL_CreateSemaphore_kern,
&SDL_DestroySemaphore_kern,
&SDL_SemWaitTimeout_kern,
&SDL_SemTryWait_kern,
&SDL_SemWait_kern,
&SDL_SemWaitTimeoutNS_kern,
&SDL_SemValue_kern,
&SDL_SemPost_kern,
};
@@ -417,19 +378,9 @@ void SDL_DestroySemaphore(SDL_sem *sem)
SDL_sem_impl_active.Destroy(sem);
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
int SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS)
{
return SDL_sem_impl_active.WaitTimeout(sem, timeout);
}
int SDL_SemTryWait(SDL_sem *sem)
{
return SDL_sem_impl_active.TryWait(sem);
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_sem_impl_active.Wait(sem);
return SDL_sem_impl_active.WaitTimeoutNS(sem, timeoutNS);
}
Uint32