mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-05 11:10:21 +00:00
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
152 lines
3.1 KiB
C
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;
|
|
}
|