another benchmark
[satcheck.git] / benchmarks / satcheck / trieber-stack / trieber-stack.c
1 #include <threads.h>
2 #include <stdlib.h>
3 // #include "librace.h"
4 #include "model-assert.h"
5 #include "libinterface.h"
6
7 #include "trieber_stack.h"
8
9 #define MAX_FREELIST 4 /* Each thread can own up to MAX_FREELIST free nodes */
10 #define INITIAL_FREE 2 /* Each thread starts with INITIAL_FREE free nodes */
11
12 #define POISON_IDX 0x666
13
14 static unsigned int (*free_lists)[MAX_FREELIST];
15
16 /* Search this thread's free list for a "new" node */
17 static unsigned int new_node()
18 {
19         int i;
20         int t = get_thread_num();
21         for (i = 0; i < MAX_FREELIST; i++) {
22                 unsigned int node = load_64(&free_lists[t][i]);
23                 if (node) {
24                         store_64(&free_lists[t][i], 0);
25                         return node;
26                 }
27         }
28         return 0;
29 }
30
31 /* Place this node index back on this thread's free list */
32 static void reclaim(unsigned int node)
33 {
34         int i;
35         int t = get_thread_num();
36
37         /* Don't reclaim NULL node */
38         //MODEL_ASSERT(node);
39
40         for (i = 0; i < MAX_FREELIST; i++) {
41                 /* Should never race with our own thread here */
42                 unsigned int idx = load_64(&free_lists[t][i]);
43
44                 /* Found empty spot in free list */
45                 if (idx == 0) {
46                         store_64(&free_lists[t][i], node);
47                         return;
48                 }
49         }
50         /* free list is full? */
51         MODEL_ASSERT(0);
52 }
53
54 void init_stack(stack_t *s, int num_threads)
55 {
56         int i, j;
57
58         /* Initialize each thread's free list with INITIAL_FREE pointers */
59         /* The actual nodes are initialized with poison indexes */
60         free_lists = malloc(num_threads * sizeof(*free_lists));
61         for (i = 0; i < num_threads; i++) {
62                 for (j = 0; j < INITIAL_FREE; j++) {
63                         free_lists[i][j] = 1 + i * MAX_FREELIST + j;
64                         atomic_init(&s->nodes[free_lists[i][j]].next, MAKE_POINTER(POISON_IDX, 0));
65                 }
66         }
67
68         /* initialize stack */
69         atomic_init(&s->top, MAKE_POINTER(0, 0));
70 }
71
72 void push(stack_t *s, unsigned int val) {
73         unsigned int nodeIdx = new_node();
74         node_t *node = &s->nodes[nodeIdx];
75         node->value = val;
76         pointer oldTop, newTop;
77         bool success;
78         while (true) {
79                 // acquire
80                 oldTop = atomic_load_explicit(&s->top, acquire);
81                 newTop = MAKE_POINTER(nodeIdx, get_count(oldTop) + 1);
82                 // relaxed
83                 atomic_store_explicit(&node->next, oldTop, relaxed);
84
85                 // release & relaxed
86                 success = atomic_compare_exchange_strong_explicit(&s->top, &oldTop,
87                         newTop, release, relaxed);
88                 if (success)
89                         break;
90         } 
91 }
92
93 unsigned int pop(stack_t *s) 
94 {
95         pointer oldTop, newTop, next;
96         node_t *node;
97         bool success;
98         int val;
99         while (true) {
100                 // acquire
101                 oldTop = atomic_load_explicit(&s->top, acquire);
102                 if (get_ptr(oldTop) == 0)
103                         return 0;
104                 node = &s->nodes[get_ptr(oldTop)];
105                 // relaxed
106                 next = atomic_load_explicit(&node->next, relaxed);
107                 newTop = MAKE_POINTER(get_ptr(next), get_count(oldTop) + 1);
108                 // release & relaxed
109                 success = atomic_compare_exchange_strong_explicit(&s->top, &oldTop,
110                         newTop, release, relaxed);
111                 if (success)
112                         break;
113         }
114         val = node->value;
115         /* Reclaim the used slot */
116         reclaim(get_ptr(oldTop));
117         return val;
118 }