Skip to content

[Build][Runtime] Add a new threading library. #59287

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 40 commits into from
Jun 9, 2022

Conversation

al45tair
Copy link
Contributor

@al45tair al45tair commented Jun 6, 2022

A fair bit of this is really shuffling things around — that's largely true for the swift::Mutex, which was an existing thing. swift::Thread is really a placeholder for when we need more support — right now, we don't need any of the functionality that e.g. std::thread has, but we do need some functionality it doesn't have. It's also desirable to be able to choose which threading package to use, especially for embedded use or for testing purposes, and if we make everything defer to the C++ library we'll only be able to use whatever the C++ library is using.

The main new things are:

  • You can ask to use a specific threading package.
  • The threading code is in its own library, so no more #includes of implementation files in order to bring them in to the standard library or concurrency code.
  • swift::Lazy now uses swift::once rather than having its own implementation that uses a macro.
  • New swift::once implementations for Linux and Windows that should be somewhat faster on those platforms.
  • Improved error handling, so the threading code raising errors can hook into the error handling used in the places it's being used.
  • Adjusted the TLS support code slightly, to avoid trying to put TLS keys in template arguments, as that isn't guaranteed to work.

rdar://90776105

@al45tair
Copy link
Contributor Author

al45tair commented Jun 6, 2022

@swift-ci Please test

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

preset=buildbot,tools=RA,stdlib=RDA
@swift-ci Please test with preset macOS platform

al45tair added 28 commits June 7, 2022 07:39
SWIFT_STDLIB_SINGLE_THREADED_RUNTIME is too much of a blunt instrument here.
It covers both the Concurrency runtime and the rest of the runtime, but we'd
like to be able to have e.g. a single-threaded Concurrency runtime while
the rest of the runtime is still thread safe (for instance).

So: rename it to SWIFT_STDLIB_SINGLE_THREADED_CONCURRENCY and make it just
control the Concurrency runtime, then add a SWIFT_STDLIB_THREADING_PACKAGE
setting at the CMake/build-script level, which defines
SWIFT_STDLIB_THREADING_xxx where xxx depends on the chosen threading package.

This is especially useful on systems where there may be a choice of threading
package that you could use.

rdar://90776105
Read/write locks are not as good as you'd think; a simple mutex is better in
almost all cases.

rdar://90776105
Moved all the threading code to one place.  Added explicit support for
Darwin, Linux, Pthreads, C11 threads and Win32 threads, including new
implementations of Once for Linux, Pthreads, C11 and Win32.

rdar://90776105
The threading unit tests currently just check the operation of Mutex.
This used to be part of the runtime tests, but now it's a separate
library we can test it separately.

rdar://90776105
Added explicit tests for `swift::once` and also for the ulock implementation
used on Linux.

rdar://90776105
The file is called Nothreads.cpp, not NoThreads.cpp.

rdar://90776105
Some things (LLDB's language plugin, for instance), include Swift headers
from outside of our build system, and may not know to define one of the
threading package defines.

rdar://90776105
Some declarations were missing from non-Darwin sources, and the Linux
header was slightly broken.

rdar://90776105
A few fixes specifically for the Linux build.

rdar://90776105
We want this initialized when we decide which threading package to
use.  This isn't a problem on Darwin or Linux where we're using the
build script, but on Windows it relies on the defaulting mechanism,
which didn't happen until further down the `CMakeLists.txt`.

rdar://90776105
When we static link against libswiftCore, we need it to contain the
actual object modules from the threading library (when it's dynamically
linked, the shared object will already contain those modules because it's
been linked against libswiftThreading), which means that the threading
library in the stdlib needs to be an OBJECT_LIBRARY rather than a STATIC
library (otherwise people will have to statically link against the
threading library as well, and that'll need to be installed, and we don't
want that).

rdar://90776105
I'd renamed the setting, but failed to update build-presets.ini.

rdar://90776105
Apparently I missed a close brace from the end of Win32.h.

rdar://90776105
Looks like I forgot to update the Win32.h implementation.

rdar://90776105
`windows.h` defines a couple of very unhelpfully named macros.
Undefine them after including it.

rdar://90776105
We're using some functions from Synchronization.lib now, after the
threading changes.

rdar://90776105
We can't safely include <windows.h> because it defines a large number
of macros, some of which clash with things in the Swift source tree,
and others of which clash with things in the LLVM source tree.  Sadly
we *also* can't just include the Windows headers we need, because they
pull in some of the problematic macros.

In this instance, the best thing seems to be to grab the definitions
for the types and functions we are going to use and put them in their
own header file.  If we define them correctly, then #including
<windows.h> before or after this header won't have any adverse effects.

rdar://90776105
We shouldn't include <windows.h> implicitly from .cpp files, but should
do it directly so that we know it's there.

Also, if we're including <windows.h>, do it at the top of the file.

rdar://90776105
The concurrency library can use the new threading library functions,
which avoids the problem of including <windows.h>.

rdar://90776105
Declaring _RTL_SRWLOCK ourselves causes clashes with <windows.h>.
Rather than doing that, declare an equivalent struct, and some overloads.

rdar://90776105
Actor.cpp does need <io.h> still, and Task.cpp should have been including
<windows.h>

rdar://90776105
TaskLocal.cpp doesn't need <handleapi.h> or <processthreadsapi.h>, both of
which want <windows.h>, which isn't included any more.

rdar://90776105
We need to link the threading unit test against Synchronization.lib
to pick up the Win32 APIs we're using.

rdar://90776105
The runtime unit tests also need to link with Synchronization.lib.

rdar://90776105
Removing thread_get_main() means we don't need a static initializer on
Darwin, which means we can delete Darwin.cpp as well.  We can also delete
Nothreads.cpp while we're about it, because there's nothing in that file.

rdar://90776105
Just formatting changes.

rdar://90776105
These changes are needed to get things building with a C11 threads shim
header on macOS.

rdar://90776105
al45tair and others added 5 commits June 7, 2022 07:39
…d special.

While most systems aren't going to have their stack bottom at zero,
using llvm::Optional<> here is cleaner.

rdar://90776105
When we're building static libraries, we don't need to include the
threading objects in both Concurrency and Core, and we also don't need
two copies of the threading library's fatal error handler.

rdar://90776105
`SWIFT_BUILD_STATIC_STDLIB` is not mutually exclusive with
`SWIFT_BUILD_DYNAMIC_STDLIB`, and Linux sets both, so we can't use
`SWIFT_BUILD_STATIC_STDLIB` to conditionalise things.

The linker error about duplicate definitions for the threading error
handler was happening because we were forced to include the object
containing that symbol; moving it to another object should fix that.

And it turns out there's a way to get CMake to include the threading
object library only when building a shared object, so use that too.

rdar://90776105
`gettid` wrapper was added in glibc 2.30, and Ubuntu 18.04 uses glibc
2.27, so use raw syscall instead of it.
The threading code is required by some of the compatibility modules,
but we weren't pulling it in unless we were building the standard library.
That breaks the build when the standard library build is disabled, so
explicitly include it.

rdar://90776105
@al45tair al45tair force-pushed the eng/PR-90776105-2 branch from b9af6b9 to c46d4af Compare June 7, 2022 06:41
@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

@swift-ci Please test

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

preset=buildbot,tools=RA,stdlib=RDA
@swift-ci Please test with preset macOS platform

@al45tair al45tair force-pushed the eng/PR-90776105-2 branch from ed93897 to c46d4af Compare June 7, 2022 13:12
A copy of the older Concurrency sources was just added to BackDeployConcurrency,
replacing the `add_subdirectory(../Concurrency)` trick it was using previously.
These need to be adjusted to work with the threading library.  Fortunately, the
necessary adjustments are the same as those required for the existing
Concurrency library, give or take.

rdar://90776105
@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

@swift-ci Please test

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

preset=buildbot,tools=RA,stdlib=RDA
@swift-ci Please test with preset macOS platform

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

@swift-ci Please test Ubuntu 18.04 platform

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

@swift-ci Please test Amazon Linux 2 platform

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

@swift-ci Please test Centos 7 platform

@al45tair
Copy link
Contributor Author

al45tair commented Jun 7, 2022

Ah, apparently the specific Linux platform CI commands aren't supported presently.

@al45tair
Copy link
Contributor Author

al45tair commented Jun 8, 2022

This was previously reviewed as #42447, modulo the last three commits, one of which was originally from #59220.

@al45tair al45tair requested a review from ahoppen June 8, 2022 08:58
@al45tair al45tair merged commit a9fe971 into swiftlang:main Jun 9, 2022
@kubamracek
Copy link
Contributor

🥳

@finagolfin
Copy link
Member

I'm seeing a static assert failure on Android armv7 since this was merged, is it possible this pull broke building the stdlib for 32-bit platforms?

swift/stdlib/public/runtime/Once.cpp:39:1: error: static_assert failed due to requirement 'sizeof(swift::threading_impl::once_t) <= sizeof(void *)' "swift_once_t must be no larger than the platform word"
static_assert(sizeof(swift_once_t) <= sizeof(void*),
^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@al45tair
Copy link
Contributor Author

@buttaface Ah, yes, sorry, it looks like I did break 32-bit Linux. Should be a straightforward enough fix, I think. PR to fix: #59371

precondition(SWIFT_HOST_VARIANT_SDK)
precondition(SWIFT_DARWIN_PLATFORMS)

string(TOUPPER "${SWIFT_THREADING_PACKAGE}" package)
Copy link
Member

Choose a reason for hiding this comment

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

I think setting this to SWIFT_THREADING_PACKAGE by default is a mistake, as it is set to the host platform by default. Since it's possible to cross-compile multiple non-host stdlibs, that means it will build all of them with the host threading library name.

I'm not sure how the couple lines just below are supposed to work either, how are you supposed to pass an empty string to build-script? I tried various things like --swift-threading-package="" and nothing worked. Even if it did, you only have threading_package_default() below taking one variable, when it needs two.

This just hit me because I cross-compile the Android armv7 SDK and it failed because it used pthreads, which doesn't support 32-bit here.

I was confused though because it built fine on the community Android armv7 CI, then I dug into it and it's because the host SDK there is LINUX so it applies that threading library to Android armv7 too, based on the default logic above. My own Android CI doesn't build for the linux host though, only for Android armv7 with the flags --cross-compile-hosts=android-armv7 --skip-local-build, so the host default logic chooses pthreads for the Android host and fails for armv7 only.

That suggests two fixes:

  1. Rethink the way the threading library is chosen by default for the stdlib, so you're not using the host threading library name for all stdlibs built.
  2. Add Android to the list of SDKs where a default threading library is chosen, and set a default.

Let me know what you think, @al45tair, you may want to get pthreads working for 32-bit too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Making pthreads work for 32-bit is a fairly trivial fix, I think, and probably worth doing (possibly the right thing is to use uintptr_t instead of uint64_t for the type of the swift::once_t), though maybe we should be picking the linux setting on Android?

The swift-threading-package setting isn't presently supposed to be explicitly set to empty, which is why that doesn't work. It's there to let you override it and explicitly specify what you want, not the opposite (not sure why you'd need to do that). If you're looking at the headers and have seen the bit in the header file where it tries to guess, that has to be there because of lldb, rather than because I thought that was a good idea.

As for the cross compilation problem, could you file a separate issue for that? The threading code gets used both for the host and the target, so I think you're right that the automatic detection might indeed need to be tweaked for the target platform.

Copy link
Member

@finagolfin finagolfin Jun 18, 2022

Choose a reason for hiding this comment

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

maybe we should be picking the linux setting on Android?

I'm not sure: both appear to work on 64-bit platforms, so I will look into it and let you know.

The swift-threading-package setting isn't presently supposed to be explicitly set to empty, which is why that doesn't work.

I thought you explicitly included the empty string in this list of threading options to allow people to set it, but I think the bash check a couple lines above wouldn't allow it through anyway.

It's there to let you override it and explicitly specify what you want, not the opposite (not sure why you'd need to do that)

OK, this check that I mentioned will never be true then? I thought the intent was for it to signify "auto-detect" for each stdlib, but it currently doesn't do that either.

As for the cross compilation problem, could you file a separate issue for that?

Will doDone, #59568.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PR to fix the remaining 32-bit issues (@compnerd fixed it already for Windows): #59586

compnerd added a commit to compnerd/apple-swift that referenced this pull request Jun 18, 2022
This repairs the Windows x86 SDK build after swiftlang#59287.  Use `intptr_t`
rather than the explicitly sized integer as this is always guaranteed to
be the size of the pointer width (irrespective of LP64/LP32 or
LLP64/LLP32).  Since this impacts only the once predicate, this
shouldn't impact any assumptions around structure sizes.
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.

5 participants