Skip to content

Commit e9173ff

Browse files
Make sure legacy executor checking mode is always used in swift_task_deinitOnExecutor()
1 parent 6b0ce0b commit e9173ff

File tree

4 files changed

+44
-31
lines changed

4 files changed

+44
-31
lines changed

stdlib/public/Concurrency/Actor.cpp

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ bool _task_serialExecutor_isSameExclusiveExecutionContext(
321321
// allowed to crash, because it is used to power "log warnings" data race
322322
// detector. This mode is going away in Swift 6, but until then we allow this.
323323
// This override exists primarily to be able to test both code-paths.
324-
enum IsCurrentExecutorCheckMode: unsigned {
324+
enum IsCurrentExecutorCheckMode : unsigned {
325325
/// The default mode when an app was compiled against "new" enough SDK.
326326
/// It allows crashing in isCurrentExecutor, and calls into `checkIsolated`.
327327
Swift6_UseCheckIsolated_AllowCrash,
@@ -332,8 +332,6 @@ enum IsCurrentExecutorCheckMode: unsigned {
332332
/// used, and `checkIsolated` cannot be invoked.
333333
Legacy_NoCheckIsolated_NonCrashing,
334334
};
335-
static IsCurrentExecutorCheckMode isCurrentExecutorMode =
336-
Swift6_UseCheckIsolated_AllowCrash;
337335

338336
// Shimming call to Swift runtime because Swift Embedded does not have
339337
// these symbols defined.
@@ -382,25 +380,16 @@ bool swift_bincompat_useLegacyNonCrashingExecutorChecks() {
382380
static void checkIsCurrentExecutorMode(void *context) {
383381
bool useLegacyMode =
384382
swift_bincompat_useLegacyNonCrashingExecutorChecks();
385-
isCurrentExecutorMode = useLegacyMode ? Legacy_NoCheckIsolated_NonCrashing
386-
: Swift6_UseCheckIsolated_AllowCrash;
383+
auto checkMode = static_cast<IsCurrentExecutorCheckMode *>(context);
384+
*checkMode = useLegacyMode ? Legacy_NoCheckIsolated_NonCrashing
385+
: Swift6_UseCheckIsolated_AllowCrash;
387386
}
388387

389388
SWIFT_CC(swift)
390-
static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor) {
389+
static bool isCurrentExecutor(SerialExecutorRef expectedExecutor,
390+
IsCurrentExecutorCheckMode checkMode) {
391391
auto current = ExecutorTrackingInfo::current();
392392

393-
// To support old applications on apple platforms which assumed this call
394-
// does not crash, try to use a more compatible mode for those apps.
395-
//
396-
// We only allow returning `false` directly from this function when operating
397-
// in 'Legacy_NoCheckIsolated_NonCrashing' mode. If allowing crashes, we
398-
// instead must call into 'checkIsolated' or crash directly.
399-
//
400-
// Whenever we confirm an executor equality, we can return true, in any mode.
401-
static swift::once_t checkModeToken;
402-
swift::once(checkModeToken, checkIsCurrentExecutorMode, nullptr);
403-
404393
if (!current) {
405394
// We have no current executor, i.e. we are running "outside" of Swift
406395
// Concurrency. We could still be running on a thread/queue owned by
@@ -417,14 +406,14 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
417406

418407
// Otherwise, as last resort, let the expected executor check using
419408
// external means, as it may "know" this thread is managed by it etc.
420-
if (isCurrentExecutorMode == Swift6_UseCheckIsolated_AllowCrash) {
409+
if (checkMode == Swift6_UseCheckIsolated_AllowCrash) {
421410
swift_task_checkIsolated(expectedExecutor); // will crash if not same context
422411

423412
// checkIsolated did not crash, so we are on the right executor, after all!
424413
return true;
425414
}
426415

427-
assert(isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing);
416+
assert(checkMode == Legacy_NoCheckIsolated_NonCrashing);
428417
return false;
429418
}
430419

@@ -455,7 +444,7 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
455444
// the crashing 'dispatch_assert_queue(main queue)' which will either crash
456445
// or confirm we actually are on the main queue; or the custom expected
457446
// executor has a chance to implement a similar queue check.
458-
if (isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing) {
447+
if (checkMode == Legacy_NoCheckIsolated_NonCrashing) {
459448
if ((expectedExecutor.isMainExecutor() && !currentExecutor.isMainExecutor()) ||
460449
(!expectedExecutor.isMainExecutor() && currentExecutor.isMainExecutor())) {
461450
return false;
@@ -508,7 +497,7 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
508497
// Note that this only works because the closure in assumeIsolated is
509498
// synchronous, and will not cause suspensions, as that would require the
510499
// presence of a Task.
511-
if (isCurrentExecutorMode == Swift6_UseCheckIsolated_AllowCrash) {
500+
if (checkMode == Swift6_UseCheckIsolated_AllowCrash) {
512501
swift_task_checkIsolated(expectedExecutor); // will crash if not same context
513502

514503
// The checkIsolated call did not crash, so we are on the right executor.
@@ -517,10 +506,28 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
517506

518507
// In the end, since 'checkIsolated' could not be used, so we must assume
519508
// that the executors are not the same context.
520-
assert(isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing);
509+
assert(checkMode == Legacy_NoCheckIsolated_NonCrashing);
521510
return false;
522511
}
523512

513+
SWIFT_CC(swift)
514+
static bool
515+
swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor) {
516+
// To support old applications on apple platforms which assumed this call
517+
// does not crash, try to use a more compatible mode for those apps.
518+
//
519+
// We only allow returning `false` directly from this function when operating
520+
// in 'Legacy_NoCheckIsolated_NonCrashing' mode. If allowing crashes, we
521+
// instead must call into 'checkIsolated' or crash directly.
522+
//
523+
// Whenever we confirm an executor equality, we can return true, in any mode.
524+
static IsCurrentExecutorCheckMode checkMode;
525+
static swift::once_t checkModeToken;
526+
swift::once(checkModeToken, checkIsCurrentExecutorMode, &checkMode);
527+
528+
return isCurrentExecutor(expectedExecutor, checkMode);
529+
}
530+
524531
/// Logging level for unexpected executors:
525532
/// 0 - no logging -- will be IGNORED when Swift6 mode of isCurrentExecutor is used
526533
/// 1 - warn on each instance -- will be IGNORED when Swift6 mode of isCurrentExecutor is used
@@ -2178,9 +2185,13 @@ static void swift_task_deinitOnExecutorImpl(void *object,
21782185
// we can just immediately continue running with the resume function
21792186
// we were passed in.
21802187
//
2181-
// Note that swift_task_isCurrentExecutor() returns true for @MainActor
2182-
// when running on the main thread without any executor
2183-
if (swift_task_isCurrentExecutor(newExecutor)) {
2188+
// Note that isCurrentExecutor() returns true for @MainActor
2189+
// when running on the main thread without any executor.
2190+
//
2191+
// We always use "legacy" checking mode here, because that's the desired
2192+
// behaviour for this use case. This does not change with SDK version or
2193+
// language mode.
2194+
if (isCurrentExecutor(newExecutor, Legacy_NoCheckIsolated_NonCrashing)) {
21842195
return work(object); // 'return' forces tail call
21852196
}
21862197

test/Concurrency/Runtime/actor_recursive_deinit.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ func isCurrent(_ a: AnyActor) -> Bool {
4343
return isCurrentExecutor(getExecutor(a))
4444
}
4545

46-
func isMainExecutor() -> Bool {
47-
isCurrentExecutor(Builtin.buildMainActorExecutorRef())
48-
}
49-
5046
actor Foo {
5147
let name: String
5248
let child: Foo?

test/Concurrency/Runtime/async_task_locals_isolated_deinit.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-run-simple-swift( -plugin-path %swift-plugin-dir -Xfrontend -disable-availability-checking -parse-stdlib %import-libdispatch)
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -plugin-path %swift-plugin-dir -Xfrontend -disable-availability-checking -parse-stdlib %import-libdispatch %s -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %env-SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 %target-run %t/a.out
25

36
// REQUIRES: libdispatch
47
// REQUIRES: executable_test

test/Distributed/Runtime/distributed_actor_deinit.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -parse-stdlib -parse-as-library) | %FileCheck %s
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -parse-stdlib -parse-as-library -module-name=main %s -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %env-SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy %target-run %t/a.out | %FileCheck %s
25

36
// REQUIRES: libdispatch
47
// REQUIRES: executable_test

0 commit comments

Comments
 (0)