clean code
[cdsspec-compiler.git] / benchmark / chase-lev-deque-bugfix / deque.c
1 #include <stdatomic.h>
2 #include <inttypes.h>
3 #include "deque.h"
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 inline bool fail(int ret) {
8         return ret == ABORT || ret == EMPTY;
9 }
10
11 Deque * create() {
12         Deque * q = (Deque *) calloc(1, sizeof(Deque));
13         Array * a = (Array *) calloc(1, sizeof(Array)+2*sizeof(atomic_int));
14         atomic_store_explicit(&q->array, a, memory_order_relaxed);
15         atomic_store_explicit(&q->top, 0, memory_order_relaxed);
16         atomic_store_explicit(&q->bottom, 0, memory_order_relaxed);
17         atomic_store_explicit(&a->size, 2, memory_order_relaxed);
18         return q;
19 }
20
21
22 /**
23         @Begin
24         @Interface_define: Take 
25         @End
26 */
27 int take(Deque *q) {
28         size_t b = atomic_load_explicit(&q->bottom, memory_order_relaxed) - 1;
29         /**
30                 @Begin
31                 @Commit_point_define_check: true
32                 @Label: TakeReadBottom
33                 @End
34         */
35         Array *a = (Array *) atomic_load_explicit(&q->array, memory_order_relaxed);
36         atomic_store_explicit(&q->bottom, b, memory_order_relaxed);
37         /**** SPEC (sequential) (testcase1.c) ****/
38         atomic_thread_fence(memory_order_seq_cst);
39         size_t t = atomic_load_explicit(&q->top, memory_order_relaxed);
40         int x;
41         if (t <= b) {
42                 /**
43                         @Begin
44                         @Commit_point_clear: true
45                         @Label: TakeClear1
46                         @End
47                 */
48
49                 /* Non-empty queue. */
50                 int size = atomic_load_explicit(&a->size,memory_order_relaxed);
51                 x = atomic_load_explicit(&a->buffer[b % size], memory_order_relaxed);
52                 /**
53                         @Begin
54                         @Commit_point_define_check: true 
55                         @Label: TakeReadBuffer
56                         @End
57                 */
58                 if (t == b) {
59                         /* Single last element in queue. */
60                         //FIXME: weaken the following seq_cst causes no spec problem
61                         bool succ = atomic_compare_exchange_strong_explicit(&q->top, &t, t +
62                                 1, memory_order_seq_cst, memory_order_relaxed);
63                         if (!succ) {
64                                 /**
65                                         @Begin
66                                         @Commit_point_clear: true
67                                         @Label: TakeClear2
68                                         @End
69                                 */
70
71                                 /**
72                                         @Begin
73                                         @Commit_point_define_check: true
74                                         @Label: TakeReadTop
75                                         @End
76                                 */
77
78                                 /* Failed race. */
79                                 x = EMPTY;
80                         }
81                         atomic_store_explicit(&q->bottom, b + 1, memory_order_relaxed);
82                 }
83         } else { /* Empty queue. */
84                 x = EMPTY;
85                 atomic_store_explicit(&q->bottom, b + 1, memory_order_relaxed);
86         }
87         return x;
88 }
89
90 void resize(Deque *q) {
91         Array *a = (Array *) atomic_load_explicit(&q->array, memory_order_relaxed);
92         size_t size=atomic_load_explicit(&a->size, memory_order_relaxed);
93         size_t new_size=size << 1;
94         Array *new_a = (Array *) calloc(1, new_size * sizeof(atomic_int) + sizeof(Array));
95         size_t top=atomic_load_explicit(&q->top, memory_order_relaxed);
96         size_t bottom=atomic_load_explicit(&q->bottom, memory_order_relaxed);
97         atomic_store_explicit(&new_a->size, new_size, memory_order_relaxed);
98         size_t i;
99
100         // Initialize the whole new array to turn off the CDSChecker UL error
101         // Check if CDSSpec checker can catch this bug
102         /*
103         for(i=0; i < new_size; i++) {
104                 atomic_store_explicit(&new_a->buffer[i % new_size], atomic_load_explicit(&a->buffer[i % size], memory_order_relaxed), memory_order_relaxed);
105         }
106         */
107         for(i=top; i < bottom; i++) {
108                 atomic_store_explicit(&new_a->buffer[i % new_size], atomic_load_explicit(&a->buffer[i % size], memory_order_relaxed), memory_order_relaxed);
109         }
110         /**** detected UL ****/
111         atomic_store_explicit(&q->array, new_a, memory_order_release);
112         //printf("resize\n");
113 }
114
115 /**
116         @Begin
117         @Interface_define: Push
118         @End
119 */
120 void push(Deque *q, int x) {
121         size_t b = atomic_load_explicit(&q->bottom, memory_order_relaxed);
122         /**** SPEC (sequential) ****/
123         size_t t = atomic_load_explicit(&q->top, memory_order_acquire);
124         Array *a = (Array *) atomic_load_explicit(&q->array, memory_order_relaxed);
125         if (b - t > atomic_load_explicit(&a->size, memory_order_relaxed) - 1) /* Full queue. */ {
126                 resize(q);
127                 // CDSSpec can actually detect the same bug if we avoid the UL error
128                 //Bug in paper...should have next line...
129                 a = (Array *) atomic_load_explicit(&q->array, memory_order_relaxed);
130         }
131         int size = atomic_load_explicit(&a->size, memory_order_relaxed);
132
133         atomic_store_explicit(&a->buffer[b % size], x, memory_order_relaxed);
134         /**
135                 @Begin
136                 @Commit_point_define_check: true
137                 @Label: PushUpdateBuffer
138                 @End
139         */
140         /**** UL & SPEC (Sync) (run with -u100 to avoid the uninitialized bug) ****/
141         atomic_thread_fence(memory_order_release);
142         atomic_store_explicit(&q->bottom, b + 1, memory_order_relaxed);
143         
144 }
145
146 /**
147         @Begin
148         @Interface_define: Steal 
149         @End
150 */
151 int steal(Deque *q) {
152         //Watch out: actually on need to be an acquire (don't count it)
153         // An old bug
154         size_t t = atomic_load_explicit(&q->top, memory_order_acquire);
155         /**
156                 @Begin
157                 @Commit_point_define_check: true
158                 @Label: StealReadTop1
159                 @End
160         */
161         /********** SPEC error (testcase3.c) **********/
162         atomic_thread_fence(memory_order_seq_cst);
163         /**** SPEC & UL ****/
164         size_t b = atomic_load_explicit(&q->bottom, memory_order_acquire);
165         
166         int x = EMPTY;
167         if (t < b) {
168                 /**
169                         @Begin
170                         @Commit_point_clear: true
171                         @Label: StealClear1
172                         @End
173                 */
174
175                 /* Non-empty queue. */
176                 /**** detected UL ****/
177                 Array *a = (Array *) atomic_load_explicit(&q->array, memory_order_acquire);
178                 int size = atomic_load_explicit(&a->size, memory_order_relaxed);
179                 x = atomic_load_explicit(&a->buffer[t % size], memory_order_relaxed);
180                 /**
181                         @Begin
182                         @Commit_point_define_check: true
183                         @Label: StealReadBuffer
184                         @End
185                 */
186                 /**** SPEC (sequential) ****/ 
187                 bool succ = atomic_compare_exchange_strong_explicit(&q->top, &t, t + 1,
188                         memory_order_seq_cst, memory_order_relaxed);
189                 if (!succ) {
190                         /**
191                                 @Begin
192                                 @Commit_point_clear: true
193                                 @Label: StealClear2
194                                 @End
195                         */
196
197                         /**
198                                 @Begin
199                                 @Commit_point_define_check: true
200                                 @Label: StealReadTop2
201                                 @End
202                         */
203
204                         /* Failed race. */
205                         return ABORT;
206                 }
207         }
208         return x;
209 }