From 587e07007d91e226a905eed658b2c0c131abe3e3 Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Mon, 5 Jun 2023 16:32:25 +0100 Subject: [PATCH] HighResolutionTimer: Complete rewrite - added unit tests - best performance timers used for each platform - fixed an issue in which timer callbacks could drift --- .../Builds/Android/app/CMakeLists.txt | 14 + .../VisualStudio2017/DemoRunner_App.vcxproj | 14 + .../DemoRunner_App.vcxproj.filters | 21 + .../VisualStudio2019/DemoRunner_App.vcxproj | 14 + .../DemoRunner_App.vcxproj.filters | 21 + .../VisualStudio2022/DemoRunner_App.vcxproj | 14 + .../DemoRunner_App.vcxproj.filters | 21 + .../Builds/Android/app/CMakeLists.txt | 14 + .../AudioPerformanceTest_App.vcxproj | 14 + .../AudioPerformanceTest_App.vcxproj.filters | 21 + .../Builds/Android/app/CMakeLists.txt | 14 + .../AudioPluginHost_App.vcxproj | 14 + .../AudioPluginHost_App.vcxproj.filters | 21 + .../AudioPluginHost_App.vcxproj | 14 + .../AudioPluginHost_App.vcxproj.filters | 21 + .../AudioPluginHost_App.vcxproj | 14 + .../AudioPluginHost_App.vcxproj.filters | 21 + .../BinaryBuilder_ConsoleApp.vcxproj | 14 + .../BinaryBuilder_ConsoleApp.vcxproj.filters | 21 + .../Builds/Android/app/CMakeLists.txt | 14 + .../NetworkGraphicsDemo_App.vcxproj | 14 + .../NetworkGraphicsDemo_App.vcxproj.filters | 21 + .../VisualStudio2017/Projucer_App.vcxproj | 14 + .../Projucer_App.vcxproj.filters | 21 + .../VisualStudio2019/Projucer_App.vcxproj | 14 + .../Projucer_App.vcxproj.filters | 21 + .../VisualStudio2022/Projucer_App.vcxproj | 14 + .../Projucer_App.vcxproj.filters | 21 + .../UnitTestRunner_ConsoleApp.vcxproj | 14 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 21 + .../UnitTestRunner_ConsoleApp.vcxproj | 14 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 21 + .../UnitTestRunner_ConsoleApp.vcxproj | 14 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 21 + .../WindowsDLL_StaticLibrary.vcxproj | 14 + .../WindowsDLL_StaticLibrary.vcxproj.filters | 21 + modules/juce_core/juce_core.cpp | 30 +- modules/juce_core/juce_core.h | 2 +- .../native/juce_BasicNativeHeaders.h | 10 +- .../native/juce_FileDescriptor_linux.cpp | 159 +++++++ .../native/juce_HighResolutionTimerThread.h | 63 +++ .../native/juce_PlatformTimerListener.h | 32 ++ .../native/juce_PlatformTimer_linux.cpp | 88 ++++ .../native/juce_PlatformTimer_mac.mm | 118 +++++ .../native/juce_PlatformTimer_wasm.cpp | 111 +++++ .../native/juce_PlatformTimer_windows.cpp | 68 +++ .../juce_core/native/juce_SharedCode_posix.h | 6 +- .../juce_core/native/juce_Threads_android.cpp | 2 - .../threads/juce_HighResolutionTimer.cpp | 417 +++++++++++++++--- .../threads/juce_HighResolutionTimer.h | 32 +- 50 files changed, 1679 insertions(+), 75 deletions(-) create mode 100644 modules/juce_core/native/juce_FileDescriptor_linux.cpp create mode 100644 modules/juce_core/native/juce_HighResolutionTimerThread.h create mode 100644 modules/juce_core/native/juce_PlatformTimerListener.h create mode 100644 modules/juce_core/native/juce_PlatformTimer_linux.cpp create mode 100644 modules/juce_core/native/juce_PlatformTimer_mac.mm create mode 100644 modules/juce_core/native/juce_PlatformTimer_wasm.cpp create mode 100644 modules/juce_core/native/juce_PlatformTimer_windows.cpp diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt index af88e9f694..fc84eaee0b 100644 --- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt +++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt @@ -1057,10 +1057,12 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -1072,6 +1074,11 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" @@ -3109,10 +3116,12 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -3124,6 +3133,11 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj index 45d59a91a9..6ac081a494 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj @@ -1343,6 +1343,9 @@ true + + true + true @@ -1373,6 +1376,15 @@ true + + true + + + true + + + true + true @@ -3339,9 +3351,11 @@ + + diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters index 6be579eaf7..30983bad63 100644 --- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters @@ -1957,6 +1957,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1993,6 +1996,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5262,6 +5277,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5271,6 +5289,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj index 38d0f3190d..281ef4282d 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj @@ -1343,6 +1343,9 @@ true + + true + true @@ -1373,6 +1376,15 @@ true + + true + + + true + + + true + true @@ -3339,9 +3351,11 @@ + + diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters index 356c495775..34375cb584 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters @@ -1957,6 +1957,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1993,6 +1996,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5262,6 +5277,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5271,6 +5289,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj index f1c2970bb7..215d8b912e 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj @@ -1343,6 +1343,9 @@ true + + true + true @@ -1373,6 +1376,15 @@ true + + true + + + true + + + true + true @@ -3339,9 +3351,11 @@ + + diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters index fa0a1e0c44..0a3fd28ca6 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters @@ -1957,6 +1957,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1993,6 +1996,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5262,6 +5277,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -5271,6 +5289,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt index f723cc32cb..312da5ad72 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt @@ -933,10 +933,12 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -948,6 +950,11 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" @@ -2683,10 +2690,12 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -2698,6 +2707,11 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj index 9fb36bd065..9b733049bd 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj @@ -1183,6 +1183,9 @@ true + + true + true @@ -1213,6 +1216,15 @@ true + + true + + + true + + + true + true @@ -2892,9 +2904,11 @@ + + diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters index 3059cd3f4e..2a66a61639 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters @@ -1666,6 +1666,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1702,6 +1705,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4539,6 +4554,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4548,6 +4566,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt index ef567e80de..7bda9de1ef 100644 --- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt @@ -966,10 +966,12 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -981,6 +983,11 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" @@ -2871,10 +2878,12 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -2886,6 +2895,11 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj index a3be4581d9..9826c0bb8d 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj @@ -1191,6 +1191,9 @@ true + + true + true @@ -1221,6 +1224,15 @@ true + + true + + + true + + + true + true @@ -3075,9 +3087,11 @@ + + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters index cfb6dfd4b4..9f9ba309d5 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters @@ -1741,6 +1741,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1777,6 +1780,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4818,6 +4833,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4827,6 +4845,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj index 62b7933b50..0807812476 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj @@ -1191,6 +1191,9 @@ true + + true + true @@ -1221,6 +1224,15 @@ true + + true + + + true + + + true + true @@ -3075,9 +3087,11 @@ + + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters index be554c81c3..cd4beb325a 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters @@ -1741,6 +1741,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1777,6 +1780,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4818,6 +4833,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4827,6 +4845,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj index 49a7f40fc2..e0fe9494d2 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj @@ -1191,6 +1191,9 @@ true + + true + true @@ -1221,6 +1224,15 @@ true + + true + + + true + + + true + true @@ -3075,9 +3087,11 @@ + + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters index ea5a96814c..4d613fc4a5 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters @@ -1741,6 +1741,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1777,6 +1780,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4818,6 +4833,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4827,6 +4845,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj index a31364d196..106049e299 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj +++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj @@ -256,6 +256,9 @@ true + + true + true @@ -286,6 +289,15 @@ true + + true + + + true + + + true + true @@ -541,9 +553,11 @@ + + diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters index 4ade108cda..4371a8c827 100644 --- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters +++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters @@ -193,6 +193,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -229,6 +232,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -636,6 +651,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -645,6 +663,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt index 1ab92381b3..6866279589 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt @@ -937,10 +937,12 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -952,6 +954,11 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" @@ -2767,10 +2774,12 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_CFHelpers_mac.h" "../../../../../modules/juce_core/native/juce_CommonFile_linux.cpp" "../../../../../modules/juce_core/native/juce_ComSmartPtr_windows.h" + "../../../../../modules/juce_core/native/juce_FileDescriptor_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_android.cpp" "../../../../../modules/juce_core/native/juce_Files_linux.cpp" "../../../../../modules/juce_core/native/juce_Files_mac.mm" "../../../../../modules/juce_core/native/juce_Files_windows.cpp" + "../../../../../modules/juce_core/native/juce_HighResolutionTimerThread.h" "../../../../../modules/juce_core/native/juce_IPAddress_posix.h" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.cpp" "../../../../../modules/juce_core/native/juce_JNIHelpers_android.h" @@ -2782,6 +2791,11 @@ set_source_files_properties( "../../../../../modules/juce_core/native/juce_Network_mac.mm" "../../../../../modules/juce_core/native/juce_Network_windows.cpp" "../../../../../modules/juce_core/native/juce_ObjCHelpers_mac.h" + "../../../../../modules/juce_core/native/juce_PlatformTimer_linux.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_mac.mm" + "../../../../../modules/juce_core/native/juce_PlatformTimer_wasm.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimer_windows.cpp" + "../../../../../modules/juce_core/native/juce_PlatformTimerListener.h" "../../../../../modules/juce_core/native/juce_Registry_windows.cpp" "../../../../../modules/juce_core/native/juce_RuntimePermissions_android.cpp" "../../../../../modules/juce_core/native/juce_SharedCode_intel.h" diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj index 0f66ce36e3..d4aa21cba2 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj @@ -1183,6 +1183,9 @@ true + + true + true @@ -1213,6 +1216,15 @@ true + + true + + + true + + + true + true @@ -2983,9 +2995,11 @@ + + diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters index b1eb60b7bc..3b54b3e3eb 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters @@ -1696,6 +1696,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1732,6 +1735,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4680,6 +4695,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4689,6 +4707,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj index 56095e89d6..279f3af3db 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj @@ -392,6 +392,9 @@ true + + true + true @@ -422,6 +425,15 @@ true + + true + + + true + + + true + true @@ -1834,9 +1846,11 @@ + + diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters index 94057670de..f4909b901c 100644 --- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters @@ -670,6 +670,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -706,6 +709,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2709,6 +2724,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2718,6 +2736,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj index 45c550edb0..deb5d71f65 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj @@ -392,6 +392,9 @@ true + + true + true @@ -422,6 +425,15 @@ true + + true + + + true + + + true + true @@ -1834,9 +1846,11 @@ + + diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters index d09847ac3c..90e63ba34e 100644 --- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters @@ -670,6 +670,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -706,6 +709,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2709,6 +2724,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2718,6 +2736,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj index 6177995928..f0ee81947f 100644 --- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj +++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj @@ -392,6 +392,9 @@ true + + true + true @@ -422,6 +425,15 @@ true + + true + + + true + + + true + true @@ -1834,9 +1846,11 @@ + + diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters index b05eca01f5..56740e1f0a 100644 --- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters +++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters @@ -670,6 +670,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -706,6 +709,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2709,6 +2724,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -2718,6 +2736,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj index c385106e67..f5ca469be2 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj @@ -1199,6 +1199,9 @@ true + + true + true @@ -1229,6 +1232,15 @@ true + + true + + + true + + + true + true @@ -3141,9 +3153,11 @@ + + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters index 835b5db398..1d12644760 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1765,6 +1765,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1801,6 +1804,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4908,6 +4923,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4917,6 +4935,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj index 52a3affa4c..f5b317edaf 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj @@ -1199,6 +1199,9 @@ true + + true + true @@ -1229,6 +1232,15 @@ true + + true + + + true + + + true + true @@ -3141,9 +3153,11 @@ + + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters index 226b78ab83..81d667dbe0 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1765,6 +1765,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1801,6 +1804,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4908,6 +4923,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4917,6 +4935,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj index d0aeb716e1..d7f609b0be 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj @@ -1199,6 +1199,9 @@ true + + true + true @@ -1229,6 +1232,15 @@ true + + true + + + true + + + true + true @@ -3141,9 +3153,11 @@ + + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters index 4f3f91a04e..43f1a50193 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1765,6 +1765,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1801,6 +1804,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4908,6 +4923,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4917,6 +4935,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj index bc0f4c4dac..620b7331b7 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj @@ -1182,6 +1182,9 @@ true + + true + true @@ -1212,6 +1215,15 @@ true + + true + + + true + + + true + true @@ -2959,9 +2971,11 @@ + + diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters index c1c2f18a9b..179fbc072d 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters @@ -1693,6 +1693,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -1729,6 +1732,18 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4647,6 +4662,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native @@ -4656,6 +4674,9 @@ JUCE Modules\juce_core\native + + JUCE Modules\juce_core\native + JUCE Modules\juce_core\native diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp index 2f178d62ff..ba5215f4bf 100644 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -187,6 +187,8 @@ #include "files/juce_FileFilter.cpp" #include "files/juce_WildcardFileFilter.cpp" #include "native/juce_ThreadPriorities_native.h" +#include "native/juce_PlatformTimerListener.h" +#include "native/juce_HighResolutionTimerThread.h" //============================================================================== #if ! JUCE_WINDOWS @@ -205,6 +207,7 @@ #include "native/juce_SharedCode_intel.h" #include "native/juce_SystemStats_mac.mm" #include "native/juce_Threads_mac.mm" + #include "native/juce_PlatformTimer_mac.mm" //============================================================================== #elif JUCE_WINDOWS @@ -213,20 +216,34 @@ #include "native/juce_Registry_windows.cpp" #include "native/juce_SystemStats_windows.cpp" #include "native/juce_Threads_windows.cpp" + #include "native/juce_PlatformTimer_windows.cpp" //============================================================================== -#elif JUCE_LINUX || JUCE_BSD +#elif JUCE_LINUX #include "native/juce_CommonFile_linux.cpp" #include "native/juce_Files_linux.cpp" #include "native/juce_Network_linux.cpp" #if JUCE_USE_CURL #include "native/juce_Network_curl.cpp" #endif - #if JUCE_BSD - #include "native/juce_SharedCode_intel.h" - #endif #include "native/juce_SystemStats_linux.cpp" #include "native/juce_Threads_linux.cpp" + #include "native/juce_FileDescriptor_linux.cpp" + #include "native/juce_PlatformTimer_linux.cpp" + +//============================================================================== +#elif JUCE_BSD + #include "native/juce_CommonFile_linux.cpp" + #include "native/juce_Files_linux.cpp" + #include "native/juce_Network_linux.cpp" + #if JUCE_USE_CURL + #include "native/juce_Network_curl.cpp" + #endif + #include "native/juce_SharedCode_intel.h" + #include "native/juce_SystemStats_linux.cpp" + #include "native/juce_Threads_linux.cpp" + #include "native/juce_FileDescriptor_linux.cpp" + #include "native/juce_PlatformTimer_linux.cpp" //============================================================================== #elif JUCE_ANDROID @@ -238,10 +255,13 @@ #include "native/juce_SystemStats_android.cpp" #include "native/juce_Threads_android.cpp" #include "native/juce_RuntimePermissions_android.cpp" + #include "native/juce_FileDescriptor_linux.cpp" + #include "native/juce_PlatformTimer_linux.cpp" +//============================================================================== #elif JUCE_WASM #include "native/juce_SystemStats_wasm.cpp" - + #include "native/juce_PlatformTimer_wasm.cpp" #endif #include "files/juce_common_MimeTypes.h" diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 65c519b6e0..3abc1dcb7a 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -315,12 +315,12 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "misc/juce_WindowsRegistry.h" #include "threads/juce_ChildProcess.h" #include "threads/juce_DynamicLibrary.h" -#include "threads/juce_HighResolutionTimer.h" #include "threads/juce_InterProcessLock.h" #include "threads/juce_Process.h" #include "threads/juce_SpinLock.h" #include "threads/juce_WaitableEvent.h" #include "threads/juce_Thread.h" +#include "threads/juce_HighResolutionTimer.h" #include "threads/juce_ThreadLocalValue.h" #include "threads/juce_ThreadPool.h" #include "threads/juce_TimeSliceThread.h" diff --git a/modules/juce_core/native/juce_BasicNativeHeaders.h b/modules/juce_core/native/juce_BasicNativeHeaders.h index f444f9c07f..1568ce5e65 100644 --- a/modules/juce_core/native/juce_BasicNativeHeaders.h +++ b/modules/juce_core/native/juce_BasicNativeHeaders.h @@ -209,6 +209,8 @@ #include #include #include + #include + #include #include #include @@ -243,6 +245,8 @@ #include #include #include + #include + #include #include #include @@ -265,11 +269,13 @@ #include #include #include + #include + #include #include #include - // If you are getting include errors here, then you to re-build the Projucer - // and re-save your .jucer file. + // If you are getting include errors here, then you need to re-build + // the Projucer and re-save your .jucer file. #include #endif diff --git a/modules/juce_core/native/juce_FileDescriptor_linux.cpp b/modules/juce_core/native/juce_FileDescriptor_linux.cpp new file mode 100644 index 0000000000..28e0a4b51b --- /dev/null +++ b/modules/juce_core/native/juce_FileDescriptor_linux.cpp @@ -0,0 +1,159 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class FileDescriptor +{ +public: + explicit FileDescriptor (int fileDescriptorId) + : id { fileDescriptorId } {} + + ~FileDescriptor() + { + if (isValid()) + close (id); + } + + bool isValid() const { return id >= 0; } + int get() const { return id; } + + template + DataType readData() const + { + if (! isValid()) + return {}; + + alignas (DataType) std::array buffer; + size_t numberOfBytesRead { 0 }; + + while (numberOfBytesRead < buffer.size()) + { + const auto result = read (get(), buffer.data() + numberOfBytesRead, buffer.size() - numberOfBytesRead); + + if (result < 0) + return {}; + + numberOfBytesRead += (size_t) result; + } + + return readUnaligned (buffer.data()); + } + + template + void writeData (const DataType& value) const + { + if (! isValid()) + return; + + alignas (DataType) std::array buffer; + writeUnaligned (buffer.data(), value); + size_t numberOfBytesWritten { 0 }; + + while (numberOfBytesWritten < buffer.size()) + { + const auto result = write (get(), buffer.data() + numberOfBytesWritten, buffer.size() - numberOfBytesWritten); + + if (result < 0) + return; + + numberOfBytesWritten += (size_t) result; + } + } + +private: + int id{}; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileDescriptor) + JUCE_DECLARE_NON_MOVEABLE (FileDescriptor) +}; + +class EventFd +{ +public: + EventFd() = default; + void signal() const { fd.writeData ((uint64_t) 1); } + + int get() const { return fd.get(); } + bool isValid() const { return fd.isValid(); } + +private: + FileDescriptor fd { eventfd (0, EFD_CLOEXEC) }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EventFd) + JUCE_DECLARE_NON_MOVEABLE (EventFd) +}; + +class TimerFd +{ +public: + TimerFd() = default; + + bool setIntervalMs (int ms) const + { + if (! fd.isValid()) + return false; + + jassert (ms >= 0); + + const auto seconds = ms / 1'000; + const auto nanoseconds = (ms % 1'000) * 1'000'000; + + const itimerspec spec + { + { seconds, nanoseconds }, + { seconds, nanoseconds } + }; + + return timerfd_settime (fd.get(), 0, &spec, nullptr) == 0; + } + + int getIntervalMs() const + { + if (! fd.isValid()) + return 0; + + itimerspec result{}; + + if (timerfd_gettime (fd.get(), &result) != 0) + return 0; + + return static_cast (result.it_interval.tv_sec * 1'000 + result.it_interval.tv_nsec / 1'000'000); + } + + int getAndClearNumberOfExpirations() const + { + return (int) fd.readData(); + } + + int get() const { return fd.get(); } + bool isValid() const { return fd.isValid(); } + +private: + FileDescriptor fd { timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK) }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimerFd) + JUCE_DECLARE_NON_MOVEABLE (TimerFd) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_HighResolutionTimerThread.h b/modules/juce_core/native/juce_HighResolutionTimerThread.h new file mode 100644 index 0000000000..a6f87b8d09 --- /dev/null +++ b/modules/juce_core/native/juce_HighResolutionTimerThread.h @@ -0,0 +1,63 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class HighResolutionTimerThread final : private Thread +{ +public: + struct Impl + { + virtual ~Impl() = default; + virtual void runThread() = 0; + virtual void signalThreadShouldExit() = 0; + }; + + HighResolutionTimerThread (Impl& implementation) + : Thread { "HighResolutionTimerThread" }, + impl { implementation } + { + startThread (Thread::Priority::highest); + } + + ~HighResolutionTimerThread() override + { + impl.signalThreadShouldExit(); + waitForThreadToExit (-1); + } + + bool isRunning() const { return isThreadRunning(); } + +private: + void run() override + { + impl.runThread(); + } + + Impl& impl; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HighResolutionTimerThread) + JUCE_DECLARE_NON_MOVEABLE (HighResolutionTimerThread) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimerListener.h b/modules/juce_core/native/juce_PlatformTimerListener.h new file mode 100644 index 0000000000..a62e24c6cf --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimerListener.h @@ -0,0 +1,32 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +struct PlatformTimerListener +{ + virtual ~PlatformTimerListener() = default; + virtual void onTimerExpired (int numberOfExpirations) = 0; +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimer_linux.cpp b/modules/juce_core/native/juce_PlatformTimer_linux.cpp new file mode 100644 index 0000000000..875ca129ad --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_linux.cpp @@ -0,0 +1,88 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final : private HighResolutionTimerThread::Impl +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : listener { ptl } {} + + void startTimer (int newIntervalMs) + { + timer.setIntervalMs (newIntervalMs); + } + + void cancelTimer() + { + startTimer (0); + } + + int getIntervalMs() const + { + return thread.isRunning() ? timer.getIntervalMs() : 0; + } + +private: + void runThread() override + { + if (! (timer.isValid() && exitThread.isValid())) + return; + + pollfd pollData[] + { + { timer.get(), POLLIN, 0 }, + { exitThread.get(), POLLIN, 0 } + }; + + const auto& [timerPollData, exitThreadPollData] = pollData; + + for (;;) + { + if (poll (pollData, numElementsInArray (pollData), -1) <= 0) + return; + + if (exitThreadPollData.revents & POLLIN) + return; + + if (timerPollData.revents & POLLIN) + listener.onTimerExpired (timer.getAndClearNumberOfExpirations()); + } + } + + void signalThreadShouldExit() override + { + exitThread.signal(); + } + + PlatformTimerListener& listener; + const TimerFd timer; + const EventFd exitThread; + HighResolutionTimerThread thread { *this }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} diff --git a/modules/juce_core/native/juce_PlatformTimer_mac.mm b/modules/juce_core/native/juce_PlatformTimer_mac.mm new file mode 100644 index 0000000000..9ad7b690f6 --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_mac.mm @@ -0,0 +1,118 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final : private HighResolutionTimerThread::Impl +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : listener { ptl } {} + + void startTimer (int newIntervalMs) + { + jassert (newIntervalMs > 0); + jassert (timer == nullptr); + + if (runLoop == nullptr) + return; + + const auto intervalSeconds = static_cast (newIntervalMs) / 1'000.0; + + CFRunLoopTimerContext context{}; + context.info = &listener; + + const auto callback = [] (CFRunLoopTimerRef, void* ctx) + { + static_cast (ctx)->onTimerExpired (1); + }; + + timer.reset (CFRunLoopTimerCreate (kCFAllocatorDefault, + intervalSeconds + CFAbsoluteTimeGetCurrent(), + intervalSeconds, + 0, + 0, + callback, + &context)); + + CFRunLoopAddTimer (runLoop, timer.get(), kCFRunLoopDefaultMode); + } + + void cancelTimer() + { + jassert (runLoop != nullptr); + jassert (timer != nullptr); + + CFRunLoopRemoveTimer (runLoop, timer.get(), kCFRunLoopDefaultMode); + timer.reset(); + } + + int getIntervalMs() const + { + return timer != nullptr ? (int) (CFRunLoopTimerGetInterval (timer.get()) * 1'000.0) : 0; + } + +private: + static void preventRunLoopFromEarlyExits() + { + CFRunLoopSourceContext context{}; + CFRunLoopAddSource (CFRunLoopGetCurrent(), + CFRunLoopSourceCreate (kCFAllocatorDefault, 0, &context), + kCFRunLoopDefaultMode); + } + + void setRunLoop() + { + CFRunLoopPerformBlock (CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^() + { + runLoopPromise.set_value (CFRunLoopGetCurrent()); + }); + } + + void runThread() override + { + preventRunLoopFromEarlyExits(); + setRunLoop(); + CFRunLoopRun(); + } + + void signalThreadShouldExit() override + { + if (runLoop != nullptr) + CFRunLoopStop (runLoop); + } + + PlatformTimerListener& listener; + CFUniquePtr timer; + std::promise runLoopPromise; + HighResolutionTimerThread thread { *this }; + CFRunLoopRef runLoop = [&]() -> CFRunLoopRef + { + return thread.isRunning() ? runLoopPromise.get_future().get() : nullptr; + }(); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimer_wasm.cpp b/modules/juce_core/native/juce_PlatformTimer_wasm.cpp new file mode 100644 index 0000000000..57df331ff8 --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_wasm.cpp @@ -0,0 +1,111 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final : private HighResolutionTimerThread::Impl +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : listener { ptl } {} + + void startTimer (int newIntervalMs) + { + if (! thread.isRunning()) + return; + + { + std::scoped_lock lock { mutex }; + intervalMs = newIntervalMs; + nextEventTime = Time::getCurrentTime() + RelativeTime::milliseconds (newIntervalMs); + } + + event.signal(); + } + + void cancelTimer() + { + jassert (thread.isRunning()); + + { + std::scoped_lock lock { mutex }; + jassert (intervalMs > 0); + intervalMs = 0; + } + + event.signal(); + } + + int getIntervalMs() const + { + std::scoped_lock lock { mutex }; + return thread.isRunning() ? intervalMs : 0; + } + +private: + int millisecondsUntilNextEvent() + { + std::scoped_lock lock { mutex }; + return intervalMs > 0 ? jmax (0, (int) (nextEventTime - Time::getCurrentTime()).inMilliseconds()) : -1; + } + + bool nextEvent() + { + std::scoped_lock lock { mutex }; + if (intervalMs <= 0 || nextEventTime > Time::getCurrentTime()) + return false; + + nextEventTime += RelativeTime::milliseconds (intervalMs); + return true; + } + + void runThread() override + { + while (! shouldExitThread.load()) + { + if (nextEvent()) + listener.onTimerExpired (1); + else + event.wait (millisecondsUntilNextEvent()); + } + } + + void signalThreadShouldExit() override + { + shouldExitThread.store (true); + event.signal(); + } + + PlatformTimerListener& listener; + mutable std::mutex mutex; + int intervalMs{}; + Time nextEventTime; + WaitableEvent event; + std::atomic shouldExitThread { false }; + HighResolutionTimerThread thread { *this }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_PlatformTimer_windows.cpp b/modules/juce_core/native/juce_PlatformTimer_windows.cpp new file mode 100644 index 0000000000..ad99b70f6c --- /dev/null +++ b/modules/juce_core/native/juce_PlatformTimer_windows.cpp @@ -0,0 +1,68 @@ +/* + ============================================================================== + + This file is part of the JUCE library. + Copyright (c) 2022 - Raw Material Software Limited + + JUCE is an open source library subject to commercial or open-source + licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + To use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +class PlatformTimer final +{ +public: + explicit PlatformTimer (PlatformTimerListener& ptl) + : listener { ptl } {} + + void startTimer (int newIntervalMs) + { + jassert (newIntervalMs > 0); + + const auto callback = [] (UINT, UINT, DWORD_PTR context, DWORD_PTR, DWORD_PTR) + { + reinterpret_cast (context)->onTimerExpired (1); + }; + + timerId = timeSetEvent ((UINT) newIntervalMs, 1, callback, (DWORD_PTR) &listener, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + intervalMs = timerId != 0 ? newIntervalMs : 0; + } + + void cancelTimer() + { + jassert (timerId != 0); + + timeKillEvent (timerId); + timerId = 0; + intervalMs = 0; + } + + int getIntervalMs() const + { + return intervalMs; + } + +private: + PlatformTimerListener& listener; + UINT timerId { 0 }; + int intervalMs { 0 }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PlatformTimer) + JUCE_DECLARE_NON_MOVEABLE (PlatformTimer) +}; + +} // namespace juce diff --git a/modules/juce_core/native/juce_SharedCode_posix.h b/modules/juce_core/native/juce_SharedCode_posix.h index 1bcb55661c..df0ba126af 100644 --- a/modules/juce_core/native/juce_SharedCode_posix.h +++ b/modules/juce_core/native/juce_SharedCode_posix.h @@ -854,7 +854,7 @@ class PosixThreadAttribute public: explicit PosixThreadAttribute (size_t stackSize) { - if (valid) + if (valid && stackSize != 0) pthread_attr_setstacksize (&attr, stackSize); } @@ -963,7 +963,9 @@ static void* makeThreadHandle (PosixThreadAttribute& attr, Thread* userData, voi { pthread_t handle = {}; - if (pthread_create (&handle, attr.get(), threadEntryProc, userData) != 0) + const auto status = pthread_create (&handle, attr.get(), threadEntryProc, userData); + + if (status != 0) return nullptr; pthread_detach (handle); diff --git a/modules/juce_core/native/juce_Threads_android.cpp b/modules/juce_core/native/juce_Threads_android.cpp index fe6088553a..68967499c1 100644 --- a/modules/juce_core/native/juce_Threads_android.cpp +++ b/modules/juce_core/native/juce_Threads_android.cpp @@ -448,6 +448,4 @@ JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {} JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {} - - } // namespace juce diff --git a/modules/juce_core/threads/juce_HighResolutionTimer.cpp b/modules/juce_core/threads/juce_HighResolutionTimer.cpp index 28ca899d96..07172d2cd4 100644 --- a/modules/juce_core/threads/juce_HighResolutionTimer.cpp +++ b/modules/juce_core/threads/juce_HighResolutionTimer.cpp @@ -23,98 +23,409 @@ namespace juce { -class HighResolutionTimer::Pimpl : public Thread +//============================================================================== +class HighResolutionTimer::Impl : private PlatformTimerListener { - using steady_clock = std::chrono::steady_clock; - using milliseconds = std::chrono::milliseconds; - public: - explicit Pimpl (HighResolutionTimer& ownerRef) - : Thread ("HighResolutionTimerThread"), - owner (ownerRef) - { - } + explicit Impl (HighResolutionTimer& o) + : owner { o } {} - using Thread::isThreadRunning; - - void start (int periodMs) + void startTimer (int newIntervalMs) { + shouldCancelCallbacks.store (true); + + const auto shouldWaitForPendingCallbacks = [&] { - const std::scoped_lock lk { mutex }; - periodMillis = periodMs; - nextTickTime = steady_clock::now() + milliseconds (periodMillis); - } + const std::scoped_lock lock { timerMutex }; - waitEvent.notify_one(); + if (timer.getIntervalMs() > 0) + timer.cancelTimer(); - if (! isThreadRunning()) - startThread (Thread::Priority::high); + if (newIntervalMs > 0) + timer.startTimer (jmax (0, newIntervalMs)); + + return callbackThreadId != std::this_thread::get_id() + && timer.getIntervalMs() <= 0; + }(); + + if (shouldWaitForPendingCallbacks) + std::scoped_lock lock { callbackMutex }; } - void stop() + int getIntervalMs() const { - { - const std::scoped_lock lk { mutex }; - periodMillis = 0; - } - - waitEvent.notify_one(); - - if (Thread::getCurrentThreadId() != getThreadId()) - stopThread (-1); + const std::scoped_lock lock { timerMutex }; + return timer.getIntervalMs(); } - int getPeriod() const + bool isTimerRunning() const { - return periodMillis; + return getIntervalMs() > 0; } private: - void run() override + void onTimerExpired (int numberOfExpirations) final { - for (;;) + callbackThreadId.store (std::this_thread::get_id()); + + std::scoped_lock lock { callbackMutex }; + + shouldCancelCallbacks.store (! isTimerRunning()); + + for (int i = 0; i < numberOfExpirations && ! shouldCancelCallbacks.load(); ++i) { + try { - std::unique_lock lk { mutex }; - - if (waitEvent.wait_until (lk, nextTickTime, [this] { return periodMillis == 0; })) - break; - - nextTickTime = steady_clock::now() + milliseconds (periodMillis); + owner.hiResTimerCallback(); + } + catch (...) + { + // Exceptions thrown in a timer callback won't be + // propagated to the main thread, it's best to find a + // way to avoid them if possible + jassertfalse; } - - owner.hiResTimerCallback(); } + + callbackThreadId.store ({}); } HighResolutionTimer& owner; - std::atomic periodMillis { 0 }; - steady_clock::time_point nextTickTime; - std::mutex mutex; - std::condition_variable waitEvent; + mutable std::mutex timerMutex; + std::mutex callbackMutex; + std::atomic callbackThreadId{}; + std::atomic shouldCancelCallbacks { false }; + PlatformTimer timer { *this }; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Impl) + JUCE_DECLARE_NON_MOVEABLE (Impl) }; +//============================================================================== HighResolutionTimer::HighResolutionTimer() - : pimpl (new Pimpl (*this)) -{ -} + : impl (std::make_unique (*this)) {} HighResolutionTimer::~HighResolutionTimer() { + // You *must* call stopTimer from the derived class destructor to + // avoid data races on the timer's vtable + jassert (! isTimerRunning()); stopTimer(); } -void HighResolutionTimer::startTimer (int periodMs) +void HighResolutionTimer::startTimer (int newIntervalMs) { - pimpl->start (jmax (1, periodMs)); + impl->startTimer (newIntervalMs); } void HighResolutionTimer::stopTimer() { - pimpl->stop(); + impl->startTimer (0); } -bool HighResolutionTimer::isTimerRunning() const noexcept { return getTimerInterval() != 0; } -int HighResolutionTimer::getTimerInterval() const noexcept { return pimpl->getPeriod(); } +int HighResolutionTimer::getTimerInterval() const noexcept +{ + return impl->getIntervalMs(); +} + +bool HighResolutionTimer::isTimerRunning() const noexcept +{ + return impl->isTimerRunning(); +} + +//============================================================================== +#if JUCE_UNIT_TESTS + +class HighResolutionTimerTests : public UnitTest +{ +public: + HighResolutionTimerTests() + : UnitTest ("HighResolutionTimer", UnitTestCategories::threads) {} + + void runTest() override + { + constexpr int maximumTimeoutMs {30'000}; + + beginTest ("Start/stop a timer"); + { + WaitableEvent timerFiredOnce; + WaitableEvent timerFiredTwice; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: timerFiredOnce.signal(); return; + case 2: timerFiredTwice.signal(); return; + default: return; + } + }}; + + expect (! timer.isTimerRunning()); + expect (timer.getTimerInterval() == 0); + + timer.startTimer (1); + expect (timer.isTimerRunning()); + expect (timer.getTimerInterval() == 1); + expect (timerFiredOnce.wait (maximumTimeoutMs)); + expect (timerFiredTwice.wait (maximumTimeoutMs)); + + timer.stopTimer(); + expect (! timer.isTimerRunning()); + expect (timer.getTimerInterval() == 0); + } + + beginTest ("Stop a timer from the timer callback"); + { + WaitableEvent stoppedTimer; + + auto timerCallback = [&](Timer& timer) + { + expect (timer.isTimerRunning()); + timer.stopTimer(); + expect (! timer.isTimerRunning()); + stoppedTimer.signal(); + }; + + Timer timer {[&]{ timerCallback (timer); }}; + timer.startTimer (1); + expect (stoppedTimer.wait (maximumTimeoutMs)); + } + + beginTest ("Restart a timer from the timer callback"); + { + WaitableEvent restartTimer; + WaitableEvent timerRestarted; + WaitableEvent timerFiredAfterRestart; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + expect (restartTimer.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 1); + + timer.startTimer (2); + expect (timer.getTimerInterval() == 2); + timerRestarted.signal(); + return; + + case 2: + expect (timer.getTimerInterval() == 2); + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timer.getTimerInterval() == 1); + + restartTimer.signal(); + expect (timerRestarted.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 2); + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + + timer.stopTimer(); + } + + beginTest ("Calling stopTimer on a timer, waits for any timer callbacks to finish"); + { + WaitableEvent timerCallbackStarted; + WaitableEvent stoppingTimer; + std::atomic timerCallbackFinished { false }; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + timerCallbackStarted.signal(); + expect (stoppingTimer.wait (maximumTimeoutMs)); + Thread::sleep (10); + timerCallbackFinished = true; + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timerCallbackStarted.wait (maximumTimeoutMs)); + + stoppingTimer.signal(); + timer.stopTimer(); + expect (timerCallbackFinished); + } + + beginTest ("Calling stopTimer on a timer, waits for any timer callbacks to finish, even if the timer callback calls stopTimer first"); + { + WaitableEvent stoppedFromInsideTimerCallback; + WaitableEvent stoppingFromOutsideTimerCallback; + std::atomic timerCallbackFinished { false }; + + Timer timer {[&]() + { + timer.stopTimer(); + stoppedFromInsideTimerCallback.signal(); + expect (stoppingFromOutsideTimerCallback.wait (maximumTimeoutMs)); + Thread::sleep (10); + timerCallbackFinished = true; + + }}; + + timer.startTimer (1); + expect (stoppedFromInsideTimerCallback.wait (maximumTimeoutMs)); + + stoppingFromOutsideTimerCallback.signal(); + timer.stopTimer(); + expect (timerCallbackFinished); + } + + beginTest ("Adjusting a timer period from outside the timer callback doesn't cause data races"); + { + WaitableEvent timerCallbackStarted; + WaitableEvent timerRestarted; + WaitableEvent timerFiredAfterRestart; + std::atomic lastCallbackCount {0}; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + expect (timer.getTimerInterval() == 1); + timerCallbackStarted.signal(); + Thread::sleep (10); + lastCallbackCount = 1; + return; + + case 2: + expect (timerRestarted.wait (maximumTimeoutMs)); + expect (timer.getTimerInterval() == 2); + lastCallbackCount = 2; + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + timer.startTimer (1); + expect (timerCallbackStarted.wait (maximumTimeoutMs)); + + timer.startTimer (2); + timerRestarted.signal(); + + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + expect (lastCallbackCount == 2); + + timer.stopTimer(); + expect (lastCallbackCount == 2); + } + + beginTest ("A timer can be restarted externally, after being stopped internally"); + { + WaitableEvent timerStopped; + WaitableEvent timerFiredAfterRestart; + + Timer timer {[&, callbackCount = 0] () mutable + { + switch (++callbackCount) + { + case 1: + timer.stopTimer(); + timerStopped.signal(); + return; + + case 2: + timerFiredAfterRestart.signal(); + return; + + default: + return; + } + }}; + + expect (! timer.isTimerRunning()); + timer.startTimer (1); + expect (timer.isTimerRunning()); + + expect (timerStopped.wait (maximumTimeoutMs)); + expect (! timer.isTimerRunning()); + + timer.startTimer (1); + expect (timer.isTimerRunning()); + expect (timerFiredAfterRestart.wait (maximumTimeoutMs)); + } + + beginTest ("Calls to `startTimer` and `getTimerInterval` succeed while a callback is blocked"); + { + WaitableEvent timerBlocked; + WaitableEvent unblockTimer; + + Timer timer {[&] + { + timerBlocked.signal(); + unblockTimer.wait(); + timer.stopTimer(); + }}; + + timer.startTimer (1); + timerBlocked.wait(); + + expect (timer.getTimerInterval() == 1); + timer.startTimer (2); + expect (timer.getTimerInterval() == 2); + + unblockTimer.signal(); + timer.stopTimer(); + } + + beginTest ("Stress test"); + { + constexpr auto maxNumTimers { 100 }; + + std::vector> timers; + timers.reserve (maxNumTimers); + + for (int i = 0; i < maxNumTimers; ++i) + { + auto timer = std::make_unique ([]{}); + timer->startTimer (1); + + if (! timer->isTimerRunning()) + break; + + timers.push_back (std::move (timer)); + } + + expect (timers.size() >= 16); + } + } + + class Timer : public HighResolutionTimer + { + public: + explicit Timer (std::function fn) + : callback (std::move (fn)) {} + + ~Timer() override { stopTimer(); } + + void hiResTimerCallback() override { callback(); } + + private: + std::function callback; + }; +}; + +static HighResolutionTimerTests highResolutionTimerTests; + +#endif } // namespace juce diff --git a/modules/juce_core/threads/juce_HighResolutionTimer.h b/modules/juce_core/threads/juce_HighResolutionTimer.h index 2ac6402a93..37bd72d1c3 100644 --- a/modules/juce_core/threads/juce_HighResolutionTimer.h +++ b/modules/juce_core/threads/juce_HighResolutionTimer.h @@ -32,8 +32,8 @@ namespace juce You should only use this class in situations where you really need accuracy, because unlike the normal Timer class, which is very lightweight and cheap - to start/stop, the HighResolutionTimer will use far more resources, and - starting/stopping it may involve launching and killing threads. + the HighResolutionTimer will use far more resources and require thread + safety considerations. @see Timer @@ -57,20 +57,29 @@ public: This will be called on a dedicated timer thread, so make sure your implementation is thread-safe! + On some platforms the dedicated timer thread may be shared with + other HighResolutionTimer's so aim to complete any work in this + callback as fast as possible. + It's perfectly ok to call startTimer() or stopTimer() from within this - callback to change the subsequent intervals. + callback to change the subsequent intervals. However, if you call + stopTimer() in the callback it's still best practice to call stopTimer() + from the destructor in order to avoid data races. */ virtual void hiResTimerCallback() = 0; //============================================================================== /** Starts the timer and sets the length of interval required. - If the timer is already started, this will reset its counter, so the - time between calling this method and the next timer callback will not be - less than the interval length passed in. + If the timer has already started, this will reset the timer, so the + time between calling this method and the next timer callback + will not be less than the interval length passed in. - @param intervalInMilliseconds the interval to use (any values less than 1 will be - rounded up to 1) + In exceptional circumstances the dedicated timer thread may not start, + if this is a potential concern for your use case, you can call isTimerRunning() + to confirm if the timer actually started. + + @param intervalInMilliseconds the interval to use (a value of zero or less will stop the timer) */ void startTimer (int intervalInMilliseconds); @@ -79,6 +88,9 @@ public: This method may block while it waits for pending callbacks to complete. Once it returns, no more callbacks will be made. If it is called from the timer's own thread, it will cancel the timer after the current callback returns. + + To prevent data races it's normally best practice to call this in the derived classes + destructor, even if stopTimer() was called in the hiResTimerCallback(). */ void stopTimer(); @@ -93,8 +105,8 @@ public: int getTimerInterval() const noexcept; private: - class Pimpl; - std::unique_ptr pimpl; + class Impl; + std::unique_ptr impl; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HighResolutionTimer) };