-
Notifications
You must be signed in to change notification settings - Fork 0
/
list_lf_smr.c
192 lines (166 loc) · 4.82 KB
/
list_lf_smr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "smr.h"
#include "test.h"
#include "arch/atomic.h"
#include "allocator.h"
#include "util.h"
#include "backoff.h"
#include <stdio.h>
struct list {
node_t *list_head;
};
void list_init(struct list **l)
{
*l = (struct list*)mapmem(sizeof(struct list));
(*l)->list_head = NULL;
}
void list_destroy(struct list **l)
{
free(*l);
}
/*
* Takes advantage of pointers always lying on 4-byte boundaries
* since words are 32-bits on x86. Hence we can mark the low-order
* two bytes of a pointer. We only mark the low-order one.
*
* Postcondition:
* 1. If list is empty, prev=head, cur=NULL, return false.
* 2. If we find a q s. th. q->key >= key (q has the *smallest* key <= key),
* then prev = &cur, cur = q, an we return (q->key == key).
* 3. If the key isn't in the list, *prev=(last node), cur=NULL, next=null,
* return false.
*
* NOTE: It is this postcondition, as it applies to prev, that requires us to
* use two levels of indirection for the head: we need prev to point to
* the right thing in the calling function, not a local head variable.
*/
int find(node_t **head, long key)
{
node_t **prev, *cur, *next = NULL;
uint32_t base = thread_id * K;
uint32_t off = 0;
try_again:
prev = head;
for (cur = *prev; cur != NULL; cur = next) {
/* Protect cur with a hazard pointer. */
HP[base + off].p = cur;
memory_barrier();
if (*prev != cur) {
goto try_again;
}
next = cur->next;
/* If the bit is marked... */
if ((unsigned long)next & 1) {
/* ... update the link and retire the element. */
if (!CAS(prev, cur, (node_t*)((unsigned long)next - 1))) {
backoff_delay();
goto try_again;
}
free_node_later(cur);
next = (node_t*)((unsigned long)next - 1);
} else {
if (*prev != cur) {
goto try_again;
}
if (cur->key >= key) {
this_thread.cur = cur;
this_thread.prev = prev;
this_thread.next = next;
return (cur->key == key);
}
prev = &cur->next;
off = !off;
}
}
this_thread.cur = cur;
this_thread.prev = prev;
this_thread.next = next;
return (0);
}
int insert(struct list *l, long key)
{
node_t **head = &l->list_head;
node_t *n = new_node();
backoff_reset();
while (1) {
if (find(head, key)) {
free_node(n);
return (0);
}
n->key = key;
n->next = this_thread.cur;
write_barrier();
if (CAS(this_thread.prev, this_thread.cur, n)) {
return (1);
} else {
backoff_delay();
}
}
}
int delete(struct list *l, long key)
{
node_t **head = &l->list_head;
backoff_reset();
while (1) {
/* Try to find the key in the list. */
if (!find(head, key)) {
return (0);
}
/* Mark if needed. */
if (!CAS(&this_thread.cur->next,
this_thread.next,
(node_t*)((unsigned long)this_thread.next + 1))) {
backoff_delay();
continue; /* Another thread interfered. */
}
write_barrier();
if (CAS(this_thread.prev,
this_thread.cur, this_thread.next)) { /* Unlink */
free_node_later(this_thread.cur); /* Reclaim */
}
/*
* If we want to revent the possibility of there being an
* unbounded number of unmarked nodes, add "else _find(head,key)."
* This is not necessary for correctness.
*/
return (1);
}
}
int search(struct list *l, long key)
{
node_t **prev, *cur, *next;
uint32_t base = thread_id * K;
uint32_t off = 0;
backoff_reset();
try_again:
prev = &l->list_head;
for (cur = *prev; cur != NULL; cur = next) {
/* Protect cur with a hazard pointer. */
HP[base + off].p = cur;
memory_barrier();
if (*prev != cur) {
goto try_again;
}
next = cur->next;
/* If the bit is marked... */
if ((unsigned long)next & 1) {
/* ... update the link and retire the element. */
if (!CAS(prev, cur, (node_t*)((unsigned long)next - 1))) {
backoff_delay();
goto try_again;
}
free_node_later(cur);
next = (node_t*)((unsigned long)next - 1);
} else {
long ckey = cur->key;
if (*prev != cur) {
goto try_again;
}
if (ckey >= key) {
return (ckey == key);
}
prev = &cur->next;
off = !off;
}
}
return (0);
}