-
Notifications
You must be signed in to change notification settings - Fork 0
/
ringstm.h
231 lines (189 loc) · 5.45 KB
/
ringstm.h
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#ifndef RING_STM_H__
#define RING_STM_H__
#include "BitFilter.h"
#include "rand_r_32.h"
#include <fcntl.h>
#include <map>
#include <pthread.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#define CFENCE __asm__ volatile("" ::: "memory")
#define MFENCE __asm__ volatile("mfence" ::: "memory")
// DEFINE METADATA
#define COMPLETED 0
#define WRITING 1
#define BITS 4096
#define RING_SIZE 8
struct RingEntry {
volatile uint64_t timestamp = 0;
BitFilter<BITS> wf;
volatile uint64_t priority = 0;
volatile int status = COMPLETED;
};
volatile uint64_t global_clock = 0;
// Ring struct that cleans itself after program ends
struct Ring {
Ring() { array = new RingEntry[RING_SIZE]; }
~Ring() { delete[] array; }
RingEntry &operator[](uint64_t index) { return array[index]; }
RingEntry *array;
};
Ring ring;
struct TX_EXCEPTION {};
/*
1.
whenever the expected
timestamp of an entry is greater than the value expected
by a transaction (either during validate or commit),
that transaction must abort.
2. a rollover test must be issued before returning, to ensure
that, after all validation is complete, the oldest entry validated
has not been overwritten (accomplished with a test on
its timestamp field).This test detects when a validation is
interrupted by a context switch, and conservatively aborts
if ring rollover occurs while the transaction is swapped out.
3.
During initialization, updates to a new ring entry’s timestamp
must follow the setting of the write filter and the status
(write-after-write ordering). Calls to check from tm_end
must block until the newest ring entry’s timestamp is set.
*/
class RingSW {
public:
void tx_begin() {
// Reset thread-local metadata
writefilter.clear();
readfilter.clear();
write_set.clear();
CFENCE;
// RV = Global-Clock
RV = global_clock;
uint64_t index = RV % RING_SIZE;
// if ( ring[RV].status != complete || ring[RV].timestamp < RV) - >RV--
if (ring[index].status != COMPLETED || ring[index].timestamp < RV) {
RV--;
}
CFENCE;
}
int64_t tx_read(int64_t *address) {
// Find the addr is in the write-set signature
if (writefilter.lookup(address)) {
// If found, find the addr is in the write-set & return the value buffered
// in write-set (IF FOUND)
if (write_set.count(address) > 0)
return write_set[address];
}
// val = *addr
CFENCE;
int64_t val = *address;
CFENCE;
// Add addr to read-set signature
readfilter.add(address);
// Check
tx_validate();
// Return val
return val;
}
void tx_write(int64_t *address, int64_t value) {
// Add (or update) the addr and value to the write-set & Add the addr to
// the write-set signature
write_set[address] = value; // This operator updates or inserts
writefilter.add(address);
}
void tx_validate() {
CFENCE;
uint64_t end = global_clock;
CFENCE;
uint64_t end_index = end % RING_SIZE;
// greater than expected Check (1)
/*if (ring[end_index].timestamp > end) {
tx_abort();
}*/
for (int i = 0; i < RING_SIZE; i++) {
if (ring[i].timestamp > end) {
tx_abort();
}
}
// if Global -Clock == RV -> return
if (end == RV)
return;
while (ring[end_index].timestamp < end) {
// WAIT
}
for (uint64_t i = end; i > RV; i--) {
int index = i % RING_SIZE;
if (ring[index].wf.intersect(&readfilter)) {
tx_abort();
}
}
while (ring[end_index].status != COMPLETED) {
// WAIT
}
// Rollover test (2)
// uint64_t rollover_check_index = (RV) % RING_SIZE;
if (global_clock > (RV + RING_SIZE)) {
tx_abort();
}
CFENCE;
RV = end;
CFENCE;
}
void tx_commit() {
// if Read Only -> return
if (write_set.size() == 0) {
return;
}
again:
CFENCE;
uint64_t commit_time = global_clock;
CFENCE;
// (3) Calls to check from tm_end
// must block until the newest ring entry’s timestamp is set.
uint64_t commit_time_index = commit_time % RING_SIZE;
while (ring[commit_time_index].timestamp != commit_time) {
// Block
}
tx_validate();
if (!(__sync_bool_compare_and_swap(&global_clock, commit_time,
(commit_time + 1)))) {
goto again;
}
uint64_t new_index = (commit_time + 1) % RING_SIZE;
CFENCE;
ring[new_index].status = WRITING;
ring[new_index].wf.fastcopy(&writefilter);
ring[new_index].timestamp = commit_time + 1;
CFENCE;
// For each entry in the write-set
CFENCE;
for (auto &entry : write_set) {
*entry.first = entry.second; // Write back
}
CFENCE;
CFENCE;
ring[new_index].status = COMPLETED;
commits++;
CFENCE;
}
void tx_abort() {
////Just jump back to tx_begin to restart the transaction
aborts++;
TX_EXCEPTION e;
throw e;
}
long commits = 0;
long aborts = 0;
private:
std::map<int64_t *, int64_t> write_set;
BitFilter<BITS> writefilter;
BitFilter<BITS> readfilter;
uint64_t RV;
};
#endif // RING_STM_H__