ms-queue: cleanups
[model-checker-benchmarks.git] / linuxrwlocks / linuxrwlocks.c
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
5 #include "librace.h"
6
7 #define RW_LOCK_BIAS            0x00100000
8 #define WRITE_LOCK_CMP          RW_LOCK_BIAS
9
10 /** Example implementation of linux rw lock along with 2 thread test
11  *  driver... */
12
13 typedef union {
14         atomic_int lock;
15 } rwlock_t;
16
17 static inline int read_can_lock(rwlock_t *lock)
18 {
19         return atomic_load_explicit(&lock->lock, memory_order_relaxed) > 0;
20 }
21
22 static inline int write_can_lock(rwlock_t *lock)
23 {
24         return atomic_load_explicit(&lock->lock, memory_order_relaxed) == RW_LOCK_BIAS;
25 }
26
27 static inline void read_lock(rwlock_t *rw)
28 {
29         int priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
30         while (priorvalue <= 0) {
31                 atomic_fetch_add_explicit(&rw->lock, 1, memory_order_relaxed);
32                 do {
33                         priorvalue = atomic_load_explicit(&rw->lock, memory_order_relaxed);
34                 } while (priorvalue <= 0);
35                 priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
36         }
37 }
38
39 static inline void write_lock(rwlock_t *rw)
40 {
41         int priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
42         while (priorvalue != RW_LOCK_BIAS) {
43                 atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_relaxed);
44                 do {
45                         priorvalue = atomic_load_explicit(&rw->lock, memory_order_relaxed);
46                 } while (priorvalue != RW_LOCK_BIAS);
47                 priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
48         }
49 }
50
51 static inline int read_trylock(rwlock_t *rw)
52 {
53         int priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
54         if (priorvalue > 0)
55                 return 1;
56
57         atomic_fetch_add_explicit(&rw->lock, 1, memory_order_relaxed);
58         return 0;
59 }
60
61 static inline int write_trylock(rwlock_t *rw)
62 {
63         int priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
64         if (priorvalue == RW_LOCK_BIAS)
65                 return 1;
66
67         atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_relaxed);
68         return 0;
69 }
70
71 static inline void read_unlock(rwlock_t *rw)
72 {
73         atomic_fetch_add_explicit(&rw->lock, 1, memory_order_release);
74 }
75
76 static inline void write_unlock(rwlock_t *rw)
77 {
78         atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_release);
79 }
80
81 rwlock_t mylock;
82 int shareddata;
83
84 static void a(void *obj)
85 {
86         int i;
87         for(i = 0; i < 2; i++) {
88                 if ((i % 2) == 0) {
89                         read_lock(&mylock);
90                         load_32(&shareddata);
91                         read_unlock(&mylock);
92                 } else {
93                         write_lock(&mylock);
94                         store_32(&shareddata,(unsigned int)i);
95                         write_unlock(&mylock);
96                 }
97         }
98 }
99
100 int user_main(int argc, char **argv)
101 {
102         thrd_t t1, t2;
103         atomic_init(&mylock.lock, RW_LOCK_BIAS);
104
105         thrd_create(&t1, (thrd_start_t)&a, NULL);
106         thrd_create(&t2, (thrd_start_t)&a, NULL);
107
108         thrd_join(t1);
109         thrd_join(t2);
110
111         return 0;
112 }