Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opening states on macOS almost crashes Bespoke #21

Closed
kenokenobingo opened this issue Aug 16, 2020 · 10 comments
Closed

Opening states on macOS almost crashes Bespoke #21

kenokenobingo opened this issue Aug 16, 2020 · 10 comments
Labels

Comments

@kenokenobingo
Copy link

When opening a state (.bsk file), Bespoke crashes or almost crashes. Sometimes there’s also a humming noise on the audio signal.

OS: macOS 10.15.6

@awwbees
Copy link
Collaborator

awwbees commented Aug 17, 2020

this does not occur for me. can you post an example .bsk file that crashes for you, so I can try to reproduce it and find more info?

@kenokenobingo
Copy link
Author

For example, this file: https://transfer.sh/zqV62/2020-08-15_14-42.bsk. (GitHub gist wasn’t working unfortunately because the file is too large.)

@awwbees
Copy link
Collaborator

awwbees commented Aug 18, 2020

hmm, unfortunately this file will not download for me, I don't seem to be able to access transfer.sh

if possible, you could email it to me at my username @gmail.com

@awwbees
Copy link
Collaborator

awwbees commented Aug 20, 2020

thank you, I received the .bsk that you sent! it also crashes for me when I load it. it appears to be crashing when loading the "sampler" module, so I likely have some bug in the savestate for sampler modules. I can't recreate a crashing save file locally, so it must be caused by something more subtle, I will keep digging to figure out what's going on. if I short-circuit the sampler loading in code, the rest of your .bsk file opens fine.

in the meantime: can you still get the crash if you don't use a "sampler" module? if not, I would advise avoiding the sampler module for now.

@kenokenobingo
Copy link
Author

Thank you! Yes, it also crashes when I try to open the patch without a sampler module.

@awwbees
Copy link
Collaborator

awwbees commented Aug 22, 2020

hmm! so to test the very basics of saving: if you just load straight into bespoke and don't add any modules, then save state, then load that basic state, does it crash? if it does, can you send that .bsk to me?

@kenokenobingo
Copy link
Author

The basic state loads very quickly and without problems.

@awwbees
Copy link
Collaborator

awwbees commented Aug 24, 2020

gotcha. so, it sounds like there must be certain modules that don't serialize correctly, either due to a bug that effects everybody, or an issue specific to your machine's configuration. if you have the time, creating the simplest possible patch that still crashes when you try to load it would be helpful to narrow down the issue.

@cosmikwolf
Copy link

on loading the example__scripting.bsk file, on bespoke version 1.0.0, on an M1 Apple Sillicon Mac Mini running OS 11.3, Bespoke plays a tiny sound, and then exits. I don't get an OS X "This app unexpectedly quit" notification like I usually do.

@asmw asmw added the bug label Nov 2, 2021
@awwbees
Copy link
Collaborator

awwbees commented Feb 23, 2022

stale issue, let's close this!

@awwbees awwbees closed this as completed Feb 23, 2022
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer identifies a few data races involving the ModularSynth::mPixelRatio
variable. For instance, appendix A, where MainContentComponent::render() reads
mPixelRatio while holding ModularSynth::mRenderLock:

   void render() override
   {
      mSynth.LockRender(true);
      // ...
      glViewport(0, 0, width * mPixelRatio, height * mPixelRatio);
      // ...
      mSynth.LockRender(false);
      // ...
   }

... but MainContentComponent::timerCallback() writes mPixelRatio without holding mRenderLock:

   void timerCallback() override
   {
      //...

      if (sRenderFrame % 30 == 0)
      {
         if (const auto* dpy = Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds()))
         {
            mPixelRatio = dpy->scale; //adjust pixel ratio based on which screen has the majority of the window
            TheSynth->SetPixelRatio(mPixelRatio);
         }
      }

      // ...
   }

This commit changes ModularSynth::SetPixelRatio() to automatically hold
mRenderLock while accessing mPixelRatio.

ModularSynth::GetPixelRatio() is not changed to hold mRenderLock,
because it is declared const, which prohibits locking/unlocking.
Callers must ensure that GetPixelRatio() is called with mRenderLock
already held (such as in Appendix B).

This particular case may be benign, but it obscures other bugs in the flood of
output from ThreadSanitizer.


Appendix A:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056e48 by thread T9 (mutexes: write M19877):
    #0 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 (BespokeSynth+0x5f35aa)
    #1 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #2 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #4 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #5 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #6 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #7 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #8 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056e48 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11ad)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 in MainContentComponent::render()
```


Appendix B:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056dc8 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::GetPixelRatio() const /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 (BespokeSynth+0xa86e4f)
    #1 ofSetColor(float, float, float, float) /home/jn/dev/synth/bespoke/Source/OpenFrameworksPort.cpp:201 (BespokeSynth+0xa86e4f)
    #2 DrawLissajous(RollingBuffer*, float, float, float, float, float, float, float) /home/jn/dev/synth/bespoke/Source/SynthGlobals.cpp:528 (BespokeSynth+0xc4dcd1)
    #3 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:514 (BespokeSynth+0x64fa42)
    #4 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #5 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #8 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #9 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#10 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#11 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#12 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056dc8 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11d3)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 in ModularSynth::GetPixelRatio() const
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer reports a race condition between LocationZoomer::Update() and ModularSynth::Draw():

   void LocationZoomer::Update()
   {
      if (mCurrentProgress < 1)
      {
         // ...
         gDrawScale = ofLerp(mStart.mZoomLevel, mDestination.mZoomLevel, ease); // A
         ofVec2f offset;
         offset.x = ofLerp(mStart.mOffset.x, mDestination.mOffset.x, ease);
         offset.y = ofLerp(mStart.mOffset.y, mDestination.mOffset.y, ease);
         TheSynth->SetDrawOffset(offset);                                       // B
         // ...
      }
   }

   void ModularSynth::Draw(void* vg)
   {
      // ...
      mDrawRect.set(-GetDrawOffset().x, -GetDrawOffset().y, ofGetWidth() / gDrawScale, ofGetHeight() / gDrawScale);
      // ...
   }


Draw() is called from the render thread, with the render lock held, and
Update() is called from the timer thread, without any locks held.

This commit changes LocationZoomer::Update to hold ModularSynth::mLockRender.

An partial alternative would be to:

 - change ModularSynth::SetDrawOffset() to hold mRenderLock automatically.
 - add locking to SynthGlobals.h, and take the lock for gDrawScale in
   LocationZoomer::Update()


```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 4 at 0x555557038004 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 (BespokeSynth+0x64dcaa)
    #1 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #2 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #4 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #5 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #6 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #7 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #8 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #9 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 4 at 0x555557038004 by main thread:
    #0 LocationZoomer::Update() /home/jn/dev/synth/bespoke/Source/LocationZoomer.cpp:57 (BespokeSynth+0x5c6e69)
    #1 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:345 (BespokeSynth+0x656a0a)
    #2 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f111b)
    #3 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #4 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #5 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #6 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #7 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #8 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #9 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    BespokeSynth#10 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    BespokeSynth#11 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#12 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#13 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#14 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#16 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#17 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#18 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#19 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#20 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is global 'gDrawScale' of size 4 at 0x555557038004 (BespokeSynth+0x1ae4004)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 in ModularSynth::Draw(void*)
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer identifies a few data races involving the ModularSynth::mPixelRatio
variable. For instance, appendix A, where MainContentComponent::render() reads
mPixelRatio while holding ModularSynth::mRenderLock:

   void render() override
   {
      mSynth.LockRender(true);
      // ...
      glViewport(0, 0, width * mPixelRatio, height * mPixelRatio);
      // ...
      mSynth.LockRender(false);
      // ...
   }

... but MainContentComponent::timerCallback() writes mPixelRatio without holding mRenderLock:

   void timerCallback() override
   {
      //...

      if (sRenderFrame % 30 == 0)
      {
         if (const auto* dpy = Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds()))
         {
            mPixelRatio = dpy->scale; //adjust pixel ratio based on which screen has the majority of the window
            TheSynth->SetPixelRatio(mPixelRatio);
         }
      }

      // ...
   }

This commit changes ModularSynth::SetPixelRatio() to automatically hold
mRenderLock while accessing mPixelRatio.

ModularSynth::GetPixelRatio() is not changed to hold mRenderLock,
because it is declared const, which prohibits locking/unlocking.
Callers must ensure that GetPixelRatio() is called with mRenderLock
already held (such as in Appendix B).

This particular case may be benign, but it obscures other bugs in the flood of
output from ThreadSanitizer.


Appendix A:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056e48 by thread T9 (mutexes: write M19877):
    #0 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 (BespokeSynth+0x5f35aa)
    #1 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #2 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #4 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #5 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #6 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #7 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #8 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056e48 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11ad)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 in MainContentComponent::render()
```


Appendix B:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056dc8 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::GetPixelRatio() const /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 (BespokeSynth+0xa86e4f)
    #1 ofSetColor(float, float, float, float) /home/jn/dev/synth/bespoke/Source/OpenFrameworksPort.cpp:201 (BespokeSynth+0xa86e4f)
    #2 DrawLissajous(RollingBuffer*, float, float, float, float, float, float, float) /home/jn/dev/synth/bespoke/Source/SynthGlobals.cpp:528 (BespokeSynth+0xc4dcd1)
    #3 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:514 (BespokeSynth+0x64fa42)
    #4 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #5 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #8 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #9 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#10 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#11 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#12 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056dc8 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11d3)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 in ModularSynth::GetPixelRatio() const
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer reports a race condition between LocationZoomer::Update() and ModularSynth::Draw():

   void LocationZoomer::Update()
   {
      if (mCurrentProgress < 1)
      {
         // ...
         gDrawScale = ofLerp(mStart.mZoomLevel, mDestination.mZoomLevel, ease); // A
         ofVec2f offset;
         offset.x = ofLerp(mStart.mOffset.x, mDestination.mOffset.x, ease);
         offset.y = ofLerp(mStart.mOffset.y, mDestination.mOffset.y, ease);
         TheSynth->SetDrawOffset(offset);                                       // B
         // ...
      }
   }

   void ModularSynth::Draw(void* vg)
   {
      // ...
      mDrawRect.set(-GetDrawOffset().x, -GetDrawOffset().y, ofGetWidth() / gDrawScale, ofGetHeight() / gDrawScale);
      // ...
   }


Draw() is called from the render thread, with the render lock held, and
Update() is called from the timer thread, without any locks held.

This commit changes LocationZoomer::Update to hold ModularSynth::mLockRender.

An partial alternative would be to:

 - change ModularSynth::SetDrawOffset() to hold mRenderLock automatically.
 - add locking to SynthGlobals.h, and take the lock for gDrawScale in
   LocationZoomer::Update()


```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 4 at 0x555557038004 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 (BespokeSynth+0x64dcaa)
    #1 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #2 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #4 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #5 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #6 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #7 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #8 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #9 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 4 at 0x555557038004 by main thread:
    #0 LocationZoomer::Update() /home/jn/dev/synth/bespoke/Source/LocationZoomer.cpp:57 (BespokeSynth+0x5c6e69)
    #1 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:345 (BespokeSynth+0x656a0a)
    #2 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f111b)
    #3 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #4 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #5 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #6 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #7 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #8 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #9 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    BespokeSynth#10 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    BespokeSynth#11 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#12 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#13 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#14 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#16 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#17 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#18 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#19 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#20 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is global 'gDrawScale' of size 4 at 0x555557038004 (BespokeSynth+0x1ae4004)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 in ModularSynth::Draw(void*)
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer identifies a few data races involving the ModularSynth::mPixelRatio
variable. For instance, appendix A, where MainContentComponent::render() reads
mPixelRatio while holding ModularSynth::mRenderLock:

   void render() override
   {
      mSynth.LockRender(true);
      // ...
      glViewport(0, 0, width * mPixelRatio, height * mPixelRatio);
      // ...
      mSynth.LockRender(false);
      // ...
   }

... but MainContentComponent::timerCallback() writes mPixelRatio without holding mRenderLock:

   void timerCallback() override
   {
      //...

      if (sRenderFrame % 30 == 0)
      {
         if (const auto* dpy = Desktop::getInstance().getDisplays().getDisplayForRect(getScreenBounds()))
         {
            mPixelRatio = dpy->scale; //adjust pixel ratio based on which screen has the majority of the window
            TheSynth->SetPixelRatio(mPixelRatio);
         }
      }

      // ...
   }

This commit changes ModularSynth::SetPixelRatio() to automatically hold
mRenderLock while accessing mPixelRatio.

ModularSynth::GetPixelRatio() is not changed to hold mRenderLock,
because it is declared const, which prohibits locking/unlocking.
Callers must ensure that GetPixelRatio() is called with mRenderLock
already held (such as in Appendix B).

This particular case may be benign, but it obscures other bugs in the flood of
output from ThreadSanitizer.


Appendix A:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056e48 by thread T9 (mutexes: write M19877):
    #0 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 (BespokeSynth+0x5f35aa)
    #1 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #2 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #4 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #5 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #6 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #7 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #8 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056e48 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11ad)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:357 in MainContentComponent::render()
```


Appendix B:

```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 8 at 0x7b8000056dc8 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::GetPixelRatio() const /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 (BespokeSynth+0xa86e4f)
    #1 ofSetColor(float, float, float, float) /home/jn/dev/synth/bespoke/Source/OpenFrameworksPort.cpp:201 (BespokeSynth+0xa86e4f)
    #2 DrawLissajous(RollingBuffer*, float, float, float, float, float, float, float) /home/jn/dev/synth/bespoke/Source/SynthGlobals.cpp:528 (BespokeSynth+0xc4dcd1)
    #3 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:514 (BespokeSynth+0x64fa42)
    #4 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #5 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #8 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #9 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#10 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#11 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#12 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 8 at 0x7b8000056dc8 by main thread:
    #0 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f11d3)
    #1 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #2 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #3 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #4 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #5 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #6 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #7 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    #8 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    #9 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#10 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#11 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#12 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#13 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#14 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#16 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#17 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#18 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is heap block of size 3688 at 0x7b8000056000 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 createMainContentComponent() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:588 (BespokeSynth+0x5f0c69)
    #2 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:101 (BespokeSynth+0x5f010a)
    #3 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f010a)
    #4 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f010a)
    #5 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    #6 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    #7 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    #8 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    #9 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.h:168 in ModularSynth::GetPixelRatio() const
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 12, 2023
ThreadSanitizer reports a race condition between LocationZoomer::Update() and ModularSynth::Draw():

   void LocationZoomer::Update()
   {
      if (mCurrentProgress < 1)
      {
         // ...
         gDrawScale = ofLerp(mStart.mZoomLevel, mDestination.mZoomLevel, ease); // A
         ofVec2f offset;
         offset.x = ofLerp(mStart.mOffset.x, mDestination.mOffset.x, ease);
         offset.y = ofLerp(mStart.mOffset.y, mDestination.mOffset.y, ease);
         TheSynth->SetDrawOffset(offset);                                       // B
         // ...
      }
   }

   void ModularSynth::Draw(void* vg)
   {
      // ...
      mDrawRect.set(-GetDrawOffset().x, -GetDrawOffset().y, ofGetWidth() / gDrawScale, ofGetHeight() / gDrawScale);
      // ...
   }


Draw() is called from the render thread, with the render lock held, and
Update() is called from the timer thread, without any locks held.

This commit changes LocationZoomer::Update to hold ModularSynth::mLockRender.

An partial alternative would be to:

 - change ModularSynth::SetDrawOffset() to hold mRenderLock automatically.
 - add locking to SynthGlobals.h, and take the lock for gDrawScale in
   LocationZoomer::Update()


```
WARNING: ThreadSanitizer: data race (pid=1608595)
  Read of size 4 at 0x555557038004 by thread T9 (mutexes: write M19877):
    #0 ModularSynth::Draw(void*) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 (BespokeSynth+0x64dcaa)
    #1 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:377 (BespokeSynth+0x5f37e7)
    #2 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #3 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #4 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #5 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    #6 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    #7 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    #8 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    #9 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Previous write of size 4 at 0x555557038004 by main thread:
    #0 LocationZoomer::Update() /home/jn/dev/synth/bespoke/Source/LocationZoomer.cpp:57 (BespokeSynth+0x5c6e69)
    #1 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:345 (BespokeSynth+0x656a0a)
    #2 non-virtual thunk to MainContentComponent::timerCallback() <null> (BespokeSynth+0x5f111b)
    #3 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115 (BespokeSynth+0xe63c3e)
    #4 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181 (BespokeSynth+0xe63d27)
    #5 juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42 (BespokeSynth+0xe64273)
    #6 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe64407)
    #7 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int>(juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}&, int&&) /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe64407)
    #8 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::{lambda(int)#1}>::_M_invoke(std::_Any_data const&, int&&) /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe64407)
    #9 std::function<void (int)>::operator()(int) const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe51c30)
    BespokeSynth#10 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359 (BespokeSynth+0xe51c30)
    BespokeSynth#11 __invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (BespokeSynth+0xe51c30)
    BespokeSynth#12 __invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void(int)>, short int)::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (BespokeSynth+0xe51c30)
    BespokeSynth#13 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (BespokeSynth+0xe51c30)
    BespokeSynth#14 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (BespokeSynth+0xe60bff)
    BespokeSynth#15 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182 (BespokeSynth+0xe60bff)
    BespokeSynth#16 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342 (BespokeSynth+0xe60bff)
    BespokeSynth#17 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109 (BespokeSynth+0xe60d7e)
    BespokeSynth#18 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262 (BespokeSynth+0x3f8c36)
    BespokeSynth#19 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#20 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

  Location is global 'gDrawScale' of size 4 at 0x555557038004 (BespokeSynth+0x1ae4004)

  Mutex M19877 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4324 (libtsan.so.2+0x558e1)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749 (BespokeSynth+0x5f34b6)
    #2 __gthread_recursive_mutex_lock /usr/include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811 (BespokeSynth+0x5f34b6)
    #3 std::recursive_mutex::lock() /usr/include/c++/12/mutex:108 (BespokeSynth+0x5f34b6)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226 (BespokeSynth+0x5f34b6)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:345 (BespokeSynth+0x5f34b6)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61 (BespokeSynth+0x13e6020)
    #7 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326 (BespokeSynth+0x13e6020)
    #8 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583 (BespokeSynth+0x13e6476)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384 (BespokeSynth+0xdc9896)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36 (BespokeSynth+0xe2550e)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (BespokeSynth+0xdd44c5)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (BespokeSynth+0xdd4655)
    BespokeSynth#13 threadEntryProc /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865 (BespokeSynth+0xdd4655)

  Thread T9 (tid=1608673, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919 (BespokeSynth+0xda95ef)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130 (BespokeSynth+0xdac173)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117 (BespokeSynth+0xdac4e8)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97 (BespokeSynth+0xdc9809)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x13dcb23)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163 (BespokeSynth+0x13dcb23)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039 (BespokeSynth+0x13dcb23)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016 (BespokeSynth+0x13dcb23)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952 (BespokeSynth+0x13dd249)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120 (BespokeSynth+0x113d764)
    BespokeSynth#11 operator() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#12 callChecked<juce::Component::sendVisibilityChangeMessage()::<lambda(juce::ComponentListener&)>, juce::Component::BailOutChecker> /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170 (BespokeSynth+0x1104d77)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631 (BespokeSynth+0x1104d77)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609 (BespokeSynth+0x117bf02)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105 (BespokeSynth+0x5f015d)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/include/c++/12/bits/unique_ptr.h:1065 (BespokeSynth+0x5f015d)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50 (BespokeSynth+0x5f015d)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297 (BespokeSynth+0xe612a0)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92 (BespokeSynth+0x11ee365)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256 (BespokeSynth+0x3f8c25)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240 (BespokeSynth+0x3f8cbe)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134 (BespokeSynth+0x38b9b8)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:491 in ModularSynth::Draw(void*)
```
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 21, 2023
==================
WARNING: ThreadSanitizer: data race (pid=795426)
  Read of size 4 at 0x7b6c00000e88 by thread T3 (mutexes: write M0):
    #0 IClickable::NotifyMouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 (BespokeSynth+0x60c873) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModuleContainer::MouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:182:20 (BespokeSynth+0xa7a6c4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModularSynth::MouseMoved(int, int) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:1288:24 (BespokeSynth+0x6b6d50) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:347:14 (BespokeSynth+0x6772f0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Previous write of size 4 at 0x7b6c00000e88 by main thread:
    #0 IClickable::SetPosition(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.h:44:10 (BespokeSynth+0x6b0333) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2421:19 (BespokeSynth+0x6b0333)
    #2 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    #9 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#11 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#13 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#15 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#16 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#18 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Location is heap block of size 1584 at 0x7b6c00000e00 allocated by main thread:
    #0 operator new(unsigned long) <null> (BespokeSynth+0x47ef66) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 Amplifier::Create() /home/jn/dev/synth/bespoke/Source/Amplifier.h:40:46 (BespokeSynth+0xa8f6b9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModuleFactory::MakeModule(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) /home/jn/dev/synth/bespoke/Source/ModuleFactory.cpp:522:17 (BespokeSynth+0xa8b5cd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 ModularSynth::CreateModule(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2524:37 (BespokeSynth+0x6bf7b8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 ModuleContainer::LoadModules(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:509:52 (BespokeSynth+0xa7cbb2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 ModularSynth::LoadLayout(ofxJSONElement) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2478:21 (BespokeSynth+0x6bec6b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2409:4 (BespokeSynth+0x6b00dc) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#16 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#18 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#19 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#20 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#21 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#23 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#24 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#25 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#26 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#27 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Mutex M0 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock <null> (BespokeSynth+0x41cb4a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749:12 (BespokeSynth+0x6772a5) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 __gthread_recursive_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811:10 (BespokeSynth+0x6772a5)
    #3 std::recursive_mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/mutex:108:17 (BespokeSynth+0x6772a5)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226:22 (BespokeSynth+0x6772a5)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:343:14 (BespokeSynth+0x6772a5)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #8 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#14 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Thread T3 'Pool' (tid=795985, running) created by main thread at:
    #0 pthread_create <null> (BespokeSynth+0x3fefbd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919:9 (BespokeSynth+0xe2a915) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130:9 (BespokeSynth+0xe2a7e6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117:12 (BespokeSynth+0xe2c21f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97:5 (BespokeSynth+0xe2bf05) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x14e2312) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163:28 (BespokeSynth+0x14e2312)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039:26 (BespokeSynth+0x14dcf04) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016:9 (BespokeSynth+0x14dcf04)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952:17 (BespokeSynth+0x14dd59f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120:13 (BespokeSynth+0x11b2127) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Component::sendVisibilityChangeMessage()::$_6::operator()(juce::ComponentListener&) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:84 (BespokeSynth+0x1162ade) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0> >::callChecked<juce::Component::sendVisibilityChangeMessage()::$_6, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::sendVisibilityChangeMessage()::$_6&&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170:13 (BespokeSynth+0x1162ade)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:28 (BespokeSynth+0x1162ade)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609:13 (BespokeSynth+0x1162446) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105:10 (BespokeSynth+0x66dac0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x66d45a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50:20 (BespokeSynth+0x66d45a)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297:5 (BespokeSynth+0xf149a8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92:30 (BespokeSynth+0x12842e9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256:16 (BespokeSynth+0xf146f2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 in IClickable::NotifyMouseMoved(float, float)
==================
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 21, 2023
Rejected approach: Introducing a ILockable class that contains the mutex
variable. This would result in diamond-shaped inheritance graphs sooner
or later, which can be resolved by declaring the inheritance as virtual,
but that would probably result in slower code than necessary.


==================
WARNING: ThreadSanitizer: data race (pid=795426)
  Read of size 4 at 0x7b6c00000e88 by thread T3 (mutexes: write M0):
    #0 IClickable::NotifyMouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 (BespokeSynth+0x60c873) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModuleContainer::MouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:182:20 (BespokeSynth+0xa7a6c4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModularSynth::MouseMoved(int, int) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:1288:24 (BespokeSynth+0x6b6d50) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:347:14 (BespokeSynth+0x6772f0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Previous write of size 4 at 0x7b6c00000e88 by main thread:
    #0 IClickable::SetPosition(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.h:44:10 (BespokeSynth+0x6b0333) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2421:19 (BespokeSynth+0x6b0333)
    #2 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    #9 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#11 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#13 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#15 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#16 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#18 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Location is heap block of size 1584 at 0x7b6c00000e00 allocated by main thread:
    #0 operator new(unsigned long) <null> (BespokeSynth+0x47ef66) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 Amplifier::Create() /home/jn/dev/synth/bespoke/Source/Amplifier.h:40:46 (BespokeSynth+0xa8f6b9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModuleFactory::MakeModule(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) /home/jn/dev/synth/bespoke/Source/ModuleFactory.cpp:522:17 (BespokeSynth+0xa8b5cd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 ModularSynth::CreateModule(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2524:37 (BespokeSynth+0x6bf7b8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 ModuleContainer::LoadModules(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:509:52 (BespokeSynth+0xa7cbb2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 ModularSynth::LoadLayout(ofxJSONElement) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2478:21 (BespokeSynth+0x6bec6b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2409:4 (BespokeSynth+0x6b00dc) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#16 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#18 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#19 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#20 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#21 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#23 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#24 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#25 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#26 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#27 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Mutex M0 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock <null> (BespokeSynth+0x41cb4a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749:12 (BespokeSynth+0x6772a5) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 __gthread_recursive_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811:10 (BespokeSynth+0x6772a5)
    #3 std::recursive_mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/mutex:108:17 (BespokeSynth+0x6772a5)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226:22 (BespokeSynth+0x6772a5)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:343:14 (BespokeSynth+0x6772a5)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #8 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#14 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Thread T3 'Pool' (tid=795985, running) created by main thread at:
    #0 pthread_create <null> (BespokeSynth+0x3fefbd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919:9 (BespokeSynth+0xe2a915) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130:9 (BespokeSynth+0xe2a7e6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117:12 (BespokeSynth+0xe2c21f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97:5 (BespokeSynth+0xe2bf05) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x14e2312) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163:28 (BespokeSynth+0x14e2312)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039:26 (BespokeSynth+0x14dcf04) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016:9 (BespokeSynth+0x14dcf04)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952:17 (BespokeSynth+0x14dd59f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120:13 (BespokeSynth+0x11b2127) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Component::sendVisibilityChangeMessage()::$_6::operator()(juce::ComponentListener&) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:84 (BespokeSynth+0x1162ade) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0> >::callChecked<juce::Component::sendVisibilityChangeMessage()::$_6, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::sendVisibilityChangeMessage()::$_6&&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170:13 (BespokeSynth+0x1162ade)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:28 (BespokeSynth+0x1162ade)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609:13 (BespokeSynth+0x1162446) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105:10 (BespokeSynth+0x66dac0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x66d45a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50:20 (BespokeSynth+0x66d45a)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297:5 (BespokeSynth+0xf149a8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92:30 (BespokeSynth+0x12842e9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256:16 (BespokeSynth+0xf146f2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 in IClickable::NotifyMouseMoved(float, float)
==================
neuschaefer added a commit to neuschaefer/BespokeSynth that referenced this issue Mar 23, 2023
Rejected approach: Introducing a ILockable class that contains the mutex
variable. This would result in diamond-shaped inheritance graphs sooner
or later, which can be resolved by declaring the inheritance as virtual,
but that would probably result in slower code than necessary.


==================
WARNING: ThreadSanitizer: data race (pid=795426)
  Read of size 4 at 0x7b6c00000e88 by thread T3 (mutexes: write M0):
    #0 IClickable::NotifyMouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 (BespokeSynth+0x60c873) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModuleContainer::MouseMoved(float, float) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:182:20 (BespokeSynth+0xa7a6c4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModularSynth::MouseMoved(int, int) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:1288:24 (BespokeSynth+0x6b6d50) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:347:14 (BespokeSynth+0x6772f0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #6 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Previous write of size 4 at 0x7b6c00000e88 by main thread:
    #0 IClickable::SetPosition(float, float) /home/jn/dev/synth/bespoke/Source/IClickable.h:44:10 (BespokeSynth+0x6b0333) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2421:19 (BespokeSynth+0x6b0333)
    #2 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    #9 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#11 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#13 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#15 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#16 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#18 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Location is heap block of size 1584 at 0x7b6c00000e00 allocated by main thread:
    #0 operator new(unsigned long) <null> (BespokeSynth+0x47ef66) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 Amplifier::Create() /home/jn/dev/synth/bespoke/Source/Amplifier.h:40:46 (BespokeSynth+0xa8f6b9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 ModuleFactory::MakeModule(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) /home/jn/dev/synth/bespoke/Source/ModuleFactory.cpp:522:17 (BespokeSynth+0xa8b5cd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 ModularSynth::CreateModule(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2524:37 (BespokeSynth+0x6bf7b8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 ModuleContainer::LoadModules(ofxJSONElement const&) /home/jn/dev/synth/bespoke/Source/ModuleContainer.cpp:509:52 (BespokeSynth+0xa7cbb2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 ModularSynth::LoadLayout(ofxJSONElement) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2478:21 (BespokeSynth+0x6bec6b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 ModularSynth::LoadLayoutFromFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:2409:4 (BespokeSynth+0x6b00dc) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 ModularSynth::Poll() /home/jn/dev/synth/bespoke/Source/ModularSynth.cpp:350:13 (BespokeSynth+0x6aeea4) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:127:14 (BespokeSynth+0x677771) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 non-virtual thunk to MainContentComponent::timerCallback() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp (BespokeSynth+0x677fd0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::Timer::TimerThread::callTimers() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:115:24 (BespokeSynth+0xf2426e) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Timer::TimerThread::CallTimersMessage::messageCallback() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/timers/juce_Timer.cpp:181:27 (BespokeSynth+0xf2404b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)::operator()(int) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:42:62 (BespokeSynth+0xf270d7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 void std::__invoke_impl<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(std::__invoke_other, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf270d7)
    BespokeSynth#14 std::enable_if<is_invocable_r_v<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>, void>::type std::__invoke_r<void, juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int>(juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf26fb0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 std::_Function_handler<void (int), juce::InternalMessageQueue::InternalMessageQueue()::'lambda'(int)>::_M_invoke(std::_Any_data const&, int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf26fb0)
    BespokeSynth#16 std::function<void (int)>::operator()(int) const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf209be) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3::operator()() const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:359:80 (BespokeSynth+0xf209be)
    BespokeSynth#18 void std::__invoke_impl<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(std::__invoke_other, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:61:14 (BespokeSynth+0xf209be)
    BespokeSynth#19 std::enable_if<is_invocable_r_v<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>, void>::type std::__invoke_r<void, juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&>(juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/invoke.h:111:2 (BespokeSynth+0xf209be)
    BespokeSynth#20 std::_Function_handler<void (), juce::LinuxEventLoop::registerFdCallback(int, std::function<void (int)>, short)::$_3>::_M_invoke(std::_Any_data const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:290:9 (BespokeSynth+0xf209be)
    BespokeSynth#21 std::function<void ()>::operator()() const /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/std_function.h:591:9 (BespokeSynth+0xf218c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 juce::InternalRunLoop::dispatchPendingEvents() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:182:13 (BespokeSynth+0xf218c9)
    BespokeSynth#23 juce::dispatchNextMessageOnSystemQueue(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:342:26 (BespokeSynth+0xf15ab7) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#24 juce::MessageManager::runDispatchLoop() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:109:19 (BespokeSynth+0xf1473d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#25 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:262:40 (BespokeSynth+0xf1473d)
    BespokeSynth#26 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#27 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

  Mutex M0 (0x7b8000056ce0) created at:
    #0 pthread_mutex_lock <null> (BespokeSynth+0x41cb4a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:749:12 (BespokeSynth+0x6772a5) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 __gthread_recursive_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12/bits/gthr-default.h:811:10 (BespokeSynth+0x6772a5)
    #3 std::recursive_mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/mutex:108:17 (BespokeSynth+0x6772a5)
    #4 ModularSynth::LockRender(bool) /home/jn/dev/synth/bespoke/Source/ModularSynth.h:226:22 (BespokeSynth+0x6772a5)
    #5 MainContentComponent::render() /home/jn/dev/synth/bespoke/Source/MainComponent.cpp:343:14 (BespokeSynth+0x6772a5)
    #6 juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp:61:5 (BespokeSynth+0x14c8c72) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #7 non-virtual thunk to juce::OpenGLAppComponent::renderOpenGL() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/utils/juce_OpenGLAppComponent.cpp (BespokeSynth+0x14c8c72)
    #8 juce::OpenGLContext::CachedImage::renderFrame() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:326:31 (BespokeSynth+0x14e1113) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #9 juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:583:19 (BespokeSynth+0x14df030) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp (BespokeSynth+0x14df19d) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:384:27 (BespokeSynth+0xe2e78b) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 juce::ThreadPool::ThreadPoolThread::run() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:36:24 (BespokeSynth+0xeaedd9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#13 juce::Thread::threadEntryPoint() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:96:13 (BespokeSynth+0xe2a2c6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#14 juce::juce_threadEntryPoint(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:118:38 (BespokeSynth+0xe6c3c9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 juce::threadEntryProc(void*) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:865:9 (BespokeSynth+0xe6c3c9)

  Thread T3 'Pool' (tid=795985, running) created by main thread at:
    #0 pthread_create <null> (BespokeSynth+0x3fefbd) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #1 juce::Thread::launchThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:919:9 (BespokeSynth+0xe2a915) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #2 juce::Thread::startThread() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_Thread.cpp:130:9 (BespokeSynth+0xe2a7e6) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #3 juce::ThreadPool::createThreads(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:117:12 (BespokeSynth+0xe2c21f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #4 juce::ThreadPool::ThreadPool(int, unsigned long) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/threads/juce_ThreadPool.cpp:97:5 (BespokeSynth+0xe2bf05) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #5 std::__detail::_MakeUniq<juce::ThreadPool>::__single_object std::make_unique<juce::ThreadPool, int>(int&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x14e2312) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #6 juce::OpenGLContext::CachedImage::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:163:28 (BespokeSynth+0x14e2312)
    #7 juce::OpenGLContext::Attachment::start() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1039:26 (BespokeSynth+0x14dcf04) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    #8 juce::OpenGLContext::Attachment::attach() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:1016:9 (BespokeSynth+0x14dcf04)
    #9 juce::OpenGLContext::Attachment::componentVisibilityChanged() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_opengl/opengl/juce_OpenGLContext.cpp:952:17 (BespokeSynth+0x14dd59f) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#10 juce::ComponentMovementWatcher::componentVisibilityChanged(juce::Component&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/layout/juce_ComponentMovementWatcher.cpp:120:13 (BespokeSynth+0x11b2127) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#11 juce::Component::sendVisibilityChangeMessage()::$_6::operator()(juce::ComponentListener&) const /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:84 (BespokeSynth+0x1162ade) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#12 void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0> >::callChecked<juce::Component::sendVisibilityChangeMessage()::$_6, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::sendVisibilityChangeMessage()::$_6&&) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_core/containers/juce_ListenerList.h:170:13 (BespokeSynth+0x1162ade)
    BespokeSynth#13 juce::Component::sendVisibilityChangeMessage() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:631:28 (BespokeSynth+0x1162ade)
    BespokeSynth#14 juce::Component::setVisible(bool) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:609:13 (BespokeSynth+0x1162446) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#15 BespokeApplication::MainWindow::MainWindow(juce::String) /home/jn/dev/synth/bespoke/Source/Main.cpp:105:10 (BespokeSynth+0x66dac0) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#16 std::__detail::_MakeUniq<BespokeApplication::MainWindow>::__single_object std::make_unique<BespokeApplication::MainWindow, char const (&) [14]>(char const (&) [14]) /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34 (BespokeSynth+0x66d45a) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#17 BespokeApplication::initialise(juce::String const&) /home/jn/dev/synth/bespoke/Source/Main.cpp:50:20 (BespokeSynth+0x66d45a)
    BespokeSynth#18 juce::JUCEApplicationBase::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297:5 (BespokeSynth+0xf149a8) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#19 juce::JUCEApplication::initialiseApp() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92:30 (BespokeSynth+0x12842e9) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#20 juce::JUCEApplicationBase::main() /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256:16 (BespokeSynth+0xf146f2) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#21 juce::JUCEApplicationBase::main(int, char const**) /home/jn/dev/synth/bespoke/libs/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240:16 (BespokeSynth+0xf14660) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)
    BespokeSynth#22 main /home/jn/dev/synth/bespoke/Source/Main.cpp:134:1 (BespokeSynth+0x66d0da) (BuildId: bf42b258c9ff339def937105d642b7193dbc302b)

SUMMARY: ThreadSanitizer: data race /home/jn/dev/synth/bespoke/Source/IClickable.cpp:74:26 in IClickable::NotifyMouseMoved(float, float)
==================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants