Skip to content

Commit 853a865

Browse files
committed
Add a basic default-actor implementation with support for
eagerly adopting and abandoning threads.
1 parent 2547533 commit 853a865

File tree

8 files changed

+1848
-1
lines changed

8 files changed

+1848
-1
lines changed

include/swift/ABI/Actor.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- Actor.h - ABI structures for actors --------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift ABI describing actors.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_ACTOR_H
18+
#define SWIFT_ABI_ACTOR_H
19+
20+
#include "swift/ABI/HeapObject.h"
21+
#include "swift/ABI/MetadataValues.h"
22+
23+
namespace swift {
24+
25+
/// The default actor implementation.
26+
class alignas(MaximumAlignment) DefaultActor : public HeapObject {
27+
public:
28+
// These constructors do not initialize the actor instance, and the
29+
// destructor does not destroy the actor instance; you must call
30+
// swift_defaultActor_{initialize,destroy} yourself.
31+
constexpr DefaultActor(const HeapMetadata *metadata)
32+
: HeapObject(metadata), PrivateData{} {}
33+
34+
constexpr DefaultActor(const HeapMetadata *metadata,
35+
InlineRefCounts::Immortal_t immortal)
36+
: HeapObject(metadata, immortal), PrivateData{} {}
37+
38+
void *PrivateData[NumWords_DefaultActor];
39+
};
40+
41+
} // end namespace swift
42+
43+
#endif

include/swift/ABI/MetadataValues.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,11 @@ enum class JobKind : size_t {
18891889
Task = 0,
18901890

18911891
/// Job kinds >= 192 are private to the implementation.
1892-
First_Reserved = 192
1892+
First_Reserved = 192,
1893+
1894+
DefaultActorInline = First_Reserved,
1895+
DefaultActorSeparate,
1896+
DefaultActorOverride
18931897
};
18941898

18951899
/// The priority of a job. Higher priorities are larger values.

include/swift/ABI/Task.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,16 @@ class alignas(MaximumAlignment) AsyncContext {
382382

383383
AsyncContext(const AsyncContext &) = delete;
384384
AsyncContext &operator=(const AsyncContext &) = delete;
385+
386+
/// Perform a return from this context.
387+
///
388+
/// Generally this should be tail-called.
389+
SWIFT_CC(swiftasync)
390+
void resumeParent(AsyncTask *task, ExecutorRef executor) {
391+
// TODO: destroy context before returning?
392+
// FIXME: force tail call
393+
return ResumeParent(task, executor, Parent);
394+
}
385395
};
386396

387397
/// An async context that supports yielding.

include/swift/Runtime/Concurrency.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/ABI/TaskStatus.h"
2121

2222
namespace swift {
23+
class DefaultActor;
2324

2425
struct AsyncTaskAndContext {
2526
AsyncTask *Task;
@@ -206,6 +207,70 @@ swift_task_getNearestDeadline(AsyncTask *task);
206207
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
207208
void swift_task_run(AsyncTask *taskToRun);
208209

210+
/// Switch the current task to a new executor if we aren't already
211+
/// running on a compatible executor.
212+
///
213+
/// The resumption function pointer and continuation should be set
214+
/// appropriately in the task.
215+
///
216+
/// Generally the compiler should inline a fast-path compatible-executor
217+
/// check to avoid doing the suspension work. This function should
218+
/// generally be tail-called, as it may continue executing the task
219+
/// synchronously if possible.
220+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swiftasync)
221+
void swift_task_switch(AsyncTask *task,
222+
ExecutorRef currentExecutor,
223+
ExecutorRef newExecutor);
224+
225+
/// Enqueue the given job to run asynchronously on the given executor.
226+
///
227+
/// The resumption function pointer and continuation should be set
228+
/// appropriately in the task.
229+
///
230+
/// Generally you should call swift_task_switch to switch execution
231+
/// synchronously when possible.
232+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
233+
void swift_task_enqueue(Job *job, ExecutorRef executor);
234+
235+
/// Enqueue the given job to run asynchronously on the global
236+
/// execution pool.
237+
///
238+
/// The resumption function pointer and continuation should be set
239+
/// appropriately in the task.
240+
///
241+
/// Generally you should call swift_task_switch to switch execution
242+
/// synchronously when possible.
243+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
244+
void swift_task_enqueueGlobal(Job *job);
245+
246+
/// A hook to take over global enqueuing.
247+
/// TODO: figure out a better abstraction plan than this.
248+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
249+
void (*swift_task_enqueueGlobal_hook)(Job *job);
250+
251+
/// Initialize the runtime storage for a default actor.
252+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
253+
void swift_defaultActor_initialize(DefaultActor *actor);
254+
255+
/// Destroy the runtime storage for a default actor.
256+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
257+
void swift_defaultActor_destroy(DefaultActor *actor);
258+
259+
/// Enqueue a job on the default actor implementation.
260+
///
261+
/// The job must be ready to run. Notably, if it's a task, that
262+
/// means that the resumption function and context should have been
263+
/// set appropriately.
264+
///
265+
/// Jobs are assumed to be "self-consuming": once it starts running,
266+
/// the job memory is invalidated and the executor should not access it
267+
/// again.
268+
///
269+
/// Jobs are generally expected to keep the actor alive during their
270+
/// execution.
271+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
272+
void swift_defaultActor_enqueue(Job *job, DefaultActor *actor);
273+
209274
}
210275

211276
#endif

0 commit comments

Comments
 (0)