test/testatomic.c
changeset 5099 1b3678ac9804
parent 5098 470ede30189c
child 5102 42a7591530d5
     1.1 --- a/test/testatomic.c	Tue Jan 25 23:23:52 2011 -0800
     1.2 +++ b/test/testatomic.c	Wed Jan 26 00:03:34 2011 -0800
     1.3 @@ -234,6 +234,11 @@
     1.4  /**************************************************************************/
     1.5  /* Lock-free FIFO test */
     1.6  
     1.7 +/* This is useful to test the impact of another thread locking the queue
     1.8 +   entirely for heavy-weight manipulation.
     1.9 + */
    1.10 +#define TEST_SPINLOCK_FIFO
    1.11 +
    1.12  #define NUM_READERS 4
    1.13  #define NUM_WRITERS 4
    1.14  #define EVENTS_PER_WRITER   1000000
    1.15 @@ -265,6 +270,14 @@
    1.16  
    1.17      char cache_pad3[CACHELINE-sizeof(SDL_atomic_t)];
    1.18  
    1.19 +#ifdef TEST_SPINLOCK_FIFO
    1.20 +    SDL_SpinLock lock;
    1.21 +    SDL_atomic_t rwcount;
    1.22 +    SDL_atomic_t watcher;
    1.23 +
    1.24 +    char cache_pad4[CACHELINE-sizeof(SDL_SpinLock)-2*sizeof(SDL_atomic_t)];
    1.25 +#endif
    1.26 +
    1.27      SDL_bool active;
    1.28  
    1.29      /* Only needed for the mutex test */
    1.30 @@ -281,6 +294,10 @@
    1.31      }
    1.32      SDL_AtomicSet(&queue->enqueue_pos, 0);
    1.33      SDL_AtomicSet(&queue->dequeue_pos, 0);
    1.34 +#ifdef TEST_SPINLOCK_FIFO
    1.35 +    queue->lock = 0;
    1.36 +    SDL_AtomicSet(&queue->rwcount, 0);
    1.37 +#endif
    1.38      queue->active = SDL_TRUE;
    1.39  }
    1.40  
    1.41 @@ -290,6 +307,15 @@
    1.42      unsigned queue_pos;
    1.43      unsigned entry_seq;
    1.44      int delta;
    1.45 +    SDL_bool status;
    1.46 +
    1.47 +#ifdef TEST_SPINLOCK_FIFO
    1.48 +    /* This is a gate so an external thread can lock the queue */
    1.49 +    SDL_AtomicLock(&queue->lock);
    1.50 +    SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
    1.51 +    SDL_AtomicIncRef(&queue->rwcount);
    1.52 +    SDL_AtomicUnlock(&queue->lock);
    1.53 +#endif
    1.54  
    1.55      queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
    1.56      for ( ; ; ) {
    1.57 @@ -300,22 +326,26 @@
    1.58          if (delta == 0) {
    1.59              /* The entry and the queue position match, try to increment the queue position */
    1.60              if (SDL_AtomicCAS(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos+1))) {
    1.61 +                /* We own the object, fill it! */
    1.62 +                entry->event = *event;
    1.63 +                SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1));
    1.64 +                status = SDL_TRUE;
    1.65                  break;
    1.66              }
    1.67          } else if (delta < 0) {
    1.68              /* We ran into an old queue entry, which means it still needs to be dequeued */
    1.69 -            return SDL_FALSE;
    1.70 +            status = SDL_FALSE;
    1.71 +            break;
    1.72          } else {
    1.73              /* We ran into a new queue entry, get the new queue position */
    1.74              queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
    1.75          }
    1.76      }
    1.77  
    1.78 -    /* We own the object, fill it! */
    1.79 -    entry->event = *event;
    1.80 -    SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1));
    1.81 -
    1.82 -    return SDL_TRUE;
    1.83 +#ifdef TEST_SPINLOCK_FIFO
    1.84 +    SDL_AtomicDecRef(&queue->rwcount);
    1.85 +#endif
    1.86 +    return status;
    1.87  }
    1.88  
    1.89  static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
    1.90 @@ -324,6 +354,15 @@
    1.91      unsigned queue_pos;
    1.92      unsigned entry_seq;
    1.93      int delta;
    1.94 +    SDL_bool status;
    1.95 +
    1.96 +#ifdef TEST_SPINLOCK_FIFO
    1.97 +    /* This is a gate so an external thread can lock the queue */
    1.98 +    SDL_AtomicLock(&queue->lock);
    1.99 +    SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
   1.100 +    SDL_AtomicIncRef(&queue->rwcount);
   1.101 +    SDL_AtomicUnlock(&queue->lock);
   1.102 +#endif
   1.103  
   1.104      queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
   1.105      for ( ; ; ) {
   1.106 @@ -334,22 +373,26 @@
   1.107          if (delta == 0) {
   1.108              /* The entry and the queue position match, try to increment the queue position */
   1.109              if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) {
   1.110 +                /* We own the object, fill it! */
   1.111 +                *event = entry->event;
   1.112 +                SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES));
   1.113 +                status = SDL_TRUE;
   1.114                  break;
   1.115              }
   1.116          } else if (delta < 0) {
   1.117              /* We ran into an old queue entry, which means we've hit empty */
   1.118 -            return SDL_FALSE;
   1.119 +            status = SDL_FALSE;
   1.120 +            break;
   1.121          } else {
   1.122              /* We ran into a new queue entry, get the new queue position */
   1.123              queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
   1.124          }
   1.125      }
   1.126  
   1.127 -    /* We own the object, fill it! */
   1.128 -    *event = entry->event;
   1.129 -    SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES));
   1.130 -
   1.131 -    return SDL_TRUE;
   1.132 +#ifdef TEST_SPINLOCK_FIFO
   1.133 +    SDL_AtomicDecRef(&queue->rwcount);
   1.134 +#endif
   1.135 +    return status;
   1.136  }
   1.137  
   1.138  static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
   1.139 @@ -358,6 +401,7 @@
   1.140      unsigned queue_pos;
   1.141      unsigned entry_seq;
   1.142      int delta;
   1.143 +    SDL_bool status = SDL_FALSE;
   1.144  
   1.145      SDL_mutexP(queue->mutex);
   1.146  
   1.147 @@ -368,21 +412,20 @@
   1.148      delta = (int)(entry_seq - queue_pos);
   1.149      if (delta == 0) {
   1.150          ++queue->enqueue_pos.value;
   1.151 +
   1.152 +        /* We own the object, fill it! */
   1.153 +        entry->event = *event;
   1.154 +        entry->sequence.value = (int)(queue_pos + 1);
   1.155 +        status = SDL_TRUE;
   1.156      } else if (delta < 0) {
   1.157          /* We ran into an old queue entry, which means it still needs to be dequeued */
   1.158 -        SDL_mutexV(queue->mutex);
   1.159 -        return SDL_FALSE;
   1.160      } else {
   1.161          printf("ERROR: mutex failed!\n");
   1.162      }
   1.163  
   1.164 -    /* We own the object, fill it! */
   1.165 -    entry->event = *event;
   1.166 -    entry->sequence.value = (int)(queue_pos + 1);
   1.167 -
   1.168      SDL_mutexV(queue->mutex);
   1.169  
   1.170 -    return SDL_TRUE;
   1.171 +    return status;
   1.172  }
   1.173  
   1.174  static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
   1.175 @@ -391,6 +434,7 @@
   1.176      unsigned queue_pos;
   1.177      unsigned entry_seq;
   1.178      int delta;
   1.179 +    SDL_bool status = SDL_FALSE;
   1.180  
   1.181      SDL_mutexP(queue->mutex);
   1.182  
   1.183 @@ -401,21 +445,20 @@
   1.184      delta = (int)(entry_seq - (queue_pos + 1));
   1.185      if (delta == 0) {
   1.186          ++queue->dequeue_pos.value;
   1.187 +
   1.188 +        /* We own the object, fill it! */
   1.189 +        *event = entry->event;
   1.190 +        entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
   1.191 +        status = SDL_TRUE;
   1.192      } else if (delta < 0) {
   1.193          /* We ran into an old queue entry, which means we've hit empty */
   1.194 -        SDL_mutexV(queue->mutex);
   1.195 -        return SDL_FALSE;
   1.196      } else {
   1.197          printf("ERROR: mutex failed!\n");
   1.198      }
   1.199  
   1.200 -    /* We own the object, fill it! */
   1.201 -    *event = entry->event;
   1.202 -    entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
   1.203 -
   1.204      SDL_mutexV(queue->mutex);
   1.205  
   1.206 -    return SDL_TRUE;
   1.207 +    return status;
   1.208  }
   1.209  
   1.210  static SDL_sem *writersDone;
   1.211 @@ -517,6 +560,29 @@
   1.212      return 0;
   1.213  }
   1.214  
   1.215 +#ifdef TEST_SPINLOCK_FIFO
   1.216 +/* This thread periodically locks the queue for no particular reason */
   1.217 +static int FIFO_Watcher(void* _data)
   1.218 +{
   1.219 +    SDL_EventQueue *queue = (SDL_EventQueue *)_data;
   1.220 +
   1.221 +    while (queue->active) {
   1.222 +        SDL_AtomicLock(&queue->lock);
   1.223 +        SDL_AtomicIncRef(&queue->watcher);
   1.224 +        while (SDL_AtomicGet(&queue->rwcount) > 0) {
   1.225 +            SDL_Delay(0);
   1.226 +        }
   1.227 +        /* Do queue manipulation here... */
   1.228 +        SDL_AtomicDecRef(&queue->watcher);
   1.229 +        SDL_AtomicUnlock(&queue->lock);
   1.230 +
   1.231 +        /* Wait a bit... */
   1.232 +        SDL_Delay(1);
   1.233 +    }
   1.234 +    return 0;
   1.235 +}
   1.236 +#endif /* TEST_SPINLOCK_FIFO */
   1.237 +
   1.238  static void RunFIFOTest(SDL_bool lock_free)
   1.239  {
   1.240      SDL_EventQueue queue;
   1.241 @@ -541,6 +607,13 @@
   1.242  
   1.243      start = SDL_GetTicks();
   1.244   
   1.245 +#ifdef TEST_SPINLOCK_FIFO
   1.246 +    /* Start a monitoring thread */
   1.247 +    if (lock_free) {
   1.248 +        SDL_CreateThread(FIFO_Watcher, &queue);
   1.249 +    }
   1.250 +#endif
   1.251 +
   1.252      /* Start the readers first */
   1.253      printf("Starting %d readers\n", NUM_READERS);
   1.254      SDL_zero(readerData);