7 #include <cdsannotate.h>
8 #include <specannotation.h>
9 #include <model_memory.h>
14 #define RW_LOCK_BIAS 0x00100000
15 #define WRITE_LOCK_CMP RW_LOCK_BIAS
21 /** Example implementation of linux rw lock along with 2 thread test
26 1. At most 1 thread can acquire the write lock, and at the same time, no
27 other threads can acquire any lock (including read/write lock).
28 2. At most RW_LOCK_BIAS threads can successfully acquire the read lock.
29 3. A read_unlock release 1 read lock, and a write_unlock release the write
30 lock. They can not release a lock that they don't acquire.
32 4. Read_lock and write_lock can not be grabbed at the same time.
33 5. Happpens-before relationship should be checked and guaranteed, which
34 should be as the following:
35 a. read_unlock hb-> write_lock
36 b. write_unlock hb-> write_lock
37 c. write_unlock hb-> read_lock
41 Interesting point for locks:
42 a. If the users unlock() before any lock(), then the model checker will fail.
43 For this case, we can not say that the data structure is buggy, how can we
44 tell them from a real data structure bug???
45 b. We should specify that for a specific thread, successful locks and
46 unlocks should always come in pairs. We could make this check as an
47 auxiliary check since it is an extra rule for how the interfaces should called.
56 bool writer_lock_acquired;
59 writer_lock_acquired = false;
62 # Since commit_point_set has no ID attached, A -> B means that for any B,
63 # the previous A happens before B.
64 Write_Unlock -> Write_Lock
65 Write_Unlock -> Write_Trylock(HB_Write_Trylock_Succ)
67 Write_Unlock -> Read_Lock
68 Write_Unlock -> Read_Trylock(HB_Read_Trylock_Succ)
72 static inline int read_can_lock(rwlock_t *lock)
74 return atomic_load_explicit(&lock->lock, memory_order_relaxed) > 0;
77 static inline int write_can_lock(rwlock_t *lock)
79 return atomic_load_explicit(&lock->lock, memory_order_relaxed) == RW_LOCK_BIAS;
87 Read_Lock_Success_1 | Read_Lock_Success_2
94 static inline void read_lock(rwlock_t *rw)
96 int priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
99 @Commit_point_define_check: priorvalue > 0
100 @Label:Read_Lock_Success_1
103 while (priorvalue <= 0) {
104 atomic_fetch_add_explicit(&rw->lock, 1, memory_order_relaxed);
105 while (atomic_load_explicit(&rw->lock, memory_order_relaxed) <= 0) {
108 priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
111 @Commit_point_define_check: priorvalue > 0
112 @Label:Read_Lock_Success_2
121 @Interface: Write_Lock
123 Write_Lock_Success_1 | Write_Lock_Success_2
125 !writer_lock_acquired && reader_lock_cnt == 0
127 writer_lock_acquired = true;
130 static inline void write_lock(rwlock_t *rw)
132 int priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
135 @Commit_point_define_check: priorvalue == RW_LOCK_BIAS
136 @Label: Write_Lock_Success_1
139 while (priorvalue != RW_LOCK_BIAS) {
140 atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_relaxed);
141 while (atomic_load_explicit(&rw->lock, memory_order_relaxed) != RW_LOCK_BIAS) {
144 priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
147 @Commit_point_define_check: priorvalue == RW_LOCK_BIAS
148 @Label: Write_Lock_Success_2
156 @Interface: Read_Trylock
158 Read_Trylock_Succ_Point | Read_Trylock_Fail_Point
160 writer_lock_acquired == false
162 HB_Read_Trylock_Succ :: __RET__ == 1
167 __COND_SAT__ ? __RET__ == 1 : __RET__ == 0
170 static inline int read_trylock(rwlock_t *rw)
172 int priorvalue = atomic_fetch_sub_explicit(&rw->lock, 1, memory_order_acquire);
175 @Potential_commit_point_define: true
176 @Label: Potential_Read_Trylock_Point
179 if (priorvalue > 0) {
182 @Commit_point_define: true
183 @Potential_commit_point_label: Potential_Read_Trylock_Point
184 @Label: Read_Trylock_Succ_Point
191 @Commit_point_define: true
192 @Potential_commit_point_label: Potential_Read_Trylock_Point
193 @Label: Read_Trylock_Fail_Point
196 atomic_fetch_add_explicit(&rw->lock, 1, memory_order_relaxed);
202 @Interface: Write_Trylock
204 Write_Trylock_Succ_Point | Write_Trylock_Fail_Point
206 !writer_lock_acquired && reader_lock_cnt == 0
208 HB_Write_Trylock_Succ :: __RET__ == 1
211 writer_lock_acquired = true;
213 __COND_SAT__ ? __RET__ == 1 : __RET__ == 0
216 static inline int write_trylock(rwlock_t *rw)
218 int priorvalue = atomic_fetch_sub_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_acquire);
221 @Potential_commit_point_define: true
222 @Label: Potential_Write_Trylock_Point
225 if (priorvalue == RW_LOCK_BIAS) {
228 @Commit_point_define: true
229 @Potential_commit_point_label: Potential_Write_Trylock_Point
230 @Label: Write_Trylock_Succ_Point
237 @Commit_point_define: true
238 @Potential_commit_point_label: Potential_Write_Trylock_Point
239 @Label: Write_Trylock_Fail_Point
242 atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_relaxed);
248 @Interface: Read_Unlock
249 @Commit_point_set: Read_Unlock_Point
251 reader_lock_cnt > 0 && !writer_lock_acquired
256 static inline void read_unlock(rwlock_t *rw)
258 atomic_fetch_add_explicit(&rw->lock, 1, memory_order_release);
261 @Commit_point_define_check: true
262 @Label: Read_Unlock_Point
269 @Interface: Write_Unlock
270 @Commit_point_set: Write_Unlock_Point
272 reader_lock_cnt == 0 && writer_lock_acquired
274 writer_lock_acquired = false;
277 static inline void write_unlock(rwlock_t *rw)
279 atomic_fetch_add_explicit(&rw->lock, RW_LOCK_BIAS, memory_order_release);
282 @Commit_point_define_check: true
283 @Label: Write_Unlock_Point
291 static void a(void *obj)
294 for(i = 0; i < 2; i++) {
297 //load_32(&shareddata);
298 printf("%d\n", shareddata);
299 read_unlock(&mylock);
302 //store_32(&shareddata,(unsigned int)i);
304 write_unlock(&mylock);
309 static void b(void *obj)
312 for(i = 0; i < 2; i++) {
314 if (read_trylock(&mylock) == 1) {
315 printf("%d\n", shareddata);
316 read_unlock(&mylock);
319 if (write_trylock(&mylock) == 1) {
321 write_unlock(&mylock);
327 int user_main(int argc, char **argv)
335 atomic_init(&mylock.lock, RW_LOCK_BIAS);
337 thrd_create(&t1, (thrd_start_t)&a, NULL);
338 thrd_create(&t2, (thrd_start_t)&b, NULL);