Skip to content

[Concurrency] Introduce TaskOptionRecord for spawn options #37885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -2036,10 +2036,11 @@ class JobFlags : public FlagSet<uint32_t> {

// Kind-specific flags.

Task_IsChildTask = 24,
Task_IsFuture = 25,
Task_IsGroupChildTask = 26,
Task_IsContinuingAsyncTask = 27,
Task_IsChildTask = 24,
Task_IsFuture = 25,
Task_IsGroupChildTask = 26,
Task_IsContinuingAsyncTask = 27,
Task_IsAsyncLetTask = 28,
};

explicit JobFlags(uint32_t bits) : FlagSet(bits) {}
Expand Down Expand Up @@ -2072,6 +2073,9 @@ class JobFlags : public FlagSet<uint32_t> {
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsContinuingAsyncTask,
task_isContinuingAsyncTask,
task_setIsContinuingAsyncTask)
FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsAsyncLetTask,
task_isAsyncLetTask,
task_setIsAsyncLetTask)
};

/// Kinds of task status record.
Expand Down Expand Up @@ -2101,6 +2105,14 @@ enum class TaskStatusRecordKind : uint8_t {
Private_RecordLock = 192
};

/// Kinds of option records that can be passed to creating asynchronous tasks.
enum class TaskOptionRecordKind : uint8_t {
/// Request a task to be kicked off, or resumed, on a specific executor.
Executor = 0,
/// Request a child task to be part of a specific task group.
TaskGroup = 1,
};

/// Flags for cancellation records.
class TaskStatusRecordFlags : public FlagSet<size_t> {
public:
Expand All @@ -2119,6 +2131,24 @@ class TaskStatusRecordFlags : public FlagSet<size_t> {
getKind, setKind)
};

/// Flags for task option records.
class TaskOptionRecordFlags : public FlagSet<size_t> {
public:
enum {
Kind = 0,
Kind_width = 8,
};

explicit TaskOptionRecordFlags(size_t bits) : FlagSet(bits) {}
constexpr TaskOptionRecordFlags() {}
TaskOptionRecordFlags(TaskOptionRecordKind kind) {
setKind(kind);
}

FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, TaskOptionRecordKind,
getKind, setKind)
};

/// Kinds of async context.
enum class AsyncContextKind {
/// An ordinary asynchronous function.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/ABI/Task.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Job;
struct OpaqueValue;
struct SwiftError;
class TaskStatusRecord;
class TaskOptionRecord;
class TaskGroup;

extern FullMetadata<DispatchClassMetadata> jobHeapMetadata;
Expand Down Expand Up @@ -537,6 +538,8 @@ inline void Job::runInFullyEstablishedContext() {
return runSimpleInFullyEstablishedContext(); // 'return' forces tail call
}

// ==== ------------------------------------------------------------------------

/// An asynchronous context within a task. Generally contexts are
/// allocated using the task-local stack alloc/dealloc operations, but
/// there's no guarantee of that, and the ABI is designed to permit
Expand Down
2 changes: 1 addition & 1 deletion include/swift/ABI/TaskLocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
//
// Swift ABI describing tasks.
// Swift ABI describing task locals.
//
//===----------------------------------------------------------------------===//

Expand Down
97 changes: 97 additions & 0 deletions include/swift/ABI/TaskOptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//===--- TaskOptions.h - ABI structures for task options --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift ABI describing task options.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_ABI_TASK_OPTIONS_H
#define SWIFT_ABI_TASK_OPTIONS_H

#include "swift/ABI/TaskLocal.h"
#include "swift/ABI/Executor.h"
#include "swift/ABI/HeapObject.h"
#include "swift/ABI/Metadata.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/Runtime/Config.h"
#include "swift/Basic/STLExtras.h"

namespace swift {

// ==== ------------------------------------------------------------------------
// ==== Task Options, for creating and waiting on tasks

/// The abstract base class for all options that may be used
/// to configure a newly spawned task.
class TaskOptionRecord {
public:
TaskOptionRecordFlags Flags;
TaskOptionRecord *Parent;

TaskOptionRecord(TaskOptionRecordKind kind,
TaskOptionRecord *parent = nullptr)
: Flags(kind) {
Parent = parent;
}

TaskOptionRecord(const TaskOptionRecord &) = delete;
TaskOptionRecord &operator=(const TaskOptionRecord &) = delete;

TaskOptionRecordKind getKind() const {
return Flags.getKind();
}

TaskOptionRecord *getParent() const {
return Parent;
}

};

/******************************************************************************/
/****************************** TASK OPTIONS **********************************/
/******************************************************************************/

class TaskGroupTaskOptionRecord : public TaskOptionRecord {
TaskGroup *Group;

public:
TaskGroupTaskOptionRecord(TaskGroup *group)
: TaskOptionRecord(TaskOptionRecordKind::TaskGroup),
Group(group) {}

TaskGroup *getGroup() const {
return Group;
}
};


/// Task option to specify on what executor the task should be executed.
///
/// Not passing this option implies that that a "best guess" or good default
/// executor should be used instead, most often this may mean the global
/// concurrent executor, or the enclosing actor's executor.
class ExecutorTaskOptionRecord : public TaskOptionRecord {
ExecutorRef *Executor;

public:
ExecutorTaskOptionRecord(ExecutorRef *executor)
: TaskOptionRecord(TaskOptionRecordKind::Executor),
Executor(executor) {}

ExecutorRef *getExecutor() const {
return Executor;
}
};

} // end namespace swift

#endif
12 changes: 7 additions & 5 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,9 @@ BUILTIN_MISC_OPERATION(StartAsyncLet, "startAsyncLet", "", Special)
BUILTIN_MISC_OPERATION_WITH_SILGEN(EndAsyncLet, "endAsyncLet", "", Special)

/// createAsyncTaskFuture(): (
/// Int, Builtin.NativeObject?, @escaping () async throws -> T
/// Int, // flags
/// Builtin.RawPointer?, // options (TaskOptionRecord*)
/// @escaping () async throws -> T // function
/// ) -> Builtin.NativeObject
///
/// Create a new asynchronous task future, given flags, an (optional) parent
Expand All @@ -815,10 +817,10 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskFuture,
"createAsyncTaskFuture", "", Special)

/// createAsyncTaskGroupFuture(): (
/// Int, // flags
/// Builtin.NativeObject?, // parent
/// Builtin.RawPointer?, // group
/// @escaping () async throws -> T
/// Int, // flags
/// Builtin.RawPointer?, // group
/// Builtin.RawPointer?, // options (TaskOptionRecord*)
/// @escaping () async throws -> T // function
/// ) -> Builtin.NativeObject
///
/// Create a new asynchronous task future, given flags, a parent task,
Expand Down
48 changes: 24 additions & 24 deletions include/swift/Runtime/Concurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

namespace swift {
class DefaultActor;
class TaskOptionRecord;

struct SwiftError;

Expand All @@ -35,54 +36,53 @@ struct AsyncTaskAndContext {
AsyncContext *InitialContext;
};

/// Create a task object with no future which will run the given
/// function.
/// Create a task object with no future which will run the given function.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
AsyncTaskAndContext swift_task_create_f(size_t flags,
ThinNullaryAsyncSignature::FunctionType *function,
size_t initialContextSize);
AsyncTaskAndContext swift_task_create_f(
size_t flags,
TaskOptionRecord *options,
ThinNullaryAsyncSignature::FunctionType *function, size_t initialContextSize);

/// Caution: not all future-initializing functions actually throw, so
/// this signature may be incorrect.
using FutureAsyncSignature =
AsyncSignature<void(void*), /*throws*/ true>;

/// Create a task object with a future which will run the given
/// closure.
/// Create a task object with a future which will run the given closure.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
AsyncTaskAndContext swift_task_create_future(
size_t flags,
TaskOptionRecord *options,
const Metadata *futureResultType,
void *closureEntryPoint,
HeapObject * /* +1 */ closureContext);
void *closureEntryPoint, HeapObject * /* +1 */ closureContext);

/// Create a task object with a future which will run the given
/// function.
/// Create a task object with a future which will run the given function.
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
AsyncTaskAndContext swift_task_create_future_f(
size_t flags,
TaskOptionRecord *options,
const Metadata *futureResultType,
FutureAsyncSignature::FunctionType *function,
size_t initialContextSize);
FutureAsyncSignature::FunctionType *function, size_t initialContextSize);

/// Create a task object with a future which will run the given
/// closure, and offer its result to the task group
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
AsyncTaskAndContext swift_task_create_group_future(
size_t flags, TaskGroup *group,
size_t flags,
TaskGroup *group,
TaskOptionRecord *options,
const Metadata *futureResultType,
void *closureEntryPoint,
HeapObject * /* +1 */ closureContext);
void *closureEntryPoint, HeapObject * /* +1 */ closureContext);

/// Create a task object with a future which will run the given
/// function, and offer its result to the task group
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
AsyncTaskAndContext swift_task_create_group_future_f(
size_t flags,
TaskGroup *group,
TaskOptionRecord *options,
const Metadata *futureResultType,
FutureAsyncSignature::FunctionType *function,
size_t initialContextSize);
FutureAsyncSignature::FunctionType *function, size_t initialContextSize);

/// Allocate memory in a task.
///
Expand Down Expand Up @@ -270,16 +270,16 @@ bool swift_taskGroup_isEmpty(TaskGroup *group);
///
/// \code
/// func swift_asyncLet_start<T>(
/// _ alet: Builtin.RawPointer,
/// asyncLet: Builtin.RawPointer,
/// options: Builtin.RawPointer?,
/// operation: __owned @Sendable () async throws -> T
/// )
/// \endcode
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
void swift_asyncLet_start(
AsyncLet *alet,
const Metadata *futureResultType,
void *closureEntryPoint,
void *closureContext);
void swift_asyncLet_start(AsyncLet *alet,
TaskOptionRecord *options,
const Metadata *futureResultType,
void *closureEntryPoint, void *closureContext);

/// This matches the ABI of a closure `<T>(Builtin.RawPointer) async -> T`
using AsyncLetWaitSignature =
Expand Down
Loading