From f50fcadb50924c69ba571bea885a10f355cf4b87 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 27 Jan 2011 00:33:26 -0800 Subject: [PATCH] Colin Leroy 2011-01-26 04:24:20 PST the pthread implementation of SDL_SemWaitTimeout() uses busy waiting, while pthread's sem_timedwait() does work. Attached are patches that make use of it --- src/thread/pthread/SDL_syssem.c | 39 ++++++++++++++++++++++++--------- test/testsem.c | 25 +++++++++++++++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/thread/pthread/SDL_syssem.c b/src/thread/pthread/SDL_syssem.c index b5b99524f..b237ddf98 100644 --- a/src/thread/pthread/SDL_syssem.c +++ b/src/thread/pthread/SDL_syssem.c @@ -97,6 +97,8 @@ int SDL_SemWait(SDL_sem *sem) int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) { int retval; + struct timeval now; + struct timespec ts_timeout; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); @@ -111,16 +113,33 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) return SDL_SemWait(sem); } - /* Ack! We have to busy wait... */ - /* FIXME: Use sem_timedwait()? */ - timeout += SDL_GetTicks(); - do { - retval = SDL_SemTryWait(sem); - if ( retval == 0 ) { - break; - } - SDL_Delay(1); - } while ( SDL_GetTicks() < timeout ); + /* Setup the timeout. sem_timedwait doesn't wait for + * a lapse of time, but until we reach a certain time. + * This time is now plus the timeout. + */ + gettimeofday(&now, NULL); + + /* Add our timeout to current time */ + now.tv_usec += (timeout % 1000) * 1000; + now.tv_sec += timeout / 1000; + + /* Wrap the second if needed */ + if ( now.tv_usec >= 1000000 ) { + now.tv_usec -= 1000000; + now.tv_sec ++; + } + + /* Convert to timespec */ + ts_timeout.tv_sec = now.tv_sec; + ts_timeout.tv_nsec = now.tv_usec * 1000; + + /* Wait. */ + do + retval = sem_timedwait(&sem->sem, &ts_timeout); + while (retval == -1 && errno == EINTR); + + if (retval == -1) + SDL_SetError(strerror(errno)); return retval; } diff --git a/test/testsem.c b/test/testsem.c index 9c0940eb9..c906432b1 100644 --- a/test/testsem.c +++ b/test/testsem.c @@ -33,6 +33,28 @@ static void killed(int sig) alive = 0; } +static void TestWaitTimeout(void) +{ + Uint32 start_ticks; + Uint32 end_ticks; + Uint32 duration; + + sem = SDL_CreateSemaphore(0); + printf("Waiting 2 seconds on semaphore\n"); + + start_ticks = SDL_GetTicks(); + SDL_SemWaitTimeout(sem, 2000); + end_ticks = SDL_GetTicks(); + + duration = end_ticks - start_ticks; + + /* Accept a little offset in the effective wait */ + if (duration > 1900 && duration < 2050) + printf("Wait done.\n"); + else + fprintf(stderr, "Wait took %d milliseconds\n", duration); +} + int main(int argc, char **argv) { SDL_Thread *threads[NUM_THREADS]; @@ -73,6 +95,9 @@ int main(int argc, char **argv) printf("Finished waiting for threads\n"); SDL_DestroySemaphore(sem); + + TestWaitTimeout(); + SDL_Quit(); return(0); }