Home | History | Annotate | Download | only in tests
      1 /**
      2  * @file  annotate_sem.c
      3  *
      4  * @brief Multithreaded test program that triggers various access patterns
      5  *        without triggering any race conditions using a binary semaphore
      6  *        implemented via busy-waiting. Annotations are used to tell DRD
      7  *        which higher-level semaphore operations are being performed.
      8  */
      9 
     10 #include <assert.h>
     11 #include <pthread.h>
     12 #include <stdio.h>
     13 #include "../../config.h"
     14 #include "../../drd/drd.h"
     15 
     16 #define THREADS 10
     17 #define ITERATIONS 1000
     18 
     19 typedef struct {
     20   volatile unsigned value;
     21 } sem_t;
     22 
     23 static sem_t s_sem;
     24 static unsigned int s_counter;
     25 
     26 static void sem_init(sem_t *p, unsigned value)
     27 {
     28   DRD_IGNORE_VAR(*p);
     29   p->value = value;
     30   ANNOTATE_SEM_INIT_PRE(p, value);
     31 }
     32 
     33 static void sem_destroy(sem_t *p)
     34 {
     35   ANNOTATE_SEM_DESTROY_POST(p);
     36 }
     37 
     38 static void sem_wait(sem_t *p)
     39 {
     40   unsigned old, new;
     41   struct timespec ts = { 0, 0 };
     42 
     43   ANNOTATE_SEM_WAIT_PRE(p);
     44   do {
     45     old = p->value;
     46     new = old - 1;
     47     nanosleep(&ts, NULL);
     48     ts.tv_nsec = 1;
     49   } while (!old || !__sync_bool_compare_and_swap(&p->value, old, new));
     50   ANNOTATE_SEM_WAIT_POST(p);
     51 }
     52 
     53 static void sem_post(sem_t *p)
     54 {
     55   ANNOTATE_SEM_POST_PRE(p);
     56   __sync_fetch_and_add(&p->value, 1);
     57 }
     58 
     59 static void *thread_func(void *arg)
     60 {
     61   unsigned int i;
     62   unsigned int sum = 0;
     63 
     64   for (i = 0; i < ITERATIONS; i++) {
     65     sem_wait(&s_sem);
     66     sum += s_counter;
     67     sem_post(&s_sem);
     68 
     69     sem_wait(&s_sem);
     70     s_counter++;
     71     sem_post(&s_sem);
     72   }
     73 
     74   return 0;
     75 }
     76 
     77 int main(int argc, const char *argv[])
     78 {
     79   pthread_t tid[THREADS];
     80   unsigned int i;
     81 
     82   sem_init(&s_sem, 1);
     83   for (i = 0; i < THREADS; i++)
     84     pthread_create(&tid[i], 0, thread_func, 0);
     85 
     86   for (i = 0; i < THREADS; i++)
     87     pthread_join(tid[i], 0);
     88 
     89   assert(s_counter == THREADS * ITERATIONS);
     90   assert(s_sem.value == 1);
     91   sem_destroy(&s_sem);
     92 
     93   fprintf(stderr, "Finished.\n");
     94 
     95   return 0;
     96 }
     97