Skip to content

Fix asyncMainDrainQueue noreturn warning #61692

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 3 commits into from
Mar 3, 2023

Conversation

etcwilde
Copy link
Member

The async main drain queue function is noreturn, but was emitting a warning due to the override compatibility returning the result of the overridden function in the wrapper override function. To work around this, I've added the OVERRIDE_TASK_NORETURN macro, which provides an override point for noreturn functions in the concurrency library that doesn't return the result from the wrapped function, avoiding the warning. In the event that the function is not set, the macro is set to the normal OVERRIDE with the return type set to void.

rdar://85521851

@etcwilde etcwilde requested a review from mikeash October 24, 2022 01:35
@etcwilde
Copy link
Member Author

@swift-ci please test

@etcwilde
Copy link
Member Author

macOS:

ld: warning: Could not find or use auto-linked library 'SwiftParserDiagnostics'
ld: warning: Could not find or use auto-linked library 'SwiftBasicFormat'
ld: warning: Could not find or use auto-linked library '_SwiftSyntaxMacros'
ld: warning: Could not find or use auto-linked library 'SwiftParser'
ld: warning: Could not find or use auto-linked library 'SwiftSyntaxBuilder'
ld: warning: Could not find or use auto-linked library 'SwiftSyntax'
ld: warning: Could not find or use auto-linked library 'SwiftDiagnostics'
ld: warning: Could not find or use auto-linked library 'SwiftOperators'
Undefined symbols for architecture x86_64:
  "type metadata accessor for SwiftParserDiagnostics.ParseDiagnosticsGenerator", referenced from:
      closure #1 () -> Swift.Int32 in SwiftCompilerSupport._parserConsistencyCheck(bufferPtr: Swift.UnsafePointer<Swift.UInt8>, bufferLength: Swift.Int, filename: Swift.UnsafePointer<Swift.UInt8>, flags: Swift.UInt32, hookCtx: Swift.OpaquePointer, diagnosticHook: @convention(c) (Swift.Int, Swift.UnsafePointer<Swift.Int8>, Swift.OpaquePointer) -> ()) -> Swift.Int32 in libSwiftCompilerSupport.a(ConsistencyCheck.swift.o)
      closure #1 () throws -> A in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) throws -> A in (extension in SwiftSyntaxBuilder):SwiftSyntaxBuilder.SyntaxExpressibleByStringInterpolation.init(stringInterpolationOrThrow: SwiftSyntaxBuilder.SyntaxStringInterpolation) throws -> A in libSwiftSyntaxBuilder.a(Syntax+StringInterpolation.swift.o)
  "static SwiftParserDiagnostics.ParseDiagnosticsGenerator.diagnostics<A where A: SwiftSyntax.SyntaxProtocol>(for: A) -> [SwiftDiagnostics.Diagnostic]", referenced from:
      closure #1 () -> Swift.Int32 in SwiftCompilerSupport._parserConsistencyCheck(bufferPtr: Swift.UnsafePointer<Swift.UInt8>, bufferLength: Swift.Int, filename: Swift.UnsafePointer<Swift.UInt8>, flags: Swift.UInt32, hookCtx: Swift.OpaquePointer, diagnosticHook: @convention(c) (Swift.Int, Swift.UnsafePointer<Swift.Int8>, Swift.OpaquePointer) -> ()) -> Swift.Int32 in libSwiftCompilerSupport.a(ConsistencyCheck.swift.o)
      closure #1 () throws -> A in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) throws -> A in (extension in SwiftSyntaxBuilder):SwiftSyntaxBuilder.SyntaxExpressibleByStringInterpolation.init(stringInterpolationOrThrow: SwiftSyntaxBuilder.SyntaxStringInterpolation) throws -> A in libSwiftSyntaxBuilder.a(Syntax+StringInterpolation.swift.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Linux:

In file included from /home/build-user/swift/stdlib/public/Concurrency/Task.cpp:1582:
/home/build-user/swift/stdlib/public/Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def:162:1: error: unknown type name 'Override_task_asyncMainDrainQueue'
OVERRIDE_TASK_NORETURN(task_asyncMainDrainQueue,
^
/home/build-user/swift/stdlib/public/Concurrency/Task.cpp:1572:12: note: expanded from macro 'OVERRIDE_TASK_NORETURN'
    static Override_##name Override;                                           \
           ^
<scratch space>:152:1: note: expanded from here
Override_task_asyncMainDrainQueue
^
In file included from /home/build-user/swift/stdlib/public/Concurrency/Task.cpp:1582:
/home/build-user/swift/stdlib/public/Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def:162:1: error: use of undeclared identifier 'getOverride_task_asyncMainDrainQueue'; did you mean 'swift_task_asyncMainDrainQueue'?
/home/build-user/swift/stdlib/public/Concurrency/Task.cpp:1575:45: note: expanded from macro 'OVERRIDE_TASK_NORETURN'
        &Predicate, [](void *) { Override = getOverride_##name(); }, nullptr); \
                                            ^
<scratch space>:153:1: note: expanded from here
getOverride_task_asyncMainDrainQueue
^
/home/build-user/swift/stdlib/public/Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def:162:1: note: 'swift_task_asyncMainDrainQueue' declared here
/home/build-user/swift/stdlib/public/Concurrency/Task.cpp:1571:32: note: expanded from macro 'OVERRIDE_TASK_NORETURN'
  attrs ccAttrs void namespace swift_##name COMPATIBILITY_PAREN(typedArgs) {   \
                               ^
<scratch space>:150:1: note: expanded from here
swift_task_asyncMainDrainQueue
^

Windows:

In file included from C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency\Task.cpp:1582:
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def(162,1): error: unknown type name 'Override_task_asyncMainDrainQueue'
OVERRIDE_TASK_NORETURN(task_asyncMainDrainQueue,
^
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency\Task.cpp(1572,12): note: expanded from macro 'OVERRIDE_TASK_NORETURN'
    static Override_##name Override;                                           \
           ^
<scratch space>(48,1): note: expanded from here
Override_task_asyncMainDrainQueue
^
In file included from C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency\Task.cpp:1582:
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def(162,1): error: use of undeclared identifier 'getOverride_task_asyncMainDrainQueue'; did you mean 'swift_task_asyncMainDrainQueue'?
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency\Task.cpp(1575,45): note: expanded from macro 'OVERRIDE_TASK_NORETURN'
        &Predicate, [](void *) { Override = getOverride_##name(); }, nullptr); \
                                            ^
<scratch space>(49,1): note: expanded from here
getOverride_task_asyncMainDrainQueue
^
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency/../CompatibilityOverride/CompatibilityOverrideConcurrency.def(162,1): note: 'swift_task_asyncMainDrainQueue' declared here
C:\Users\swift-ci\jenkins\workspace\swift-PR-windows\swift\stdlib\public\Concurrency\Task.cpp(1571,32): note: expanded from macro 'OVERRIDE_TASK_NORETURN'
  attrs ccAttrs void namespace swift_##name COMPATIBILITY_PAREN(typedArgs) {   \
                               ^
<scratch space>(46,1): note: expanded from here
swift_task_asyncMainDrainQueue
^

@etcwilde etcwilde force-pushed the ewilde/fix-noreturn-warning branch from b931348 to d635a2d Compare October 24, 2022 11:39
@etcwilde
Copy link
Member Author

@swift-ci please test

Copy link
Contributor

@mikeash mikeash left a comment

Choose a reason for hiding this comment

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

Looks good, thanks!

@etcwilde
Copy link
Member Author

Linux:

/tmp/lit-tmp-hv4anj_5/async_task_detach-aedf8a.o:async_task_detach-aedf8a.o:function main: error: undefined reference to 'swift_task_asyncMainDrainQueue'

Windows:

_Concurrency.obj : error LNK2019: unresolved external symbol swift_task_asyncMainDrainQueue referenced in function $ss13_runAsyncMainyyyyYaKcF

The async main drain queue function is noreturn, but was emitting a
warning due to the override compatibility returning the result of the
overridden function in the wrapper override function. To work around
this, I've added the `OVERRIDE_TASK_NORETURN` macro, which provides an
override point for noreturn functions in the concurrency library that
doesn't return the result from the wrapped function, avoiding the
warning. In the event that the function is not set, the macro is set to
the normal `OVERRIDE` with the return type set to `void`.
@etcwilde etcwilde force-pushed the ewilde/fix-noreturn-warning branch from d635a2d to ec7a926 Compare March 2, 2023 03:51
etcwilde added 2 commits March 1, 2023 22:16
The swift_task_asyncMainDrainQueue function acts as the entrypoint into
driving the main queues, ultimately running the whole program and acting
as the backing driver of the main actor. Making the function hookable
means that custom concurrency runtimes can implement their own async
entrypoints, allowing async top-level code and async-main to "just
work".
This patch tests that the hook actually works. Not going to lie, the
test is pretty disgusting. The function we're testing is a noreturn
function, which introduces some interesting challenges when we need to
return to finish the test.

I need to somehow exit the function without killing the process, but
also without returning. If I just use a loop properly, the test will
hang for the age of the universe. If I don't and return from the hook,
the test will abort or crash. I tried removing the abort after the hook
in the hook override macro to see if we could sneak past the compiler,
and no, that explodes on the return pointer.

So, here's the workaround. C++11 threads don't seem to have a way to
kill themselves, but you can use `pthread_exit` or `pthread_kill` to
either kill yourself or kill another thread. So the override function
sets the `Ran` to true, and then exits (which is noreturn, so we haven't
broken that contract), killing itself and allowing us to join without
returning from the inferior. The main thread immediately waits for the
original thread to die. Since it blocks, we avoid the possible race on
setting the state of `Ran` in the override hook and where it gets
checked in the test. If that becomes an issue, we could probably just
wrap the `Ran` bool in an atomic and call it a day.

Anyway, it's well past my bedtime and I'm playing with threads. This can
only end in a creative disaster. :D
@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

@swift-ci please test

@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

@mikeash I had some fun writing that test. Turns out it's pretty tricky testing a noreturn function when you need to return control to validate the run of the test. I used pthreads, but if you have any better ideas, I'm all ears.

@mikeash
Copy link
Contributor

mikeash commented Mar 2, 2023

I don't think I have any better ideas. You could get out of it by throwing an exception, but I don't think that qualifies as "better."

@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

macOS failure:
swift/SwiftCompilerSources/Sources/Basic/SourceLoc.swift:63:49: error: value of type 'swift.CharSourceRange' has no member 'getByteLength' self.init(start: start, byteLength: bridged.getByteLength())

Not my fault this time.

@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

@swift-ci please test macOS

@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

macOS failure should be fixed by: #64029

@etcwilde
Copy link
Member Author

etcwilde commented Mar 2, 2023

@swift-ci please test macOS

@etcwilde etcwilde merged commit 877d03f into swiftlang:main Mar 3, 2023
@etcwilde etcwilde deleted the ewilde/fix-noreturn-warning branch April 2, 2023 05:47
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.

2 participants