Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit cc2e32f

Browse files
authored
Merge pull request swiftlang#34902 from jckarter/continuation-resume-operations
Concurrency: Implement `resume(returning:)` and `resume(throwing:)` for Unsafe*Continuation.
2 parents 276e1a2 + 185f44e commit cc2e32f

File tree

3 files changed

+98
-5
lines changed

3 files changed

+98
-5
lines changed

include/swift/Runtime/Concurrency.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
namespace swift {
2323
class DefaultActor;
2424

25+
struct SwiftError;
26+
2527
struct AsyncTaskAndContext {
2628
AsyncTask *Task;
2729
AsyncContext *InitialContext;
@@ -270,6 +272,24 @@ void swift_defaultActor_destroy(DefaultActor *actor);
270272
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
271273
void swift_defaultActor_enqueue(Job *job, DefaultActor *actor);
272274

275+
/// Resume a task from its continuation, given a normal result value.
276+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
277+
void swift_continuation_resume(/* +1 */ OpaqueValue *result,
278+
void *continuation,
279+
const Metadata *resumeType);
280+
281+
/// Resume a task from its throwing continuation, given a normal result value.
282+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
283+
void swift_continuation_throwingResume(/* +1 */ OpaqueValue *result,
284+
void *continuation,
285+
const Metadata *resumeType);
286+
287+
/// Resume a task from its throwing continuation by throwing an error.
288+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
289+
void swift_continuation_throwingResumeWithError(/* +1 */ SwiftError *error,
290+
void *continuation,
291+
const Metadata *resumeType);
292+
273293
}
274294

275295
#endif

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,28 @@ public struct PartialAsyncTask {
2525
public struct UnsafeContinuation<T> {
2626
@usableFromInline internal var context: Builtin.RawUnsafeContinuation
2727

28-
public func resume(returning: __owned T) { }
29-
3028
@_alwaysEmitIntoClient
3129
internal init(_ context: Builtin.RawUnsafeContinuation) {
3230
self.context = context
3331
}
32+
33+
@_silgen_name("swift_continuation_resume")
34+
public func resume(returning value: __owned T)
3435
}
3536

3637
@frozen
3738
public struct UnsafeThrowingContinuation<T> {
3839
@usableFromInline internal var context: Builtin.RawUnsafeContinuation
3940

40-
public func resume(returning: __owned T) { }
41-
public func resume(throwing: __owned Error) { }
42-
4341
@_alwaysEmitIntoClient
4442
internal init(_ context: Builtin.RawUnsafeContinuation) {
4543
self.context = context
4644
}
45+
46+
@_silgen_name("swift_continuation_throwingResume")
47+
public func resume(returning: __owned T)
48+
@_silgen_name("swift_continuation_throwingResumeWithError")
49+
public func resume(throwing: __owned Error)
4750
}
4851

4952
#if _runtime(_ObjC)

stdlib/public/Concurrency/Task.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include "swift/Runtime/HeapObject.h"
2121
#include "TaskPrivate.h"
2222

23+
// TODO: We shouldn't need this
24+
#include <dispatch/dispatch.h>
25+
2326
using namespace swift;
2427
using FutureFragment = AsyncTask::FutureFragment;
2528

@@ -355,3 +358,70 @@ void swift::swift_task_run(AsyncTask *taskToRun) {
355358
size_t swift::swift_task_getJobFlags(AsyncTask *task) {
356359
return task->Flags.getOpaqueValue();
357360
}
361+
362+
namespace {
363+
364+
/// Structure that gets filled in when a task is suspended by `withUnsafeContinuation`.
365+
struct AsyncContinuationContext {
366+
// These fields are unnecessary for resuming a continuation.
367+
void *Unused1;
368+
void *Unused2;
369+
// Storage slot for the error result, if any.
370+
SwiftError *ErrorResult;
371+
// Pointer to where to store a normal result.
372+
OpaqueValue *NormalResult;
373+
374+
// Executor on which to resume execution.
375+
ExecutorRef ResumeExecutor;
376+
};
377+
378+
static void resumeTaskAfterContinuation(AsyncTask *task,
379+
AsyncContinuationContext *context) {
380+
#if __APPLE__
381+
// TODO: Enqueue the task on the specific executor in the continuation
382+
// context.
383+
//
384+
// For now, just enqueue the task resumption on the global concurrent queue
385+
// so that we're able to return back to the caller of resume.
386+
387+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
388+
^{
389+
task->run(context->ResumeExecutor);
390+
});
391+
#else
392+
swift_unreachable("not implemented");
393+
#endif
394+
}
395+
396+
397+
}
398+
399+
SWIFT_CC(swift)
400+
void swift::swift_continuation_resume(/* +1 */ OpaqueValue *result,
401+
void *continuation,
402+
const Metadata *resumeType) {
403+
auto task = reinterpret_cast<AsyncTask*>(continuation);
404+
auto context = reinterpret_cast<AsyncContinuationContext*>(task->ResumeContext);
405+
resumeType->vw_initializeWithTake(context->NormalResult, result);
406+
407+
resumeTaskAfterContinuation(task, context);
408+
}
409+
410+
SWIFT_CC(swift)
411+
void swift::swift_continuation_throwingResume(/* +1 */ OpaqueValue *result,
412+
void *continuation,
413+
const Metadata *resumeType) {
414+
return swift_continuation_resume(result, continuation, resumeType);
415+
}
416+
417+
418+
SWIFT_CC(swift)
419+
void swift::swift_continuation_throwingResumeWithError(/* +1 */ SwiftError *error,
420+
void *continuation,
421+
const Metadata *resumeType) {
422+
auto task = reinterpret_cast<AsyncTask*>(continuation);
423+
auto context = reinterpret_cast<AsyncContinuationContext*>(task->ResumeContext);
424+
context->ErrorResult = error;
425+
426+
resumeTaskAfterContinuation(task, context);
427+
}

0 commit comments

Comments
 (0)