ms-queue: add initialization
[model-checker-benchmarks.git] / ms-queue / my_queue.c
1 #include <threads.h>
2 #include <stdlib.h>
3 #include "librace.h"
4
5 #include "my_queue.h"
6
7 static unsigned int *node_nums;
8
9 static unsigned int new_node()
10 {
11         return node_nums[get_thread_num()];
12 }
13
14 static void reclaim(unsigned int node)
15 {
16         node_nums[get_thread_num()] = node;
17 }
18
19 void init_queue(queue_t *q, int num_threads)
20 {
21         unsigned int i;
22         pointer head;
23         pointer tail;
24         pointer next;
25
26         node_nums = malloc(num_threads * sizeof(*node_nums));
27         for (i = 0; i < num_threads; i++)
28                 node_nums[i] = 2 + i;
29
30         /* Note: needed to add this init manually */
31         atomic_init(&q->nodes[0].next, 0);
32
33         /* initialize queue */
34         head = MAKE_POINTER(1, 0);
35         tail = MAKE_POINTER(1, 0);
36         next = MAKE_POINTER(0, 0); // (NULL, 0)
37
38         atomic_init(&q->head, head);
39         atomic_init(&q->tail, tail);
40         atomic_init(&q->nodes[1].next, next);
41
42         /* initialize avail list */
43         for (i = 2; i < MAX_NODES; i++) {
44                 next = MAKE_POINTER(i + 1, 0);
45                 atomic_init(&q->nodes[i].next, next);
46         }
47
48         next = MAKE_POINTER(0, 0); // (NULL, 0)
49         atomic_init(&q->nodes[MAX_NODES].next, next);
50 }
51
52 void enqueue(queue_t *q, unsigned int val)
53 {
54         int success = 0;
55         unsigned int node;
56         pointer tail;
57         pointer next;
58         pointer tmp;
59
60         node = new_node();
61         store_32(&q->nodes[node].value, val);
62         tmp = atomic_load(&q->nodes[node].next);
63         set_ptr(&tmp, 0); // NULL
64         atomic_store(&q->nodes[node].next, tmp);
65
66         while (!success) {
67                 tail = atomic_load(&q->tail);
68                 next = atomic_load(&q->nodes[get_ptr(tail)].next);
69                 if (tail == atomic_load(&q->tail)) {
70                         if (get_ptr(next) == 0) { // == NULL
71                                 pointer value = MAKE_POINTER(node, get_count(next) + 1);
72                                 success = atomic_compare_exchange_weak(&q->nodes[get_ptr(tail)].next,
73                                                 &next, value);
74                         }
75                         if (!success) {
76                                 unsigned int ptr = get_ptr(atomic_load(&q->nodes[get_ptr(tail)].next));
77                                 pointer value = MAKE_POINTER(ptr,
78                                                 get_count(tail) + 1);
79                                 atomic_compare_exchange_strong(&q->tail,
80                                                 &tail, value);
81                                 thrd_yield();
82                         }
83                 }
84         }
85         atomic_compare_exchange_strong(&q->tail,
86                         &tail,
87                         MAKE_POINTER(node, get_count(tail) + 1));
88 }
89
90 unsigned int dequeue(queue_t *q)
91 {
92         unsigned int value;
93         int success = 0;
94         pointer head;
95         pointer tail;
96         pointer next;
97
98         while (!success) {
99                 head = atomic_load(&q->head);
100                 tail = atomic_load(&q->tail);
101                 next = atomic_load(&q->nodes[get_ptr(head)].next);
102                 if (atomic_load(&q->head) == head) {
103                         if (get_ptr(head) == get_ptr(tail)) {
104                                 if (get_ptr(next) == 0) { // NULL
105                                         return 0; // NULL
106                                 }
107                                 atomic_compare_exchange_strong(&q->tail,
108                                                 &tail,
109                                                 MAKE_POINTER(get_ptr(next), get_count(tail) + 1));
110                                 thrd_yield();
111                         } else {
112                                 value = load_32(&q->nodes[get_ptr(next)].value);
113                                 success = atomic_compare_exchange_weak(&q->head,
114                                                 &head,
115                                                 MAKE_POINTER(get_ptr(next), get_count(head) + 1));
116                                 if (!success)
117                                         thrd_yield();
118                         }
119                 }
120         }
121         reclaim(get_ptr(head));
122         return value;
123 }