ftmemsim-valgrind/drd/tests/annotate_rwlock.c
Bart Van Assche e73284e37f - Added support for most of the ANNOTATE_...() macro's supported by
ThreadSanitizer.                                                              
- Modified DRD's error reporting code such that it does no longer let           
  the Valgrind core print the Valgrind thread ID but that it now prints         
  the DRD thread ID and name. Updated expected output files where               
  necessary.                                                                    
- Modified drd/test/Makefile.am such that the tests using gcc's built-in        
  functions for atomic memory access such that these are only compiled when     
  the gcc version in use supports these built-in functions.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10186
2009-05-31 18:53:54 +00:00

152 lines
3.1 KiB
C

/**
* @file annotate_rwlock.c
*
* @brief Multithreaded test program that triggers various access patterns
* without triggering any race conditions using a reader-writer lock
* implemented via busy-waiting. Annotations are used to tell DRD
* which higher-level rwlock operations are being performed.
*/
#define _GNU_SOURCE 1
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include "../../config.h"
#include "../../drd/drd.h"
#ifndef HAVE_BUILTIN_ATOMIC
#error Sorry, but this test program can only be compiled by a compiler that\
has built-in functions for atomic memory access.
#endif
typedef struct {
volatile int locked;
int writer_count;
int reader_count;
} rwlock_t;
static rwlock_t s_rwlock;
static int s_counter;
static void rwlock_init(rwlock_t* p)
{
DRD_IGNORE_VAR(*p);
p->locked = 0;
p->writer_count = 0;
p->reader_count = 0;
ANNOTATE_RWLOCK_CREATE(p);
}
static void rwlock_destroy(rwlock_t* p)
{
ANNOTATE_RWLOCK_DESTROY(p);
assert(p->locked == 0);
assert(p->writer_count == 0);
assert(p->reader_count == 0);
}
static void rwlock_rdlock(rwlock_t* p)
{
while (1)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->writer_count == 0)
break;
pthread_yield();
__sync_fetch_and_sub(&p->locked, 1);
}
p->reader_count++;
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
__sync_fetch_and_sub(&p->locked, 1);
ANNOTATE_RWLOCK_ACQUIRED(p, 0);
}
static void rwlock_wrlock(rwlock_t* p)
{
while (1)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->reader_count == 0)
break;
pthread_yield();
__sync_fetch_and_sub(&p->locked, 1);
}
p->writer_count++;
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
__sync_fetch_and_sub(&p->locked, 1);
ANNOTATE_RWLOCK_ACQUIRED(p, 1);
}
static void rwlock_unlock(rwlock_t* p)
{
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
;
if (p->reader_count > 0)
{
p->reader_count--;
ANNOTATE_RWLOCK_RELEASED(p, 0);
}
else
{
p->writer_count--;
ANNOTATE_RWLOCK_RELEASED(p, 1);
}
assert(p->reader_count >= 0);
assert(p->writer_count >= 0);
assert(p->reader_count == 0 || p->writer_count == 0);
__sync_fetch_and_sub(&p->locked, 1);
}
static void* thread_func(void* arg)
{
int i;
int sum = 0;
for (i = 0; i < 1000; i++)
{
rwlock_rdlock(&s_rwlock);
sum += s_counter;
rwlock_unlock(&s_rwlock);
rwlock_wrlock(&s_rwlock);
s_counter++;
rwlock_unlock(&s_rwlock);
}
return 0;
}
int main(int argc, char** argv)
{
const int thread_count = 10;
pthread_t tid[thread_count];
int i;
rwlock_init(&s_rwlock);
for (i = 0; i < thread_count; i++)
{
pthread_create(&tid[i], 0, thread_func, 0);
}
for (i = 0; i < thread_count; i++)
{
pthread_join(tid[i], 0);
}
rwlock_destroy(&s_rwlock);
fprintf(stderr, "Finished.\n");
return 0;
}