Skip to content

Avoid using temp_await on loadRootPackage #7009

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

Merged
merged 8 commits into from
Dec 12, 2023
Merged

Conversation

MaxDesiatov
Copy link
Contributor

@MaxDesiatov MaxDesiatov commented Oct 16, 2023

Motivation:

Using locks to convert asynchronous functions to synchronous is dangerous, since this can deadlock the Swift Concurrency thread pool. Unfortunately, temp_await (AKA tsc_await) function utilizes exactly this approach.

As SourceKit-LSP starts adopting Swift Concurrency (swiftlang/sourcekit-lsp#850), we should avoid using temp_await in our codebase and make the callers of corresponding async or callback-taking functions themselves async. Otherwise there's a risk of deadlocks in SourceKit-LSP itself, since their Swift Concurrency tasks may be blocked by our uses of temp_await under the hood. We have ~60 uses of temp_await in our codebase, carefully removing them in small portions will reduce the potential disruption.

Modifications:

loadRootPackage already has an async overload in Workspace. Converted callers in SwiftPM commands to use AsyncSwiftCommand protocol instead of SwiftCommand. Also, test cases were made async too.

Result:

Reduced the number of temp_await uses in Source.

@@ -8803,13 +8800,15 @@ final class WorkspaceTests: XCTestCase {

let observability = ObservabilitySystem.makeForTesting()
let wks = try workspace.getOrCreateWorkspace()
XCTAssertNoThrow(try temp_await {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XCTAssertNoThrow doesn't support async 🥲

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

1 similar comment
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov MaxDesiatov self-assigned this Oct 16, 2023
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

2 similar comments
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

MaxDesiatov added a commit that referenced this pull request Oct 17, 2023
Follow up to #7009, which provides the detailed motivation: we should avoid `temp_await` as it can lead to deadlocks when combined with Swift Concurrency.
MaxDesiatov added a commit that referenced this pull request Oct 17, 2023
Follow up to #7009, which provides the detailed motivation: we should avoid `temp_await` as it can lead to deadlocks when combined with Swift Concurrency.
@MaxDesiatov MaxDesiatov requested a review from compnerd October 17, 2023 18:05
@MaxDesiatov
Copy link
Contributor Author

@compnerd would you be able to confirm that this change is fine from the perspective of Swift Concurrency support on Windows?

@compnerd
Copy link
Member

@compnerd would you be able to confirm that this change is fine from the perspective of Swift Concurrency support on Windows?

I think that as long as we restrict this to 5.10/5.11 it should be okay. Of course we should run through the test suite as well.

@MaxDesiatov
Copy link
Contributor Author

There are no plans to backport it to 5.9. How far are we from enabling the test suite on Windows CI? Until then is the only way to test it on Windows to build latest 5.10 locally and to run swift test locally too?

@MaxDesiatov MaxDesiatov added the next waiting for next merge window label Oct 19, 2023
@MaxDesiatov MaxDesiatov removed the next waiting for next merge window label Nov 28, 2023
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov MaxDesiatov force-pushed the maxd/async-load-package branch from 7b28181 to 1d5922d Compare December 7, 2023 21:37
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

MaxDesiatov added a commit that referenced this pull request Dec 7, 2023
Follow up to #7009,
which provides the detailed motivation: we should avoid `temp_await` as
it can lead to deadlocks when combined with Swift Concurrency.

---------

Co-authored-by: Yim Lee <yim_lee@apple.com>
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

@MaxDesiatov MaxDesiatov enabled auto-merge (squash) December 12, 2023 14:48
Copy link
Contributor

@AndrewHoos AndrewHoos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It all looks great except for checkPrecomputeResolution. I don't see why the checkPrecomputeResolution method needs to have a closure. Closures normally are for async callbacks, context managers, or optional extra validation (e.g. assert throws). It seems like that API should get reworked to by natively async

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

@@ -71,7 +69,7 @@ extension SwiftPackageTool {
let args = [swiftFormat.pathString] + formatOptions + [packagePath.pathString] + paths
print("Running:", args.map{ $0.spm_shellEscaped() }.joined(separator: " "))

let result = try TSCBasic.Process.popen(arguments: args)
let result = try await TSCBasic.Process.popen(arguments: args)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked, but I wonder if this is actually non-blocking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I'm cleaning that up on TSC side now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapped that with a concurrent queue in swiftlang/swift-tools-support-core#450

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣 ask me if I have deadlocked the swift concurrency pool before...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to use the safe_async wrapper until that lands?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've enabled auto-merge on that one, so I don't think there will be a significant amount of time when this PR is merged, but one in TSC isn't.

@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

1 similar comment
@MaxDesiatov
Copy link
Contributor Author

@swift-ci test windows

MaxDesiatov added a commit that referenced this pull request Dec 12, 2023
Follow up to #7009,
which provides the detailed motivation: we should avoid `temp_await` as
it can lead to deadlocks when combined with Swift Concurrency.
@MaxDesiatov MaxDesiatov merged commit 6bed023 into main Dec 12, 2023
@MaxDesiatov MaxDesiatov deleted the maxd/async-load-package branch December 12, 2023 19:14
MaxDesiatov added a commit that referenced this pull request Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants