/** * @file annotate_sem.c * * @brief Multithreaded test program that triggers various access patterns * without triggering any race conditions using a binary semaphore * implemented via busy-waiting. Annotations are used to tell DRD * which higher-level semaphore operations are being performed. */ #include #include #include #include "../../config.h" #include "../../drd/drd.h" #define THREADS 10 #define ITERATIONS 1000 typedef struct { volatile unsigned value; } sem_t; static sem_t s_sem; static unsigned int s_counter; static void sem_init(sem_t *p, unsigned value) { DRD_IGNORE_VAR(*p); p->value = value; ANNOTATE_SEM_INIT_PRE(p, value); } static void sem_destroy(sem_t *p) { ANNOTATE_SEM_DESTROY_POST(p); } static void sem_wait(sem_t *p) { unsigned old, new; struct timespec ts = { 0, 0 }; ANNOTATE_SEM_WAIT_PRE(p); do { old = p->value; new = old - 1; nanosleep(&ts, NULL); ts.tv_nsec = 1; } while (!old || !__sync_bool_compare_and_swap(&p->value, old, new)); ANNOTATE_SEM_WAIT_POST(p); } static void sem_post(sem_t *p) { ANNOTATE_SEM_POST_PRE(p); __sync_fetch_and_add(&p->value, 1); } static void *thread_func(void *arg) { unsigned int i; unsigned int sum = 0; for (i = 0; i < ITERATIONS; i++) { sem_wait(&s_sem); sum += s_counter; sem_post(&s_sem); sem_wait(&s_sem); s_counter++; sem_post(&s_sem); } return 0; } int main(int argc, const char *argv[]) { pthread_t tid[THREADS]; unsigned int i; sem_init(&s_sem, 1); for (i = 0; i < THREADS; i++) pthread_create(&tid[i], 0, thread_func, 0); for (i = 0; i < THREADS; i++) pthread_join(tid[i], 0); assert(s_counter == THREADS * ITERATIONS); assert(s_sem.value == 1); sem_destroy(&s_sem); fprintf(stderr, "Finished.\n"); return 0; }