# HG changeset patch # User Sam Lantinga # Date 1296117206 28800 # Node ID 99acf3d856cb89b2312b10cc9c1c305610e43362 # Parent 3500563bb2f8263c3a4d9360d513e1e624c5dde9 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 diff -r 3500563bb2f8 -r 99acf3d856cb src/thread/pthread/SDL_syssem.c --- a/src/thread/pthread/SDL_syssem.c Wed Jan 26 12:26:27 2011 -0800 +++ b/src/thread/pthread/SDL_syssem.c Thu Jan 27 00:33:26 2011 -0800 @@ -97,6 +97,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"); @@ -111,16 +113,33 @@ 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 -r 3500563bb2f8 -r 99acf3d856cb test/testsem.c --- a/test/testsem.c Wed Jan 26 12:26:27 2011 -0800 +++ b/test/testsem.c Thu Jan 27 00:33:26 2011 -0800 @@ -33,6 +33,28 @@ 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 @@ printf("Finished waiting for threads\n"); SDL_DestroySemaphore(sem); + + TestWaitTimeout(); + SDL_Quit(); return(0); }