forked from robertdavidgraham/masscan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxring.c
210 lines (168 loc) · 4.81 KB
/
xring.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include "xring.h"
#include "pixie-threads.h"
#include "pixie-timer.h"
#include "string_s.h"
#include <stdio.h>
typedef uint64_t Element;
#define XRING_SIZE 16
struct XRing
{
volatile unsigned long long head;
volatile unsigned long long tail;
volatile Element ring[XRING_SIZE];
};
/***************************************************************************
***************************************************************************/
static Element
xring_remove(struct XRing *xring)
{
volatile Element *ring = xring->ring;
Element num;
if (xring->tail >= xring->head)
return 0;
num = ring[xring->tail & (XRING_SIZE-1)];
if (num) {
ring[xring->tail & (XRING_SIZE-1)] = 0;
xring->tail++;
return num;
/*
int x = pixie_locked_CAS64(&ring[xring->tail & (XRING_SIZE-1)], 0, num);
if (x) {
xring->tail++;
return num;
} else {
goto again;
}*/
} else {
return 0;
}
}
enum {XringSuccess, XringFailure};
/***************************************************************************
***************************************************************************/
static int
xring_add(struct XRing *xring, Element value)
{
volatile Element *ring = xring->ring;
Element num;
if (value == 0) {
return XringFailure;
}
if (xring->head >= xring->tail + XRING_SIZE) {
//printf("-");
return XringFailure;
}
num = xring->ring[xring->head & (XRING_SIZE-1)];
if (num == 0) {
ring[xring->head & (XRING_SIZE-1)] = value;
xring->head++;
return XringSuccess;
/*int x = pixie_locked_CAS64(&ring[xring->head & (XRING_SIZE-1)], value, 0);
if (x) {
xring->head++;
return XringSuccess;
} else {
return XringFailure;
}*/
}
return XringFailure;
}
/***************************************************************************
***************************************************************************/
struct Test
{
struct XRing xring[1];
unsigned producer_started;
unsigned producer_done;
unsigned consumer_done;
unsigned long long total_count;
volatile int not_active;
};
/***************************************************************************
***************************************************************************/
static void
test_consumer_thread(void *v)
{
struct Test *test = (struct Test *)v;
struct XRing *xring = test->xring;
while (!test->not_active) {
Element e;
e = xring_remove(xring);
if (e == 0)
;
else {
test->total_count += e;
}
}
while (xring->tail < xring->head) {
Element e;
e = xring_remove(xring);
if (e == 0)
;
else {
test->total_count += e;
}
}
test->consumer_done = 1;
}
/***************************************************************************
***************************************************************************/
static void
test_producer_thread(void *v)
{
struct Test *test = (struct Test *)v;
unsigned i = 1000;
struct XRing *xring = test->xring;
pixie_locked_add_u32(&test->producer_started, 1);
while (i) {
while (xring_add(xring, i) == XringFailure)
;
i--;
}
pixie_locked_add_u32(&test->producer_done, 1);
}
/***************************************************************************
***************************************************************************/
static uint64_t
run_test(struct Test *test)
{
unsigned i;
const unsigned THREADS = 1;
memset(test, 0, sizeof(*test));
/* Generate producer threads */
for (i=0; i<THREADS; i++) {
pixie_begin_thread(test_producer_thread, 0, test);
}
/* Wait for threads to start */
while (test->producer_started < THREADS)
pixie_usleep(10);
/* Now start consuming */
pixie_begin_thread(test_consumer_thread, 0, test);
/* Wait for producer threads to end */
while (test->producer_done < THREADS)
pixie_usleep(10);
/* Tell consumer thread to end */
test->not_active = 1;
/* Wait for consumer thread to end */
while (!test->consumer_done)
pixie_usleep(10);
return test->total_count;
}
/***************************************************************************
***************************************************************************/
int
xring_selftest(void)
{
unsigned i;
for (i=0; i<1000; i++) {
uint64_t result;
struct Test test[1];
result = run_test(test);
if (result != 500500) {
printf("xring: selftest failed with %" PRIu64 "\n", result);
return 1;
} else
;
}
return 0;
}