Skip to content

build: Repair the build on WASI platform (take 3) #5057

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 12 commits into from
Aug 9, 2024

Conversation

kateinoigakukun
Copy link
Member

I forgot to tell @MaxDesiatov we need several additional changes other than #5052

@kateinoigakukun
Copy link
Member Author

@swift-ci test

@MaxDesiatov MaxDesiatov added the WASI WebAssembly System Interface-related changes label Aug 7, 2024
@MaxDesiatov
Copy link
Contributor

I merged that one, but that introduced conflicts unfortunately 😢

…bxml2

`find_package(LibXml2 REQUIRED)` sets `LIBXML2_INCLUDE_DIR` to the correct
include directory for the libxml2 headers. Use this variable instead of
hardcoding `/usr/include/libxml2`. This allows the build to work with
custom libxml2 builds on WASI.
This commit disables libdispatch and threads on WASI, and enables
wasi-libc emulation features.
Because networking is not a part of WASI Preview 1. We can add it back
when it is available.
…uilds

Those headers has been imported by Swift side through
`CoreFoundation/Base.subproj/SwiftRuntime/CoreFoundation.h` since
44031b5 but we switched to
use CoreFoundation.h directly after the recore, and the header was not
updated in 44031b5
Treat WASI as an usual Unix-like system
We had been using the vendored BlocksRuntime on WASI, but the build
configuration was removed during the recore. This change restores the
vendored BlocksRuntime build configuration on WASI.
Mark them available on WASI. Otherwise, the `static inline` implementations
are activated and the build fails with multiple definitions.
@@ -600,7 +600,7 @@ CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
#if TARGET_OS_WASI
hint = NULL;
#else
hint = __builtin_frame_address(0);
hint = __builtin_return_address(0);
Copy link
Member Author

@kateinoigakukun kateinoigakukun Aug 7, 2024

Choose a reason for hiding this comment

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

It was accidentally changed in #5052 We should continue using __builtin_return_address on non-WASI platforms.

@kateinoigakukun
Copy link
Member Author

@swift-ci test

@@ -471,7 +471,7 @@ open class XMLParser : NSObject {
open var allowedExternalEntityURLs: Set<URL>?

#if os(WASI)
private static var _currentParser: XMLParser?
private nonisolated(unsafe) static var _currentParser: XMLParser?
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems unsafe at first look, since any thread can call setCurrentParser and effectively traffic XMLParser between actors. Can you elaborate a bit more on why this is necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

WASI preview1 ABI is always single-threaded, so memory access to the same storage should not happen simultaneously. So any data storage should be safe to access from any isolation context on WASI, but 6 lang mode requires explicit marking here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps the better question is what does actor isolation mean on WASI where everything is single threaded? This will allow this mutable state to pass between actor isolations on WASI, is that ok because we know it's single threaded? Or should this instead be some form of task-local storage to prevent it from traveling across actors?

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't need task local storage at all here because there is no suspension point during XMLParser.parse call. No suspension point means no Task switching, thus it's guaranteed that XMLParser.setCurrentParser(self) is not called twice before resetting the storage by XMLParser.setCurrentParser(nil).
The only exception is the case where user provided XMLParserDelegate methods call XMLParser.parse(), but the reentrancy issue is not specific to os(WASI) branch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. The reentrancy possibility isn't unique to WASI, but its ability to manipulate the underlying nonisolated(unsafe) variable across actor isolations is unique to WASI with this change (on other platforms, that variable is thread-specific - which should probably be marked as unavailable from async for this reason).

The example I'm thinking of is: someone calls XMLParser.parse(), in a delegate callout they create a new detached task on a different actor calling XMLParser.parse() again. At this point, we have two actors manipulating the same underlying nonisolated(unsafe) variable. Typically, that'd be a concurrency violation because two actors are mutating the same shared state. Since WASI is single-threaded, we know that this can't data race in practice, but it's still a violation in the Swift 6 concurrency design and I'm not sure how to rationalize that with the thread model of WASI at the moment (cc @hborla in case you have any insight here)

Copy link
Member Author

Choose a reason for hiding this comment

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

The example I'm thinking of is: someone calls XMLParser.parse(), in a delegate callout they create a new detached task on a different actor calling XMLParser.parse() again.

Having a closer look, I noticed the problem exists even in non-WASI code path since jobs associated with two different Tasks can be scheduled on the same thread, and in that case two different tasks can manipulate the same thread local variable.

So we had two issues in the existing code, 1. reentrancy issue, 2. sharing mutable storage across Tasks. I'll send a fix for them in another PR and exclude the commit from this PR. Does it make sense?

Copy link
Member Author

Choose a reason for hiding this comment

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

@jmschonfeld Opened another PR to fix the issues #5061

@MaxDesiatov MaxDesiatov requested a review from jmschonfeld August 8, 2024 10:26
@MaxDesiatov
Copy link
Contributor

@swift-ci test

@MaxDesiatov
Copy link
Contributor

@swift-ci test windows

@@ -471,7 +471,7 @@ open class XMLParser : NSObject {
open var allowedExternalEntityURLs: Set<URL>?

#if os(WASI)
private static var _currentParser: XMLParser?
private nonisolated(unsafe) static var _currentParser: XMLParser?
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. The reentrancy possibility isn't unique to WASI, but its ability to manipulate the underlying nonisolated(unsafe) variable across actor isolations is unique to WASI with this change (on other platforms, that variable is thread-specific - which should probably be marked as unavailable from async for this reason).

The example I'm thinking of is: someone calls XMLParser.parse(), in a delegate callout they create a new detached task on a different actor calling XMLParser.parse() again. At this point, we have two actors manipulating the same underlying nonisolated(unsafe) variable. Typically, that'd be a concurrency violation because two actors are mutating the same shared state. Since WASI is single-threaded, we know that this can't data race in practice, but it's still a violation in the Swift 6 concurrency design and I'm not sure how to rationalize that with the thread model of WASI at the moment (cc @hborla in case you have any insight here)

We accidentally changed it to `__builtin_frame_address` in
7f38264 but we should keep it as
`__builtin_return_address` as it was before.
To avoid shippig BlocksRuntime as a separate library, build it as an
object library and include it in CoreFoundation static archive.
We ported BlocksRuntime CMakeLists.txt from the state of
02b7d8f but we don't find any
reason to set POSITION_INDEPENDENT_CODE=FALSE for BlocksRuntime.
@jmschonfeld
Copy link
Contributor

@swift-ci please test

@kateinoigakukun
Copy link
Member Author

@swift-ci test Windows

@kateinoigakukun kateinoigakukun merged commit 6450f42 into swiftlang:main Aug 9, 2024
2 of 3 checks passed
@kateinoigakukun kateinoigakukun deleted the yt/repair-wasi-build branch August 9, 2024 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WASI WebAssembly System Interface-related changes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants