From e1dc854f8f0455e981ebc25ffcf18387240d7303 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski <ktoso@apple.com> Date: Mon, 28 Apr 2025 17:37:18 +0900 Subject: [PATCH 1/3] [Concurrency] Change isIsolatingCurrent... to return Bool? This changes the isIsolatingCurrentContext function to return `Bool?` and removes all the witness table trickery we did previously to detect if it was implemented or not. This comes at a cost of trying to invoke it always, before `checkIsolated`, but it makes for an simpler implementation and more checkable even by third party Swift code which may want to ask this question. Along with the `withSerialExecutor` function, this now enables us to check the isolation at runtime when we have an `any Actor` e.g. from `#isolation`. Updates SE-0471 according to https://forums.swift.org/t/se-0471-improved-custom-serialexecutor-isolation-checking-for-concurrency-runtime/78834/ review discussions --- include/swift/ABI/Executor.h | 38 +++++++- include/swift/ABI/Metadata.h | 8 -- include/swift/ABI/MetadataValues.h | 22 +---- include/swift/Runtime/Concurrency.h | 10 +- include/swift/Runtime/ConcurrencyHooks.def | 2 +- lib/IRGen/GenProto.cpp | 26 ----- stdlib/public/Concurrency/Actor.cpp | 94 +++++++------------ .../public/Concurrency/ConcurrencyHooks.cpp | 4 +- .../Concurrency/CooperativeGlobalExecutor.cpp | 2 +- stdlib/public/Concurrency/Executor.swift | 34 +++++-- .../public/Concurrency/ExecutorBridge.swift | 16 +++- stdlib/public/Concurrency/ExecutorImpl.cpp | 23 ++--- stdlib/public/Concurrency/ExecutorImpl.h | 11 ++- stdlib/public/Concurrency/GlobalExecutor.cpp | 19 ++-- ...IsolatingCurrentContext_swift62_mode.swift | 2 +- ...IsolatingCurrentContext_swift62_mode.swift | 2 +- .../actor_isIsolatingCurrentContext.swift | 31 +++++- test/abi/macOS/arm64/concurrency.swift | 7 +- test/abi/macOS/x86_64/concurrency.swift | 7 +- test/embedded/Inputs/executor.c | 2 +- 20 files changed, 185 insertions(+), 175 deletions(-) diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h index 1257673826434..998c13798c9e8 100644 --- a/include/swift/ABI/Executor.h +++ b/include/swift/ABI/Executor.h @@ -17,10 +17,12 @@ #ifndef SWIFT_ABI_EXECUTOR_H #define SWIFT_ABI_EXECUTOR_H -#include <inttypes.h> +#include "../../../stdlib/public/Concurrency/Error.h" + #include "swift/ABI/Actor.h" #include "swift/ABI/HeapObject.h" #include "swift/Runtime/Casting.h" +#include <inttypes.h> namespace swift { class AsyncContext; @@ -413,6 +415,40 @@ class AsyncFunctionPointer { uint32_t ExpectedContextSize; }; +/// Type-safe wrapper around the return value of `isIsolatingCurrentContext`. +enum class IsIsolatingCurrentContextDecision : int8_t { + // The function call could not determine if the current context is isolated + // by this executor or not. Default value for executors which do not implement + // `isIsolatingCurrentContext`. + Unknown, + // The current context is definitely not isolated by this executor. + NotIsolated, + // The current context is definitely isolated by this executor. + Isolated, +}; + +inline IsIsolatingCurrentContextDecision +getIsIsolatingCurrentContextDecisionFromInt(int8_t value) { + switch (value) { + case -1: return IsIsolatingCurrentContextDecision::Unknown; + case 0: return IsIsolatingCurrentContextDecision::NotIsolated; + case 1: return IsIsolatingCurrentContextDecision::Isolated; + default: + swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); + return IsIsolatingCurrentContextDecision::Unknown; // silence warning about missing return + } +} + +inline StringRef getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDecision decision) { + switch (decision) { + case IsIsolatingCurrentContextDecision::Unknown: return "Unknown"; + case IsIsolatingCurrentContextDecision::NotIsolated: return "NotIsolated"; + case IsIsolatingCurrentContextDecision::Isolated: return "Isolated"; + } + swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); + return "<Unexpected Value>"; // silence warning about missing return +} + } #endif diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 0789767055800..52d6355ebb289 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -2984,14 +2984,6 @@ struct TargetProtocolConformanceDescriptor final return Demangle::makeSymbolicMangledNameStringRef(this->template getTrailingObjects<TargetGlobalActorReference<Runtime>>()->type); } - /// True if this is a conformance to 'SerialExecutor' which has a non-default - /// (i.e. not the stdlib's default implementation) witness. This means that - /// the developer has implemented this method explicitly and we should prefer - /// calling it. - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext() const { - return Flags.hasNonDefaultSerialExecutorIsIsolatingCurrentContext(); - } - /// Retrieve the protocol conformance of the global actor type to the /// GlobalActor protocol. const TargetProtocolConformanceDescriptor<Runtime> * diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index f239ae336c9cb..d16f44e075496 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -754,14 +754,6 @@ class ConformanceFlags { IsConformanceOfProtocolMask = 0x01u << 18, HasGlobalActorIsolation = 0x01u << 19, - // Used to detect if this is a conformance to SerialExecutor that has - // an user defined implementation of 'isIsolatingCurrentContext'. This - // requirement is special in the sense that if a non-default impl is present - // we will avoid calling the `checkIsolated` method which would lead to a - // crash. In other words, this API "soft replaces" 'checkIsolated' so we - // must at runtime the presence of a non-default implementation. - HasNonDefaultSerialExecutorIsIsolatingCurrentContext = 0x01u << 20, - NumConditionalPackDescriptorsMask = 0xFFu << 24, NumConditionalPackDescriptorsShift = 24 }; @@ -828,15 +820,7 @@ class ConformanceFlags { : 0)); } - ConformanceFlags withHasNonDefaultSerialExecutorIsIsolatingCurrentContext( - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext) const { - return ConformanceFlags((Value & ~HasNonDefaultSerialExecutorIsIsolatingCurrentContext) - | (hasNonDefaultSerialExecutorIsIsolatingCurrentContext - ? HasNonDefaultSerialExecutorIsIsolatingCurrentContext - : 0)); - } - - /// Retrieve the type reference kind kind. + /// Retrieve the type reference kind. TypeReferenceKind getTypeReferenceKind() const { return TypeReferenceKind( (Value & TypeMetadataKindMask) >> TypeMetadataKindShift); @@ -880,10 +864,6 @@ class ConformanceFlags { return Value & HasGlobalActorIsolation; } - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext() const { - return Value & HasNonDefaultSerialExecutorIsIsolatingCurrentContext; - } - /// Retrieve the # of conditional requirements. unsigned getNumConditionalRequirements() const { return (Value & NumConditionalRequirementsMask) diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index e87ff57ca4e31..6b376c52b770a 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -777,12 +777,12 @@ bool swift_task_invokeSwiftCheckIsolated(SerialExecutorRef executor); /// Invoke an executor's `isIsolatingCurrentContext` implementation; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -bool swift_task_isIsolatingCurrentContext(SerialExecutorRef executor); +IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContext(SerialExecutorRef executor); /// Invoke a Swift executor's `isIsolatingCurrentContext` implementation; returns /// `true` if it invoked the Swift implementation, `false` otherwise. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -bool swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor); +IsIsolatingCurrentContextDecision swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor); /// A count in nanoseconds. using JobDelay = unsigned long long; @@ -1041,12 +1041,6 @@ enum swift_task_is_current_executor_flag : uint64_t { /// The routine MUST NOT assert on failure. /// Even at the cost of not calling 'checkIsolated' if it is available. MustNotAssert = 0x10, - - /// The routine should use 'isIsolatingCurrentContext' function on the - /// 'expected' executor instead of `checkIsolated`. - /// - /// This is a variant of `MustNotAssert` - UseIsIsolatingCurrentContext = 0x20, }; SWIFT_EXPORT_FROM(swift_Concurrency) diff --git a/include/swift/Runtime/ConcurrencyHooks.def b/include/swift/Runtime/ConcurrencyHooks.def index 960753e4411ff..b4a9fa92691e1 100644 --- a/include/swift/Runtime/ConcurrencyHooks.def +++ b/include/swift/Runtime/ConcurrencyHooks.def @@ -47,7 +47,7 @@ SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueGlobalWithDeadline, SWIFT_CONCURRENCY_HOOK(void, swift_task_checkIsolated, SerialExecutorRef executor); -SWIFT_CONCURRENCY_HOOK(bool, swift_task_isIsolatingCurrentContext, +SWIFT_CONCURRENCY_HOOK(IsIsolatingCurrentContextDecision, swift_task_isIsolatingCurrentContext, SerialExecutorRef executor); SWIFT_CONCURRENCY_HOOK(bool, swift_task_isOnExecutor, diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 3e6d92110386c..108d922a27613 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -2225,7 +2225,6 @@ namespace { Flags = Flags.withIsSynthesizedNonUnique(conf->isSynthesizedNonUnique()); Flags = Flags.withIsConformanceOfProtocol(conf->isConformanceOfProtocol()); Flags = Flags.withHasGlobalActorIsolation(isolation.isGlobalActor()); - Flags = withSerialExecutorCheckingModeFlags(Flags, conf); } else { Flags = Flags.withIsRetroactive(false) .withIsSynthesizedNonUnique(false); @@ -2442,31 +2441,6 @@ namespace { B.addRelativeAddress(globalActorConformanceDescriptor); } - static ConformanceFlags - withSerialExecutorCheckingModeFlags(ConformanceFlags Flags, const NormalProtocolConformance *conf) { - ProtocolDecl *proto = conf->getProtocol(); - auto &C = proto->getASTContext(); - - ConformanceFlags UpdatedFlags = Flags; - if (proto->isSpecificProtocol(swift::KnownProtocolKind::SerialExecutor)) { - conf->forEachValueWitness([&](const ValueDecl *req, - Witness witness) { - bool nameMatch = witness.getDecl()->getBaseIdentifier() == C.Id_isIsolatingCurrentContext; - if (nameMatch) { - if (DeclContext *NominalOrExtension = witness.getDecl()->getDeclContext()) { - // If the witness is NOT the default implementation in the _Concurrency library, - // we should record that this is an user provided implementation and we should call it. - bool hasNonDefaultIsIsolatingCurrentContext = - !NominalOrExtension->getParentModule()->isConcurrencyModule(); - UpdatedFlags = UpdatedFlags.withHasNonDefaultSerialExecutorIsIsolatingCurrentContext( - hasNonDefaultIsIsolatingCurrentContext); - } - } - }); - } - - return UpdatedFlags; - } }; } diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 71ca7325f6e97..0ae95bc8e1dd4 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -410,9 +410,6 @@ static void _swift_task_debug_dumpIsCurrentExecutorFlags( if (options.contains(swift_task_is_current_executor_flag::Assert)) SWIFT_TASK_DEBUG_LOG("%s swift_task_is_current_executor_flag::%s", hint, "Assert"); - if (options.contains(swift_task_is_current_executor_flag::UseIsIsolatingCurrentContext)) - SWIFT_TASK_DEBUG_LOG("%s swift_task_is_current_executor_flag::%s", - hint, "UseIsIsolatingCurrentContext"); } // Shimming call to Swift runtime because Swift Embedded does not have @@ -470,13 +467,6 @@ swift_task_is_current_executor_flag swift_bincompat_selectDefaultIsCurrentExecut // Remove the assert option which is what would cause the "crash" mode options = swift_task_is_current_executor_flag( options & ~swift_task_is_current_executor_flag::Assert); - } else if (strcmp(modeStr, "isIsolatingCurrentContext") == 0) { - options = swift_task_is_current_executor_flag( - options | swift_task_is_current_executor_flag::UseIsIsolatingCurrentContext); - // When we're using the isIsolatingCurrentContext we don't want to use crashing APIs, - // so disable it explicitly. - options = swift_task_is_current_executor_flag( - options & ~swift_task_is_current_executor_flag::Assert); } else if (strcmp(modeStr, "crash") == 0 || strcmp(modeStr, "swift6") == 0) { options = swift_task_is_current_executor_flag( @@ -501,43 +491,11 @@ extern "C" SWIFT_CC(swift) void _swift_task_enqueueOnExecutor( Job *job, HeapObject *executor, const Metadata *executorType, const SerialExecutorWitnessTable *wtable); -/// Check the executor's witness table for specific information about e.g. -/// being able ignore `checkIsolated` and only call `isIsolatingCurrentContext`. -static swift_task_is_current_executor_flag -_getIsolationCheckingOptionsFromExecutorWitnessTable(const SerialExecutorWitnessTable *_wtable) { - const WitnessTable* wtable = reinterpret_cast<const WitnessTable*>(_wtable); -#if SWIFT_STDLIB_USE_RELATIVE_PROTOCOL_WITNESS_TABLES - auto description = lookThroughOptionalConditionalWitnessTable( - reinterpret_cast<const RelativeWitnessTable*>(wtable)) - ->getDescription(); -#else - auto description = wtable->getDescription(); -#endif - if (!description) { - return swift_task_is_current_executor_flag::None; - } - - if (description->hasNonDefaultSerialExecutorIsIsolatingCurrentContext()) { - // The specific executor has implemented `isIsolatingCurrentContext` and - // we do not have to call `checkIsolated`. - return swift_task_is_current_executor_flag::UseIsIsolatingCurrentContext; - } - - // No changes to the checking mode. - return swift_task_is_current_executor_flag::None; -} - SWIFT_CC(swift) static bool swift_task_isCurrentExecutorWithFlagsImpl( SerialExecutorRef expectedExecutor, swift_task_is_current_executor_flag flags) { auto current = ExecutorTrackingInfo::current(); - if (expectedExecutor.getIdentity() && expectedExecutor.hasSerialExecutorWitnessTable()) { - if (auto *wtable = expectedExecutor.getSerialExecutorWitnessTable()) { - auto executorSpecificMode = _getIsolationCheckingOptionsFromExecutorWitnessTable(wtable); - flags = swift_task_is_current_executor_flag(flags | executorSpecificMode); - } - } auto options = SwiftTaskIsCurrentExecutorOptions(flags); _swift_task_debug_dumpIsCurrentExecutorFlags(__FUNCTION__, flags); @@ -557,16 +515,26 @@ static bool swift_task_isCurrentExecutorWithFlagsImpl( // We cannot use 'complexEquality' as it requires two executor instances, // and we do not have a 'current' executor here. - if (options.contains(swift_task_is_current_executor_flag::UseIsIsolatingCurrentContext)) { - SWIFT_TASK_DEBUG_LOG("executor checking mode option: UseIsIsolatingCurrentContext; invoke (%p).isIsolatingCurrentContext", - expectedExecutor.getIdentity()); - // The executor has the most recent 'isIsolatingCurrentContext' API - // so available so we prefer calling that to 'checkIsolated'. - auto result = swift_task_isIsolatingCurrentContext(expectedExecutor); - - SWIFT_TASK_DEBUG_LOG("executor checking mode option: UseIsIsolatingCurrentContext; invoke (%p).isIsolatingCurrentContext => %s", - expectedExecutor.getIdentity(), result ? "pass" : "fail"); - return result; + // Invoke the 'isIsolatingCurrentContext', if "undecided" (i.e. nil), we need to make further calls + SWIFT_TASK_DEBUG_LOG("executor checking, invoke (%p).isIsolatingCurrentContext", + expectedExecutor.getIdentity()); + // The executor has the most recent 'isIsolatingCurrentContext' API + // so available so we prefer calling that to 'checkIsolated'. + auto isIsolatingCurrentContextDecision = swift_task_isIsolatingCurrentContext(expectedExecutor); + + SWIFT_TASK_DEBUG_LOG("executor checking mode option: UseIsIsolatingCurrentContext; invoke (%p).isIsolatingCurrentContext => %s", + expectedExecutor.getIdentity(), getIsIsolatingCurrentContextDecisionNameStr(isIsolatingCurrentContextDecision)); + switch (isIsolatingCurrentContextDecision) { + case IsIsolatingCurrentContextDecision::Isolated: + // We know for sure that this serial executor is isolating this context, return the decision. + return true; + case IsIsolatingCurrentContextDecision::NotIsolated: + // We know for sure that this serial executor is NOT isolating this context, return this decision. + return false; + case IsIsolatingCurrentContextDecision::Unknown: + // We don't know, so we have to continue trying to check using other methods. + // This most frequently would happen if a serial executor did not implement isIsolatingCurrentContext. + break; } // Otherwise, as last resort, let the expected executor check using @@ -675,18 +643,20 @@ static bool swift_task_isCurrentExecutorWithFlagsImpl( // Invoke the 'isIsolatingCurrentContext' function if we can; If so, we can // avoid calling the `checkIsolated` because their result will be the same. - if (options.contains(swift_task_is_current_executor_flag::UseIsIsolatingCurrentContext)) { - SWIFT_TASK_DEBUG_LOG("executor checking: can call (%p).isIsolatingCurrentContext", - expectedExecutor.getIdentity()); + SWIFT_TASK_DEBUG_LOG("executor checking: call (%p).isIsolatingCurrentContext", + expectedExecutor.getIdentity()); - bool checkResult = swift_task_isIsolatingCurrentContext(expectedExecutor); + const auto isIsolatingCurrentContextDecision = swift_task_isIsolatingCurrentContext(expectedExecutor); - SWIFT_TASK_DEBUG_LOG("executor checking: can call (%p).isIsolatingCurrentContext => %p", - expectedExecutor.getIdentity(), checkResult ? "pass" : "fail"); - return checkResult; - } else { - SWIFT_TASK_DEBUG_LOG("executor checking: can NOT call (%p).isIsolatingCurrentContext", - expectedExecutor.getIdentity()); + SWIFT_TASK_DEBUG_LOG("executor checking: can call (%p).isIsolatingCurrentContext => %p", + expectedExecutor.getIdentity(), getIsIsolatingCurrentContextDecisionNameStr(isIsolatingCurrentContextDecision)); + switch (isIsolatingCurrentContextDecision) { + case IsIsolatingCurrentContextDecision::Isolated: + return true; + case IsIsolatingCurrentContextDecision::NotIsolated: + return false; + case IsIsolatingCurrentContextDecision::Unknown: + break; } // This provides a last-resort check by giving the expected SerialExecutor the diff --git a/stdlib/public/Concurrency/ConcurrencyHooks.cpp b/stdlib/public/Concurrency/ConcurrencyHooks.cpp index 26fd5c8159954..f690ead4876f4 100644 --- a/stdlib/public/Concurrency/ConcurrencyHooks.cpp +++ b/stdlib/public/Concurrency/ConcurrencyHooks.cpp @@ -111,13 +111,13 @@ swift::swift_task_checkIsolated(SerialExecutorRef executor) { swift_task_checkIsolatedOrig(executor); } -SWIFT_CC(swift) static bool +SWIFT_CC(swift) static IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextOrig(SerialExecutorRef executor) { return swift_task_isIsolatingCurrentContextImpl( *reinterpret_cast<SwiftExecutorRef *>(&executor)); } -bool +IsIsolatingCurrentContextDecision swift::swift_task_isIsolatingCurrentContext(SerialExecutorRef executor) { if (SWIFT_UNLIKELY(swift_task_isIsolatingCurrentContext_hook)) return swift_task_isIsolatingCurrentContext_hook(executor, swift_task_isIsolatingCurrentContextOrig); diff --git a/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp b/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp index 7cc503e836c25..80bf1491ce6b0 100644 --- a/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp +++ b/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp @@ -155,7 +155,7 @@ void swift_task_checkIsolatedImpl(SwiftExecutorRef executor) { } SWIFT_CC(swift) -bool swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { +IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { return swift_executor_invokeSwiftIsIsolatingCurrentContext(executor); } diff --git a/stdlib/public/Concurrency/Executor.swift b/stdlib/public/Concurrency/Executor.swift index a4ec7618b6829..0b1dbc3644cd2 100644 --- a/stdlib/public/Concurrency/Executor.swift +++ b/stdlib/public/Concurrency/Executor.swift @@ -343,8 +343,25 @@ public protocol SerialExecutor: Executor { @available(SwiftStdlib 6.0, *) func checkIsolated() + /// Checks if the current execution context is isolated by this executor. + /// + /// This function can be called by the runtime in order to perform assertions, + /// or attempt to issue warnings about unexpected isolation. + /// + /// This method will be invoked _before_ `checkIsolated` and may also be invoked + /// when crashing is not an acceptable outcome of a check (e.g. when attempting to issue isolation _warnings_). + /// + /// Implementations should prefer to implement this method rather than `checkIsolated()` since it can often + /// result in more tailored error messages. It is allowed, and useful for backwards compatibility with old + /// runtimes which are not able to invoke `isIsolatingCurrentContext()` to implement `checkIsolated()`, + /// even if an implementation is able to implement this method. Often times an implementation of `checkIsolated()`, + /// would then invoke `isIsolatingCurrentContext()` and crash if the returned value was `false`. + /// + /// The default implementation returns `nil` is used to indicate that it is "unknown" if the current context is + /// isolated by this serial executor. The runtime then _may_ proceed to invoke `checkIsolated()` as a last-resort + /// attempt to verify the isolation of the current context. @available(SwiftStdlib 6.2, *) - func isIsolatingCurrentContext() -> Bool + func isIsolatingCurrentContext() -> Bool? } @@ -381,9 +398,8 @@ extension SerialExecutor { extension SerialExecutor { @available(SwiftStdlib 6.2, *) - public func isIsolatingCurrentContext() -> Bool { - self.checkIsolated() - return true + public func isIsolatingCurrentContext() -> Bool? { + return nil } } @@ -865,9 +881,13 @@ internal func _task_serialExecutor_checkIsolated<E>(executor: E) @available(SwiftStdlib 6.2, *) @_silgen_name("_task_serialExecutor_isIsolatingCurrentContext") -internal func _task_serialExecutor_isIsolatingCurrentContext<E>(executor: E) -> Bool - where E: SerialExecutor { - return executor.isIsolatingCurrentContext() +internal func _task_serialExecutor_isIsolatingCurrentContext<E>(executor: E) -> Int8 + where E: SerialExecutor { + switch executor.isIsolatingCurrentContext() { + case nil: -1 // unknown + case .some(false): 0 // not isolated + case .some(true): 1 // isolated! + } } /// Obtain the executor ref by calling the executor's `asUnownedSerialExecutor()`. diff --git a/stdlib/public/Concurrency/ExecutorBridge.swift b/stdlib/public/Concurrency/ExecutorBridge.swift index db718d53aa334..d160d424acc44 100644 --- a/stdlib/public/Concurrency/ExecutorBridge.swift +++ b/stdlib/public/Concurrency/ExecutorBridge.swift @@ -35,12 +35,20 @@ internal func checkIsolated<E>(executor: E) where E: SerialExecutor { executor.checkIsolated() } +/// Invokes the swift function isIsolatingCurrentContext on the given executor, +/// and converts between the `Optional<Bool>` into: +/// -1: unknown +/// 0: not isolated +/// 1: isolated @available(SwiftStdlib 6.2, *) @_silgen_name("_swift_task_isIsolatingCurrentContextSwift") -internal func isIsolatingCurrentContext<E>(executor: E) -> Bool - where E: SerialExecutor -{ - return executor.isIsolatingCurrentContext() +internal func isIsolatingCurrentContext<E>(executor: E) -> Int8 + where E: SerialExecutor { + switch executor.isIsolatingCurrentContext() { + case nil: -1 // unknown + case .some(false): 0 // not isolated + case .some(true): 1 // isolated! + } } @available(SwiftStdlib 6.2, *) diff --git a/stdlib/public/Concurrency/ExecutorImpl.cpp b/stdlib/public/Concurrency/ExecutorImpl.cpp index 5f8e1aa45a0dc..27b49a775ffa6 100644 --- a/stdlib/public/Concurrency/ExecutorImpl.cpp +++ b/stdlib/public/Concurrency/ExecutorImpl.cpp @@ -56,31 +56,28 @@ extern "C" SWIFT_CC(swift) void swift_task_checkIsolatedImpl( extern "C" SWIFT_CC(swift) -bool _swift_task_isIsolatingCurrentContextSwift( +int8_t _swift_task_isIsolatingCurrentContextSwift( HeapObject *executor, const Metadata *executorType, const SerialExecutorWitnessTable *witnessTable ); -extern "C" SWIFT_CC(swift) bool swift_task_isIsolatingCurrentContextImpl( +extern "C" SWIFT_CC(swift) IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl( SerialExecutorRef executor) { HeapObject *identity = executor.getIdentity(); // We might be being called with an actor rather than a "proper" // SerialExecutor; in that case, we won't have a SerialExecutor witness // table. - if (executor.hasSerialExecutorWitnessTable()) { - return _swift_task_isIsolatingCurrentContextSwift( - identity, swift_getObjectType(identity), - executor.getSerialExecutorWitnessTable()); - } else { - const Metadata *objectType = swift_getObjectType(executor.getIdentity()); - auto typeName = swift_getTypeName(objectType, true); - - swift_Concurrency_fatalError( - 0, "Incorrect actor executor assumption; expected '%.*s' executor.\n", - (int)typeName.length, typeName.data); + if (!executor.hasSerialExecutorWitnessTable()) { + return IsIsolatingCurrentContextDecision::Unknown; } + + auto decision = _swift_task_isIsolatingCurrentContextSwift( + identity, swift_getObjectType(identity), + executor.getSerialExecutorWitnessTable()); + + return getIsIsolatingCurrentContextDecisionFromInt(decision); } extern "C" SWIFT_CC(swift) bool swift_task_isMainExecutorImpl( diff --git a/stdlib/public/Concurrency/ExecutorImpl.h b/stdlib/public/Concurrency/ExecutorImpl.h index a068c456b3c05..c66c5d1f10ed5 100644 --- a/stdlib/public/Concurrency/ExecutorImpl.h +++ b/stdlib/public/Concurrency/ExecutorImpl.h @@ -31,6 +31,8 @@ #define __ptrauth_objc_isa_pointer #endif +#include "swift/ABI/Executor.h" + #include <inttypes.h> #include <stdbool.h> #include <stdlib.h> @@ -226,10 +228,12 @@ swift_executor_invokeSwiftCheckIsolated(SwiftExecutorRef executor) { return _swift_task_invokeSwiftCheckIsolated_c(executor); } +using swift::IsIsolatingCurrentContextDecision; + /// Check if the current context is isolated by the specified executor. -static inline bool +static inline IsIsolatingCurrentContextDecision swift_executor_invokeSwiftIsIsolatingCurrentContext(SwiftExecutorRef executor) { - extern bool _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor); + extern IsIsolatingCurrentContextDecision _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor); return _swift_task_invokeSwiftIsIsolatingCurrentContext_c(executor); } @@ -292,7 +296,8 @@ SWIFT_CC(swift) void swift_task_enqueueMainExecutorImpl(SwiftJob * _Nonnull job) SWIFT_CC(swift) void swift_task_checkIsolatedImpl(SwiftExecutorRef executor); /// Check if the specified executor isolates the current context. -SWIFT_CC(swift) bool swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor); +SWIFT_CC(swift) +swift::IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor); /// Get a reference to the main executor. SWIFT_CC(swift) SwiftExecutorRef swift_task_getMainExecutorImpl(void); diff --git a/stdlib/public/Concurrency/GlobalExecutor.cpp b/stdlib/public/Concurrency/GlobalExecutor.cpp index 833abb1a02f15..1aac25115f32d 100644 --- a/stdlib/public/Concurrency/GlobalExecutor.cpp +++ b/stdlib/public/Concurrency/GlobalExecutor.cpp @@ -88,23 +88,28 @@ extern "C" bool _swift_task_invokeSwiftCheckIsolated_c(SwiftExecutorRef executor extern "C" SWIFT_CC(swift) -bool _task_serialExecutor_isIsolatingCurrentContext( +int8_t _task_serialExecutor_isIsolatingCurrentContext( HeapObject *executor, const Metadata *selfType, const SerialExecutorWitnessTable *wtable); -SWIFT_CC(swift) -bool swift::swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor) +using swift::IsIsolatingCurrentContextDecision; + +SWIFT_CC(swift) IsIsolatingCurrentContextDecision +swift::swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor) { - if (!executor.hasSerialExecutorWitnessTable()) - return false; + if (!executor.hasSerialExecutorWitnessTable()) { + return IsIsolatingCurrentContextDecision::NotIsolated; + } - return _task_serialExecutor_isIsolatingCurrentContext( + auto decision = _task_serialExecutor_isIsolatingCurrentContext( executor.getIdentity(), swift_getObjectType(executor.getIdentity()), executor.getSerialExecutorWitnessTable()); + + return getIsIsolatingCurrentContextDecisionFromInt(decision); } -extern "C" bool _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor) +extern "C" swift::IsIsolatingCurrentContextDecision _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor) { return swift_task_invokeSwiftIsIsolatingCurrentContext(*reinterpret_cast<SerialExecutorRef *>(&executor)); } diff --git a/test/Concurrency/Runtime/actor_assert_precondition_executor_isIsolatingCurrentContext_swift62_mode.swift b/test/Concurrency/Runtime/actor_assert_precondition_executor_isIsolatingCurrentContext_swift62_mode.swift index e651b7f1abfcf..5cd7a28976288 100644 --- a/test/Concurrency/Runtime/actor_assert_precondition_executor_isIsolatingCurrentContext_swift62_mode.swift +++ b/test/Concurrency/Runtime/actor_assert_precondition_executor_isIsolatingCurrentContext_swift62_mode.swift @@ -30,7 +30,7 @@ final class IsIsolatingExecutor: SerialExecutor { print("called: checkIsolated") } - func isIsolatingCurrentContext() -> Bool { + func isIsolatingCurrentContext() -> Bool? { print("called: isIsolatingCurrentContext") return true } diff --git a/test/Concurrency/Runtime/actor_assert_precondition_executor_not_implemented_isIsolatingCurrentContext_swift62_mode.swift b/test/Concurrency/Runtime/actor_assert_precondition_executor_not_implemented_isIsolatingCurrentContext_swift62_mode.swift index dc83d4d708ce8..05f79173eabfd 100644 --- a/test/Concurrency/Runtime/actor_assert_precondition_executor_not_implemented_isIsolatingCurrentContext_swift62_mode.swift +++ b/test/Concurrency/Runtime/actor_assert_precondition_executor_not_implemented_isIsolatingCurrentContext_swift62_mode.swift @@ -30,7 +30,7 @@ final class IsIsolatingExecutor: SerialExecutor { print("called: checkIsolated") } - func isIsolatingCurrentContext() -> Bool { + func isIsolatingCurrentContext() -> Bool? { print("called: isIsolatingCurrentContext") return true } diff --git a/test/Concurrency/Runtime/actor_isIsolatingCurrentContext.swift b/test/Concurrency/Runtime/actor_isIsolatingCurrentContext.swift index 1a43d7ca584a9..d5667edeb4c97 100644 --- a/test/Concurrency/Runtime/actor_isIsolatingCurrentContext.swift +++ b/test/Concurrency/Runtime/actor_isIsolatingCurrentContext.swift @@ -30,12 +30,34 @@ final class IsIsolatingExecutor: SerialExecutor { print("called: checkIsolated") } - func isIsolatingCurrentContext() -> Bool { + func isIsolatingCurrentContext() -> Bool? { print("called: isIsolatingCurrentContext") return true } } +@available(SwiftStdlib 6.2, *) +final class UnknownIfIsIsolatingExecutor: SerialExecutor { + init() {} + + func enqueue(_ job: consuming ExecutorJob) { + job.runSynchronously(on: self.asUnownedSerialExecutor()) + } + + func asUnownedSerialExecutor() -> UnownedSerialExecutor { + UnownedSerialExecutor(ordinary: self) + } + + func checkIsolated() { + print("called: checkIsolated") + } + + func isIsolatingCurrentContext() -> Bool? { + print("called: isIsolatingCurrentContext; return nil") + return nil + } +} + @available(SwiftStdlib 6.2, *) final class NoChecksImplementedExecutor: SerialExecutor { init() {} @@ -78,7 +100,7 @@ actor ActorOnIsCheckImplementingExecutor<Ex: SerialExecutor> { self.executor.asUnownedSerialExecutor() } - func checkIsIsolatingCurrentContext() async -> Bool { + func checkIsIsolatingCurrentContext() async -> Bool? { executor.isIsolatingCurrentContext() } } @@ -87,6 +109,7 @@ actor ActorOnIsCheckImplementingExecutor<Ex: SerialExecutor> { static func main() async { let hasIsIsolatingCurrentContextExecutor = IsIsolatingExecutor() let hasIsCheckActor = ActorOnIsCheckImplementingExecutor(on: hasIsIsolatingCurrentContextExecutor) + let unknownIsIsolatingActor = ActorOnIsCheckImplementingExecutor(on: UnknownIfIsIsolatingExecutor()) let anyActor: any Actor = hasIsCheckActor @@ -99,5 +122,9 @@ actor ActorOnIsCheckImplementingExecutor<Ex: SerialExecutor> { let inside = await hasIsCheckActor.checkIsIsolatingCurrentContext() assert(inside == true) // CHECK: called: isIsolatingCurrentContext + + _ = unknownIsIsolatingActor.preconditionIsolated() + // CHECK: called: isIsolatingCurrentContext; return nil + // CHECK: called: checkIsolated } } diff --git a/test/abi/macOS/arm64/concurrency.swift b/test/abi/macOS/arm64/concurrency.swift index a821e4a270556..39f9999d72878 100644 --- a/test/abi/macOS/arm64/concurrency.swift +++ b/test/abi/macOS/arm64/concurrency.swift @@ -404,12 +404,13 @@ Added: _$ss19DiscardingTaskGroupV05startB28SynchronouslyUnlessCancelled4name8pri Added: _$ss27ThrowingDiscardingTaskGroupV05startC13Synchronously4name8priority9operationySSSg_ScPSgyyYaKYAcntF Added: _$ss27ThrowingDiscardingTaskGroupV05startC28SynchronouslyUnlessCancelled4name8priority9operationySSSg_ScPSgyyYaKYAcntF +// isIsolatingCurrentContext Added: _swift_task_invokeSwiftIsIsolatingCurrentContext Added: _swift_task_isIsolatingCurrentContext Added: _swift_task_isIsolatingCurrentContext_hook -Added: _$sScf25isIsolatingCurrentContextSbyFTj -Added: _$sScf25isIsolatingCurrentContextSbyFTq -Added: _$sScfsE25isIsolatingCurrentContextSbyF +Added: _$sScfsE25isIsolatingCurrentContextSbSgyF +Added: _$sScf25isIsolatingCurrentContextSbSgyFTj +Added: _$sScf25isIsolatingCurrentContextSbSgyFTq // CoroutineAccessors Added: _swift_task_dealloc_through diff --git a/test/abi/macOS/x86_64/concurrency.swift b/test/abi/macOS/x86_64/concurrency.swift index 6fed1d757d715..8e406898f8eb6 100644 --- a/test/abi/macOS/x86_64/concurrency.swift +++ b/test/abi/macOS/x86_64/concurrency.swift @@ -404,12 +404,13 @@ Added: _$ss19DiscardingTaskGroupV05startB28SynchronouslyUnlessCancelled4name8pri Added: _$ss27ThrowingDiscardingTaskGroupV05startC13Synchronously4name8priority9operationySSSg_ScPSgyyYaKYAcntF Added: _$ss27ThrowingDiscardingTaskGroupV05startC28SynchronouslyUnlessCancelled4name8priority9operationySSSg_ScPSgyyYaKYAcntF +// isIsolatingCurrentContext Added: _swift_task_invokeSwiftIsIsolatingCurrentContext Added: _swift_task_isIsolatingCurrentContext Added: _swift_task_isIsolatingCurrentContext_hook -Added: _$sScf25isIsolatingCurrentContextSbyFTj -Added: _$sScf25isIsolatingCurrentContextSbyFTq -Added: _$sScfsE25isIsolatingCurrentContextSbyF +Added: _$sScfsE25isIsolatingCurrentContextSbSgyF +Added: _$sScf25isIsolatingCurrentContextSbSgyFTj +Added: _$sScf25isIsolatingCurrentContextSbSgyFTq // CoroutineAccessors Added: _swift_task_dealloc_through diff --git a/test/embedded/Inputs/executor.c b/test/embedded/Inputs/executor.c index 7032b3af833d3..a9babfb536937 100644 --- a/test/embedded/Inputs/executor.c +++ b/test/embedded/Inputs/executor.c @@ -308,7 +308,7 @@ void swift_task_checkIsolatedImpl(SwiftExecutorRef executor) { /// Check if the specified executor is the current executor. SWIFT_CC(swift) -bool swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { +IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { return swift_executor_invokeSwiftIsIsolatingCurrentContext(executor); } From ea16df04ace614c0b2217d2dcff8c860869b05ca Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski <ktoso@apple.com> Date: Mon, 28 Apr 2025 19:11:33 +0900 Subject: [PATCH 2/3] [Concurrency] adjust how we fail creating an IsIsolatingCurrentContextDecision --- include/swift/ABI/Executor.h | 25 +++----------------- stdlib/public/Concurrency/GlobalExecutor.cpp | 22 +++++++++++++++++ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h index 998c13798c9e8..10891328ebbe2 100644 --- a/include/swift/ABI/Executor.h +++ b/include/swift/ABI/Executor.h @@ -17,8 +17,6 @@ #ifndef SWIFT_ABI_EXECUTOR_H #define SWIFT_ABI_EXECUTOR_H -#include "../../../stdlib/public/Concurrency/Error.h" - #include "swift/ABI/Actor.h" #include "swift/ABI/HeapObject.h" #include "swift/Runtime/Casting.h" @@ -427,27 +425,10 @@ enum class IsIsolatingCurrentContextDecision : int8_t { Isolated, }; -inline IsIsolatingCurrentContextDecision -getIsIsolatingCurrentContextDecisionFromInt(int8_t value) { - switch (value) { - case -1: return IsIsolatingCurrentContextDecision::Unknown; - case 0: return IsIsolatingCurrentContextDecision::NotIsolated; - case 1: return IsIsolatingCurrentContextDecision::Isolated; - default: - swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); - return IsIsolatingCurrentContextDecision::Unknown; // silence warning about missing return - } -} +IsIsolatingCurrentContextDecision +getIsIsolatingCurrentContextDecisionFromInt(int8_t value); -inline StringRef getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDecision decision) { - switch (decision) { - case IsIsolatingCurrentContextDecision::Unknown: return "Unknown"; - case IsIsolatingCurrentContextDecision::NotIsolated: return "NotIsolated"; - case IsIsolatingCurrentContextDecision::Isolated: return "Isolated"; - } - swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); - return "<Unexpected Value>"; // silence warning about missing return -} +StringRef getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDecision decision); } diff --git a/stdlib/public/Concurrency/GlobalExecutor.cpp b/stdlib/public/Concurrency/GlobalExecutor.cpp index 1aac25115f32d..2863ad88a8c14 100644 --- a/stdlib/public/Concurrency/GlobalExecutor.cpp +++ b/stdlib/public/Concurrency/GlobalExecutor.cpp @@ -160,6 +160,28 @@ extern "C" void swift_job_dealloc(SwiftJob *job, void *ptr) { return _swift_task_dealloc_specific(task, ptr); } +IsIsolatingCurrentContextDecision +swift::getIsIsolatingCurrentContextDecisionFromInt(int8_t value) { + switch (value) { + case -1: return IsIsolatingCurrentContextDecision::Unknown; + case 0: return IsIsolatingCurrentContextDecision::NotIsolated; + case 1: return IsIsolatingCurrentContextDecision::Isolated; + default: + swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); + } +} + +StringRef +swift::getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDecision decision) { + switch (decision) { + case IsIsolatingCurrentContextDecision::Unknown: return "Unknown"; + case IsIsolatingCurrentContextDecision::NotIsolated: return "NotIsolated"; + case IsIsolatingCurrentContextDecision::Isolated: return "Isolated"; + } + swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); +} + + /*****************************************************************************/ /****************************** MAIN EXECUTOR *******************************/ /*****************************************************************************/ From 68727075740ff96a6fba3e9362751ebd7296a830 Mon Sep 17 00:00:00 2001 From: Konrad 'ktoso' Malawski <ktoso@apple.com> Date: Tue, 29 Apr 2025 22:28:31 +0900 Subject: [PATCH 3/3] [embedded][Concurrency] Further refine C-api boundary for isIsolating... --- include/swift/ABI/Executor.h | 6 +++--- include/swift/Runtime/Concurrency.h | 4 ++-- include/swift/Runtime/ConcurrencyHooks.def | 2 +- stdlib/public/Concurrency/Actor.cpp | 7 +++++-- stdlib/public/Concurrency/ConcurrencyHooks.cpp | 12 +++++++----- .../Concurrency/CooperativeGlobalExecutor.cpp | 2 +- stdlib/public/Concurrency/ExecutorImpl.cpp | 12 +++++------- stdlib/public/Concurrency/ExecutorImpl.h | 17 +++++++++-------- stdlib/public/Concurrency/GlobalExecutor.cpp | 16 ++++++++-------- test/embedded/Inputs/executor.c | 2 +- .../CompatibilityOverrideConcurrency.cpp | 4 ++-- 11 files changed, 44 insertions(+), 40 deletions(-) diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h index 10891328ebbe2..5523255c05076 100644 --- a/include/swift/ABI/Executor.h +++ b/include/swift/ABI/Executor.h @@ -418,11 +418,11 @@ enum class IsIsolatingCurrentContextDecision : int8_t { // The function call could not determine if the current context is isolated // by this executor or not. Default value for executors which do not implement // `isIsolatingCurrentContext`. - Unknown, + Unknown = -1, // The current context is definitely not isolated by this executor. - NotIsolated, + NotIsolated = 0, // The current context is definitely isolated by this executor. - Isolated, + Isolated = 1, }; IsIsolatingCurrentContextDecision diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index 6b376c52b770a..f509c2ab36fbf 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -777,12 +777,12 @@ bool swift_task_invokeSwiftCheckIsolated(SerialExecutorRef executor); /// Invoke an executor's `isIsolatingCurrentContext` implementation; SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContext(SerialExecutorRef executor); +int8_t swift_task_isIsolatingCurrentContext(SerialExecutorRef executor); /// Invoke a Swift executor's `isIsolatingCurrentContext` implementation; returns /// `true` if it invoked the Swift implementation, `false` otherwise. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -IsIsolatingCurrentContextDecision swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor); +int8_t swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor); /// A count in nanoseconds. using JobDelay = unsigned long long; diff --git a/include/swift/Runtime/ConcurrencyHooks.def b/include/swift/Runtime/ConcurrencyHooks.def index b4a9fa92691e1..f087fd23e13e2 100644 --- a/include/swift/Runtime/ConcurrencyHooks.def +++ b/include/swift/Runtime/ConcurrencyHooks.def @@ -47,7 +47,7 @@ SWIFT_CONCURRENCY_HOOK(void, swift_task_enqueueGlobalWithDeadline, SWIFT_CONCURRENCY_HOOK(void, swift_task_checkIsolated, SerialExecutorRef executor); -SWIFT_CONCURRENCY_HOOK(IsIsolatingCurrentContextDecision, swift_task_isIsolatingCurrentContext, +SWIFT_CONCURRENCY_HOOK(int8_t, swift_task_isIsolatingCurrentContext, SerialExecutorRef executor); SWIFT_CONCURRENCY_HOOK(bool, swift_task_isOnExecutor, diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 0ae95bc8e1dd4..c59f05da93d58 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -520,7 +520,9 @@ static bool swift_task_isCurrentExecutorWithFlagsImpl( expectedExecutor.getIdentity()); // The executor has the most recent 'isIsolatingCurrentContext' API // so available so we prefer calling that to 'checkIsolated'. - auto isIsolatingCurrentContextDecision = swift_task_isIsolatingCurrentContext(expectedExecutor); + auto isIsolatingCurrentContextDecision = + getIsIsolatingCurrentContextDecisionFromInt( + swift_task_isIsolatingCurrentContext(expectedExecutor)); SWIFT_TASK_DEBUG_LOG("executor checking mode option: UseIsIsolatingCurrentContext; invoke (%p).isIsolatingCurrentContext => %s", expectedExecutor.getIdentity(), getIsIsolatingCurrentContextDecisionNameStr(isIsolatingCurrentContextDecision)); @@ -646,7 +648,8 @@ static bool swift_task_isCurrentExecutorWithFlagsImpl( SWIFT_TASK_DEBUG_LOG("executor checking: call (%p).isIsolatingCurrentContext", expectedExecutor.getIdentity()); - const auto isIsolatingCurrentContextDecision = swift_task_isIsolatingCurrentContext(expectedExecutor); + const auto isIsolatingCurrentContextDecision = + getIsIsolatingCurrentContextDecisionFromInt(swift_task_isIsolatingCurrentContext(expectedExecutor)); SWIFT_TASK_DEBUG_LOG("executor checking: can call (%p).isIsolatingCurrentContext => %p", expectedExecutor.getIdentity(), getIsIsolatingCurrentContextDecisionNameStr(isIsolatingCurrentContextDecision)); diff --git a/stdlib/public/Concurrency/ConcurrencyHooks.cpp b/stdlib/public/Concurrency/ConcurrencyHooks.cpp index f690ead4876f4..642f887e133c0 100644 --- a/stdlib/public/Concurrency/ConcurrencyHooks.cpp +++ b/stdlib/public/Concurrency/ConcurrencyHooks.cpp @@ -111,18 +111,20 @@ swift::swift_task_checkIsolated(SerialExecutorRef executor) { swift_task_checkIsolatedOrig(executor); } -SWIFT_CC(swift) static IsIsolatingCurrentContextDecision +SWIFT_CC(swift) static int8_t swift_task_isIsolatingCurrentContextOrig(SerialExecutorRef executor) { return swift_task_isIsolatingCurrentContextImpl( *reinterpret_cast<SwiftExecutorRef *>(&executor)); } -IsIsolatingCurrentContextDecision +int8_t swift::swift_task_isIsolatingCurrentContext(SerialExecutorRef executor) { - if (SWIFT_UNLIKELY(swift_task_isIsolatingCurrentContext_hook)) - return swift_task_isIsolatingCurrentContext_hook(executor, swift_task_isIsolatingCurrentContextOrig); - else + if (SWIFT_UNLIKELY(swift_task_isIsolatingCurrentContext_hook)) { + return swift_task_isIsolatingCurrentContext_hook( + executor, swift_task_isIsolatingCurrentContextOrig); + } else { return swift_task_isIsolatingCurrentContextOrig(executor); + } } // Implemented in Swift because we need to obtain the user-defined flags on the executor ref. diff --git a/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp b/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp index 80bf1491ce6b0..647b90421d798 100644 --- a/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp +++ b/stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp @@ -155,7 +155,7 @@ void swift_task_checkIsolatedImpl(SwiftExecutorRef executor) { } SWIFT_CC(swift) -IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { +int8_t swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { return swift_executor_invokeSwiftIsIsolatingCurrentContext(executor); } diff --git a/stdlib/public/Concurrency/ExecutorImpl.cpp b/stdlib/public/Concurrency/ExecutorImpl.cpp index 27b49a775ffa6..74bc4c13987d4 100644 --- a/stdlib/public/Concurrency/ExecutorImpl.cpp +++ b/stdlib/public/Concurrency/ExecutorImpl.cpp @@ -62,22 +62,20 @@ int8_t _swift_task_isIsolatingCurrentContextSwift( const SerialExecutorWitnessTable *witnessTable ); -extern "C" SWIFT_CC(swift) IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl( +extern "C" SWIFT_CC(swift) int8_t +swift_task_isIsolatingCurrentContextImpl( SerialExecutorRef executor) { HeapObject *identity = executor.getIdentity(); // We might be being called with an actor rather than a "proper" // SerialExecutor; in that case, we won't have a SerialExecutor witness // table. - if (!executor.hasSerialExecutorWitnessTable()) { - return IsIsolatingCurrentContextDecision::Unknown; - } + if (!executor.hasSerialExecutorWitnessTable()) + return static_cast<uint8_t>(IsIsolatingCurrentContextDecision::Unknown); - auto decision = _swift_task_isIsolatingCurrentContextSwift( + return _swift_task_isIsolatingCurrentContextSwift( identity, swift_getObjectType(identity), executor.getSerialExecutorWitnessTable()); - - return getIsIsolatingCurrentContextDecisionFromInt(decision); } extern "C" SWIFT_CC(swift) bool swift_task_isMainExecutorImpl( diff --git a/stdlib/public/Concurrency/ExecutorImpl.h b/stdlib/public/Concurrency/ExecutorImpl.h index c66c5d1f10ed5..44fb28a904581 100644 --- a/stdlib/public/Concurrency/ExecutorImpl.h +++ b/stdlib/public/Concurrency/ExecutorImpl.h @@ -31,8 +31,6 @@ #define __ptrauth_objc_isa_pointer #endif -#include "swift/ABI/Executor.h" - #include <inttypes.h> #include <stdbool.h> #include <stdlib.h> @@ -228,12 +226,15 @@ swift_executor_invokeSwiftCheckIsolated(SwiftExecutorRef executor) { return _swift_task_invokeSwiftCheckIsolated_c(executor); } -using swift::IsIsolatingCurrentContextDecision; - /// Check if the current context is isolated by the specified executor. -static inline IsIsolatingCurrentContextDecision +/// +/// The numeric values correspond to `swift::IsIsolatingCurrentContextDecision`. +/// +/// Specifically ONLY `1` means "isolated", while smaller values mean not isolated or unknown. +/// See ``IsIsolatingCurrentContextDecision`` for details. +static inline int8_t swift_executor_invokeSwiftIsIsolatingCurrentContext(SwiftExecutorRef executor) { - extern IsIsolatingCurrentContextDecision _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor); + extern int8_t _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor); return _swift_task_invokeSwiftIsIsolatingCurrentContext_c(executor); } @@ -296,8 +297,8 @@ SWIFT_CC(swift) void swift_task_enqueueMainExecutorImpl(SwiftJob * _Nonnull job) SWIFT_CC(swift) void swift_task_checkIsolatedImpl(SwiftExecutorRef executor); /// Check if the specified executor isolates the current context. -SWIFT_CC(swift) -swift::IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor); +SWIFT_CC(swift) int8_t + swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor); /// Get a reference to the main executor. SWIFT_CC(swift) SwiftExecutorRef swift_task_getMainExecutorImpl(void); diff --git a/stdlib/public/Concurrency/GlobalExecutor.cpp b/stdlib/public/Concurrency/GlobalExecutor.cpp index 2863ad88a8c14..788ee0afeecc3 100644 --- a/stdlib/public/Concurrency/GlobalExecutor.cpp +++ b/stdlib/public/Concurrency/GlobalExecutor.cpp @@ -93,25 +93,26 @@ int8_t _task_serialExecutor_isIsolatingCurrentContext( const Metadata *selfType, const SerialExecutorWitnessTable *wtable); -using swift::IsIsolatingCurrentContextDecision; - -SWIFT_CC(swift) IsIsolatingCurrentContextDecision +SWIFT_CC(swift) int8_t swift::swift_task_invokeSwiftIsIsolatingCurrentContext(SerialExecutorRef executor) { if (!executor.hasSerialExecutorWitnessTable()) { - return IsIsolatingCurrentContextDecision::NotIsolated; + return static_cast<int8_t>(IsIsolatingCurrentContextDecision::NotIsolated); } auto decision = _task_serialExecutor_isIsolatingCurrentContext( executor.getIdentity(), swift_getObjectType(executor.getIdentity()), executor.getSerialExecutorWitnessTable()); - return getIsIsolatingCurrentContextDecisionFromInt(decision); + return decision; } -extern "C" swift::IsIsolatingCurrentContextDecision _swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor) +extern "C" int8_t +_swift_task_invokeSwiftIsIsolatingCurrentContext_c(SwiftExecutorRef executor) { - return swift_task_invokeSwiftIsIsolatingCurrentContext(*reinterpret_cast<SerialExecutorRef *>(&executor)); + return + static_cast<int8_t>(swift_task_invokeSwiftIsIsolatingCurrentContext( + *reinterpret_cast<SerialExecutorRef *>(&executor))); } extern "C" void _swift_job_run_c(SwiftJob *job, SwiftExecutorRef executor) @@ -181,7 +182,6 @@ swift::getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDeci swift_Concurrency_fatalError(0, "Unexpected IsIsolatingCurrentContextDecision value"); } - /*****************************************************************************/ /****************************** MAIN EXECUTOR *******************************/ /*****************************************************************************/ diff --git a/test/embedded/Inputs/executor.c b/test/embedded/Inputs/executor.c index a9babfb536937..cf5f9455fc565 100644 --- a/test/embedded/Inputs/executor.c +++ b/test/embedded/Inputs/executor.c @@ -308,7 +308,7 @@ void swift_task_checkIsolatedImpl(SwiftExecutorRef executor) { /// Check if the specified executor is the current executor. SWIFT_CC(swift) -IsIsolatingCurrentContextDecision swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { +int8_t swift_task_isIsolatingCurrentContextImpl(SwiftExecutorRef executor) { return swift_executor_invokeSwiftIsIsolatingCurrentContext(executor); } diff --git a/unittests/runtime/CompatibilityOverrideConcurrency.cpp b/unittests/runtime/CompatibilityOverrideConcurrency.cpp index 5a4358a635170..2f220bcf177ed 100644 --- a/unittests/runtime/CompatibilityOverrideConcurrency.cpp +++ b/unittests/runtime/CompatibilityOverrideConcurrency.cpp @@ -92,11 +92,11 @@ swift_task_checkIsolated_override(SerialExecutorRef executor, } SWIFT_CC(swift) -static bool +static int8_t swift_task_isIsolatingCurrentContext_override(SerialExecutorRef executor, swift_task_isIsolatingCurrentContext_original original) { Ran = true; - return true; + return 0; } SWIFT_CC(swift)