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 510599acf3d856cb
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
     1.1 --- a/src/thread/pthread/SDL_syssem.c	Wed Jan 26 12:26:27 2011 -0800
     1.2 +++ b/src/thread/pthread/SDL_syssem.c	Thu Jan 27 00:33:26 2011 -0800
     1.3 @@ -97,6 +97,8 @@
     1.4  int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
     1.5  {
     1.6  	int retval;
     1.7 +	struct timeval now;
     1.8 +	struct timespec ts_timeout;
     1.9  
    1.10  	if ( ! sem ) {
    1.11  		SDL_SetError("Passed a NULL semaphore");
    1.12 @@ -111,16 +113,33 @@
    1.13  		return SDL_SemWait(sem);
    1.14  	}
    1.15  
    1.16 -	/* Ack!  We have to busy wait... */
    1.17 -	/* FIXME: Use sem_timedwait()? */
    1.18 -	timeout += SDL_GetTicks();
    1.19 -	do {
    1.20 -		retval = SDL_SemTryWait(sem);
    1.21 -		if ( retval == 0 ) {
    1.22 -			break;
    1.23 -		}
    1.24 -		SDL_Delay(1);
    1.25 -	} while ( SDL_GetTicks() < timeout );
    1.26 +	/* Setup the timeout. sem_timedwait doesn't wait for
    1.27 +	 * a lapse of time, but until we reach a certain time.
    1.28 +	 * This time is now plus the timeout.
    1.29 +	 */
    1.30 +	gettimeofday(&now, NULL);
    1.31 +
    1.32 +	/* Add our timeout to current time */
    1.33 +	now.tv_usec += (timeout % 1000) * 1000;
    1.34 +	now.tv_sec += timeout / 1000;
    1.35 +
    1.36 +	/* Wrap the second if needed */
    1.37 +	if ( now.tv_usec >= 1000000 ) {
    1.38 +		now.tv_usec -= 1000000;
    1.39 +		now.tv_sec ++;
    1.40 +	}
    1.41 +
    1.42 +	/* Convert to timespec */
    1.43 +	ts_timeout.tv_sec = now.tv_sec;
    1.44 +	ts_timeout.tv_nsec = now.tv_usec * 1000;
    1.45 +
    1.46 +	/* Wait. */
    1.47 +	do
    1.48 +		retval = sem_timedwait(&sem->sem, &ts_timeout);
    1.49 +	while (retval == -1 && errno == EINTR);
    1.50 +
    1.51 +	if (retval == -1)
    1.52 +		SDL_SetError(strerror(errno));
    1.53  
    1.54  	return retval;
    1.55  }
     2.1 --- a/test/testsem.c	Wed Jan 26 12:26:27 2011 -0800
     2.2 +++ b/test/testsem.c	Thu Jan 27 00:33:26 2011 -0800
     2.3 @@ -33,6 +33,28 @@
     2.4  	alive = 0;
     2.5  }
     2.6  
     2.7 +static void TestWaitTimeout(void)
     2.8 +{
     2.9 +	Uint32 start_ticks;
    2.10 +	Uint32 end_ticks;
    2.11 +	Uint32 duration;
    2.12 +
    2.13 +	sem = SDL_CreateSemaphore(0);
    2.14 +	printf("Waiting 2 seconds on semaphore\n");
    2.15 +
    2.16 +	start_ticks = SDL_GetTicks();
    2.17 +	SDL_SemWaitTimeout(sem, 2000);
    2.18 +	end_ticks = SDL_GetTicks();
    2.19 +
    2.20 +	duration = end_ticks - start_ticks;
    2.21 +	
    2.22 +	/* Accept a little offset in the effective wait */
    2.23 +	if (duration > 1900 && duration < 2050)
    2.24 +		printf("Wait done.\n");
    2.25 +	else
    2.26 +		fprintf(stderr, "Wait took %d milliseconds\n", duration);
    2.27 +}
    2.28 +
    2.29  int main(int argc, char **argv)
    2.30  {
    2.31  	SDL_Thread *threads[NUM_THREADS];
    2.32 @@ -73,6 +95,9 @@
    2.33  	printf("Finished waiting for threads\n");
    2.34  
    2.35  	SDL_DestroySemaphore(sem);
    2.36 +
    2.37 +	TestWaitTimeout();
    2.38 +
    2.39  	SDL_Quit();
    2.40  	return(0);
    2.41  }