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