From 366dda0369f32b61b766b403a9c0f1bd3bf85ea1 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 8 Apr 2024 09:28:43 +0900 Subject: [PATCH] [Concurrency] Add missing runSynchronously to ExecutorJob It was present on UnownedJob but we should have parity with this on the non copyable type as well. Resolves rdar://126044533 --- .../public/Concurrency/PartialAsyncTask.swift | 87 +++++++++++++++++++ ...nc_task_executor_default_actor_funcs.swift | 6 ++ 2 files changed, 93 insertions(+) diff --git a/stdlib/public/Concurrency/PartialAsyncTask.swift b/stdlib/public/Concurrency/PartialAsyncTask.swift index cc77eb5241d40..f18e650210bf3 100644 --- a/stdlib/public/Concurrency/PartialAsyncTask.swift +++ b/stdlib/public/Concurrency/PartialAsyncTask.swift @@ -109,6 +109,23 @@ public struct UnownedJob: Sendable { _swiftJobRun(self, executor) } + /// Run this job isolated to the passed task executor. + /// + /// This operation runs the job on the calling thread and *blocks* until the job completes. + /// The intended use of this method is for an executor to determine when and where it + /// wants to run the job and then call this method on it. + /// + /// The passed in executor reference is used to establish the executor context for the job, + /// and should be the same executor as the one semantically calling the `runSynchronously` method. + /// + /// This operation consumes the job, preventing it accidental use after it has been run. + /// + /// Converting a `ExecutorJob` to an ``UnownedJob`` and invoking ``UnownedJob/runSynchronously(_:)` on it multiple times is undefined behavior, + /// as a job can only ever be run once, and must not be accessed after it has been run. + /// + /// - Parameter executor: the task executor this job will be run on. + /// + /// - SeeAlso: ``runSynchronously(isolatedTo:taskExecutor:)`` @_unavailableInEmbedded @available(SwiftStdlib 6.0, *) @_alwaysEmitIntoClient @@ -117,6 +134,24 @@ public struct UnownedJob: Sendable { _swiftJobRunOnTaskExecutor(self, executor) } + /// Run this job isolated to the passed in serial executor, while executing it on the specified task executor. + /// + /// This operation runs the job on the calling thread and *blocks* until the job completes. + /// The intended use of this method is for an executor to determine when and where it + /// wants to run the job and then call this method on it. + /// + /// The passed in executor reference is used to establish the executor context for the job, + /// and should be the same executor as the one semantically calling the `runSynchronously` method. + /// + /// This operation consumes the job, preventing it accidental use after it has been run. + /// + /// Converting a `ExecutorJob` to an ``UnownedJob`` and invoking ``UnownedJob/runSynchronously(_:)` on it multiple times is undefined behavior, + /// as a job can only ever be run once, and must not be accessed after it has been run. + /// + /// - Parameter serialExecutor: the executor this job will be semantically running on. + /// - Parameter taskExecutor: the task executor this job will be run on. + /// + /// - SeeAlso: ``runSynchronously(on:)`` @_unavailableInEmbedded @available(SwiftStdlib 6.0, *) @_alwaysEmitIntoClient @@ -286,6 +321,58 @@ extension ExecutorJob { __consuming public func runSynchronously(on executor: UnownedSerialExecutor) { _swiftJobRun(UnownedJob(self), executor) } + + /// Run this job on the passed in task executor. + /// + /// This operation runs the job on the calling thread and *blocks* until the job completes. + /// The intended use of this method is for an executor to determine when and where it + /// wants to run the job and then call this method on it. + /// + /// The passed in executor reference is used to establish the executor context for the job, + /// and should be the same executor as the one semantically calling the `runSynchronously` method. + /// + /// This operation consumes the job, preventing it accidental use after it has been run. + /// + /// Converting a `ExecutorJob` to an ``UnownedJob`` and invoking ``UnownedJob/runSynchronously(_:)` on it multiple times is undefined behavior, + /// as a job can only ever be run once, and must not be accessed after it has been run. + /// + /// - Parameter executor: the executor this job will be run on. + /// + /// - SeeAlso: ``runSynchronously(isolatedTo:taskExecutor:)`` + @_unavailableInEmbedded + @available(SwiftStdlib 6.0, *) + @_alwaysEmitIntoClient + @inlinable + __consuming public func runSynchronously(on executor: UnownedTaskExecutor) { + _swiftJobRunOnTaskExecutor(UnownedJob(self), executor) + } + + /// Run this job isolated to the passed in serial executor, while executing it on the specified task executor. + /// + /// This operation runs the job on the calling thread and *blocks* until the job completes. + /// The intended use of this method is for an executor to determine when and where it + /// wants to run the job and then call this method on it. + /// + /// The passed in executor reference is used to establish the executor context for the job, + /// and should be the same executor as the one semantically calling the `runSynchronously` method. + /// + /// This operation consumes the job, preventing it accidental use after it has been run. + /// + /// Converting a `ExecutorJob` to an ``UnownedJob`` and invoking ``UnownedJob/runSynchronously(_:)` on it multiple times is undefined behavior, + /// as a job can only ever be run once, and must not be accessed after it has been run. + /// + /// - Parameter serialExecutor: the executor this job will be semantically running on. + /// - Parameter taskExecutor: the task executor this job will be run on. + /// + /// - SeeAlso: ``runSynchronously(on:)`` + @_unavailableInEmbedded + @available(SwiftStdlib 6.0, *) + @_alwaysEmitIntoClient + @inlinable + __consuming public func runSynchronously(isolatedTo serialExecutor: UnownedSerialExecutor, + taskExecutor: UnownedTaskExecutor) { + _swiftJobRunOnTaskExecutor(UnownedJob(self), serialExecutor, taskExecutor) + } } #endif // !SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY diff --git a/test/Concurrency/Runtime/async_task_executor_default_actor_funcs.swift b/test/Concurrency/Runtime/async_task_executor_default_actor_funcs.swift index 0869d796bc273..7574c3bd17473 100644 --- a/test/Concurrency/Runtime/async_task_executor_default_actor_funcs.swift +++ b/test/Concurrency/Runtime/async_task_executor_default_actor_funcs.swift @@ -25,6 +25,12 @@ final class NaiveQueueExecutor: TaskExecutor { } } + public func apiTest(serialExecutor: any SerialExecutor, _ job: consuming ExecutorJob) { + job.runSynchronously( + isolatedTo: serialExecutor.asUnownedSerialExecutor(), + taskExecutor: self.asUnownedTaskExecutor()) + } + } actor ThreaddyTheDefaultActor {