Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

waitForStatusRecordUnlockIfNotSelfLocked deadlocks on macOS 14.0 #67110

Open
eaigner opened this issue Jul 4, 2023 · 1 comment
Open

waitForStatusRecordUnlockIfNotSelfLocked deadlocks on macOS 14.0 #67110

eaigner opened this issue Jul 4, 2023 · 1 comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels

Comments

@eaigner
Copy link

eaigner commented Jul 4, 2023

Description

waitForStatusRecordUnlockIfNotSelfLocked deadlocks on macOS 14.0 beta 2. There must have been some changes to libswiftConcurrency in Sonoma, since it does (obviously) not occur on 13.4.1 (22F82).

I have tested this with my own code as well as with Apples AsyncChannel implementation

Steps to reproduce

The exact condition is unknown, but sometimes CheckedContinuation.resume(...) does not return and keeps spinning, thus locking up the application. As for the AsyncChannel package, it deadlocks here

Expected behavior

CheckedContinuation.resume(...) should return immediately, as guaranteed.

Environment

  • Swift compiler version info

    swift-driver version: 1.75.2 Apple Swift version 5.8.1 (swiftlang-5.8.0.124.5 clang-1403.0.22.11.100)
    Target: arm64-apple-macosx14.0

  • Xcode version info

    Version 15.0 beta (15A5160n)

  • Deployment target:

    14.0 Beta (23A5276g)

Here is a stacktracke I recorded

(lldb) bt
* thread #23, queue = 'com.apple.root.user-initiated-qos.cooperative'
    frame #0: 0x000000018504c66c libsystem_kernel.dylib`__ulock_wait + 8
    frame #1: 0x00000001850b770c libsystem_platform.dylib`_os_unfair_lock_lock_slow + 208
    frame #2: 0x00000001086482fc libclang_rt.tsan_osx_dynamic.dylib`wrap_os_unfair_lock_lock + 188
    frame #3: 0x000000022104c3c0 libswift_Concurrency.dylib`waitForStatusRecordUnlockIfNotSelfLocked(swift::AsyncTask*, swift::ActiveTaskStatus&) + 184
    frame #4: 0x000000022104c7c4 libswift_Concurrency.dylib`withStatusRecordLock(swift::AsyncTask*, swift::ActiveTaskStatus, __swift::__runtime::llvm::function_ref<void (swift::ActiveTaskStatus)>, __swift::__runtime::llvm::function_ref<void (swift::ActiveTaskStatus, swift::ActiveTaskStatus&)>) + 84
    frame #5: 0x000000022104ca4c libswift_Concurrency.dylib`swift::updateStatusRecord(swift::AsyncTask*, swift::TaskStatusRecord*, __swift::__runtime::llvm::function_ref<void ()>, swift::ActiveTaskStatus&, __swift::__runtime::llvm::function_ref<void (swift::ActiveTaskStatus, swift::ActiveTaskStatus&)>) + 56
    frame #6: 0x0000000221045ed4 libswift_Concurrency.dylib`swift::AsyncTask::flagAsAndEnqueueOnExecutor(swift::ExecutorRef) + 128
    frame #7: 0x000000022104b284 libswift_Concurrency.dylib`resumeTaskAfterContinuation(swift::AsyncTask*, swift::ContinuationAsyncContext*) + 192
    frame #8: 0x0000000221049a88 libswift_Concurrency.dylib`swift_continuation_throwingResumeImpl(swift::AsyncTask*) + 244
    frame #9: 0x0000000105a93194 MYAPP`UnsafeContinuation.resume(returning:) at <compiler-generated>:0
    frame #10: 0x0000000105a8ec28 MYAPP`UnsafeContinuation.resume<>() at <compiler-generated>:0
  * frame #11: 0x0000000105abb264 MYAPP`closure #1 in ChannelStorage.next(stateMachine=AsyncAlgorithms.ChannelStateMachine<Git.FormatParser.ParsedLine, Swift.Never> @ 0x00000001323381e0) at ChannelStorage.swift:104:33
    frame #12: 0x0000000105abb3dc MYAPP`partial apply for closure #1 in ChannelStorage.next() at <compiler-generated>:0
    frame #13: 0x0000000105b325a4 MYAPP`closure #1 in ManagedCriticalState.withCriticalRegion<τ_0_0>(header=0x1323381e0, lock=0x132338210, critical=0x105abb384) at Locking.swift:136:18
    frame #14: 0x0000000105b32690 MYAPP`partial apply for closure #1 in ManagedCriticalState.withCriticalRegion<τ_0_0>(_:) at <compiler-generated>:0
    frame #15: 0x0000000194f7019c libswiftCore.dylib`Swift.ManagedBuffer.withUnsafeMutablePointers<τ_0_0>((Swift.UnsafeMutablePointer<τ_0_0>, Swift.UnsafeMutablePointer<τ_0_1>) throws -> τ_1_0) throws -> τ_1_0 + 180
    frame #16: 0x0000000105b3243c MYAPP`ManagedCriticalState.withCriticalRegion<τ_0_0>(critical=0x105abb384, self=AsyncAlgorithms.ManagedCriticalState<AsyncAlgorithms.ChannelStateMachine<Git.FormatParser.ParsedLine, Swift.Never>> @ 0x000000016bacab68) at Locking.swift:133:16
    frame #17: 0x0000000105ab9fac MYAPP`ChannelStorage.next(self=AsyncAlgorithms.ChannelStorage<Git.FormatParser.ParsedLine, Swift.Never> @ 0x00000001394f4c40) at ChannelStorage.swift:97:50
    frame #18: 0x0000000105aa5940 MYAPP`AsyncChannel.Iterator.next(self=AsyncAlgorithms.AsyncChannel<Git.FormatParser.ParsedLine>.Iterator @ 0x0000000137710870) at AsyncChannel.swift:57
    frame #19: 0x00000001056bb070 MYAPP`closure #1 in closure #1 in GitCommand.log(entries=0x00000001341c5160, lines=0x0000000138f0fd20) at GitCommand+Log.swift:21
    frame #20: 0x00000001056c0484 MYAPP`partial apply for closure #1 in closure #1 in GitCommand.log(order:query:arguments:entries:) at <compiler-generated>:0
@eaigner eaigner added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Jul 4, 2023
@mikeash
Copy link
Contributor

mikeash commented Jul 25, 2023

Cancellation handlers are called from a tricky context which holds a lock in the task. I'm not sure if that can be improved. As it is, the cancellation handler needs to be careful if it's going to do any locking, as it does here. To avoid deadlocks, you want to either avoid manipulating the task while holding a lock that the cancellation handler will acquire, or avoid acquiring a lock in the cancellation handler at all (maybe have it spawn a concurrent task which then does the real work).

AsyncChannel does indeed suffer from this as well. I've filed a bug for that.

I updated the documentation to add a warning about the deadlock potential here: #67457

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels
Projects
None yet
Development

No branches or pull requests

2 participants