3 // #include "librace.h"
4 // #include "model-assert.h"
6 #include "libinterface.h"
7 #include "ms-queue-freelist.h"
10 #define MAX_FREELIST 4 /* Each thread can own up to MAX_FREELIST free nodes */
11 #define INITIAL_FREE 2 /* Each thread starts with INITIAL_FREE free nodes */
13 #define POISON_IDX 0x666
15 static unsigned int (*free_lists)[MAX_FREELIST];
17 /* Search this thread's free list for a "new" node */
18 static unsigned int new_node()
21 int t = get_thread_num();
22 for (i = 0; i < MAX_FREELIST; i++) {
23 unsigned int node = load_32(&free_lists[t][i]);
25 store_32(&free_lists[t][i], 0);
29 /* free_list is empty? */
34 /* Place this node index back on this thread's free list */
35 static void reclaim(unsigned int node)
38 int t = get_thread_num();
40 /* Don't reclaim NULL node */
41 // MODEL_ASSERT(node);
43 for (i = 0; i < MAX_FREELIST; i++) {
44 /* Should never race with our own thread here */
45 unsigned int idx = load_32(&free_lists[t][i]);
47 /* Found empty spot in free list */
49 store_32(&free_lists[t][i], node);
53 /* free list is full? */
57 void init_queue(queue_t *q, int num_threads)
61 /* Initialize each thread's free list with INITIAL_FREE pointers */
62 /* The actual nodes are initialized with poison indexes */
63 free_lists = malloc(num_threads * sizeof(*free_lists));
64 for (i = 0; i < num_threads; i++) {
65 for (j = 0; j < INITIAL_FREE; j++) {
66 free_lists[i][j] = 2 + i * MAX_FREELIST + j;
67 store_32(&q->nodes[free_lists[i][j]].next, MAKE_POINTER(POISON_IDX, 0));
71 /* initialize queue */
72 store_32(&q->head, MAKE_POINTER(1, 0));
73 store_32(&q->tail, MAKE_POINTER(1, 0));
74 store_32(&q->nodes[1].next, MAKE_POINTER(0, 0));
77 void enqueue(queue_t *q, unsigned int val)
86 store_32(&q->nodes[node].value, val);
87 tmp = load_32(&q->nodes[node].next);
88 // manually inlined macro: set_ptr(&tmp, 0); // NULL
89 tmp = (tmp & ~PTR_MASK);
90 store_32(&q->nodes[node].next, tmp);
93 pointer_t * qt = &q->tail;
95 pointer_t * qn = &q->nodes[tail & PTR_MASK].next;
97 if (tail == load_32(&q->tail)) {
99 /* Check for uninitialized 'next' */
100 // MODEL_ASSERT(get_ptr(next) != POISON_IDX);
102 if ((next & PTR_MASK) == 0) { // == NULL
103 pointer value = MAKE_POINTER(node, ((next & COUNT_MASK) >> 32) + 1);
104 success = rmw_32(CAS, &q->nodes[tail & PTR_MASK].next,
105 (uint32_t)&next, value);
108 unsigned int ptr = (load_32(&q->nodes[tail & PTR_MASK].next) & PTR_MASK);
109 pointer value = MAKE_POINTER(ptr,
110 ((tail & COUNT_MASK) >> 32) + 1);
111 rmw_32(CAS, &q->tail,
112 (uint32_t)&tail, value);
117 rmw_32(CAS, &q->tail,
119 MAKE_POINTER(node, ((tail & COUNT_MASK) >> 32) + 1));
122 bool dequeue(queue_t *q, unsigned int *retVal)
130 head = load_32(&q->head);
131 tail = load_32(&q->tail);
132 next = load_32(&q->nodes[(head & PTR_MASK)].next);
133 if (load_32(&q->head) == head) {
134 if ((head & PTR_MASK) == (tail & PTR_MASK)) {
136 /* Check for uninitialized 'next' */
137 // MODEL_ASSERT(get_ptr(next) != POISON_IDX);
139 if (get_ptr(next) == 0) { // NULL
140 return false; // NULL
142 rmw_32(CAS, &q->tail,
144 MAKE_POINTER((next & PTR_MASK), ((tail & COUNT_MASK) >> 32) + 1));
147 *retVal = load_32(&q->nodes[(next & PTR_MASK)].value);
148 success = rmw_32(CAS, &q->head,
150 MAKE_POINTER((next & PTR_MASK), ((head & COUNT_MASK) >> 32) + 1));
156 reclaim((head & PTR_MASK));
161 static int procs = 2;
162 static queue_t *queue;
163 static thrd_t *threads;
164 static unsigned int *input;
165 static unsigned int *output;
166 static int num_threads;
170 thrd_t curr = thrd_current();
172 for (i = 0; i < num_threads; i++)
173 if (curr.priv == threads[i].priv)
175 /* MODEL_ASSERT(0); */
181 static void main_task(void *param)
184 int pid = *((int *)param);
187 enqueue(queue, input[0]);
188 succ1 = dequeue(queue, &output[0]);
189 //printf("Dequeue: %d\n", output[0]);
192 enqueue(queue, input[1]);
193 succ2 = dequeue(queue, &output[1]);
197 int user_main(int argc, char **argv)
201 unsigned int in_sum = 0, out_sum = 0;
203 queue = calloc(1, sizeof(*queue));
204 // MODEL_ASSERT(queue);
207 threads = malloc(num_threads * sizeof(thrd_t));
208 param = malloc(num_threads * sizeof(*param));
209 input = calloc(num_threads, sizeof(*input));
210 output = calloc(num_threads, sizeof(*output));
212 init_queue(queue, num_threads);
213 for (i = 0; i < num_threads; i++) {
215 thrd_create(&threads[i], main_task, ¶m[i]);
217 for (i = 0; i < num_threads; i++)
218 thrd_join(threads[i]);
220 for (i = 0; i < num_threads; i++) {
222 out_sum += output[i];
224 for (i = 0; i < num_threads; i++)
225 printf("input[%d] = %u\n", i, input[i]);
226 for (i = 0; i < num_threads; i++)
227 printf("output[%d] = %u\n", i, output[i]);
228 /* if (succ1 && succ2) */
229 /* MODEL_ASSERT(in_sum == out_sum); */
231 /* MODEL_ASSERT (false); */