19
19
#include " llvm/ADT/Optional.h"
20
20
#include " llvm/ADT/STLExtras.h"
21
21
#include " llvm/ADT/SmallString.h"
22
+ #include " llvm/Support/Mutex.h"
22
23
#include < ctime>
23
24
24
25
namespace indexstore {
@@ -203,6 +204,29 @@ class IndexStore {
203
204
typedef std::function<void (UnitEventNotification)> UnitEventHandler;
204
205
typedef std::function<void (indexstore_unit_event_notification_t )> RawUnitEventHandler;
205
206
207
+ private:
208
+ struct EventHandlerContext {
209
+ RawUnitEventHandler handler;
210
+ #if __has_feature(thread_sanitizer)
211
+ std::unique_ptr<llvm::sys::Mutex> eventHandlerMutex;
212
+ #endif
213
+
214
+ EventHandlerContext (RawUnitEventHandler handler) : handler(std::move(handler)) {
215
+ #if __has_feature(thread_sanitizer)
216
+ eventHandlerMutex = std::make_unique<llvm::sys::Mutex>();
217
+ #endif
218
+ }
219
+
220
+ ~EventHandlerContext () {
221
+ #if __has_feature(thread_sanitizer)
222
+ // See comment in event_handler_finalizer.
223
+ assert (!eventHandlerMutex);
224
+ #endif
225
+ }
226
+ };
227
+
228
+ public:
229
+
206
230
void setUnitEventHandler (UnitEventHandler handler) {
207
231
auto localLib = std::weak_ptr<IndexStoreLibrary>(library);
208
232
if (!handler) {
@@ -212,7 +236,7 @@ class IndexStore {
212
236
213
237
#pragma clang diagnostic push
214
238
#pragma clang diagnostic ignored "-Wc++14-extensions"
215
- auto fnPtr = new RawUnitEventHandler ([handler, localLib=std::move (localLib)](
239
+ auto fnPtr = new EventHandlerContext ([handler, localLib=std::move (localLib)](
216
240
indexstore_unit_event_notification_t evt_note) {
217
241
if (auto lib = localLib.lock ()) {
218
242
handler (UnitEventNotification (evt_note, lib));
@@ -223,13 +247,29 @@ class IndexStore {
223
247
}
224
248
225
249
private:
226
- static void event_handler (void *ctx, indexstore_unit_event_notification_t evt) {
227
- auto fnPtr = (RawUnitEventHandler*)ctx;
228
- (*fnPtr)(evt);
250
+ static void event_handler (void *ctx_, indexstore_unit_event_notification_t evt) {
251
+ auto ctx = (EventHandlerContext*)ctx_;
252
+
253
+ #if __has_feature(thread_sanitizer)
254
+ // See comment in event_handler_finalizer.
255
+ llvm::sys::ScopedLock L (*ctx->eventHandlerMutex );
256
+ #endif
257
+
258
+ (ctx->handler )(evt);
229
259
}
230
- static void event_handler_finalizer (void *ctx) {
231
- auto fnPtr = (RawUnitEventHandler*)ctx;
232
- delete fnPtr;
260
+ static void event_handler_finalizer (void *ctx_) {
261
+ auto ctx = (EventHandlerContext*)ctx_;
262
+
263
+ #if __has_feature(thread_sanitizer)
264
+ // We need to convince TSan that the event handler callback never overlaps the
265
+ // destructor of the context. We use `eventHandlerMutex` to ensure TSan can
266
+ // see the synchronization, and we need to move the mutex out of the context
267
+ // so that it can be held during `delete` below.
268
+ auto mutexPtr = std::move (ctx->eventHandlerMutex );
269
+ llvm::sys::ScopedLock L (*mutexPtr);
270
+ #endif
271
+
272
+ delete ctx;
233
273
}
234
274
235
275
public:
0 commit comments