Initial tests for "Skeletal support for TSan-compatible annotations"
(r10810). The rwlock test is kludged and needs de-kludging.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10811 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/helgrind/tests/annotate_rwlock.c b/helgrind/tests/annotate_rwlock.c
new file mode 100644
index 0000000..8842b3c
--- /dev/null
+++ b/helgrind/tests/annotate_rwlock.c
@@ -0,0 +1,176 @@
+
+/* This program is a marginally modified copy of
+ drd/tests/annotate_rwlock.c,
+
+ which was originally written by Bart van Assche.
+
+ Unfortunately due to the need to #include helgrind.h instead of
+ drd.h, it can't be an exact copy.
+*/
+
+/**
+ * @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 <unistd.h> /* usleep() */
+#include "../../config.h"
+#include "../../helgrind/helgrind.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;
+#ifdef __APPLE__
+ /* Darwin doesn't have an implementation of pthread_yield(). */
+ usleep(100 * 1000);
+#else
+ pthread_yield();
+#endif
+ (void) __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);
+ (void) __sync_fetch_and_sub(&p->locked, 1);
+ //ANNOTATE_READERLOCK_ACQUIRED(p);
+ 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;
+#ifdef __APPLE__
+ /* Darwin doesn't have an implementation of pthread_yield(). */
+ usleep(100 * 1000);
+#else
+ pthread_yield();
+#endif
+ (void) __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);
+ (void) __sync_fetch_and_sub(&p->locked, 1);
+ // ANNOTATE_WRITERLOCK_ACQUIRED(p);
+ 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_READERLOCK_RELEASED(p);
+ ANNOTATE_RWLOCK_RELEASED(p, 0);
+ }
+ else
+ {
+ p->writer_count--;
+ //ANNOTATE_WRITERLOCK_RELEASED(p);
+ ANNOTATE_RWLOCK_RELEASED(p, 1);
+ }
+ assert(p->reader_count >= 0);
+ assert(p->writer_count >= 0);
+ assert(p->reader_count == 0 || p->writer_count == 0);
+ (void) __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;
+}