Post

Replies

Boosts

Views

Created

Concurrency Crash - PushToTalk Framework
With the integration of Apple's pushToTalk framework - we create the PTChannelManager using its async initializer from AppDidFinishLaunching - using an actor to ensure the PTChannelManager is only created once. With this we have been seeing a lot of crashes for users in our analytics dashboards happening about ~2 seconds after app launch around a task-dealloc. Here is a simplified version of our actor and Manager - where the manager just shows the init. The init of it is an async optional init because the creation of the PTChannelManager uses an async throws. actor PushToTalkDeviceContainer { private var internalPushToTalkManagerTask: Task<PushToTalkManager?, Never>? func pushToTalkManager() async -> PushToTalkManager? { #if !os(visionOS) if let internalPushToTalkManagerTask { return await internalPushToTalkManagerTask.value } let internalPushToTalkManagerTask = Task<PushToTalkManager?, Never> { return await PushToTalkManagerImp() } self.internalPushToTalkManagerTask = internalPushToTalkManagerTask return await internalPushToTalkManagerTask.value #else return nil #endif } } public class PushToTalkManagerImp: PushToTalkManager { public let onPushToTalkDelegationEvent: AnyPublisher<PushToTalkDelegationEvent, Never> public let onPushToTalkAudioSessionChange: AnyPublisher<PushToTalkManagerAudioSessionChange, Never> public let onChannelRestoration: AnyPublisher<UUID, Never> private let ptChannelManager: PTChannelManager private let restorationDelegate: PushToTalkRestorationDelegate private let delegate: PushToTalkDelegate init?() async { self.delegate = PushToTalkDelegate() self.restorationDelegate = PushToTalkRestorationDelegate() self.onPushToTalkDelegationEvent = delegate.pushToTalkDelegationSubject.eraseToAnyPublisher() self.onPushToTalkAudioSessionChange = delegate.audioSessionSubject.eraseToAnyPublisher() self.onChannelRestoration = restorationDelegate.restorationDelegateSubject.eraseToAnyPublisher() do { ptChannelManager = try await PTChannelManager.channelManager(delegate: delegate, restorationDelegate: restorationDelegate) } catch { return nil } } } The crash stack trace is as follows: 0 libsystem_kernel.dylib 0x00000001e903342c __pthread_kill + 8 (:-1) 1 libsystem_pthread.dylib 0x00000001fcdd2c0c pthread_kill + 268 (pthread.c:1721) 2 libsystem_c.dylib 0x00000001a7ed6c34 __abort + 136 (abort.c:159) 3 libsystem_c.dylib 0x00000001a7ed6bac abort + 192 (abort.c:126) 4 libswift_Concurrency.dylib 0x00000001ab2bf7c8 swift::swift_Concurrency_fatalErrorv(unsigned int, char const*, char*) + 32 (Error.cpp:25) 5 libswift_Concurrency.dylib 0x00000001ab2bf7e8 swift::swift_Concurrency_fatalError(unsigned int, char const*, ...) + 32 (Error.cpp:35) 6 libswift_Concurrency.dylib 0x00000001ab2c39a8 swift_task_dealloc + 128 (TaskAlloc.cpp:59) 7 MyApp 0x0000000104908e04 PushToTalkManagerImp.__allocating_init() + 40 (PushToTalkManager.swift:0) 8 MyApp 0x0000000104908e04 closure #1 in PushToTalkDeviceContainer.pushToTalkManager() + 60 9 MyApp 0x00000001041882e9 specialized thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out A) + 1 (<compiler-generated>:0) 10 MyApp 0x0000000103a652bd partial apply for specialized thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out A) + 1 (<compiler-generated>:0) 11 libswift_Concurrency.dylib 0x00000001ab2c2775 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1 (Task.cpp:463)
3
0
1k
Jun ’24