# System Qt6 in CI is not built with -fsanitize=thread, so TSan cannot see
# the synchronization in QCoreApplication::postEvent / event-queue mutex.
# This makes every queued signal/slot delivery look like a race -- either on
# the QMetaCallEvent itself (caught by called_from_lib) or on the by-value
# arguments copied into our slot via the moc-generated dispatcher (caught by
# the qt_static_metacall pattern, which only matches the moc shim).
called_from_lib:libQt6Core.so
race:qt_static_metacall
race:QtPrivate::QMetaTypeForType

# CalcWorker is torn down via the standard Qt deleteLater + QThread::finished
# idiom: the worker's destructor runs on the worker thread when its event loop
# flushes deferred-delete events, and the happens-before chain back to earlier
# main-thread invokeMethod calls passes through uninstrumented Qt internals.
# The destructor itself is = default with no body, so there is no real shared
# state to race on -- only the object-lifetime sync that TSan cannot observe.
race:Avogadro::QtGui::CalcWorker::~CalcWorker

# BackgroundFileFormatTest tears its worker down the same way. The main
# thread's quit() is what triggers the deferred delete, but that ordering
# passes through the same uninstrumented Qt event queue. The destructor only
# deletes m_format, which was used on the worker thread alone.
race:Avogadro::QtGui::BackgroundFileFormat::~BackgroundFileFormat

# Qt6 on Linux uses glib's main loop by default, which wakes worker threads
# via an eventfd. Synchronization happens through the kernel fd, which TSan
# doesn't model; glib itself isn't instrumented either.
called_from_lib:libglib-2.0.so

# Surfaces' EDT runs QtConcurrent::run -> nested QtConcurrent::map, and hands
# results back through QFutureWatcher. QThreadPool/QFutureInterface sync inside
# uninstrumented libQt6Core (futex QMutex), so every hand-off (main -> worker,
# outer task -> inner map workers, worker -> main) looks like a race. We cannot
# match QtConcurrent frames: every pool-thread stack has them, and that would
# hide all pool races. ~MapKernel is the teardown vs forThreadFunction case.
# Trade-off: this also blinds TSan to a real race inside the EDT fill itself.
# That race is prevented by construction (x-slab partitioning: each task writes
# only voxels of its own indexX) and checked by the exact voxel comparison in
# surfacestest.cpp. With a TSan-instrumented Qt, remove these entries first.
race:Avogadro::QtPlugins::Surfaces::calculateEDT
race:Avogadro::QtPlugins::Surfaces::performEDTStep
race:~MapKernel
