Colin Leroy 2011-01-26 04:24:20 PST SDL-1.2
authorSam Lantinga <slouken@libsdl.org>
Thu, 27 Jan 2011 00:33:26 -0800
branchSDL-1.2
changeset 5105 99acf3d856cb
parent 5101 3500563bb2f8
child 5127 32f0f603a0c8
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
test/testsem.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;
 }
--- 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);
 }