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
--- 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;
}
--- 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);
}