Skip to content

Commit 7f737d2

Browse files
committed
Synchronize with cancellation when removing a task from a task group
We were detaching the child by just modifying the list, but the cancellation path was assuming that that would not be done without holding the task status lock. This patch just fixes the current runtime; the back-deployment side is complicated. Fixes rdar://88398824
1 parent e79aefa commit 7f737d2

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)