Skip to content

Commit 185f44e

Browse files
committed
Concurrency: Implement resume(returning:) and resume(throwing:) for Unsafe*Continuation.
1 parent 8914ba6 commit 185f44e

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
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;
@@ -271,6 +273,24 @@ void swift_defaultActor_destroy(DefaultActor *actor);
271273
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
272274
void swift_defaultActor_enqueue(Job *job, DefaultActor *actor);
273275

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

276296
#endif

stdlib/public/Concurrency/PartialAsyncTask.swift

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

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

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

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

4851
#if _runtime(_ObjC)
@@ -92,4 +95,4 @@ public func withUnsafeThrowingContinuation<T>(
9295
return try await Builtin.withUnsafeThrowingContinuation {
9396
fn(UnsafeThrowingContinuation<T>($0))
9497
}
95-
}
98+
}

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
JobFlags swift::swift_task_getJobFlags(AsyncTask *task) {
356359
return task->Flags;
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)