Skip to content

Commit efe5d66

Browse files
committed
[Concurrency] Refactor executors so they are in their own object module.
C++ executor implementations were `#include`ed into `GlobalExecutor.cpp`, which makes it difficult to replace the global executor when using the Embedded Concurrency library. Refactor things so that they build into separate objects, which means replacing them is just a matter of writing the relevant functions yourself. rdar://135380149
1 parent cd6864a commit efe5d66

File tree

13 files changed

+407
-221
lines changed

13 files changed

+407
-221
lines changed

include/swift/Runtime/Concurrency.h

Lines changed: 34 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,13 @@ void swift_task_enqueueGlobal(Job *job);
720720
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
721721
void swift_task_checkIsolated(SerialExecutorRef executor);
722722

723+
/// Invoke a Swift executor's `checkIsolated` implementation; returns
724+
/// `true` if it invoked the Swift implementation, `false` otherwise.
725+
/// Executors will want to call this from their `swift_task_checkIsolatedImpl`
726+
/// implementation.
727+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
728+
bool swift_task_invokeSwiftCheckIsolated(SerialExecutorRef executor);
729+
723730
/// A count in nanoseconds.
724731
using JobDelay = unsigned long long;
725732

@@ -760,71 +767,29 @@ void swift_task_enqueueOnDispatchQueue(Job *job, HeapObject *queue);
760767

761768
#endif
762769

763-
/// A hook to take over global enqueuing.
764-
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobal_original)(Job *job);
765-
SWIFT_EXPORT_FROM(swift_Concurrency)
766-
SWIFT_CC(swift) void (*swift_task_enqueueGlobal_hook)(
767-
Job *job, swift_task_enqueueGlobal_original original);
768-
769-
/// A hook to take over global enqueuing with delay.
770-
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_original)(
771-
unsigned long long delay, Job *job);
772-
SWIFT_EXPORT_FROM(swift_Concurrency)
773-
SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDelay_hook)(
774-
unsigned long long delay, Job *job,
775-
swift_task_enqueueGlobalWithDelay_original original);
776-
777-
typedef SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_original)(
778-
long long sec,
779-
long long nsec,
780-
long long tsec,
781-
long long tnsec,
782-
int clock, Job *job);
783-
SWIFT_EXPORT_FROM(swift_Concurrency)
784-
SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_hook)(
785-
long long sec,
786-
long long nsec,
787-
long long tsec,
788-
long long tnsec,
789-
int clock, Job *job,
790-
swift_task_enqueueGlobalWithDeadline_original original);
791-
792-
typedef SWIFT_CC(swift) void (*swift_task_checkIsolated_original)(SerialExecutorRef executor);
793-
SWIFT_EXPORT_FROM(swift_Concurrency)
794-
SWIFT_CC(swift) void (*swift_task_checkIsolated_hook)(
795-
SerialExecutorRef executor, swift_task_checkIsolated_original original);
796-
797-
798-
typedef SWIFT_CC(swift) bool (*swift_task_isOnExecutor_original)(
799-
HeapObject *executor,
800-
const Metadata *selfType,
801-
const SerialExecutorWitnessTable *wtable);
802-
SWIFT_EXPORT_FROM(swift_Concurrency)
803-
SWIFT_CC(swift) bool (*swift_task_isOnExecutor_hook)(
804-
HeapObject *executor,
805-
const Metadata *selfType,
806-
const SerialExecutorWitnessTable *wtable,
807-
swift_task_isOnExecutor_original original);
808-
809-
/// A hook to take over main executor enqueueing.
810-
typedef SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_original)(
811-
Job *job);
812-
SWIFT_EXPORT_FROM(swift_Concurrency)
813-
SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_hook)(
814-
Job *job, swift_task_enqueueMainExecutor_original original);
815-
816-
/// A hook to override the entrypoint to the main runloop used to drive the
817-
/// concurrency runtime and drain the main queue. This function must not return.
818-
/// Note: If the hook is wrapping the original function and the `compatOverride`
819-
/// is passed in, the `original` function pointer must be passed into the
820-
/// compatibility override function as the original function.
821-
typedef SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_original)();
822-
typedef SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_override)(
823-
swift_task_asyncMainDrainQueue_original original);
824-
SWIFT_EXPORT_FROM(swift_Concurrency)
825-
SWIFT_CC(swift) void (*swift_task_asyncMainDrainQueue_hook)(
826-
swift_task_asyncMainDrainQueue_original original,
827-
swift_task_asyncMainDrainQueue_override compatOverride);
770+
// Declare all the hooks
771+
#define SWIFT_CONCURRENCY_HOOK(returnType, name, ...) \
772+
typedef SWIFT_CC(swift) returnType (*name##_original)(__VA_ARGS__); \
773+
typedef SWIFT_CC(swift) returnType \
774+
(*name##_hook_t)(__VA_ARGS__, name##_original original); \
775+
SWIFT_EXPORT_FROM(swift_Concurrency) name##_hook_t name##_hook
776+
777+
#define SWIFT_CONCURRENCY_HOOK0(returnType, name) \
778+
typedef SWIFT_CC(swift) returnType (*name##_original)(); \
779+
typedef SWIFT_CC(swift) returnType \
780+
(*name##_hook_t)(name##_original original); \
781+
SWIFT_EXPORT_FROM(swift_Concurrency) name##_hook_t name##_hook
782+
783+
#define SWIFT_CONCURRENCY_HOOK_OVERRIDE0(returnType, name) \
784+
typedef SWIFT_CC(swift) returnType (*name##_original)(); \
785+
typedef SWIFT_CC(swift) returnType (*name##_override)( \
786+
name##_original original); \
787+
typedef SWIFT_CC(swift) returnType \
788+
(*name##_hook_t)(name##_original original, \
789+
name##_override compatOverride); \
790+
SWIFT_EXPORT_FROM(swift_Concurrency) name##_hook_t name##_hook
791+
792+
#include "ConcurrencyHooks.def"
828793

829794
/// Initialize the runtime storage for a default actor.
830795
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
@@ -951,6 +916,10 @@ SerialExecutorRef swift_task_getCurrentExecutor(void);
951916
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
952917
SerialExecutorRef swift_task_getMainExecutor(void);
953918

919+
/// Test if an executor is the main executor.
920+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
921+
bool swift_task_isMainExecutor(SerialExecutorRef executor);
922+
954923
/// Return the preferred task executor of the current task,
955924
/// or ``TaskExecutorRef::undefined()`` if no preference.
956925
///
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//===--- Concurrency.h - Runtime interface for concurrency ------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Hooks for concurrency
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
// To use this file, define the following macros:
18+
//
19+
// SWIFT_CONCURRENCY_HOOK(returnType, name, ...)
20+
// SWIFT_CONCURRENCY_HOOK0(returnType, name)
21+
// SWIFT_CONCURRENCY_HOOK_OVERRIDE0(returnType, name)
22+
//
23+
// Then include the file somewhere.
24+
25+
#ifndef SWIFT_CONCURRENCY_HOOK
26+
#define SWIFT_CONCURRENCY_HOOK(returnType, name, ...)
27+
#endif
28+
29+
#ifndef SWIFT_CONCURRENCY_HOOK0
30+
#define SWIFT_CONCURRENCY_HOOK0(returnType, name)
31+
#endif
32+
33+
#ifndef SWIFT_CONCURRENCY_HOOK_OVERRIDE0
34+
#define SWIFT_CONCURRENCY_HOOK_OVERRIDE0(returnType, name)
35+
#endif
36+
37+
// .............................................................................
38+
39+
SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueGlobal, Job *job);
40+
41+
SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueGlobalWithDelay,
42+
unsigned long long delay, Job *job);
43+
44+
SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueGlobalWithDeadline,
45+
long long sec,
46+
long long nsec,
47+
long long tsec,
48+
long long tnsec,
49+
int clock, Job *job);
50+
51+
SWIFT_CONCURRENCY_HOOK(void, swift_task_checkIsolated, SerialExecutorRef executor);
52+
53+
SWIFT_CONCURRENCY_HOOK(bool, swift_task_isOnExecutor,
54+
HeapObject *executor,
55+
const Metadata *selfType,
56+
const SerialExecutorWitnessTable *wtable);
57+
58+
SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueMainExecutor, Job *job);
59+
60+
SWIFT_CONCURRENCY_HOOK0(SerialExecutorRef, swift_task_getMainExecutor);
61+
62+
SWIFT_CONCURRENCY_HOOK(bool, swift_task_isMainExecutor, SerialExecutorRef);
63+
64+
/// A hook to override the entrypoint to the main runloop used to drive the
65+
/// concurrency runtime and drain the main queue. This function must not return.
66+
/// Note: If the hook is wrapping the original function and the `compatOverride`
67+
/// is passed in, the `original` function pointer must be passed into the
68+
/// compatibility override function as the original function.
69+
SWIFT_CONCURRENCY_HOOK_OVERRIDE0(void, swift_task_asyncMainDrainQueue);
70+
71+
// .............................................................................
72+
73+
#undef SWIFT_CONCURRENCY_HOOK
74+
#undef SWIFT_CONCURRENCY_HOOK0
75+
#undef SWIFT_CONCURRENCY_HOOK_OVERRIDE0

stdlib/public/Concurrency/Actor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#define SWIFT_OBJC_INTEROP 1
4444
#endif
4545
#include "llvm/ADT/PointerIntPair.h"
46+
4647
#include "TaskPrivate.h"
4748
#include "VoucherSupport.h"
4849

stdlib/public/Concurrency/CMakeLists.txt

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ else()
4343
message(FATAL_ERROR "Invalid value for SWIFT_CONCURRENCY_GLOBAL_EXECUTOR (\"${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}\").")
4444
endif()
4545

46-
if(NOT SWIFT_CONCURRENCY_USES_DISPATCH)
47-
48-
endif()
49-
5046
if(NOT swift_concurrency_async_fp_mode)
5147
set(swift_concurrency_async_fp_mode "always")
5248
endif()
@@ -78,6 +74,7 @@ set(SWIFT_RUNTIME_CONCURRENCY_C_SOURCES
7874
AsyncLet.cpp
7975
Clock.cpp
8076
GlobalExecutor.cpp
77+
Hooks.cpp
8178
EmbeddedSupport.cpp
8279
Error.cpp
8380
Setup.cpp
@@ -92,6 +89,27 @@ set(SWIFT_RUNTIME_CONCURRENCY_C_SOURCES
9289
linker-support/magic-symbols-for-install-name.c
9390
)
9491

92+
if("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "dispatch")
93+
set(SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES
94+
DispatchGlobalExecutor.cpp
95+
)
96+
elseif("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "singlethreaded")
97+
set(SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES
98+
CooperativeGlobalExecutor.cpp
99+
)
100+
elseif("${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "hooked" OR
101+
"${SWIFT_CONCURRENCY_GLOBAL_EXECUTOR}" STREQUAL "none")
102+
set(SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES
103+
NonDispatchGlobalExecutor.cpp
104+
)
105+
endif()
106+
107+
set(LLVM_OPTIONAL_SOURCES
108+
CooperativeGlobalExecutor.cpp
109+
DispatchGlobalExecutor.cpp
110+
NonDispatchGlobalExecutor.cpp
111+
)
112+
95113
set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES
96114
Actor.swift
97115
AsyncLet.swift
@@ -158,6 +176,7 @@ set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES
158176

159177
add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
160178
${SWIFT_RUNTIME_CONCURRENCY_C_SOURCES}
179+
${SWIFT_RUNTIME_CONCURRENCY_EXECUTOR_SOURCES}
161180
${SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES}
162181

163182
SWIFT_MODULE_DEPENDS_ANDROID Android
@@ -230,7 +249,7 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB AND SWIFT_SHOULD_BUILD_EMBEDDED_CONCURRENC
230249
set(extra_c_compile_flags -D__MACH__ -D__APPLE__ -ffreestanding)
231250
set(extra_swift_compile_flags -Xcc -D__MACH__ -Xcc -D__APPLE__ -Xcc -ffreestanding)
232251
endif()
233-
252+
234253
set(SWIFT_SDK_embedded_THREADING_PACKAGE none)
235254
set(SWIFT_SDK_embedded_ARCH_${mod}_MODULE "${mod}")
236255
set(SWIFT_SDK_embedded_LIB_SUBDIR "embedded")
@@ -243,6 +262,8 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB AND SWIFT_SHOULD_BUILD_EMBEDDED_CONCURRENC
243262
IS_STDLIB IS_FRAGILE
244263

245264
${SWIFT_RUNTIME_CONCURRENCY_C_SOURCES}
265+
CooperativeGlobalExecutor.cpp
266+
246267
# TODO: Only a subset of Swift Concurrency .swift sources, for now.
247268
Actor.swift
248269
AsyncLet.swift

stdlib/public/Concurrency/CooperativeGlobalExecutor.inc renamed to stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
///
2424
///===------------------------------------------------------------------===///
2525

26+
#include "swift/Runtime/Concurrency.h"
27+
2628
#include <chrono>
2729
#ifndef SWIFT_THREADING_NONE
2830
# include <thread>
@@ -37,6 +39,10 @@
3739
# define NSEC_PER_SEC 1000000000ull
3840
#endif
3941

42+
#include "ExecutorHooks.h"
43+
44+
using namespace swift;
45+
4046
namespace {
4147

4248
struct JobQueueTraits {
@@ -104,14 +110,14 @@ static Job *DelayedJobQueue = nullptr;
104110

105111
/// Insert a job into the cooperative global queue.
106112
SWIFT_CC(swift)
107-
static void swift_task_enqueueGlobalImpl(Job *job) {
113+
void swift::swift_task_enqueueGlobalImpl(Job *job) {
108114
assert(job && "no job provided");
109115
JobQueue.enqueue(job);
110116
}
111117

112118
/// Enqueues a task on the main executor.
113119
SWIFT_CC(swift)
114-
static void swift_task_enqueueMainExecutorImpl(Job *job) {
120+
void swift::swift_task_enqueueMainExecutorImpl(Job *job) {
115121
// The cooperative executor does not distinguish between the main
116122
// queue and the global queue.
117123
swift_task_enqueueGlobalImpl(job);
@@ -136,15 +142,13 @@ static void insertDelayedJob(Job *newJob, JobDeadline deadline) {
136142
}
137143

138144
SWIFT_CC(swift)
139-
static void swift_task_checkIsolatedImpl(SerialExecutorRef executor) {
140-
_task_serialExecutor_checkIsolated(
141-
executor.getIdentity(), swift_getObjectType(executor.getIdentity()),
142-
executor.getSerialExecutorWitnessTable());
145+
void swift::swift_task_checkIsolatedImpl(SerialExecutorRef executor) {
146+
swift_task_invokeSwiftCheckIsolated(executor);
143147
}
144148

145149
/// Insert a job into the cooperative global queue with a delay.
146150
SWIFT_CC(swift)
147-
static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
151+
void swift::swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
148152
Job *newJob) {
149153
assert(newJob && "no job provided");
150154

@@ -157,7 +161,7 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
157161
}
158162

159163
SWIFT_CC(swift)
160-
static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
164+
void swift::swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
161165
long long nsec,
162166
long long tsec,
163167
long long tnsec,
@@ -252,3 +256,13 @@ swift_task_donateThreadToGlobalExecutorUntil(bool (*condition)(void *),
252256
swift_job_run(job, SerialExecutorRef::generic());
253257
}
254258
}
259+
260+
SWIFT_CC(swift)
261+
SerialExecutorRef swift::swift_task_getMainExecutorImpl() {
262+
return SerialExecutorRef::generic();
263+
}
264+
265+
SWIFT_CC(swift)
266+
bool swift::swift_task_isMainExecutorImpl(SerialExecutorRef executor) {
267+
return executor.isGeneric();
268+
}

0 commit comments

Comments
 (0)