Skip to content

Commit 1177cde

Browse files
committed
Use current public Dispatch API to schedule global work.
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.
1 parent b22407e commit 1177cde

File tree

55 files changed

+643
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+643
-237
lines changed

CMakeLists.txt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,18 @@ option(SWIFT_BUILD_ONLY_SYNTAXPARSERLIB "Only build the Swift Syntax Parser libr
435435
option(SWIFT_BUILD_SOURCEKIT "Build SourceKit" TRUE)
436436
option(SWIFT_ENABLE_SOURCEKIT_TESTS "Enable running SourceKit tests" ${SWIFT_BUILD_SOURCEKIT})
437437

438-
if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)
438+
# Use dispatch as the system scheduler by default.
439+
# For convenience, we set this to false when concurrency is disabled.
440+
# TODO: don't do this when building a single-threaded runtime
441+
set(SWIFT_CONCURRENCY_USES_DISPATCH FALSE)
442+
if(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY)
443+
set(SWIFT_CONCURRENCY_USES_DISPATCH TRUE)
444+
endif()
445+
446+
if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT OR SWIFT_CONCURRENCY_USES_DISPATCH)
439447
if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
440448
if(NOT EXISTS "${SWIFT_PATH_TO_LIBDISPATCH_SOURCE}")
441-
message(SEND_ERROR "SyntaxParserLib and SourceKit require libdispatch on non-Darwin hosts. Please specify SWIFT_PATH_TO_LIBDISPATCH_SOURCE")
449+
message(SEND_ERROR "SyntaxParserLib, SourceKit, and concurrency require libdispatch on non-Darwin hosts. Please specify SWIFT_PATH_TO_LIBDISPATCH_SOURCE")
442450
endif()
443451
endif()
444452
endif()
@@ -941,7 +949,7 @@ if (LLVM_ENABLE_DOXYGEN)
941949
message(STATUS "Doxygen: enabled")
942950
endif()
943951

944-
if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)
952+
if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT OR SWIFT_CONCURRENCY_USES_DISPATCH)
945953
if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
946954
if(CMAKE_C_COMPILER_ID STREQUAL Clang AND
947955
CMAKE_C_COMPILER_VERSION VERSION_GREATER 3.8

include/swift/ABI/Executor.h

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_ABI_EXECUTOR_H
1919

2020
#include <inttypes.h>
21+
#include "swift/ABI/HeapObject.h"
2122

2223
namespace swift {
2324
class AsyncContext;
@@ -65,6 +66,10 @@ class ExecutorRef {
6566
return reinterpret_cast<DefaultActor*>(Value & ~PointerMask);
6667
}
6768

69+
uintptr_t getRawValue() const {
70+
return Value;
71+
}
72+
6873
/// Do we have to do any work to start running as the requested
6974
/// executor?
7075
bool mustSwitchToRun(ExecutorRef newExecutor) const {
@@ -87,10 +92,53 @@ using TaskContinuationFunction =
8792
SWIFT_CC(swiftasync)
8893
void (AsyncTask *, ExecutorRef, AsyncContext *);
8994

90-
template <class Fn>
95+
template <class AsyncSignature>
96+
class AsyncFunctionPointer;
97+
template <class AsyncSignature>
9198
struct AsyncFunctionTypeImpl;
92-
template <class Result, class... Params>
93-
struct AsyncFunctionTypeImpl<Result(Params...)> {
99+
100+
/// The abstract signature for an asynchronous function.
101+
template <class Sig, bool HasErrorResult>
102+
struct AsyncSignature;
103+
104+
template <class DirectResultTy, class... ArgTys, bool HasErrorResult>
105+
struct AsyncSignature<DirectResultTy(ArgTys...), HasErrorResult> {
106+
bool hasDirectResult = !std::is_same<DirectResultTy, void>::value;
107+
using DirectResultType = DirectResultTy;
108+
109+
bool hasErrorResult = HasErrorResult;
110+
111+
using FunctionPointer = AsyncFunctionPointer<AsyncSignature>;
112+
using FunctionType = typename AsyncFunctionTypeImpl<AsyncSignature>::type;
113+
};
114+
115+
/// A signature for a thin async function that takes no arguments
116+
/// and returns no results.
117+
using ThinNullaryAsyncSignature =
118+
AsyncSignature<void(), false>;
119+
120+
/// A signature for a thick async function that takes no formal
121+
/// arguments and returns no results.
122+
using ThickNullaryAsyncSignature =
123+
AsyncSignature<void(HeapObject*), false>;
124+
125+
/// A class which can be used to statically query whether a type
126+
/// is a specialization of AsyncSignature.
127+
template <class T>
128+
struct IsAsyncSignature {
129+
static const bool value = false;
130+
};
131+
template <class DirectResultTy, class... ArgTys, bool HasErrorResult>
132+
struct IsAsyncSignature<AsyncSignature<DirectResultTy(ArgTys...),
133+
HasErrorResult>> {
134+
static const bool value = true;
135+
};
136+
137+
template <class Signature>
138+
struct AsyncFunctionTypeImpl {
139+
static_assert(IsAsyncSignature<Signature>::value,
140+
"template argument is not an AsyncSignature");
141+
94142
// TODO: expand and include the arguments in the parameters.
95143
using type = TaskContinuationFunction;
96144
};
@@ -102,11 +150,11 @@ using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
102150
///
103151
/// Eventually, this will always be signed with the data key
104152
/// using a type-specific discriminator.
105-
template <class FnType>
153+
template <class AsyncSignature>
106154
class AsyncFunctionPointer {
107155
public:
108156
/// The function to run.
109-
RelativeDirectPointer<AsyncFunctionType<FnType>,
157+
RelativeDirectPointer<AsyncFunctionType<AsyncSignature>,
110158
/*nullable*/ false,
111159
int32_t> Function;
112160

include/swift/AST/Builtins.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,12 @@ BUILTIN_MISC_OPERATION(TypePtrAuthDiscriminator, "typePtrAuthDiscriminator", "n"
723723
// int_instrprof_increment has type (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> ().
724724
BUILTIN_MISC_OPERATION(IntInstrprofIncrement, "int_instrprof_increment", "", Special)
725725

726+
/// Initialize the default-actor instance in a default actor object.
727+
BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Special)
728+
729+
/// Destroy the default-actor instance in a default actor object.
730+
BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special)
731+
726732
// BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are
727733
// specially emitted during SIL generation.
728734
//

include/swift/Runtime/Concurrency.h

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,21 @@ struct AsyncTaskAndContext {
4242
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
4343
AsyncTaskAndContext swift_task_create(JobFlags flags,
4444
AsyncTask *parent,
45-
const AsyncFunctionPointer<void()> *function);
45+
const ThinNullaryAsyncSignature::FunctionPointer *function);
4646

4747
/// Create a task object with no future which will run the given
4848
/// function.
4949
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
5050
AsyncTaskAndContext swift_task_create_f(JobFlags flags,
5151
AsyncTask *parent,
52-
AsyncFunctionType<void()> *function,
52+
ThinNullaryAsyncSignature::FunctionType *function,
5353
size_t initialContextSize);
5454

55+
/// Caution: not all future-initializing functions actually throw, so
56+
/// this signature may be incorrect.
57+
using FutureAsyncSignature =
58+
AsyncSignature<void(void*), /*throws*/ true>;
59+
5560
/// Create a task object with a future which will run the given
5661
/// function.
5762
///
@@ -68,14 +73,15 @@ AsyncTaskAndContext swift_task_create_f(JobFlags flags,
6873
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
6974
AsyncTaskAndContext swift_task_create_future(
7075
JobFlags flags, AsyncTask *parent, const Metadata *futureResultType,
71-
const AsyncFunctionPointer<void()> *function);
76+
const FutureAsyncSignature::FunctionPointer *function);
7277

7378
/// Create a task object with a future which will run the given
7479
/// function.
7580
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
7681
AsyncTaskAndContext swift_task_create_future_f(
7782
JobFlags flags, AsyncTask *parent, const Metadata *futureResultType,
78-
AsyncFunctionType<void()> *function, size_t initialContextSize);
83+
FutureAsyncSignature::FunctionType *function,
84+
size_t initialContextSize);
7985

8086
/// Allocate memory in a task.
8187
///
@@ -127,6 +133,9 @@ struct TaskFutureWaitResult {
127133
OpaqueValue *storage;
128134
};
129135

136+
using TaskFutureWaitSignature =
137+
AsyncSignature<TaskFutureWaitResult(AsyncTask *), /*throws*/ false>;
138+
130139
/// Wait for a future task to complete.
131140
///
132141
/// This can be called from any thread. Its Swift signature is
@@ -135,8 +144,8 @@ struct TaskFutureWaitResult {
135144
/// func swift_task_future_wait(on task: Builtin.NativeObject) async
136145
/// -> TaskFutureWaitResult
137146
/// \endcode
138-
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
139-
AsyncFunctionType<TaskFutureWaitResult(AsyncTask *task)>
147+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
148+
TaskFutureWaitSignature::FunctionType
140149
swift_task_future_wait;
141150

142151
/// Add a status record to a task. The record should not be
@@ -204,9 +213,18 @@ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
204213
NearestTaskDeadline
205214
swift_task_getNearestDeadline(AsyncTask *task);
206215

207-
// TODO: Remove this hack.
216+
/// Run the given async function and block the current thread until
217+
/// it returns. This is a hack added for testing purposes; eventually
218+
/// top-level code will be an async context, and the need for this in
219+
/// tests should go away. We *definitely* do not want this to be part
220+
/// of the standard feature set.
221+
///
222+
/// The argument is a `() async -> ()` function, whose ABI is currently
223+
/// quite complex. Eventually this should use a different convention;
224+
/// that's rdar://72105841.
208225
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
209-
void swift_task_run(AsyncTask *taskToRun);
226+
void swift_task_runAndBlockThread(const void *function,
227+
HeapObject *functionContext);
210228

211229
/// Switch the current task to a new executor if we aren't already
212230
/// running on a compatible executor.

lib/AST/Builtins.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,13 @@ static ValueDecl *getConvertTaskToJob(ASTContext &ctx, Identifier id) {
14391439
_job);
14401440
}
14411441

1442+
static ValueDecl *getDefaultActorInitDestroy(ASTContext &ctx,
1443+
Identifier id) {
1444+
return getBuiltinFunction(ctx, id, _thin,
1445+
_parameters(_nativeObject),
1446+
_void);
1447+
}
1448+
14421449
static ValueDecl *getAutoDiffCreateLinearMapContext(ASTContext &ctx,
14431450
Identifier id) {
14441451
return getBuiltinFunction(
@@ -2651,6 +2658,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
26512658
case BuiltinValueKind::TriggerFallbackDiagnostic:
26522659
return getTriggerFallbackDiagnosticOperation(Context, Id);
26532660

2661+
case BuiltinValueKind::InitializeDefaultActor:
2662+
case BuiltinValueKind::DestroyDefaultActor:
2663+
return getDefaultActorInitDestroy(Context, Id);
2664+
26542665
case BuiltinValueKind::WithUnsafeContinuation:
26552666
return getWithUnsafeContinuation(Context, Id, /*throws=*/false);
26562667

stdlib/public/Concurrency/Actor.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
///
1111
///===----------------------------------------------------------------------===///
1212
///
13-
/// The standard actor implementation for Swift actors.
13+
/// The default actor implementation for Swift actors, plus related
14+
/// routines such as generic executor enqueuing and switching.
1415
///
1516
///===----------------------------------------------------------------------===///
1617

@@ -1357,21 +1358,9 @@ void swift::swift_task_enqueue(Job *job, ExecutorRef executor) {
13571358
if (executor.isDefaultActor())
13581359
return asImpl(executor.getDefaultActor())->enqueue(job);
13591360

1361+
// Just assume it's actually a default actor that we haven't tagged
1362+
// properly.
13601363
// FIXME: call the general method.
1361-
job->run(executor);
1364+
return asImpl(reinterpret_cast<DefaultActor*>(executor.getRawValue()))
1365+
->enqueue(job);
13621366
}
1363-
1364-
SWIFT_CC(swift)
1365-
void (*swift::swift_task_enqueueGlobal_hook)(Job *job) = nullptr;
1366-
1367-
void swift::swift_task_enqueueGlobal(Job *job) {
1368-
assert(job && "no job provided");
1369-
1370-
// If the hook is defined, use it.
1371-
if (swift_task_enqueueGlobal_hook)
1372-
return swift_task_enqueueGlobal_hook(job);
1373-
1374-
// FIXME: implement this properly
1375-
job->run(ExecutorRef::generic());
1376-
}
1377-

0 commit comments

Comments
 (0)