Windows doesn't have dlsym. Since I don't have a Windows box, I'm just
if-def'ing it out for the time being. Since we don't want Windows going
off and doing dangerous things, I threw in an abort just to be safe.
Adding execution and death test to ensure that we crash appropriately
when the main function throws an uncaught exception, and that the async
main runs correctly.
Also switching to doing the CFRunLoopRun lookup with `RTLD_DEFAULT`
since `RTLD_SELF` isn't available on Linux.
Switching to `try await` since `await try` is no longer the right way to
do that.
Using exit(0) instead of EXIT_SUCCESS since the C++ importer doesn't
mark imported macros with @actorIndependent yet.
This patch has two desirable effects for the price of one.
1. An uncaught error thrown from main will now explode
2. Move us off of using runAsyncAndBlock
The issue with runAsyncAndBlock is that it blocks the main thread
outright. UI and the main actor need to run on the main thread or bad
things happen, so blocking the main thread results in a bad day for
them.
Instead, we're using CFRunLoopRun to run the core-foundation run loop on
the main thread, or, dispatch_main if CFRunLoopRun isn't available.
The issue with just using dispatch_main is that it doesn't actually
guarantee that it will run the tasks on the main thread either, just
that it clears the main queue. We don't want to require everything that
uses concurrency to have to include CoreFoundation either, but dispatch
is already required, which supplies dispatch_main, which just empties
out the main queue.
This patch adds the async-main start-point for programs.
When a `static func main() async` is inserted into the main program, it
gets called through `_runAsyncMain` instead of calling directly. This
starts the program in an async context, which is good because then we
can do async stuff from there.
The following code
```
@main struct MyProgram {
static func main() async {
// async code
}
}
```
is turned into
```
@main struct MyProgram {
static func $main() {
_runAsyncMain(main)
}
static func main() async {
// async code
}
}
```
_runAsyncMain code-gen's to the same thing as runAsyncAndBlock, which
emits a call to `swift_task_runAndBlockThread`.
To help catch runtime issues adopting `withUnsafeContinuation`, such as callback-based APIs that misleadingly
invoke their callback multiple times and/or not at all, provide a couple of classes that can take ownership of
a fresh `UnsafeContinuation` or `UnsafeThrowingContinuation`, and log attempts to resume the continuation multiple times
or discard the object without ever resuming the continuation.
The `try await` ordering is both easier to read and indicates the order
of operations better, because the suspension point occurs first and
then one can observe a thrown error.
move comments to the wired up continuations
remove duplicated continuations; leep the wired up ones
before moving to C++ for queue impl
trying to next wait via channel_poll
submitting works; need to impl next()
Currently, the only thing in the system that donates a thread
to run it is swift_runAndBlockThread, but we'll probably need
others. Nothing in the concurrency runtime should block via a
semaphore in this configuration.
As an outrageous hack, work around the layering problems with
using libdispatch from the concurrency library on non-Darwin
systems by making those systems use the cooperative global
executor. This is only acceptable as a temporary solution
for landing this change and setting things onto the right
long-term design.
We expect to iterate on this quite a bit, both publicly
and internally, but this is a fine starting-point.
I've renamed runAsync to runAsyncAndBlock to underline
very clearly what it does and why it's not long for this
world. I've also had to give it a radically different
implementation in an effort to make it continue to work
given an actor implementation that is no longer just
running all work synchronously.
The major remaining bit of actor-scheduling work is to
make swift_task_enqueue actually do something sensible
based on the executor it's been given; currently it's
expecting a flag that IRGen simply doesn't know to set.
Use the StackAllocator as task allocator.
TODO: we could pass an initial pre-allocated first slab to the allocator, which is allocated on the stack or with the parent task's allocator.
rdar://problem/71157018
libdispatch is not part of the system on Linux and Windows, and dispatch
has not been used for the standard library up until this point. The
current usage is limited to the Apple platforms, so rather than adding
another build of dispatch, conditionally include the header instead.
Bridging an async Swift method back to an ObjC completion-handler-based API requires
that the ObjC thunk spawn a task on which to execute the Swift async API and pass
its results back on to the completion handler.
of adding a property.
This better matches what the actual implementation expects,
and it avoids some possibilities of weird mismatches. However,
it also requires special-case initialization, destruction, and
dynamic-layout support, none of which I've added yet.
In order to get NSObject default actor subclasses to use Swift
refcounting (and thus avoid the need for the default actor runtime
to generally use ObjC refcounting), I've had to introduce a
SwiftNativeNSObject which we substitute as the superclass when
inheriting directly from NSObject. This is something we could
do in all NSObject subclasses; for now, I'm just doing it in
actors, although it's all actors and not just default actors.
We are not yet taking advantage of our special knowledge of this
class anywhere except the reference-counting code.
I went around in circles exploring a number of alternatives for
doing this; at one point I basically had a completely parallel
"ForImplementation" superclass query. That proved to be a lot
of added complexity and created more problems than it solved.
We also don't *really* get any benefit from this subclassing
because there still wouldn't be a consistent superclass for all
actors. So instead it's very ad-hoc.