Repository: ReactiveX/RxSwift
File: RxSwift/ObservableType+Extensions.swift (Swift)

Code before:
                        onError(error)
                    }
                    else {
                        Hooks.defaultErrorHandler(callStack, error)
                    }
                    disposable.dispose()
                case .completed:
                    onCompleted?()
                    disposable.dispose()
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}

import class Foundation.NSRecursiveLock

extension Hooks {
    public typealias DefaultErrorHandler = (_ subscriptionCallStack: [String], _ error: Error) -> ()
    public typealias SubscriptionCallstackGenerationHandler = () -> [String]

    fileprivate static let _lock = RecursiveLock()
    fileprivate static let _subscriptionCallstackLock = RecursiveLock()
    fileprivate static var _defaultErrorHandler: DefaultErrorHandler = { subscriptionCallStack, error in
        #if DEBUG
            let serializedCallStack = subscriptionCallStack.joined(separator: "\n")
            print("Unhandled error happened: \(error)\n subscription called from:\n\(serializedCallStack)")
        #endif
    }
    fileprivate static var _subscriptionCallstackGenerationHandler: SubscriptionCallstackGenerationHandler = {
        #if DEBUG
            return Hooks.recordCallStackOnError ? Thread.callStackSymbols : []
        #else
            return []
        #endif
    }

    /// Error handler called in case onError handler wasn't provided.
    public static var defaultErrorHandler: DefaultErrorHandler {
        get {
            _lock.lock(); defer { _lock.unlock() }
            return _defaultErrorHandler
        }
        set {
            _lock.lock(); defer { _lock.unlock() }
            _defaultErrorHandler = newValue
        }
    }

Review comment (suggestion):
We can reuse `_lock`, don't see any reason for additional `_subscriptionCallstackLock`.

Code after:
                        onError(error)
                    }
                    else {
                        Hooks.defaultErrorHandler(callStack, error)
                    }
                    disposable.dispose()
                case .completed:
                    onCompleted?()
                    disposable.dispose()
                }
            }
            return Disposables.create(
                self.asObservable().subscribe(observer),
                disposable
            )
    }
}

import class Foundation.NSRecursiveLock

extension Hooks {
    public typealias DefaultErrorHandler = (_ subscriptionCallStack: [String], _ error: Error) -> ()
    public typealias CustomCaptureSubscriptionCallstack = () -> [String]

    fileprivate static let _lock = RecursiveLock()
    fileprivate static var _defaultErrorHandler: DefaultErrorHandler = { subscriptionCallStack, error in
        #if DEBUG
            let serializedCallStack = subscriptionCallStack.joined(separator: "\n")
            print("Unhandled error happened: \(error)\n subscription called from:\n\(serializedCallStack)")
        #endif
    }
    fileprivate static var _customCaptureSubscriptionCallstack: CustomCaptureSubscriptionCallstack = {
        #if DEBUG
            return Thread.callStackSymbols
        #else
            return []
        #endif
    }

    /// Error handler called in case onError handler wasn't provided.
    public static var defaultErrorHandler: DefaultErrorHandler {
        get {
            _lock.lock(); defer { _lock.unlock() }
            return _defaultErrorHandler
        }
        set {
            _lock.lock(); defer { _lock.unlock() }
            _defaultErrorHandler = newValue
        }
    }