Skip to content

Commit fb7b09e

Browse files
authored
Merge pull request #61534 from rjmccall/task-group-detach-race
Synchronize with cancellation when removing a task from a task group.
2 parents 89c032c + 7f737d2 commit fb7b09e

File tree

13 files changed

+335
-107
lines changed

13 files changed

+335
-107
lines changed

include/swift/ABI/TaskGroup.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ class alignas(Alignment_TaskGroup) TaskGroup {
4444
/// Checks the cancellation status of the group.
4545
bool isCancelled();
4646

47-
// Add a child task to the group. Always called with the status record lock of
48-
// the parent task held
47+
// Add a child task to the task group. Always called while holding the
48+
// status record lock of the task group's owning task.
4949
void addChildTask(AsyncTask *task);
5050

51+
// Remove a child task from the task group. Always called while holding
52+
// the status record lock of the task group's owning task.
53+
void removeChildTask(AsyncTask *task);
54+
5155
// Provide accessor for task group's status record
5256
TaskGroupTaskStatusRecord *getTaskRecord();
5357
};

include/swift/ABI/TaskStatus.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,24 @@ class ChildTaskStatusRecord : public TaskStatusRecord {
150150
///
151151
/// A record always is a specific `TaskGroupImpl`.
152152
///
153+
/// This record holds references to all the non-completed children of
154+
/// the task group. It may also hold references to completed children
155+
/// which have not yet been found by `next()`.
156+
///
153157
/// The child tasks are stored as an invasive single-linked list, starting
154158
/// from `FirstChild` and continuing through the `NextChild` pointers of all
155159
/// the linked children.
156160
///
157-
/// All children of the specific `Group` are stored "by" this record,
158-
/// so that they may be cancelled when this task becomes cancelled.
161+
/// This list structure should only ever be modified:
162+
/// - while holding the status record lock of the owning task, so that
163+
/// asynchronous operations such as cancellation can walk the structure
164+
/// without having to acquire a secondary lock, and
165+
/// - synchronously with the owning task, so that the owning task doesn't
166+
/// have to acquire the status record lock just to walk the structure
167+
/// itself.
159168
///
160169
/// When the group exits, it may simply remove this single record from the task
161-
/// running it. As it has guaranteed that the tasks have already completed.
170+
/// running it, as it has guaranteed that the tasks have already completed.
162171
///
163172
/// Group child tasks DO NOT have their own `ChildTaskStatusRecord` entries,
164173
/// and are only tracked by their respective `TaskGroupTaskStatusRecord`.

stdlib/public/BackDeployConcurrency/CompatibilityOverrideConcurrency.def

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@
3434
/// entries, or define one or more of the more specific OVERRIDE_* variants to
3535
/// get only those entries.
3636

37-
// NOTE: this file is used to build the definition of OverrideSection in
38-
// CompatibilityOverride.cpp, which is part of the ABI. Moving or removing
39-
// entries in this file will break the ABI. Additional entries can be added to
40-
// the end. ABI breaks or version-specific changes can be accommodated by
41-
// changing the name of the override section in that file.
37+
// NOTE: the entries in this file are used to build the struct layout for
38+
// OverrideSection in CompatibilityOverride.cpp, which is built into the
39+
// concurrency runtime. The back-deployment concurrency runtime targets
40+
// the same compatibility overrides as the OS-deployed runtime in Swift 5.6.
41+
// This file should not be edited.
4242

4343
#ifdef OVERRIDE
4444
# define OVERRIDE_ACTOR OVERRIDE

stdlib/public/CompatibilityOverride/CompatibilityOverride.h

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- CompatibilityOverride.h - Back-deploying compatibility fixes --*- C++ -*-===//
1+
//===--- CompatibilityOverride.h - Back-deployment patches ------*- C++ -*-===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -10,7 +10,71 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
//
13-
// Support back-deploying compatibility fixes for newer apps running on older runtimes.
13+
// The compatibility override system supports the back-deployment of
14+
// bug fixes and ABI additions to existing Swift systems. This is
15+
// primarily of interest on Apple platforms, since other platforms don't
16+
// ship with a stable Swift runtime that cannot simply be replaced.
17+
//
18+
// The compatibility override system works as follows:
19+
//
20+
// 1. Certain runtime functions are "hooked" so that they can be replaced
21+
// by the program at launch time. The function at the public symbol
22+
// (we will use `swift_task_cancel` as a consistent example) is a
23+
// thunk that either calls the standard implementation or its dynamic
24+
// replacement. If a dynamic replacement is called, it is passed
25+
// the standard implementation as an extra argument.
26+
//
27+
// 2. The public thunks are defined in different .cpp files throughout
28+
// the runtime by the COMPATIBILITY_OVERRIDE macro below, triggered
29+
// by an #include at the bottom of the file. The list of definitions
30+
// to expand in a particular file is defined by the appropriate
31+
// CompatibilityOverride*.def file for the current runtime component
32+
// (i.e. either the main runtime or the concurrency runtime).
33+
// The standard implementation must be defined in that file as a
34+
// function with the suffix `Impl`, e.g. `swift_task_cancelImpl`.
35+
// Usually the standard implementation should be static, and
36+
// everywhere else in the runtime should call the public symbol.
37+
//
38+
// 3. The public thunks determine their replacement by calling an
39+
// override accessor for the symbol the first time they are called.
40+
// These accessors are named e.g. `swift::getOverride_swift_task_cancel`
41+
// and are defined by CompatibilityOverride.cpp, which is built
42+
// separately for each runtime component using different build
43+
// settings.
44+
//
45+
// 4. The override accessors check for a Mach-O section with a specific
46+
// name, and if it exists, they interpret the section as a struct
47+
// with one field per replaceable function. The order of fields is
48+
// determined by the appropriate CompatibilityOverride*.def file.
49+
// The section name, the struct layout, and the function signatures of
50+
// the replacement functions are the only parts of this which are ABI;
51+
// everything else is an internal detail of the runtime which can be
52+
// changed if useful.
53+
//
54+
// 5. The name of the Mach-O section is specific to both the current
55+
// runtime component and the current version of the Swift runtime.
56+
// Therefore, a compatibility override library always targets a
57+
// specific runtime version and implicitly does nothing on other
58+
// versions.
59+
//
60+
// 6. Compatibility override libraries define a Mach-O section with the
61+
// appropriate name and layout for their target component and version
62+
// and initialize the appropriate fields within it to the replacement
63+
// functions. This occurs in the Overrides.cpp file in the library.
64+
// Compatibility override libraries are linked against later override
65+
// libraries for the same component, so if a patch needs to be applied
66+
// to multiple versions, the last version can define public symbols
67+
// that the other versions can use (assuming that any internal runtime
68+
// structures are roughly compatible).
69+
//
70+
// 7. Compatibility override libraries are rebuilt with every Swift
71+
// release in case that release requires new patches to the target
72+
// runtime. They are therefore live code, unlike e.g. the
73+
// back-deployment concurrency runtime.
74+
//
75+
// 8. The back-deployment concurrency runtime looks for the same section
76+
// name as the OS-installed 5.6 runtime and therefore will be patched
77+
// by the 5.6 compatibility override library.
1478
//
1579
//===----------------------------------------------------------------------===//
1680

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
//===----------------------------------------------------------------------===//
1212
//
1313
// This file defines x-macros used for metaprogramming with the set of
14-
// compatibility override functions.
14+
// compatibility override functions. See CompatibilityOverride.h for
15+
// a detailed explanation of how this system works.
1516
//
1617
//===----------------------------------------------------------------------===//
1718

@@ -32,13 +33,42 @@
3233
///
3334
/// The entries are organized by group. A user may define OVERRIDE to get all
3435
/// entries, or define one or more of the more specific OVERRIDE_* variants to
35-
/// get only those entries.
36-
37-
// NOTE: this file is used to build the definition of OverrideSection in
38-
// CompatibilityOverride.cpp, which is part of the ABI. Moving or removing
39-
// entries in this file will break the ABI. Additional entries can be added to
40-
// the end. ABI breaks or version-specific changes can be accommodated by
41-
// changing the name of the override section in that file.
36+
/// get only those entries. The more specific OVERRIDE_* variants group
37+
/// entries into the functions that are emitted in the specified file;
38+
/// for example, OVERRIDE_ACTOR identifies the functions that are defined
39+
/// in Actor.cpp.
40+
41+
// NOTE: the entries in this file are used to build the struct layout for
42+
// the OverrideSection in the CompatibilityOverride.cpp that is built into
43+
// the concurrency runtime. A matching file must be used to build the
44+
// ConcurrencyOverrideSection in Overrides.cpp for future compatibility
45+
// override libraries that target this release.
46+
//
47+
// Because compatibility override libraries target a specific release of
48+
// Swift, there is no inherent reason the entries in this file cannot be
49+
// arbitrarily rearranged between release cycles, as long as a matching
50+
// file is used to build any future compatibility override library
51+
// targeting this release. However, the targeting of compatibility
52+
// override libraries is precise only to a specific major+minor release
53+
// number (e.g. 5.6). Therefore, care must be taken to avoid ABI breaks
54+
// in this file between patch releases, or else it will become impossible
55+
// to create a compatibility override library for this release:
56+
//
57+
// - Moving or removing entries in this file will break the ABI.
58+
//
59+
// - Changing an entry to use a different implementation file is allowed,
60+
// but do not move the entry to be grouped with the other entries for
61+
// the implementation file, as this will break the ABI.
62+
//
63+
// - New entries can be added to the end without breaking the ABI. This
64+
// is possible even if there have already been patch releases for this
65+
// major+minor release, since older patch releases of the runtime will
66+
// simply not read the new fields. It is not possible if a compatibility
67+
// override library has already been released for this major+minor
68+
// release, but that is unlikely for releases under active development.
69+
//
70+
// When creating a new compatibility override library, always clone the
71+
// last .def files from the appropriate release branch and edit this comment.
4272

4373
#ifdef OVERRIDE
4474
# define OVERRIDE_ACTOR OVERRIDE
@@ -319,9 +349,9 @@ OVERRIDE_TASK_STATUS(task_hasTaskGroupStatusRecord, bool,
319349
OVERRIDE_TASK_STATUS(task_cancel, void, SWIFT_EXPORT_FROM(swift_Concurrency),
320350
SWIFT_CC(swift), swift::, (AsyncTask *task), (task))
321351

322-
OVERRIDE_TASK_STATUS(task_cancel_group_child_tasks, void,
323-
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
324-
swift::, (TaskGroup *group), (group))
352+
OVERRIDE_TASK_GROUP(task_cancel_group_child_tasks, void,
353+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
354+
swift::, (TaskGroup *group), (group))
325355

326356
OVERRIDE_TASK_STATUS(task_escalate, JobPriority,
327357
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),

stdlib/public/CompatibilityOverride/CompatibilityOverrideRuntime.def

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
//===----------------------------------------------------------------------===//
1212
//
1313
// This file defines x-macros used for metaprogramming with the set of
14-
// compatibility override functions.
14+
// compatibility override functions. See CompatibilityOverride.h for
15+
// a detailed explanation of how this system works.
1516
//
1617
//===----------------------------------------------------------------------===//
1718

@@ -31,15 +32,43 @@
3132
/// parentheses
3233
///
3334
/// The entries are organized by group. A user may define OVERRIDE to get all
34-
/// entries, or define one or more of OVERRIDE_METADATALOOKUP, OVERRIDE_CASTING,
35-
/// OVERRIDE_OBJC, OVERRIDE_FOREIGN, OVERRIDE_PROTOCOLCONFORMANCE,
36-
/// and OVERRIDE_KEYPATH to get only those entries.
37-
38-
// NOTE: this file is used to build the definition of OverrideSection in
39-
// CompatibilityOverride.cpp, which is part of the ABI. Moving or removing
40-
// entries in this file will break the ABI. Additional entries can be added to
41-
// the end. ABI breaks or version-specific changes can be accommodated by
42-
// changing the name of the override section in that file.
35+
/// entries, or define one or more of the more specific OVERRIDE_* variants to
36+
/// get only those entries. The more specific OVERRIDE_* variants group
37+
/// entries into the functions that are emitted in the specified file;
38+
/// for example, OVERRIDE_CASTING identifies the functions that are defined
39+
/// in Casting.cpp.
40+
41+
// NOTE: the entries in this file are used to build the struct layout for
42+
// the OverrideSection in the CompatibilityOverride.cpp that is built into
43+
// the primary runtime. A matching file must be used to build the
44+
// RuntimeOverrideSection in Overrides.cpp for future compatibility
45+
// override libraries that target this release.
46+
//
47+
// Because compatibility override libraries target a specific release of
48+
// Swift, there is no inherent reason the entries in this file cannot be
49+
// arbitrarily rearranged between release cycles, as long as a matching
50+
// file is used to build any future compatibility override library
51+
// targeting this release. However, the targeting of compatibility
52+
// override libraries is precise only to a specific major+minor release
53+
// number (e.g. 5.6). Therefore, care must be taken to avoid ABI breaks
54+
// in this file between patch releases, or else it will become impossible
55+
// to create a compatibility override library for this release:
56+
//
57+
// - Moving or removing entries in this file will break the ABI.
58+
//
59+
// - Changing an entry to use a different implementation file is allowed,
60+
// but do not move the entry to be grouped with the other entries for
61+
// the implementation file, as this will break the ABI.
62+
//
63+
// - New entries can be added to the end without breaking the ABI. This
64+
// is possible even if there have already been patch releases for this
65+
// major+minor release, since older patch releases of the runtime will
66+
// simply not read the new fields. It is not possible if a compatibility
67+
// override library has already been released for this major+minor
68+
// release, but that is unlikely for releases under active development.
69+
//
70+
// When creating a new compatibility override library, always clone the
71+
// last .def files from the appropriate release branch and edit this comment.
4372

4473
#ifdef OVERRIDE
4574
# define OVERRIDE_METADATALOOKUP OVERRIDE

0 commit comments

Comments
 (0)