From 4c5cee578a7d7117f3beb2c1f8d703e81b7e9805 Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Mon, 18 Sep 2023 16:41:43 +0100 Subject: [PATCH] AudioWorkgroup: Fix an issue with reference counters --- .../utilities/juce_AudioWorkgroup.cpp | 73 ++++++++++++------- .../native/juce_CoreAudio_mac.cpp | 8 +- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/modules/juce_audio_basics/utilities/juce_AudioWorkgroup.cpp b/modules/juce_audio_basics/utilities/juce_AudioWorkgroup.cpp index 58d93cccfe..65027bb5c1 100644 --- a/modules/juce_audio_basics/utilities/juce_AudioWorkgroup.cpp +++ b/modules/juce_audio_basics/utilities/juce_AudioWorkgroup.cpp @@ -62,10 +62,7 @@ private: static void detach (os_workgroup_t wg, os_workgroup_join_token_s token) { if (@available (macos 11.0, ios 14.0, *)) - { os_workgroup_leave (wg, &token); - os_release (wg); - } } static bool attach (os_workgroup_t wg, os_workgroup_join_token_s& tokenOut) @@ -73,10 +70,7 @@ private: if (@available (macos 11.0, ios 14.0, *)) { if (wg != nullptr && os_workgroup_join (wg, &tokenOut) == 0) - { - os_retain (wg); return true; - } } return false; @@ -97,16 +91,7 @@ private: class AudioWorkgroup::WorkgroupProvider { public: - explicit WorkgroupProvider (os_workgroup_t ptr) : handle (ptr) {} - - WorkgroupProvider clone() const - { - if (handle == nullptr) - return WorkgroupProvider { nullptr }; - - os_retain (handle.get()); - return WorkgroupProvider { handle.get() }; - } + explicit WorkgroupProvider (os_workgroup_t ptr) : handle { ptr } {} void join (WorkgroupToken& token) const { @@ -118,29 +103,65 @@ public: // is left before the new one is joined. token.reset(); - if (handle != nullptr) + if (handle.get() != nullptr) token = WorkgroupToken { [provider = WorkgroupToken::TokenProvider { handle.get() }] { return &provider; } }; } static os_workgroup_t getWorkgroup (const AudioWorkgroup& wg) { - if (auto* p = wg.getWorkgroupProvider()) - return p->handle.get(); + if (auto* provider = wg.getWorkgroupProvider()) + return provider->handle.get(); return nullptr; } private: - struct Release + struct ScopedWorkgroupRetainer { - void operator() (os_workgroup_t wg) const + ScopedWorkgroupRetainer (os_workgroup_t wg) : handle { wg } { - if (wg != nullptr) - os_release (wg); + if (handle != nullptr) + os_retain (handle); } + + ~ScopedWorkgroupRetainer() + { + if (handle != nullptr) + os_release (handle); + } + + ScopedWorkgroupRetainer (const ScopedWorkgroupRetainer& other) + : ScopedWorkgroupRetainer { other.handle } {} + + ScopedWorkgroupRetainer& operator= (const ScopedWorkgroupRetainer& other) + { + ScopedWorkgroupRetainer { other }.swap (*this); + return *this; + } + + ScopedWorkgroupRetainer (ScopedWorkgroupRetainer&& other) noexcept + { + swap (other); + } + + ScopedWorkgroupRetainer& operator= (ScopedWorkgroupRetainer&& other) noexcept + { + swap (other); + return *this; + } + + void swap (ScopedWorkgroupRetainer& other) noexcept + { + std::swap (handle, other.handle); + } + + os_workgroup_t get() const noexcept { return handle; } + + private: + os_workgroup_t handle { nullptr }; }; - std::unique_ptr, Release> handle; + ScopedWorkgroupRetainer handle; }; #else @@ -152,8 +173,6 @@ class AudioWorkgroup::WorkgroupProvider public: explicit WorkgroupProvider() = default; - WorkgroupProvider clone() const { return WorkgroupProvider{}; } - void join (WorkgroupToken& t) const { t.reset(); } static void* getWorkgroup (const AudioWorkgroup&) { return nullptr; } @@ -165,7 +184,7 @@ AudioWorkgroup::AudioWorkgroup (const AudioWorkgroup& other) : erased ([&]() -> Erased { if (auto* p = other.getWorkgroupProvider()) - return [provider = p->clone()] { return &provider; }; + return [provider = *p] { return &provider; }; return nullptr; }()) {} diff --git a/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp index 1cef003b7d..bec57749f5 100644 --- a/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp +++ b/modules/juce_audio_devices/native/juce_CoreAudio_mac.cpp @@ -474,7 +474,13 @@ public: pa.mScope = kAudioObjectPropertyScopeWildcard; pa.mElement = juceAudioObjectPropertyElementMain; - return makeRealAudioWorkgroup (audioObjectGetProperty (deviceID, pa).value_or (nullptr)); + if (auto* workgroup = audioObjectGetProperty (deviceID, pa).value_or (nullptr)) + { + ScopeGuard scope { [&] { os_release (workgroup); } }; + return makeRealAudioWorkgroup (workgroup); + } + + return {}; }(); #endif