changes to ms-queue
[cdsspec-compiler.git] / benchmark / ms-queue / my_queue.c
1 #include <threads.h>
2 #include <stdlib.h>
3 #include "librace.h"
4 #include "model-assert.h"
5
6 #include "my_queue.h"
7
8 #define relaxed memory_order_relaxed
9 #define release memory_order_release
10 #define acquire memory_order_acquire
11
12 #define MAX_FREELIST 4 /* Each thread can own up to MAX_FREELIST free nodes */
13 #define INITIAL_FREE 3 /* Each thread starts with INITIAL_FREE free nodes */
14
15 #define POISON_IDX 0x666
16
17 static unsigned int (*free_lists)[MAX_FREELIST];
18
19 /* Search this thread's free list for a "new" node */
20 static unsigned int new_node()
21 {
22         int i;
23         int t = get_thread_num();
24         for (i = 0; i < MAX_FREELIST; i++) {
25                 //unsigned int node = load_32(&free_lists[t][i]);
26                 unsigned int node = free_lists[t][i];
27                 //unsigned int node = free_lists[t][i];
28                 if (node) {
29                         //store_32(&free_lists[t][i], 0);
30                         free_lists[t][i] = 0;
31                         //free_lists[t][i] = 0;
32                         return node;
33                 }
34         }
35         /* free_list is empty? */
36         //MODEL_ASSERT(0);
37         return 0;
38 }
39
40 /* Place this node index back on this thread's free list */
41 static void reclaim(unsigned int node)
42 {
43         int i;
44         int t = get_thread_num();
45
46         /* Don't reclaim NULL node */
47         //MODEL_ASSERT(node);
48
49         for (i = 0; i < MAX_FREELIST; i++) {
50                 /* Should never race with our own thread here */
51                 //unsigned int idx = load_32(&free_lists[t][i]);
52                 unsigned int idx = free_lists[t][i];
53                 //unsigned int idx = free_lists[t][i];
54
55                 /* Found empty spot in free list */
56                 if (idx == 0) {
57                         //store_32(&free_lists[t][i], node);
58                         free_lists[t][i] = node;
59                         //free_lists[t][i] = node;
60                         return;
61                 }
62         }
63         /* free list is full? */
64         //MODEL_ASSERT(0);
65 }
66
67 void init_queue(queue_t *q, int num_threads)
68 {
69         int i, j;
70
71         /* Initialize each thread's free list with INITIAL_FREE pointers */
72         /* The actual nodes are initialized with poison indexes */
73         free_lists = malloc(num_threads * sizeof(*free_lists));
74         for (i = 0; i < num_threads; i++) {
75                 for (j = 0; j < INITIAL_FREE; j++) {
76                         free_lists[i][j] = 2 + i * MAX_FREELIST + j;
77                         atomic_init(&q->nodes[free_lists[i][j]].next, MAKE_POINTER(POISON_IDX, 0));
78                 }
79         }
80
81         /* initialize queue */
82         atomic_init(&q->head, MAKE_POINTER(1, 0));
83         atomic_init(&q->tail, MAKE_POINTER(1, 0));
84         atomic_init(&q->nodes[1].next, MAKE_POINTER(0, 0));
85 }
86
87 /**
88         @Begin
89         @Interface_define: Enqueue
90         @End
91 */
92 void enqueue(queue_t *q, unsigned int val)
93 {
94         int success = 0;
95         unsigned int node;
96         pointer tail;
97         pointer next;
98         pointer tmp;
99
100         node = new_node();
101         //store_32(&q->nodes[node].value, val);
102         q->nodes[node].value = val;
103         //q->nodes[node].value = val;
104         tmp = atomic_load_explicit(&q->nodes[node].next, relaxed);
105         set_ptr(&tmp, 0); // NULL
106         atomic_store_explicit(&q->nodes[node].next, tmp, relaxed);
107
108         while (!success) {
109                 /**** detected UL (2 threads, 1 enqueue & 1 dequeue)  ****/
110                 tail = atomic_load_explicit(&q->tail, acquire);
111                 /****FIXME: miss ****/
112                 next = atomic_load_explicit(&q->nodes[get_ptr(tail)].next, acquire);
113                 if (tail == atomic_load_explicit(&q->tail, relaxed)) {
114
115                         /* Check for uninitialized 'next' */
116                         //MODEL_ASSERT(get_ptr(next) != POISON_IDX);
117
118                         if (get_ptr(next) == 0) { // == NULL
119                                 pointer value = MAKE_POINTER(node, get_count(next) + 1);
120                                 /**** correctness error (1 dequeue & 1 enqueue) ****/
121                                 success = atomic_compare_exchange_strong_explicit(&q->nodes[get_ptr(tail)].next,
122                                                 &next, value, release, relaxed);
123                                 /**
124                                         @Begin
125                                         @Commit_point_define_check: success == true
126                                         @Label: Enqueue_Success_Point
127                                         @End
128                                 */
129                         }
130                         if (!success) {
131                                 // This routine helps the other enqueue to update the tail
132                                 /**** detected UL (2 threads, 1 enqueue & 1 dequeue) ****/
133                                 unsigned int ptr = get_ptr(atomic_load_explicit(&q->nodes[get_ptr(tail)].next, acquire));
134                                 pointer value = MAKE_POINTER(ptr,
135                                                 get_count(tail) + 1);
136                                 /****FIXME: miss ****/
137                                 bool succ = false;
138                                 succ = atomic_compare_exchange_strong_explicit(&q->tail,
139                                                 &tail, value, release, relaxed);
140                                 if (succ) {
141                                         //printf("miss2_enqueue CAS succ\n");
142                                 }
143                                 //printf("miss2_enqueue\n");
144                                 thrd_yield();
145                         }
146                 }
147         }
148         /**** correctness error (1 dequeue & 1 enqueue) ****/
149         atomic_compare_exchange_strong_explicit(&q->tail,
150                         &tail,
151                         MAKE_POINTER(node, get_count(tail) + 1),
152                         release, relaxed);
153 }
154
155 /**
156         @Begin
157         @Interface_define: Dequeue
158         @End
159 */
160 bool dequeue(queue_t *q, unsigned int *retVal)
161 {
162         unsigned int value;
163         int success = 0;
164         pointer head;
165         pointer tail;
166         pointer next;
167
168         while (!success) {
169                 /**** FIXME: miss ****/
170                 head = atomic_load_explicit(&q->head, acquire);
171                 // This must be acquire otherwise we have a bug with 1 enqueue &
172                 // 1 dequeue
173                 /**** correctness error (1 dequeue & 1 enqueue) ****/
174                 tail = atomic_load_explicit(&q->tail, acquire);
175                 /**** correctness error (1 dequeue & 1 enqueue) ****/
176                 next = atomic_load_explicit(&q->nodes[get_ptr(head)].next, acquire);
177                 //printf("miss3_dequeue\n");
178                 if (atomic_load_explicit(&q->head, relaxed) == head) {
179                         if (get_ptr(head) == get_ptr(tail)) {
180
181                                 /* Check for uninitialized 'next' */
182                                 //MODEL_ASSERT(get_ptr(next) != POISON_IDX);
183
184                                 if (get_ptr(next) == 0) { // NULL
185                                         /**
186                                                 @Begin
187                                                 @Commit_point_define_check: true
188                                                 @Label: Dequeue_Empty_Point
189                                                 @End
190                                         */
191                                         return false; // NULL
192                                 }
193                                 /****FIXME: miss (not reached) ****/
194                                 bool succ = false;
195                                 succ = atomic_compare_exchange_strong_explicit(&q->tail,
196                                                 &tail,
197                                                 MAKE_POINTER(get_ptr(next), get_count(tail) + 1),
198                                                 release, relaxed);
199                                 if (succ) {
200                                         //printf("miss4_dequeue CAS succ\n");
201                                 }
202                                 //printf("miss4_dequeue\n");
203                                 thrd_yield();
204                         } else {
205                                 //*retVal = load_32(&q->nodes[get_ptr(next)].value);
206                                 *retVal = q->nodes[get_ptr(next)].value;
207                                 //value = q->nodes[get_ptr(next)].value;
208                                 /**** FIXME: miss (not reached) ****/
209                                 success = atomic_compare_exchange_strong_explicit(&q->head,
210                                                 &head,
211                                                 MAKE_POINTER(get_ptr(next), get_count(head) + 1),
212                                                 release, relaxed);
213                                 /**
214                                         @Begin
215                                         @Commit_point_define_check: success == true
216                                         @Label: Dequeue_Success_Point
217                                         @End
218                                 */
219                                 if (!success)
220                                         thrd_yield();
221                         }
222                 }
223         }
224         reclaim(get_ptr(head));
225         return true;
226 }