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

Fix SIGINT handling during swift run #4224

Merged
merged 2 commits into from
Mar 17, 2022
Merged

Conversation

kkebo
Copy link
Contributor

@kkebo kkebo commented Mar 17, 2022

I fixed SIGINT handling during swift run.

Motivation:

Since Swift 5.6, Ctrl-C no longer works during swift run.

The issue was introduced in #3815. That PR added signal(SIGINT, SIG_IGN) for handling SIGINT by DispatchSourceSignal. That's no problem, but exec(...) replaces the process, so once exec(...) is called, DispatchSourceSignal can't handle SIGINT anymore and no one can handle it. Therefore, it is necessary to cancel signal(SIGINT, SIG_IGN) before calling exec(...).

Modifications:

I created a wrapper function of exec(...) that calls signal(SIGINT, SIG_DFL) just before exec(...) in order to cancel signal(SIGINT, SIG_IGN), and use it from SwiftRunTool (2 methods), WatchmanHelper, and SnippetCard.

Result:

Ctrl-C will work again during swift run.

@@ -158,6 +166,9 @@ public struct SwiftRunTool: SwiftCommand {
try ProcessEnv.chdir(swiftTool.originalWorkingDirectory)
}

// SwiftTool can't handle signals anymore, so reset the signal handler to SIG_DFL before call exec()
signal(SIGINT, SIG_DFL)
Copy link
Member

Choose a reason for hiding this comment

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

thanks for the fix @kkk669 makes sense. could we maybe create a wrapper for exec in this file that reset the signal handler first then delegates to the "real" exec? this way we can keep it DRYer. wdyt?

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 agree with you. Should I create a wrapper just for SwiftRunTool? Or should I create it so that it can be used from other commands? If there is a possibility of using exec for other commands in the future, I feel that a wrapper should be created for the entire Commands target.

Copy link
Member

Choose a reason for hiding this comment

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

good point. lets add to SwiftTool and then we can call that from any other tool

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the direction. I will try.

Copy link
Contributor Author

@kkebo kkebo Mar 17, 2022

Choose a reason for hiding this comment

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

I created a wrapper function in bff14cc 72d8c92.

With this change, not only SwiftRunTool but also WatchmanHelper and SnippetCard now call the wrapper.

I wasn't sure whether to create SwiftTool.exec or global exec, but in the end I went with the latter. Because I believe that it will prevent mistakes like using TSCBasic.exec in the future.

import Darwin
#else
import Glibc
#endif
Copy link
Member

Choose a reason for hiding this comment

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

#if canImport(WinSDK)
import WinSDK
#elseif canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#endif

more idiomatic / correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I also think so. I'll change it to that form.

SwiftTool.swift has the same problem.

https://github.com/apple/swift-package-manager/blob/0e804edf19e05ddd02d05c1534d4ceea01117e5f/Sources/Commands/SwiftTool.swift#L26_L32

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

@kkebo kkebo Mar 17, 2022

Choose a reason for hiding this comment

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

These imports were removed in bff14cc 72d8c92.

@tomerd
Copy link
Member

tomerd commented Mar 17, 2022

@swift-ci smoke test

@@ -286,6 +286,14 @@ extension SwiftCommand {
public static var _errorLabel: String { "error" }
}

/// A safe wrapper of TSCBasic.exec.
static func exec(path: String, args: [String]) throws -> Never {
Copy link
Member

@tomerd tomerd Mar 17, 2022

Choose a reason for hiding this comment

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

remove static, or make into a static func of SwiftTool

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the Commands module, this wrapper function is called by default if
you write `try exec(path: ..., args: ...)`.
@tomerd
Copy link
Member

tomerd commented Mar 17, 2022

@swift-ci smoke test

@tomerd
Copy link
Member

tomerd commented Mar 17, 2022

thanks again @kkk669 could you also crate a cherry-pick PR against the release/5.6 branch, this may be worth including in a patch version

@tomerd tomerd merged commit 9ad75c5 into apple:main Mar 17, 2022
@kkebo kkebo deleted the fix-swift-run-sigint branch March 18, 2022 00:25
kkebo added a commit to kkebo/swift-package-manager that referenced this pull request Mar 18, 2022
* Fix SIGINT handling during `swift run`
* Create a safe wrapper of TSCBasic.exec
* In the Commands module, this wrapper function is called by default if
you write `try exec(path: ..., args: ...)`.

Co-authored-by: Kenta Kubo <kkk669@users.noreply.github.com>
@kkebo
Copy link
Contributor Author

kkebo commented Mar 18, 2022

@tomerd Thank you for merging this. I've created #4231.

@compnerd
Copy link
Collaborator

This broke the windows build: https://ci-external.swift.org/job/oss-swift-windows-toolchain-x86_64-vs2019/1178/console

@kkebo
Copy link
Contributor Author

kkebo commented Mar 18, 2022

@compnerd Thank you for mentioning it. I'll investigate it. Currently, I'm preparing a Windows VM.

@kkebo
Copy link
Contributor Author

kkebo commented Mar 18, 2022

Perhaps I found the cause. On Windows, signal(SIGINT, SIG_IGN) isn't called, so I had to enclose the wrapper of TSCBasic.exec with #if !(os(Windows)).

kkebo added a commit to kkebo/swift-package-manager that referenced this pull request Mar 18, 2022
kkebo added a commit to kkebo/swift-package-manager that referenced this pull request Mar 18, 2022
compnerd pushed a commit that referenced this pull request Mar 19, 2022
kkebo added a commit to kkebo/swift-package-manager that referenced this pull request Mar 19, 2022
tomerd pushed a commit that referenced this pull request Mar 24, 2022
…4235, #4250) (#4231)

* Fix SIGINT handling during `swift run` (#4224)
* Fix SIGINT handling during `swift run`
* Create a safe wrapper of TSCBasic.exec
* add test fixture for handling SIGINT on "swift run" (#4250)

Co-authored-by: tomer doron <tomer@apple.com>

rdar://90574791
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants