Repository navigation
Expand file tree
/
Copy pathAtomicStackRDCSS.java
More file actions
209 lines (152 loc) · 5.07 KB
/
Copy pathAtomicStackRDCSS.java
File metadata and controls
209 lines (152 loc) · 5.07 KB
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Michael Harris
// COP4520 - pa2
// Modified AtomicStack to include RDCSS
import java.util.*;
import java.util.concurrent.atomic.*;
// node class
class Node<T> {
public T val;
public Node<T> next;
// custom node constructor, sets node value
public Node(T _val) {
this.val = _val;
this.next = null;
}
// accessor/setters
public T getVal() {
return val;
}
public void setVal(T e) {
val = e;
}
public Node<T> getNext() {
return next;
}
}
// descriptor for rdcss object:
class RDCSSDescriptor<T> {
AtomicInteger a1; //ctrl address
Integer o1; //expected value at a1
AtomicReference<Node<T>> a2; //data address
Node<T> o2; //expected value at a2
Node<T> n2; //new value
boolean pending; //pending op in this descriptor
// initialize
public RDCSSDescriptor(AtomicInteger a1, Integer o1, AtomicReference<Node<T>> a2, Node<T> o2, Node<T> n2) {
this.a1 = a1; this.o1 = o1; this.a2 = a2; this.o2 = o2; this.n2 = n2; this.pending = true;
}
}
// RDCSS stack class
public class AtomicStackRDCSS<T> {
AtomicReference<Node<T>> head;
AtomicInteger size;
AtomicInteger numOps;
// for pre-allocating nodes
ArrayList<Node<T>> Nodes;
AtomicInteger node_Idx;
public AtomicStackRDCSS() {
head = new AtomicReference<>();
numOps = new AtomicInteger(0);
size = new AtomicInteger(0);
// pre-allocate 100000 nodes and set index to 0
node_Idx = new AtomicInteger(0);
Nodes = new ArrayList<>(Driver.MAX_NUM_NODES);
// do the allocation, constant is in Driver.java
for (int i = 0; i < Driver.MAX_NUM_NODES; i++)
Nodes.add(new Node<>(null));
}
// restricted form of CAS2 where only data section is subject to update
public RDCSSDescriptor<T> RDCSS(RDCSSDescriptor<T> d) {
RDCSSDescriptor<T> r;
do {
r = CAS(d, d.a2, d.o2, d.n2); //C1
// try and finish
if (!r.pending)
Complete(r); //H1
} while(!r.pending); //B1
if (r.o2 == d.o2)
Complete(d);
numOps.getAndIncrement();
return r;
}
// if a2 is an in-progress descriptor, run complete on it, otherwise kick it back
public RDCSSDescriptor<T> RDCSSRead(RDCSSDescriptor<T> d) {
do {
if (!d.pending) //R1
Complete(d); //H2
} while(!d.pending); //B2
return d;
}
// finish the operation
public void Complete(RDCSSDescriptor<T> currDesc) {
//if the control address holds the expected value,
if (currDesc.a1.compareAndSet(currDesc.o1, currDesc.a1.get())) { //R2
//pointer is changed to the new value
CAS(currDesc, currDesc.a2, currDesc.o2, currDesc.n2); //C2
currDesc.pending = true;
}
//otherwise the old value is re-instated
else
CAS(currDesc, currDesc.a2, currDesc.o2, currDesc.o2); //C3
}
// update the node and the descriptor if it was successful. return value used in RDCSS(d)
public RDCSSDescriptor<T> CAS(RDCSSDescriptor<T> desc, AtomicReference<Node<T>> addr, Node<T> oldVal, Node<T> newVal) {
if (addr.compareAndSet(oldVal, newVal)) {
desc.pending = false;
}
return desc;
}
// push function, modified from part 1 to use RDCSS
public boolean push(T e) {
if (size.get() >= Driver.MAX_NUM_NODES) {
System.out.println("\nMaximum nodes inserted, ABA hazard in play. Expand Driver.MAX_NUM_NODES!");
java.lang.System.exit(0);
}
Node<T> currHead;
Integer currSize;
RDCSSDescriptor<T> newDesc;
// grab node from pool and set value
Node<T> newNode = Nodes.get(node_Idx.getAndIncrement());
newNode.setVal(e);
// much like the do loop from part 1..
do {
currSize = size.get();
// link current head in as new head's.next
currHead = head.get();
newNode.next = currHead;
// create new descriptor for RDCSS
newDesc = new RDCSSDescriptor<T>(size, currSize, this.head, currHead, newNode);
// reinit and try again until a2 is enqueued
} while((RDCSS(newDesc)).a2.get() != this.head.get());
return true;
}
// pop function, modified from part 1 to use RDCSS
public T pop() {
Node<T> currHead;
Integer currSize;
Node<T> newHead;
RDCSSDescriptor<T> newDesc;
do {
currSize = size.get();
currHead = head.get();
// can't pop empty stack
if (currHead == null)
return null;
// setup new head after pop
newHead = currHead.next;
// setup descriptor to do write op
newDesc = new RDCSSDescriptor<T>(size, currSize, this.head, currHead, newHead);
// reinit and try again until head is expected value
} while((RDCSS(newDesc)).a2.get() != this.head.get());
// return pop value
return currHead.getVal();
}
// from hw1
public int getNumOps() {
return numOps.get();
}
// elements in data structure
public int size() {
return size.get();
}
}