From 84aa3d544be7fde6f6f155e63afca81b804244b5 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 18 Mar 2025 11:27:33 -0400 Subject: [PATCH 1/3] [Swift 6] Add AtomicBox to CoreInternal --- .../HeartbeatLogging/HeartbeatStorage.swift | 20 ++++----- .../Sources/Utilities/AtomicBox.swift | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift diff --git a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift index 07088a5cf68..3e428f8a88e 100644 --- a/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift +++ b/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift @@ -59,27 +59,23 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol { // `nonisolated(unsafe)` to disable concurrency-safety checks. The // property's access is protected by an external synchronization mechanism // (see `instancesLock` property). - private nonisolated(unsafe) static var cachedInstances: [ - String: WeakContainer - ] = [:] + private nonisolated(unsafe) static var cachedInstances: AtomicBox< + [String: WeakContainer] + > = AtomicBox([:]) #else // TODO(Xcode 16): Delete this block when minimum supported Xcode is // Xcode 16. - private static var cachedInstances: [ - String: WeakContainer - ] = [:] + static var cachedInstances: AtomicBox<[String: WeakContainer]> = + AtomicBox([:]) #endif // compiler(>=6) - /// Used to synchronize concurrent access to the `cachedInstances` property. - private static let instancesLock = NSLock() - /// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise, /// makes a new instance with the given `id`. /// /// - Parameter id: A string identifier. /// - Returns: A `HeartbeatStorage` instance. static func getInstance(id: String) -> HeartbeatStorage { - instancesLock.withLock { + cachedInstances.withLock { cachedInstances in if let cachedInstance = cachedInstances[id]?.object { return cachedInstance } else { @@ -110,8 +106,8 @@ final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol { deinit { // Removes the instance if it was cached. - _ = Self.instancesLock.withLock { - Self.cachedInstances.removeValue(forKey: id) + Self.cachedInstances.withLock { value in + value.removeValue(forKey: id) } } diff --git a/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift new file mode 100644 index 00000000000..f582e549182 --- /dev/null +++ b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift @@ -0,0 +1,43 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +public final class AtomicBox { + private var _value: T + private let lock = NSLock() + + public init(_ value: T) { + _value = value + } + + public func value() -> T { + lock.withLock { + _value + } + } + + @discardableResult + public func withLock(_ mutatingBody: (_ value: inout T) -> Void) -> T { + lock.withLock { + mutatingBody(&_value) + return _value + } + } + + @discardableResult + public func withLock(_ mutatingBody: (_ value: inout T) throws -> R) rethrows -> R { + try lock.withLock { + try mutatingBody(&_value) + } + } +} From b3ae3569b5a0aea6558f3e22cc5b371d49834c86 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 18 Mar 2025 12:23:14 -0400 Subject: [PATCH 2/3] [CoreInternal] Add AtomicBox --- FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift index f582e549182..f53c53524d7 100644 --- a/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift +++ b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -public final class AtomicBox { +final class AtomicBox { private var _value: T private let lock = NSLock() From 08b406a9857153ec185910ad83e65ef84cad4989 Mon Sep 17 00:00:00 2001 From: Nick Cooke <36927374+ncooke3@users.noreply.github.com> Date: Tue, 18 Mar 2025 12:30:12 -0400 Subject: [PATCH 3/3] add foundation import --- FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift index f53c53524d7..6346d05701c 100644 --- a/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift +++ b/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation + final class AtomicBox { private var _value: T private let lock = NSLock()