Colin Leroy 2011-01-26 04:24:20 PST
authorSam Lantinga <slouken@libsdl.org>
Thu, 27 Jan 2011 00:34:12 -0800
changeset 5106d547877e355e
parent 5104 5fe0330b0fd6
child 5107 30da7089dcb4
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	Thu Jan 27 00:19:46 2011 -0800
     1.2 +++ b/src/thread/pthread/SDL_syssem.c	Thu Jan 27 00:34:12 2011 -0800
     1.3 @@ -21,6 +21,7 @@
     1.4  */
     1.5  #include "SDL_config.h"
     1.6  
     1.7 +#include <errno.h>
     1.8  #include <pthread.h>
     1.9  #include <semaphore.h>
    1.10  
    1.11 @@ -102,6 +103,8 @@
    1.12  SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
    1.13  {
    1.14      int retval;
    1.15 +    struct timeval now;
    1.16 +    struct timespec ts_timeout;
    1.17  
    1.18      if (!sem) {
    1.19          SDL_SetError("Passed a NULL semaphore");
    1.20 @@ -116,16 +119,34 @@
    1.21          return SDL_SemWait(sem);
    1.22      }
    1.23  
    1.24 -    /* Ack!  We have to busy wait... */
    1.25 -    /* FIXME: Use sem_timedwait()? */
    1.26 -    timeout += SDL_GetTicks();
    1.27 +    /* Setup the timeout. sem_timedwait doesn't wait for
    1.28 +    * a lapse of time, but until we reach a certain time.
    1.29 +    * This time is now plus the timeout.
    1.30 +    */
    1.31 +    gettimeofday(&now, NULL);
    1.32 +
    1.33 +    /* Add our timeout to current time */
    1.34 +    now.tv_usec += (timeout % 1000) * 1000;
    1.35 +    now.tv_sec += timeout / 1000;
    1.36 +
    1.37 +    /* Wrap the second if needed */
    1.38 +    if ( now.tv_usec >= 1000000 ) {
    1.39 +        now.tv_usec -= 1000000;
    1.40 +        now.tv_sec ++;
    1.41 +    }
    1.42 +
    1.43 +    /* Convert to timespec */
    1.44 +    ts_timeout.tv_sec = now.tv_sec;
    1.45 +    ts_timeout.tv_nsec = now.tv_usec * 1000;
    1.46 +
    1.47 +    /* Wait. */
    1.48      do {
    1.49 -        retval = SDL_SemTryWait(sem);
    1.50 -        if (retval == 0) {
    1.51 -            break;
    1.52 -        }
    1.53 -        SDL_Delay(1);
    1.54 -    } while (SDL_GetTicks() < timeout);
    1.55 +        retval = sem_timedwait(&sem->sem, &ts_timeout);
    1.56 +    } while (retval < 0 && errno == EINTR);
    1.57 +
    1.58 +    if (retval < 0) {
    1.59 +        SDL_SetError("sem_timedwait() failed");
    1.60 +    }
    1.61  
    1.62      return retval;
    1.63  }
     2.1 --- a/test/testsem.c	Thu Jan 27 00:19:46 2011 -0800
     2.2 +++ b/test/testsem.c	Thu Jan 27 00:34:12 2011 -0800
     2.3 @@ -39,6 +39,29 @@
     2.4      alive = 0;
     2.5  }
     2.6  
     2.7 +static void
     2.8 +TestWaitTimeout(void)
     2.9 +{
    2.10 +    Uint32 start_ticks;
    2.11 +    Uint32 end_ticks;
    2.12 +    Uint32 duration;
    2.13 +
    2.14 +    sem = SDL_CreateSemaphore(0);
    2.15 +    printf("Waiting 2 seconds on semaphore\n");
    2.16 +
    2.17 +    start_ticks = SDL_GetTicks();
    2.18 +    SDL_SemWaitTimeout(sem, 2000);
    2.19 +    end_ticks = SDL_GetTicks();
    2.20 +
    2.21 +    duration = end_ticks - start_ticks;
    2.22 +
    2.23 +    /* Accept a little offset in the effective wait */
    2.24 +    if (duration > 1900 && duration < 2050)
    2.25 +        printf("Wait done.\n");
    2.26 +    else
    2.27 +        fprintf(stderr, "Wait took %d milliseconds\n", duration);
    2.28 +}
    2.29 +
    2.30  int
    2.31  main(int argc, char **argv)
    2.32  {
    2.33 @@ -81,6 +104,9 @@
    2.34      printf("Finished waiting for threads\n");
    2.35  
    2.36      SDL_DestroySemaphore(sem);
    2.37 +
    2.38 +    TestWaitTimeout();
    2.39 +
    2.40      SDL_Quit();
    2.41      return (0);
    2.42  }