@@ -321,7 +321,7 @@ bool _task_serialExecutor_isSameExclusiveExecutionContext(
321
321
// allowed to crash, because it is used to power "log warnings" data race
322
322
// detector. This mode is going away in Swift 6, but until then we allow this.
323
323
// This override exists primarily to be able to test both code-paths.
324
- enum IsCurrentExecutorCheckMode: unsigned {
324
+ enum IsCurrentExecutorCheckMode : unsigned {
325
325
// / The default mode when an app was compiled against "new" enough SDK.
326
326
// / It allows crashing in isCurrentExecutor, and calls into `checkIsolated`.
327
327
Swift6_UseCheckIsolated_AllowCrash,
@@ -332,8 +332,6 @@ enum IsCurrentExecutorCheckMode: unsigned {
332
332
// / used, and `checkIsolated` cannot be invoked.
333
333
Legacy_NoCheckIsolated_NonCrashing,
334
334
};
335
- static IsCurrentExecutorCheckMode isCurrentExecutorMode =
336
- Swift6_UseCheckIsolated_AllowCrash;
337
335
338
336
// Shimming call to Swift runtime because Swift Embedded does not have
339
337
// these symbols defined.
@@ -382,25 +380,16 @@ bool swift_bincompat_useLegacyNonCrashingExecutorChecks() {
382
380
static void checkIsCurrentExecutorMode (void *context) {
383
381
bool useLegacyMode =
384
382
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;
387
386
}
388
387
389
388
SWIFT_CC (swift)
390
- static bool swift_task_isCurrentExecutorImpl (SerialExecutorRef expectedExecutor) {
389
+ static bool isCurrentExecutor (SerialExecutorRef expectedExecutor,
390
+ IsCurrentExecutorCheckMode checkMode) {
391
391
auto current = ExecutorTrackingInfo::current ();
392
392
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
-
404
393
if (!current) {
405
394
// We have no current executor, i.e. we are running "outside" of Swift
406
395
// Concurrency. We could still be running on a thread/queue owned by
@@ -417,14 +406,14 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
417
406
418
407
// Otherwise, as last resort, let the expected executor check using
419
408
// 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) {
421
410
swift_task_checkIsolated (expectedExecutor); // will crash if not same context
422
411
423
412
// checkIsolated did not crash, so we are on the right executor, after all!
424
413
return true ;
425
414
}
426
415
427
- assert (isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing);
416
+ assert (checkMode == Legacy_NoCheckIsolated_NonCrashing);
428
417
return false ;
429
418
}
430
419
@@ -455,7 +444,7 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
455
444
// the crashing 'dispatch_assert_queue(main queue)' which will either crash
456
445
// or confirm we actually are on the main queue; or the custom expected
457
446
// executor has a chance to implement a similar queue check.
458
- if (isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing) {
447
+ if (checkMode == Legacy_NoCheckIsolated_NonCrashing) {
459
448
if ((expectedExecutor.isMainExecutor () && !currentExecutor.isMainExecutor ()) ||
460
449
(!expectedExecutor.isMainExecutor () && currentExecutor.isMainExecutor ())) {
461
450
return false ;
@@ -508,7 +497,7 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
508
497
// Note that this only works because the closure in assumeIsolated is
509
498
// synchronous, and will not cause suspensions, as that would require the
510
499
// presence of a Task.
511
- if (isCurrentExecutorMode == Swift6_UseCheckIsolated_AllowCrash) {
500
+ if (checkMode == Swift6_UseCheckIsolated_AllowCrash) {
512
501
swift_task_checkIsolated (expectedExecutor); // will crash if not same context
513
502
514
503
// The checkIsolated call did not crash, so we are on the right executor.
@@ -517,10 +506,28 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
517
506
518
507
// In the end, since 'checkIsolated' could not be used, so we must assume
519
508
// that the executors are not the same context.
520
- assert (isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing);
509
+ assert (checkMode == Legacy_NoCheckIsolated_NonCrashing);
521
510
return false ;
522
511
}
523
512
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
+
524
531
// / Logging level for unexpected executors:
525
532
// / 0 - no logging -- will be IGNORED when Swift6 mode of isCurrentExecutor is used
526
533
// / 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,
2178
2185
// we can just immediately continue running with the resume function
2179
2186
// we were passed in.
2180
2187
//
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)) {
2184
2195
return work (object); // 'return' forces tail call
2185
2196
}
2186
2197
0 commit comments