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

Fix thread safety/data races between game and sound effect mixer threads #10147

Merged
merged 3 commits into from Nov 11, 2022

Conversation

JGRennison
Copy link
Contributor

@JGRennison JGRennison commented Nov 7, 2022

Motivation / Problem

There were data races on the MixerChannel active states. Marking a channel active form the game thread side was not properly synchronised with checking if it was active from the mixer thread, and vice versa when the mixer thread marked it no longer active.
Less importantly, the effect volume setting was not updated in a technically thread safe manner.

ThreadSanitizer output
==================
WARNING: ThreadSanitizer: data race (pid=643182)
  Write of size 1 at 0x557a9e63bbc6 by thread T17 (mutexes: write M3621):
    #0 WriteValue(void*, unsigned int, long long) /home/jgr/openttd/trunk/src/saveload/saveload.cpp:833 (openttd+0x15c3c0c)
    #1 IntSettingDesc::Write(void const*, int) const /home/jgr/openttd/trunk/src/settings.cpp:511 (openttd+0x1c5503e)
    #2 IntSettingDesc::MakeValueValidAndWrite(void const*, int) const /home/jgr/openttd/trunk/src/settings.cpp:443 (openttd+0x1c54c04)
    #3 IntSettingDesc::ParseValue(IniItem const*, void*) const /home/jgr/openttd/trunk/src/settings.cpp:612 (openttd+0x1c558fe)
    #4 IniLoadSettings /home/jgr/openttd/trunk/src/settings.cpp:605 (openttd+0x1c5574f)
    #5 HandleSettingDescs /home/jgr/openttd/trunk/src/settings.cpp:1159 (openttd+0x1c59113)
    #6 LoadFromConfig(bool) /home/jgr/openttd/trunk/src/settings.cpp:1222 (openttd+0x1c595f2)
    #7 AfterNewGRFScan::OnNewGRFsScanned() /home/jgr/openttd/trunk/src/openttd.cpp:440 (openttd+0x1b91c97)
    #8 DoScanNewGRFFiles(NewGRFScanCallback*) /home/jgr/openttd/trunk/src/newgrf_config.cpp:716 (openttd+0x1abba1a)
    #9 ScanNewGRFFiles(NewGRFScanCallback*) /home/jgr/openttd/trunk/src/newgrf_config.cpp:734 (openttd+0x1abbb2f)
    #10 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1453 (openttd+0x1b8f6e0)
    #11 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:37 (openttd+0x16b9fab)
    #12 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:44 (openttd+0x16ba031)
    #13 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:81 (openttd+0x16ba1a4)
    #14 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:65 (openttd+0x16bb89b)
    #15 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/9/bits/invoke.h:60 (openttd+0x16bcf7e)
    #16 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/9/bits/invoke.h:95 (openttd+0x16bcda7)
    #17 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/9/thread:244 (openttd+0x16bcbe4)
    #18 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/9/thread:251 (openttd+0x16bcb32)
    #19 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/9/thread:195 (openttd+0x16bcae4)
    #20 <null> <null> (libstdc++.so.6+0xd6de3)

  Previous read of size 1 at 0x557a9e63bbc6 by thread T16 (mutexes: write M3544):
    #0 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:167 (openttd+0x1a05c9f)
    #1 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e8d5)
    #2 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Location is global '_settings_client' of size 640 at 0x557a9e63b9a0 (openttd+0x000005bf2bc6)

  Mutex M3621 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0633)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d234a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d6388)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba732)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aaf76)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16aaff3)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Mutex M3544 (0x7b0c000390f0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T17 'ottd:game' (tid=643228, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:53 (openttd+0x16bb9ea)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:87 (openttd+0x16ba2be)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:634 (openttd+0x16aafd4)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T16 'SDLAudioP2' (tid=643227, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/saveload/saveload.cpp:833 in WriteValue(void*, unsigned int, long long)
==================
==================
WARNING: ThreadSanitizer: data race (pid=643182)
  Write of size 1 at 0x557a9bd803e0 by thread T17 (mutexes: write M3621):
    #0 MxActivateChannel(MixerChannel*) /home/jgr/openttd/trunk/src/mixer.cpp:234 (openttd+0x1a06149)
    #1 StartSound /home/jgr/openttd/trunk/src/sound.cpp:193 (openttd+0x1d58f3a)
    #2 SndPlayScreenCoordFx /home/jgr/openttd/trunk/src/sound.cpp:259 (openttd+0x1d5933c)
    #3 SndPlayVehicleFx(unsigned short, Vehicle const*) /home/jgr/openttd/trunk/src/sound.cpp:283 (openttd+0x1d595ff)
    #4 Train::PlayLeaveStationSound() const /home/jgr/openttd/trunk/src/train_cmd.cpp:2116 (openttd+0x1ed1b58)
    #5 Vehicle::HandleLoading(bool) /home/jgr/openttd/trunk/src/vehicle.cpp:2333 (openttd+0x1f068db)
    #6 TrainLocoHandler /home/jgr/openttd/trunk/src/train_cmd.cpp:3870 (openttd+0x1ed8a46)
    #7 Train::Tick() /home/jgr/openttd/trunk/src/train_cmd.cpp:4007 (openttd+0x1ed943c)
    #8 CallVehicleTicks() /home/jgr/openttd/trunk/src/vehicle.cpp:973 (openttd+0x1effccf)
    #9 StateGameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1396 (openttd+0x1b8f316)
    #10 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1492 (openttd+0x1b8f929)
    #11 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:37 (openttd+0x16b9fab)
    #12 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:44 (openttd+0x16ba031)
    #13 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:81 (openttd+0x16ba1a4)
    #14 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:65 (openttd+0x16bb89b)
    #15 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/9/bits/invoke.h:60 (openttd+0x16bcf7e)
    #16 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/9/bits/invoke.h:95 (openttd+0x16bcda7)
    #17 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/9/thread:244 (openttd+0x16bcbe4)
    #18 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/9/thread:251 (openttd+0x16bcb32)
    #19 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/9/thread:195 (openttd+0x16bcae4)
    #20 <null> <null> (libstdc++.so.6+0xd6de3)

  Previous read of size 1 at 0x557a9bd803e0 by thread T16 (mutexes: write M3544):
    #0 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:173 (openttd+0x1a05d20)
    #1 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e8d5)
    #2 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Location is global '_channels' of size 384 at 0x557a9bd803e0 (openttd+0x0000033373e0)

  Mutex M3621 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0633)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d234a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d6388)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba732)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aaf76)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16aaff3)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Mutex M3544 (0x7b0c000390f0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T17 'ottd:game' (tid=643228, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:53 (openttd+0x16bb9ea)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:87 (openttd+0x16ba2be)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:634 (openttd+0x16aafd4)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T16 'SDLAudioP2' (tid=643227, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/mixer.cpp:234 in MxActivateChannel(MixerChannel*)
==================
==================
WARNING: ThreadSanitizer: data race (pid=643182)
  Read of size 1 at 0x557a9bd80408 by thread T16 (mutexes: write M3544):
    #0 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:174 (openttd+0x1a05d3b)
    #1 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e8d5)
    #2 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Previous write of size 1 at 0x557a9bd80408 by thread T17 (mutexes: write M3621):
    #0 MxSetChannelRawSrc(MixerChannel*, signed char*, unsigned long, unsigned int, bool) /home/jgr/openttd/trunk/src/mixer.cpp:214 (openttd+0x1a05fef)
    #1 SetBankSource /home/jgr/openttd/trunk/src/sound.cpp:153 (openttd+0x1d58bf6)
    #2 StartSound /home/jgr/openttd/trunk/src/sound.cpp:187 (openttd+0x1d58eeb)
    #3 SndPlayScreenCoordFx /home/jgr/openttd/trunk/src/sound.cpp:259 (openttd+0x1d5933c)
    #4 SndPlayVehicleFx(unsigned short, Vehicle const*) /home/jgr/openttd/trunk/src/sound.cpp:283 (openttd+0x1d595ff)
    #5 Train::PlayLeaveStationSound() const /home/jgr/openttd/trunk/src/train_cmd.cpp:2116 (openttd+0x1ed1b58)
    #6 Vehicle::HandleLoading(bool) /home/jgr/openttd/trunk/src/vehicle.cpp:2333 (openttd+0x1f068db)
    #7 TrainLocoHandler /home/jgr/openttd/trunk/src/train_cmd.cpp:3870 (openttd+0x1ed8a46)
    #8 Train::Tick() /home/jgr/openttd/trunk/src/train_cmd.cpp:4007 (openttd+0x1ed943c)
    #9 CallVehicleTicks() /home/jgr/openttd/trunk/src/vehicle.cpp:973 (openttd+0x1effccf)
    #10 StateGameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1396 (openttd+0x1b8f316)
    #11 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1492 (openttd+0x1b8f929)
    #12 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:37 (openttd+0x16b9fab)
    #13 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:44 (openttd+0x16ba031)
    #14 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:81 (openttd+0x16ba1a4)
    #15 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:65 (openttd+0x16bb89b)
    #16 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/9/bits/invoke.h:60 (openttd+0x16bcf7e)
    #17 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/9/bits/invoke.h:95 (openttd+0x16bcda7)
    #18 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/9/thread:244 (openttd+0x16bcbe4)
    #19 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/9/thread:251 (openttd+0x16bcb32)
    #20 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/9/thread:195 (openttd+0x16bcae4)
    #21 <null> <null> (libstdc++.so.6+0xd6de3)

  Location is global '_channels' of size 384 at 0x557a9bd803e0 (openttd+0x000003337408)

  Mutex M3544 (0x7b0c000390f0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Mutex M3621 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0633)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d234a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d6388)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba732)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aaf76)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16aaff3)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T16 'SDLAudioP2' (tid=643227, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T17 'ottd:game' (tid=643228, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:53 (openttd+0x16bb9ea)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:87 (openttd+0x16ba2be)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:634 (openttd+0x16aafd4)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/mixer.cpp:174 in MxMixSamples(void*, unsigned int)
==================
==================
WARNING: ThreadSanitizer: data race (pid=643182)
  Read of size 4 at 0x557a9bd803fc by thread T16 (mutexes: write M3544):
    #0 mix_int16 /home/jgr/openttd/trunk/src/mixer.cpp:68 (openttd+0x1a053db)
    #1 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:175 (openttd+0x1a05d5e)
    #2 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e8d5)
    #3 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Previous write of size 4 at 0x557a9bd803fc by thread T17 (mutexes: write M3621):
    #0 MxSetChannelRawSrc(MixerChannel*, signed char*, unsigned long, unsigned int, bool) /home/jgr/openttd/trunk/src/mixer.cpp:213 (openttd+0x1a05fd8)
    #1 SetBankSource /home/jgr/openttd/trunk/src/sound.cpp:153 (openttd+0x1d58bf6)
    #2 StartSound /home/jgr/openttd/trunk/src/sound.cpp:187 (openttd+0x1d58eeb)
    #3 SndPlayScreenCoordFx /home/jgr/openttd/trunk/src/sound.cpp:259 (openttd+0x1d5933c)
    #4 SndPlayVehicleFx(unsigned short, Vehicle const*) /home/jgr/openttd/trunk/src/sound.cpp:283 (openttd+0x1d595ff)
    #5 Train::PlayLeaveStationSound() const /home/jgr/openttd/trunk/src/train_cmd.cpp:2116 (openttd+0x1ed1b58)
    #6 Vehicle::HandleLoading(bool) /home/jgr/openttd/trunk/src/vehicle.cpp:2333 (openttd+0x1f068db)
    #7 TrainLocoHandler /home/jgr/openttd/trunk/src/train_cmd.cpp:3870 (openttd+0x1ed8a46)
    #8 Train::Tick() /home/jgr/openttd/trunk/src/train_cmd.cpp:4007 (openttd+0x1ed943c)
    #9 CallVehicleTicks() /home/jgr/openttd/trunk/src/vehicle.cpp:973 (openttd+0x1effccf)
    #10 StateGameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1396 (openttd+0x1b8f316)
    #11 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1492 (openttd+0x1b8f929)
    #12 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:37 (openttd+0x16b9fab)
    #13 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:44 (openttd+0x16ba031)
    #14 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:81 (openttd+0x16ba1a4)
    #15 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:65 (openttd+0x16bb89b)
    #16 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/9/bits/invoke.h:60 (openttd+0x16bcf7e)
    #17 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/9/bits/invoke.h:95 (openttd+0x16bcda7)
    #18 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/9/thread:244 (openttd+0x16bcbe4)
    #19 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/9/thread:251 (openttd+0x16bcb32)
    #20 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/9/thread:195 (openttd+0x16bcae4)
    #21 <null> <null> (libstdc++.so.6+0xd6de3)

  Location is global '_channels' of size 384 at 0x557a9bd803e0 (openttd+0x0000033373fc)

  Mutex M3544 (0x7b0c000390f0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Mutex M3621 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0633)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d234a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d6388)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba732)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aaf76)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16aaff3)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T16 'SDLAudioP2' (tid=643227, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T17 'ottd:game' (tid=643228, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:53 (openttd+0x16bb9ea)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:87 (openttd+0x16ba2be)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:634 (openttd+0x16aafd4)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/mixer.cpp:68 in mix_int16
==================
==================
WARNING: ThreadSanitizer: data race (pid=643182)
  Write of size 1 at 0x557a9bd80440 by thread T17 (mutexes: write M3621):
    #0 MxActivateChannel(MixerChannel*) /home/jgr/openttd/trunk/src/mixer.cpp:234 (openttd+0x1a06149)
    #1 StartSound /home/jgr/openttd/trunk/src/sound.cpp:193 (openttd+0x1d58f3a)
    #2 SndPlayScreenCoordFx /home/jgr/openttd/trunk/src/sound.cpp:259 (openttd+0x1d5933c)
    #3 SndPlayVehicleFx(unsigned short, Vehicle const*) /home/jgr/openttd/trunk/src/sound.cpp:283 (openttd+0x1d595ff)
    #4 PlayShipSound /home/jgr/openttd/trunk/src/ship_cmd.cpp:278 (openttd+0x1d232e9)
    #5 Ship::PlayLeaveStationSound() const /home/jgr/openttd/trunk/src/ship_cmd.cpp:284 (openttd+0x1d23338)
    #6 Vehicle::HandleLoading(bool) /home/jgr/openttd/trunk/src/vehicle.cpp:2333 (openttd+0x1f068db)
    #7 ShipController /home/jgr/openttd/trunk/src/ship_cmd.cpp:658 (openttd+0x1d24a7a)
    #8 Ship::Tick() /home/jgr/openttd/trunk/src/ship_cmd.cpp:841 (openttd+0x1d25902)
    #9 CallVehicleTicks() /home/jgr/openttd/trunk/src/vehicle.cpp:973 (openttd+0x1effccf)
    #10 StateGameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1396 (openttd+0x1b8f316)
    #11 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1492 (openttd+0x1b8f929)
    #12 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:37 (openttd+0x16b9fab)
    #13 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:44 (openttd+0x16ba031)
    #14 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:81 (openttd+0x16ba1a4)
    #15 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:65 (openttd+0x16bb89b)
    #16 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/9/bits/invoke.h:60 (openttd+0x16bcf7e)
    #17 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/9/bits/invoke.h:95 (openttd+0x16bcda7)
    #18 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/9/thread:244 (openttd+0x16bcbe4)
    #19 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/9/thread:251 (openttd+0x16bcb32)
    #20 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/9/thread:195 (openttd+0x16bcae4)
    #21 <null> <null> (libstdc++.so.6+0xd6de3)

  Previous read of size 1 at 0x557a9bd80440 by thread T16 (mutexes: write M3544):
    #0 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:173 (openttd+0x1a05d20)
    #1 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e8d5)
    #2 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Location is global '_channels' of size 384 at 0x557a9bd803e0 (openttd+0x000003337440)

  Mutex M3621 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0633)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d234a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d6388)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba732)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aaf76)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16aaff3)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Mutex M3544 (0x7b0c000390f0) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T17 'ottd:game' (tid=643228, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:53 (openttd+0x16bb9ea)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:87 (openttd+0x16ba2be)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:634 (openttd+0x16aafd4)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:813 (openttd+0x1b8ae4f)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

  Thread T16 'SDLAudioP2' (tid=643227, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e583e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e53c0)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:800 (openttd+0x1b8ad7b)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488dd5)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/mixer.cpp:234 in MxActivateChannel(MixerChannel*)
==================

The reporting of performance measurements via PerformanceMeasurer framerate(PFE_SOUND) was also not thread safe.

ThreadSanitizer output (performance measurement)
==================
==================
WARNING: ThreadSanitizer: data race (pid=734716)
  Read of size 4 at 0x556dabf0b8c8 by main thread (mutexes: write M1016, write M1017):
    #0 FramerateWindow::UpdateWidgetSize(int, Dimension*, Dimension const&, Dimension*, Dimension*) /home/jgr/openttd/trunk/src/framerate_gui.cpp:552 (openttd+0x184eb22)
    #1 NWidgetLeaf::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:2634 (openttd+0x1f9d891)
    #2 NWidgetHorizontal::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1269 (openttd+0x1f940e7)
    #3 NWidgetVertical::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1454 (openttd+0x1f954df)
    #4 NWidgetVertical::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1454 (openttd+0x1f954df)
    #5 NWidgetBackground::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1934 (openttd+0x1f98e62)
    #6 NWidgetHorizontal::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1269 (openttd+0x1f940e7)
    #7 NWidgetVertical::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1454 (openttd+0x1f954df)
    #8 NWidgetStacked::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1125 (openttd+0x1f93089)
    #9 NWidgetVertical::SetupSmallestSize(Window*, bool) /home/jgr/openttd/trunk/src/widget.cpp:1454 (openttd+0x1f954df)
    #10 Window::InitializeData(int) /home/jgr/openttd/trunk/src/window.cpp:1411 (openttd+0x1fa7f54)
    #11 Window::FinishInitNested(int) /home/jgr/openttd/trunk/src/window.cpp:1778 (openttd+0x1faa89c)
    #12 Window::InitNested(int) /home/jgr/openttd/trunk/src/window.cpp:1792 (openttd+0x1faaab1)
    #13 FramerateWindow::FramerateWindow(WindowDesc*, int) /home/jgr/openttd/trunk/src/framerate_gui.cpp:433 (openttd+0x184e0fc)
    #14 FramerateWindow* AllocateWindowDescFront<FramerateWindow>(WindowDesc*, int, bool) /home/jgr/openttd/trunk/src/window_gui.h:944 (openttd+0x1850fa8)
    #15 ShowFramerateWindow() /home/jgr/openttd/trunk/src/framerate_gui.cpp:1009 (openttd+0x184c3c1)
    #16 ConFramerateWindow /home/jgr/openttd/trunk/src/console_cmds.cpp:2286 (openttd+0x17938ca)
    #17 IConsoleCmdExec(char const*, unsigned int) /home/jgr/openttd/trunk/src/console.cpp:394 (openttd+0x17799cd)
    #18 IConsoleWindow::OnKeyPress(char32_t, unsigned short) /home/jgr/openttd/trunk/src/console_gui.cpp:249 (openttd+0x17b8c5d)
    #19 HandleKeypress(unsigned int, char32_t) /home/jgr/openttd/trunk/src/window.cpp:2634 (openttd+0x1faf89f)
    #20 VideoDriver_SDL_Base::PollEvent() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:451 (openttd+0x16aa3d0)
    #21 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:133 (openttd+0x16ba7b1)
    #22 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aafb6)
    #23 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16ab033)
    #24 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:815 (openttd+0x1b8b5b9)
    #25 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488e15)

  Previous write of size 4 at 0x556dabf0b8c8 by thread T2 (mutexes: write M940):
    #0 Add /home/jgr/openttd/trunk/src/framerate_gui.cpp:79 (openttd+0x184b466)
    #1 PerformanceMeasurer::~PerformanceMeasurer() /home/jgr/openttd/trunk/src/framerate_gui.cpp:254 (openttd+0x184bf7e)
    #2 MxMixSamples(void*, unsigned int) /home/jgr/openttd/trunk/src/mixer.cpp:146 (openttd+0x1a05f1f)
    #3 fill_sound_buffer /home/jgr/openttd/trunk/src/sound/sdl2_s.cpp:31 (openttd+0x168e915)
    #4 <null> <null> (libSDL2-2.0.so.0+0x2556e)

  Location is global '(anonymous namespace)::_pf_data' of size 238728 at 0x556dabef3700 (openttd+0x0000032c68c8)

  Mutex M1016 (0x7b6800000060) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0673)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d238a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d63c8)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:124 (openttd+0x16ba75b)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aafb6)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16ab033)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:815 (openttd+0x1b8b5b9)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488e15)

  Mutex M1017 (0x7b6800000038) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4165 (libtsan.so.0+0x526fc)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:749 (openttd+0x11d0673)
    #2 std::mutex::lock() /usr/include/c++/9/bits/std_mutex.h:100 (openttd+0x11d238a)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/9/bits/std_mutex.h:159 (openttd+0x11d63c8)
    #4 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:125 (openttd+0x16ba772)
    #5 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:619 (openttd+0x16aafb6)
    #6 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:637 (openttd+0x16ab033)
    #7 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:815 (openttd+0x1b8b5b9)
    #8 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488e15)

  Mutex M940 (0x7b0c0000d980) created at:
    #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1220 (libtsan.so.0+0x4a616)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee6e6)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e587e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e5400)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:802 (openttd+0x1b8b4e5)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488e15)

  Thread T2 'SDLAudioP2' (tid=734890, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5ea79)
    #1 <null> <null> (libSDL2-2.0.so.0+0xee1ba)
    #2 DriverFactoryBase::SelectDriverImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:122 (openttd+0x17e587e)
    #3 DriverFactoryBase::SelectDriver(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Driver::Type) /home/jgr/openttd/trunk/src/driver.cpp:87 (openttd+0x17e5400)
    #4 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:802 (openttd+0x1b8b4e5)
    #5 main /home/jgr/openttd/trunk/src/os/unix/unix.cpp:262 (openttd+0x1488e15)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/framerate_gui.cpp:552 in FramerateWindow::UpdateWidgetSize(int, Dimension*, Dimension const&, Dimension*, Dimension*)
==================

Description

Use a std::atomic for mixer channel active states, with proper ordering semantic so that the MixerChannel access is thread-safe.
Use a std::atomic for the effect volume (in a similar way to how music volume is handled).
Store PFE_SOUND measurements into a mutex-protected buffer which is then drained by the main thread.

Limitations

N/A

Checklist for review

Some things are not automated, and forgotten often. This list is a reminder for the reviewers.

  • The bug fix is important enough to be backported? (label: 'backport requested')
  • This PR touches english.txt or translations? Check the guidelines
  • This PR affects the save game format? (label 'savegame upgrade')
  • This PR affects the GS/AI API? (label 'needs review: Script API')
    • ai_changelog.hpp, gs_changelog.hpp need updating.
    • The compatibility wrappers (compat_*.nut) need updating.
  • This PR affects the NewGRF API? (label 'needs review: NewGRF')

@@ -1079,3 +1096,15 @@ void ConPrintFramerate()
IConsolePrint(CC_ERROR, "No performance measurements have been taken yet.");
}
}

void ProcessPendingPerformanceMeasurements()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to have some comments explaining why only the sound performance stuff is ever "pending"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some explanatory text

src/mixer.cpp Show resolved Hide resolved
@michicc michicc merged commit 64b437f into OpenTTD:master Nov 11, 2022
PeterN added a commit to PeterN/OpenTTD that referenced this pull request Dec 10, 2022
@JGRennison JGRennison deleted the fix-sound-mixer-data-races branch January 9, 2024 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants