Add data structures with bugs that tsan11/tsan11rec cannot detect
[c11concurrency-benchmarks.git] / tsan11-missingbug / rwlock-test.cc
diff --git a/tsan11-missingbug/rwlock-test.cc b/tsan11-missingbug/rwlock-test.cc
new file mode 100644 (file)
index 0000000..560f53d
--- /dev/null
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <atomic>
+#include <pthread.h>
+#include <assert.h>
+// #include <stdatomic.h>
+
+using namespace std;
+
+#define RW_LOCK_BIAS       0x00100000
+#define WRITE_LOCK_CMP   RW_LOCK_BIAS
+
+/** Example implementation of linux rw lock along with 2 thread test
+ *  driver... */
+
+typedef union {
+       atomic_int lock;
+} rwlock_t;
+
+static inline void read_lock(rwlock_t *rw)
+{
+       int priorvalue = rw->lock.fetch_sub(1, memory_order_acquire);
+       while (priorvalue <= 0) {
+               rw->lock.fetch_add(1, memory_order_relaxed);
+               while (rw->lock.load(memory_order_relaxed) <= 0) {
+                       pthread_yield();
+               }
+               priorvalue = rw->lock.fetch_sub(1, memory_order_acquire);
+       }
+}
+
+// Injected bug for the two fetch_sub ***
+static inline void write_lock(rwlock_t *rw)
+{
+       int priorvalue = rw->lock.fetch_sub(RW_LOCK_BIAS, memory_order_relaxed);        // Should be acquire
+       while (priorvalue != RW_LOCK_BIAS) {
+               rw->lock.fetch_add(RW_LOCK_BIAS, memory_order_relaxed);
+               while (rw->lock.load(memory_order_relaxed) != RW_LOCK_BIAS) {
+                       pthread_yield();
+               }
+               priorvalue = rw->lock.fetch_sub(RW_LOCK_BIAS, memory_order_relaxed);    // Should be acquire
+       }
+}
+
+static inline void read_unlock(rwlock_t *rw)
+{
+       rw->lock.fetch_add(1, memory_order_release);
+}
+
+static inline void write_unlock(rwlock_t *rw)
+{
+       rw->lock.fetch_add(RW_LOCK_BIAS, memory_order_release);
+}
+
+rwlock_t mylock;
+atomic_int data1, data2;
+
+void * a(void *obj)
+{
+       int i;
+       for(i = 0; i < 4; i++) {
+               if ((i % 2) == 0) {
+                       read_lock(&mylock);
+                       int d1 = data1.load(memory_order_relaxed);
+                       int d2 = data2.load(memory_order_relaxed);
+                       assert(d1 == d2);
+                       read_unlock(&mylock);
+               } else {
+                       write_lock(&mylock);
+                       data1.store(i, memory_order_relaxed);
+                       data2.store(i, memory_order_relaxed);
+                       write_unlock(&mylock);
+               }
+       }
+
+       return NULL;
+}
+
+int main(int argc, char **argv)
+{
+       pthread_t t1, t2, t3;
+       mylock.lock.store(RW_LOCK_BIAS);
+
+       pthread_create(&t1, NULL, &a, NULL);
+       pthread_create(&t2, NULL, &a, NULL);
+       pthread_create(&t3, NULL, &a, NULL);
+
+       pthread_join(t1, NULL);
+       pthread_join(t2, NULL);
+       pthread_join(t3, NULL);
+
+       return 0;
+}