Skip to content

Commit 6b95ff7

Browse files
committed
[Concurrenncy] add internal way to assert we're on expected executor
1 parent 307ec5a commit 6b95ff7

File tree

5 files changed

+56
-1
lines changed

5 files changed

+56
-1
lines changed

include/swift/Runtime/Concurrency.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,13 @@ void swift_task_enqueueGlobalWithDeadline(long long sec, long long nsec,
729729
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
730730
void swift_task_enqueueMainExecutor(Job *job);
731731

732+
/// Return true if the caller is running in a Task on the passed Executor.
733+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
734+
bool swift_task_isOnExecutor(
735+
HeapObject * executor,
736+
const Metadata *selfType,
737+
const SerialExecutorWitnessTable *wtable);
738+
732739
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
733740

734741
/// Enqueue the given job on the main executor.
@@ -766,6 +773,17 @@ SWIFT_CC(swift) void (*swift_task_enqueueGlobalWithDeadline_hook)(
766773
int clock, Job *job,
767774
swift_task_enqueueGlobalWithDeadline_original original);
768775

776+
typedef SWIFT_CC(swift) bool (*swift_task_isOnExecutor_original)(
777+
HeapObject *executor,
778+
const Metadata *selfType,
779+
const SerialExecutorWitnessTable *wtable);
780+
SWIFT_EXPORT_FROM(swift_Concurrency)
781+
SWIFT_CC(swift) bool (*swift_task_isOnExecutor_hook)(
782+
HeapObject *executor,
783+
const Metadata *selfType,
784+
const SerialExecutorWitnessTable *wtable,
785+
swift_task_isOnExecutor_original original);
786+
769787
/// A hook to take over main executor enqueueing.
770788
typedef SWIFT_CC(swift) void (*swift_task_enqueueMainExecutor_original)(
771789
Job *job);

lib/AST/Decl.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9357,7 +9357,6 @@ Type TypeBase::getSwiftNewtypeUnderlyingType() {
93579357

93589358
const VarDecl *ClassDecl::getUnownedExecutorProperty() const {
93599359
auto &C = getASTContext();
9360-
auto module = getParentModule();
93619360

93629361
if (!isAnyActor())
93639362
return nullptr;

stdlib/public/Concurrency/Executor.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ public struct UnownedSerialExecutor: Sendable {
6969
}
7070
}
7171

72+
/// Checks if the current task is running on the expected executor.
73+
///
74+
/// Generally, Swift programs should be constructed such that it is statically
75+
/// known that a specific executor is used, for example by using global actors or
76+
/// custom executors. However, in some APIs it may be useful to provide an
77+
/// additional runtime check for this, especially when moving towards Swift
78+
/// concurrency from other runtimes which frequently use such assertions.
79+
/// - Parameter executor: The expected executor.
80+
@available(SwiftStdlib 5.9, *)
81+
@_silgen_name("swift_task_isOnExecutor")
82+
public func _taskIsOnExecutor<Executor: SerialExecutor>(_ executor: Executor) -> Bool
83+
7284
// Used by the concurrency runtime
7385
@available(SwiftStdlib 5.1, *)
7486
@_silgen_name("_swift_task_enqueueOnExecutor")

stdlib/public/Concurrency/GlobalExecutor.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ void (*swift::swift_task_enqueueGlobalWithDeadline_hook)(
7979
int clock, Job *job,
8080
swift_task_enqueueGlobalWithDeadline_original original) = nullptr;
8181

82+
SWIFT_CC(swift)
83+
bool (*swift::swift_task_isOnExecutor_hook)(
84+
HeapObject *executor,
85+
const Metadata *selfType,
86+
const SerialExecutorWitnessTable *wtable,
87+
swift_task_isOnExecutor_original original) = nullptr;
88+
8289
SWIFT_CC(swift)
8390
void (*swift::swift_task_enqueueMainExecutor_hook)(
8491
Job *job, swift_task_enqueueMainExecutor_original original) = nullptr;
@@ -125,6 +132,24 @@ void swift::swift_task_enqueueGlobalWithDeadline(
125132
swift_task_enqueueGlobalWithDeadlineImpl(sec, nsec, tsec, tnsec, clock, job);
126133
}
127134

135+
SWIFT_CC(swift)
136+
static bool swift_task_isOnExecutorImpl(HeapObject *executor,
137+
const Metadata *selfType,
138+
const SerialExecutorWitnessTable *wtable) {
139+
auto executorRef = ExecutorRef::forOrdinary(executor, wtable);
140+
return swift_task_isCurrentExecutor(executorRef);
141+
}
142+
143+
bool swift::swift_task_isOnExecutor(HeapObject *executor,
144+
const Metadata *selfType,
145+
const SerialExecutorWitnessTable *wtable) {
146+
if (swift_task_isOnExecutor_hook)
147+
return swift_task_isOnExecutor_hook(
148+
executor, selfType, wtable, swift_task_isOnExecutorImpl);
149+
else
150+
return swift_task_isOnExecutorImpl(executor, selfType, wtable);
151+
}
152+
128153
/*****************************************************************************/
129154
/****************************** MAIN EXECUTOR *******************************/
130155
/*****************************************************************************/

test/Concurrency/Runtime/custom_executors_protocol.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ actor MyActor: WithSpecifiedExecutor {
6363
}
6464

6565
func test(expectedExecutor: some SerialExecutor) {
66+
precondition(_taskIsOnExecutor(expectedExecutor), "Expected to be on: \(expectedExecutor)")
6667
checkIfMainQueue(expectedAnswer: true)
6768
print("\(Self.self): on executor \(expectedExecutor)")
6869
}

0 commit comments

Comments
 (0)