From e861aaacd4cee82badc28e0664fe920907d99684 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 27 Jan 2011 00:34:12 -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 | 26 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/thread/pthread/SDL_syssem.c b/src/thread/pthread/SDL_syssem.c index 0e0feaf40..7328eafb8 100644 --- a/src/thread/pthread/SDL_syssem.c +++ b/src/thread/pthread/SDL_syssem.c @@ -21,6 +21,7 @@ */ #include "SDL_config.h" +#include #include #include @@ -102,6 +103,8 @@ 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"); @@ -116,16 +119,34 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) return SDL_SemWait(sem); } - /* Ack! We have to busy wait... */ - /* FIXME: Use sem_timedwait()? */ - timeout += SDL_GetTicks(); + /* 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 = SDL_SemTryWait(sem); - if (retval == 0) { - break; - } - SDL_Delay(1); - } while (SDL_GetTicks() < timeout); + retval = sem_timedwait(&sem->sem, &ts_timeout); + } while (retval < 0 && errno == EINTR); + + if (retval < 0) { + SDL_SetError("sem_timedwait() failed"); + } return retval; } diff --git a/test/testsem.c b/test/testsem.c index 6d9622867..c4787e9b8 100644 --- a/test/testsem.c +++ b/test/testsem.c @@ -39,6 +39,29 @@ 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) { @@ -81,6 +104,9 @@ main(int argc, char **argv) printf("Finished waiting for threads\n"); SDL_DestroySemaphore(sem); + + TestWaitTimeout(); + SDL_Quit(); return (0); }