Skip to content

Commit cbfe3ed

Browse files
authored
Merge pull request swiftlang#37060 from ktoso/wip-main-remove-task-current
2 parents 6ba245d + fd8ec39 commit cbfe3ed

File tree

4 files changed

+45
-152
lines changed

4 files changed

+45
-152
lines changed

stdlib/public/Concurrency/Task.swift

Lines changed: 20 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -33,37 +33,11 @@ import Swift
3333
/// unless implementing a scheduler.
3434
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
3535
public struct Task {
36-
internal let _task: Builtin.NativeObject
37-
38-
// May only be created by the standard library.
39-
internal init(_ task: Builtin.NativeObject) {
40-
self._task = task
41-
}
42-
}
43-
44-
// ==== Current Task -----------------------------------------------------------
45-
46-
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
47-
extension Task {
48-
49-
/// Returns 'current' `Task` instance, representing the task from within which
50-
/// this function was called.
51-
///
52-
/// All functions available on the Task
53-
@available(*, deprecated, message: "`Task.current` has been deprecated and will be removed, use static functions on Task instead.")
54-
public static var current: Task? {
55-
guard let _task = _getCurrentAsyncTask() else {
56-
return nil
57-
}
58-
59-
// FIXME: This retain seems pretty wrong, however if we don't we WILL crash
60-
// with "destroying a task that never completed" in the task's destroy.
61-
// How do we solve this properly?
62-
Builtin.retain(_task)
63-
64-
return Task(_task)
65-
}
66-
36+
// Task instances should not be used as they could be stored away,
37+
// and sine some tasks may be task-local allocated such stored away
38+
// references could point at already destroyed task memory (!).
39+
//
40+
// If necessary to obtain a task instance, please use withUnsafeCurrentTask.
6741
}
6842

6943
// ==== Task Priority ----------------------------------------------------------
@@ -79,19 +53,12 @@ extension Task {
7953
/// - SeeAlso: `Task.priority`
8054
public static var currentPriority: Priority {
8155
withUnsafeCurrentTask { task in
82-
task?.priority ?? Priority.default
83-
}
84-
}
56+
guard let task = task else {
57+
return Priority.default
58+
}
8559

86-
/// Returns the `current` task's priority.
87-
///
88-
/// If no current `Task` is available, returns `Priority.default`.
89-
///
90-
/// - SeeAlso: `Task.Priority`
91-
/// - SeeAlso: `Task.currentPriority`
92-
@available(*, deprecated, message: "Storing `Task` instances has been deprecated, and as such instance functions on Task are deprecated and will be removed soon. Use the static 'Task.currentPriority' instead.")
93-
public var priority: Priority {
94-
getJobFlags(_task).priority
60+
return getJobFlags(task._task).priority
61+
}
9562
}
9663

9764
/// Task priority may inform decisions an `Executor` makes about how and when
@@ -152,19 +119,22 @@ extension Task {
152119
/// i.e. the task will run regardless of the handle still being present or not.
153120
/// Dropping a handle however means losing the ability to await on the task's result
154121
/// and losing the ability to cancel it.
122+
///
123+
// Implementation notes:
124+
// A task handle can ONLY be obtained for a detached task, and as such shares
125+
// no lifetime concerns with regards to holding and storing the `_task` with
126+
// the `Task` type, which would have also be obtainable for any task, including
127+
// a potentially task-local allocated one. I.e. it is always safe to store away
128+
// a Task.Handle, yet the same is not true for the "current task" which may be
129+
// a async-let created task, at risk of getting destroyed while the reference
130+
// lingers around.
155131
public struct Handle<Success, Failure: Error>: Sendable {
156132
internal let _task: Builtin.NativeObject
157133

158134
internal init(_ task: Builtin.NativeObject) {
159135
self._task = task
160136
}
161137

162-
/// Returns the `Task` that this handle refers to.
163-
@available(*, deprecated, message: "Storing `Task` instances has been deprecated and will be removed soon.")
164-
public var task: Task {
165-
Task(_task)
166-
}
167-
168138
/// Wait for the task to complete, returning (or throwing) its result.
169139
///
170140
/// ### Priority
@@ -256,23 +226,6 @@ extension Task.Handle: Equatable {
256226
}
257227
}
258228

259-
// ==== Conformances -----------------------------------------------------------
260-
261-
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
262-
extension Task: Hashable {
263-
public func hash(into hasher: inout Hasher) {
264-
UnsafeRawPointer(Builtin.bridgeToRawPointer(_task)).hash(into: &hasher)
265-
}
266-
}
267-
268-
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
269-
extension Task: Equatable {
270-
public static func ==(lhs: Self, rhs: Self) -> Bool {
271-
UnsafeRawPointer(Builtin.bridgeToRawPointer(lhs._task)) ==
272-
UnsafeRawPointer(Builtin.bridgeToRawPointer(rhs._task))
273-
}
274-
}
275-
276229
// ==== Job Flags --------------------------------------------------------------
277230

278231
@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
@@ -606,7 +559,7 @@ extension Task {
606559
extension Task {
607560

608561
@available(*, deprecated, message: "`Task.unsafeCurrent` was replaced by `withUnsafeCurrentTask { task in ... }`, and will be removed soon.")
609-
public static var unsafeCurrent: UnsafeCurrentTask? {
562+
public static var unsafeCurrent: UnsafeCurrentTask? { // TODO: remove as soon as possible
610563
guard let _task = _getCurrentAsyncTask() else {
611564
return nil
612565
}
@@ -670,15 +623,6 @@ public struct UnsafeCurrentTask {
670623
self._task = task
671624
}
672625

673-
/// Returns `Task` representing the same asynchronous context as this 'UnsafeCurrentTask'.
674-
///
675-
/// Operations on `Task` (unlike `UnsafeCurrentTask`) are safe to be called
676-
/// from any other task (or thread).
677-
@available(*, deprecated, message: "Storing `Task` instances has been deprecated and will be removed soon.")
678-
public var task: Task {
679-
Task(_task)
680-
}
681-
682626
/// Returns `true` if the task is cancelled, and should stop executing.
683627
///
684628
/// - SeeAlso: `checkCancellation()`

stdlib/public/Concurrency/TaskCancellation.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,13 @@ extension Task {
6666
/// - SeeAlso: `checkCancellation()`
6767
@available(*, deprecated, message: "Storing `Task` instances has been deprecated and will be removed soon. Use the static 'Task.isCancelled' instead.")
6868
public var isCancelled: Bool {
69-
_taskIsCancelled(_task)
69+
withUnsafeCurrentTask { task in
70+
guard let task = task else {
71+
return false
72+
}
73+
74+
return _taskIsCancelled(task._task)
75+
}
7076
}
7177

7278
/// Check if the task is cancelled and throw an `CancellationError` if it was.

stdlib/public/Concurrency/TaskLocal.swift

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,22 @@ extension Task {
7777
public static func local<Key>(
7878
_ keyPath: KeyPath<TaskLocalValues, Key>
7979
) -> Key.Value where Key: TaskLocalKey {
80-
guard let task = Task.current else {
81-
return Key.defaultValue
80+
withUnsafeCurrentTask { current in
81+
guard let task = current else {
82+
return Key.defaultValue
83+
}
84+
85+
let value = _taskLocalValueGet(
86+
task._task, keyType: Key.self, inheritance: Key.inherit.rawValue)
87+
guard let rawValue = value else {
88+
return Key.defaultValue
89+
}
90+
91+
// Take the value; The type should be correct by construction
92+
let storagePtr =
93+
rawValue.bindMemory(to: Key.Value.self, capacity: 1)
94+
return UnsafeMutablePointer<Key.Value>(mutating: storagePtr).pointee
8295
}
83-
84-
let value = _taskLocalValueGet(
85-
task._task, keyType: Key.self, inheritance: Key.inherit.rawValue)
86-
guard let rawValue = value else {
87-
return Key.defaultValue
88-
}
89-
90-
// Take the value; The type should be correct by construction
91-
let storagePtr =
92-
rawValue.bindMemory(to: Key.Value.self, capacity: 1)
93-
return UnsafeMutablePointer<Key.Value>(mutating: storagePtr).pointee
9496
}
9597

9698
/// Bind the task local key to the given value for the scope of the `body` function.
@@ -106,7 +108,9 @@ extension Task {
106108
boundTo value: Key.Value,
107109
operation: () async throws -> BodyResult
108110
) async rethrows -> BodyResult where Key: TaskLocalKey {
109-
let _task = Task.current!._task // !-safe, guaranteed to have task available inside async function
111+
let _task = withUnsafeCurrentTask { current in
112+
current!._task // !-safe, guaranteed to have task available inside async function
113+
}
110114

111115
_taskLocalValuePush(_task, keyType: Key.self, value: value)
112116
defer { _taskLocalValuePop(_task) }

test/Concurrency/Runtime/async_task_equals_hashCode.swift

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)