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
sem_init(sem_t * p,unsigned value)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
sem_destroy(sem_t * p)33 static void sem_destroy(sem_t *p)
34 {
35 ANNOTATE_SEM_DESTROY_POST(p);
36 }
37
sem_wait(sem_t * p)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
sem_post(sem_t * p)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
thread_func(void * arg)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
main(int argc,const char * argv[])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