getMainExecutor and asyncMainDrainQueue function declarations are needed
to compile programs with the asyn-main function. The functions are
declared internal, so they don't show up in the swift interface files.
The concurrency runtime now deploys back to macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, which corresponds to the 5.1 release of the stdlib.
Adjust macro usages accordingly.
This patch updates the asynchronous main function to run the first thunk
of the function synchronously through a call to `swift_job_run`.
The runloop is killed by exiting or aborting the task that it is running
on. As such, we need to ensure that the task contains an async function
that either calls exit explicitly or aborts. The AsyncEntryPoint, that
contains this code, was added in the previous patch. This patch adds the
pieces for the actual implementation of this behaviour as well as adding
the necessary code to start the runloop.
There are now four layers of main functions before hitting the "real"
code.
@main: This is the actual main entrypoint of the program. This
constructs the task containing @async_main, grabs the main executor,
runs swift_job_run to run the first part synchronously, and finally
kicks off the runloop with a call to _asyncMainDrainQueue. This is
generated in the call to `emitAsyncMainThreadStart`.
@async_main: This thunk exists to ensure that the main function calls
`exit` at some point so that the runloop stops. It also handles emitting
an error if the user-written main function throws.
e.g:
```
func async_main() async -> () {
do {
try await Main.$main()
exit(0)
} catch {
_errorInMain(error)
}
}
```
Main.$main(): This still has the same behaviour as with the
synchronous case. It just calls `try await Main.main()` and exists to
simplify typechecking.
Main.main(): This is the actual user-specified main. It serves the same
purpose as in the synchronous, allowing the programmer to write code,
but it's async!
The control flow in `emitFunctionDefinition` is a little confusing (to
me anyway), so here it is spelled out:
If the main function is synchronous, the `constant.kind` will be a
`SILDeclRef::Kind::EntryPoint`, but the `decl` won't be async, so it
drops down to `emitArtificalTopLevel` anyway.
If the main function is async and we're generating `@main`, the
`constant.kind` will be `SILDeclRef::Kind::AsyncEntryPoint`, so we also
call `emitArtificalTopLevel`. `emitArtificalTopLevel` is responsible for
detecting whether the decl is async and deciding whether to emit code to
extract the argc/argv variables that get passed into the actual main
entrypoint to the program. If we're generating the `@async_main` body,
the kind will be `SILDeclRef::Kind::EntryPoint` and the `decl` will be
async, so we grab the mainEntryPoint decl and call
`emitAsyncMainThreadStart` to generate the wrapping code.
Note; there is a curious change in `SILLocation::getSourceLoc()`
where instead of simply checking `isFilenameAndLocation()`, I change it
to `getStorageKind() == FilenameAndLocationKind`. This is because the
SILLocation returned is to a FilenameAndLocationKind, but the actual
storage returns true for the call to `isNull()` inside of the
`isFilenameAndLocation()` call. This results in us incorrectly falling
through to the `getASTNode()` call below that, which asserts when asked
to get the AST node of a location.
I also did a little bit of refactoring in the SILGenModule for grabbing
intrinsics. Previously, there was only a `getConcurrencyIntrinsic`
function, which would only load FuncDecls out of the concurrency
module. The `exit` function is in the concurrency shims module, so I
refactored the load code to take a ModuleDecl to search from.
The emitBuiltinCreateAsyncTask function symbol is exposed from
SILGenBuiltin so that it is available from SILGenFunction. There is a
fair bit of work involved going from what is available at the SGF to
what is needed for actually calling the CreateAsyncTask builtin, so in
order to avoid additional maintenance, it's good to re-use that.
Swift 5.5 does not implement support for structural types that are
Sendable, which breaks type checking of the newer _Concurrency module.
Work around the issue with an `#if` in the offending inline code.
Fixes rdar://82602353.
This builtin never occurs in @inlinable code. But apparently we still
need to add a language feature for every builtin. This must allow
older compilers to reparse the library source (though I don't know why
that would ever happen!)
Fixes rdar://80525569 error: module 'Builtin' has no member named 'hopToActor')
The `swift_task_create` entry point is our general runtime ABI for
launching tasks. Make the various Swift APIs sitting on top of it
always-emit-into-client to take them out of the ABI. This reduces the
number of ABI entry points and allows us to make more ABI-compatible
changes to the Swift side.
We're not actually performing the adjustments at the moment due to an
unrelated bug, and will want to perform them within
`swift_task_create_common` based on inheritContext and the given
priority.
Rather than using group task options constructed from the Swift parts
of the _Concurrency library and passed through `createAsyncTask`'s
options, introduce a separate builtin that always takes a group. Move
the responsibility for creating the options structure into IRGen, so
we don't need to expose the TaskGroupTaskOptionRecord type in Swift.
Introduce a builtin `createAsyncTask` that maps to `swift_task_create`,
and use that for the non-group task creation operations based on the
task-creation flags. `swift_task_create` and the thin function version
`swift_task_create_f` go through the dynamically-replaceable
`swift_task_create_common`, where all of the task creation logic is
present.
While here, move copying of task locals and the initial scheduling of
the task into `swift_task_create_common`, enabling by separate flags.
introduce new options parameter to all task spawning
[Concurrency] ABI for asynclet start to accept options
[Concurrency] fix unittest usages of changed task creation ABI
[Concurrency] introduce constants for parameter indexes in ownership
[Concurrency] fix test/SILOptimizer/closure_lifetime_fixup_concurrency.swift
If a Swift async method is actor-constrained, then when it's projected into ObjC, it should still
run its task on the correct actor, along with the completion handler that ObjC passes into it.
Fixes rdar://76415650.
If the optimizer is doing it's job, then @MainActor can't be used to
force another actor-independent async callee onto the main actor.
Instead, explicitly hop, which communicates the actual intent and is robust.
Based on feedback from the second review, we decided to go with
high/default/low/background, with aliases for the Dispatch-inspired
names. While here, make TaskPriority be backed by a UInt8 to better
describe the actual restrictions, and start removing userInteractive,
because clients shouldn't be able to specify it.
The `Task` type has oscillated somewhat from being purely a namespace,
to having instances that are used (albeit rarely), back to purely
being a namespace that isn't used for all that many names. Many of the
names that used to be on Task have already been moved out, e.g., for
creating new detached tasks, creating new task groups, adding
cancellation handlers, etc.
Collapse `Task.Handle<Success, Failure>` into `Task<Success, Failure>`.
`Task.Handle` is the type that is most frequently referenced in the
concurrency library, so giving it the short name `Task` is most
appropriate. Replace the top-level async/detach functions with a
`Task` initializer and `Task.detached`, respectively.
The `Task` type can still act as a namespace for static operations
such as, e.g., `Task.isCancelled`. Do this with an extension of the
form:
extension Task where Success == Never, Failure == Never { ... }
We've been accruing a number of compatibility shims. Move them all
into their own source file, deprecate them, and make them
always-emit-into-client so they don't have any ABI impact.
There exist Swift builds that support `Sendable` but not the attributes
used on `async`. Make sure that have an implementation of
`_runTaskForBridgedAsyncMethod` that does something.
Fixes rdar://77637570.
This commit changes JobFlags storage to be 32bits, but leaves the runtime
API expressed in terms of size_t. This allows us to pack an Id in the
32bits we freed up.
The offset of this Id in the AsyncTask is an ABI constant. This way
introspection tools can extract the currently running task identifier
without any need for special APIs.
* [Concurrency] Reduce overhead of Task.yield and Task.sleep
Instead of creating a new task, we create a simple job that wraps a Builtin.RawUnsafeContinuation and resumes the continuation when it is executed. The job instance is allocated on the task local allocator, meaning we don't malloc anything.
* Update stdlib/public/Concurrency/Task.swift
Co-authored-by: Konrad `ktoso` Malawski <konrad.malawski@project13.pl>
Co-authored-by: Konrad `ktoso` Malawski <konrad.malawski@project13.pl>
- Introduce an UnownedSerialExecutor type into the concurrency library.
- Create a SerialExecutor protocol which allows an executor type to
change how it executes jobs.
- Add an unownedExecutor requirement to the Actor protocol.
- Change the ABI for ExecutorRef so that it stores a SerialExecutor
witness table pointer in the implementation field. This effectively
makes ExecutorRef an `unowned(unsafe) SerialExecutor`, except that
default actors are represented without a witness table pointer (just
a bit-pattern).
- Synthesize the unownedExecutor method for default actors (i.e. actors
that don't provide an unownedExecutor property).
- Make synthesized unownedExecutor properties `final`, and give them
a semantics attribute specifying that they're for default actors.
- Split `Builtin.buildSerialExecutorRef` into a few more precise
builtins. We're not using the main-actor one yet, though.
Pitch thread:
https://forums.swift.org/t/support-custom-executors-in-swift-concurrency/44425
Per updates to the Structured Concurrency protocol, make the `async`
operation (1) overloaded on throwing-ness and (2) return an appropriate
`Task.Handle`.
When `Task.currentPriority` is evaluated outside of an actual task,
query the system to determine the priority at which the code is
currently executing. This is the behavior that `async` specifies.
Extend that to `currentPriority` rather than guessing `.default`.