13
13
//
14
14
// ===----------------------------------------------------------------------===//
15
15
#include " xray_buffer_queue.h"
16
+ #include " sanitizer_common/sanitizer_atomic.h"
16
17
#include " sanitizer_common/sanitizer_common.h"
17
18
#include " sanitizer_common/sanitizer_libc.h"
18
19
#include " sanitizer_common/sanitizer_posix.h"
24
25
using namespace __xray ;
25
26
using namespace __sanitizer ;
26
27
28
+ namespace {
29
+
30
+ void decRefCount (unsigned char *ControlBlock, size_t Size , size_t Count) {
31
+ if (ControlBlock == nullptr )
32
+ return ;
33
+ auto *RefCount = reinterpret_cast <atomic_uint64_t *>(ControlBlock);
34
+ if (atomic_fetch_sub (RefCount, 1 , memory_order_acq_rel) == 1 )
35
+ deallocateBuffer (ControlBlock, (Size * Count) + kCacheLineSize );
36
+ }
37
+
38
+ void incRefCount (unsigned char *ControlBlock) {
39
+ if (ControlBlock == nullptr )
40
+ return ;
41
+ auto *RefCount = reinterpret_cast <atomic_uint64_t *>(ControlBlock);
42
+ atomic_fetch_add (RefCount, 1 , memory_order_acq_rel);
43
+ }
44
+
45
+ } // namespace
46
+
27
47
BufferQueue::ErrorCode BufferQueue::init (size_t BS, size_t BC) {
28
48
SpinMutexLock Guard (&Mutex);
29
49
30
50
if (!finalizing ())
31
51
return BufferQueue::ErrorCode::AlreadyInitialized;
32
52
53
+ cleanupBuffers ();
54
+
33
55
bool Success = false ;
34
56
BufferSize = BS;
35
57
BufferCount = BC;
36
- BackingStore = allocateBuffer (BufferSize * BufferCount);
58
+ BackingStore = allocateBuffer (( BufferSize * BufferCount) + kCacheLineSize );
37
59
if (BackingStore == nullptr )
38
60
return BufferQueue::ErrorCode::NotEnoughMemory;
39
61
40
62
auto CleanupBackingStore = __sanitizer::at_scope_exit ([&, this ] {
41
63
if (Success)
42
64
return ;
43
- deallocateBuffer (BackingStore, BufferSize * BufferCount);
65
+ deallocateBuffer (BackingStore, (BufferSize * BufferCount) + kCacheLineSize );
66
+ BackingStore = nullptr ;
44
67
});
45
68
46
69
Buffers = initArray<BufferRep>(BufferCount);
@@ -52,13 +75,21 @@ BufferQueue::ErrorCode BufferQueue::init(size_t BS, size_t BC) {
52
75
atomic_fetch_add (&Generation, 1 , memory_order_acq_rel);
53
76
54
77
Success = true ;
78
+
79
+ // First, we initialize the refcount in the RefCountedBackingStore, which we
80
+ // treat as being at the start of the BackingStore pointer.
81
+ auto ControlBlock = reinterpret_cast <atomic_uint64_t *>(BackingStore);
82
+ atomic_store (ControlBlock, 1 , memory_order_release);
83
+
55
84
for (size_t i = 0 ; i < BufferCount; ++i) {
56
85
auto &T = Buffers[i];
57
86
auto &Buf = T.Buff ;
58
87
atomic_store (&Buf.Extents , 0 , memory_order_release);
59
88
Buf.Generation = generation ();
60
- Buf.Data = reinterpret_cast < char *>( BackingStore) + (BufferSize * i);
89
+ Buf.Data = BackingStore + kCacheLineSize + (BufferSize * i);
61
90
Buf.Size = BufferSize;
91
+ Buf.BackingStore = BackingStore;
92
+ Buf.Count = BufferCount;
62
93
T.Used = false ;
63
94
}
64
95
@@ -99,9 +130,12 @@ BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) {
99
130
++LiveBuffers;
100
131
}
101
132
133
+ incRefCount (BackingStore);
102
134
Buf.Data = B->Buff .Data ;
103
135
Buf.Generation = generation ();
104
136
Buf.Size = B->Buff .Size ;
137
+ Buf.BackingStore = BackingStore;
138
+ Buf.Count = BufferCount;
105
139
B->Used = true ;
106
140
return ErrorCode::Ok;
107
141
}
@@ -116,18 +150,24 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {
116
150
Buf.Data > reinterpret_cast <char *>(BackingStore) +
117
151
(BufferCount * BufferSize)) {
118
152
if (Buf.Generation != generation ()) {
153
+ decRefCount (Buf.BackingStore , Buf.Size , Buf.Count );
119
154
Buf.Data = nullptr ;
120
155
Buf.Size = 0 ;
121
156
Buf.Generation = 0 ;
157
+ Buf.Count = 0 ;
158
+ Buf.BackingStore = nullptr ;
122
159
return BufferQueue::ErrorCode::Ok;
123
160
}
124
161
return BufferQueue::ErrorCode::UnrecognizedBuffer;
125
162
}
126
163
127
164
if (LiveBuffers == 0 ) {
165
+ decRefCount (Buf.BackingStore , Buf.Size , Buf.Count );
128
166
Buf.Data = nullptr ;
129
167
Buf.Size = Buf.Size ;
130
168
Buf.Generation = 0 ;
169
+ Buf.BackingStore = nullptr ;
170
+ Buf.Count = 0 ;
131
171
return ErrorCode::Ok;
132
172
}
133
173
@@ -141,13 +181,18 @@ BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) {
141
181
B->Buff .Data = Buf.Data ;
142
182
B->Buff .Size = Buf.Size ;
143
183
B->Buff .Generation = Buf.Generation ;
184
+ B->Buff .BackingStore = Buf.BackingStore ;
185
+ B->Buff .Count = Buf.Count ;
144
186
B->Used = true ;
187
+ decRefCount (Buf.BackingStore , Buf.Size , Buf.Count );
145
188
atomic_store (&B->Buff .Extents ,
146
189
atomic_load (&Buf.Extents , memory_order_acquire),
147
190
memory_order_release);
148
191
Buf.Data = nullptr ;
149
192
Buf.Size = 0 ;
150
193
Buf.Generation = 0 ;
194
+ Buf.BackingStore = nullptr ;
195
+ Buf.Count = 0 ;
151
196
return ErrorCode::Ok;
152
197
}
153
198
@@ -157,9 +202,15 @@ BufferQueue::ErrorCode BufferQueue::finalize() {
157
202
return ErrorCode::Ok;
158
203
}
159
204
160
- BufferQueue::~BufferQueue () {
205
+ void BufferQueue::cleanupBuffers () {
161
206
for (auto B = Buffers, E = Buffers + BufferCount; B != E; ++B)
162
207
B->~BufferRep ();
163
208
deallocateBuffer (Buffers, BufferCount);
164
- deallocateBuffer (BackingStore, BufferSize * BufferCount);
209
+ decRefCount (BackingStore, BufferSize, BufferCount);
210
+ BackingStore = nullptr ;
211
+ Buffers = nullptr ;
212
+ BufferCount = 0 ;
213
+ BufferSize = 0 ;
165
214
}
215
+
216
+ BufferQueue::~BufferQueue () { cleanupBuffers (); }
0 commit comments