1
+ //===----------------------------------------------------------------------===//
2
+ //
3
+ // This source file is part of the Swift.org open source project
4
+ //
5
+ // Copyright (c) 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
+ import Swift
14
+ @_implementationOnly import _SwiftConcurrencyShims
15
+
16
+ // ==== DiscardingTaskGroup ---------------------------------------------------
17
+
18
+ @available ( SwiftStdlib 5 . 8 , * )
19
+ @inlinable
20
+ @_unsafeInheritExecutor
21
+ public func withDiscardingTaskGroup< GroupResult> (
22
+ returning returnType: GroupResult . Type = GroupResult . self,
23
+ body: ( inout DiscardingTaskGroup ) async -> GroupResult
24
+ ) async -> GroupResult {
25
+ #if compiler(>=5.5) && $BuiltinTaskGroupWithArgument
26
+ let flags = taskGroupCreateFlags (
27
+ discardResults: true
28
+ )
29
+
30
+ let _group = Builtin . createTaskGroupWithFlags ( flags, GroupResult . self)
31
+ var group = DiscardingTaskGroup ( group: _group)
32
+ defer { Builtin . destroyTaskGroup ( _group) }
33
+
34
+ let result = await body ( & group)
35
+
36
+ try ! await group. awaitAllRemainingTasks ( ) // try!-safe, cannot throw since this is a non throwing group
37
+ return result
38
+ #else
39
+ fatalError ( " Swift compiler is incompatible with this SDK version " )
40
+ #endif
41
+ }
42
+
43
+ ///
44
+ /// - SeeAlso: ``TaskGroup``
45
+ /// - SeeAlso: ``ThrowingTaskGroup``
46
+ /// - SeeAlso: ``ThrowingDiscardingTaskGroup``
47
+ @available ( SwiftStdlib 5 . 8 , * )
48
+ @frozen
49
+ public struct DiscardingTaskGroup {
50
+
51
+ @usableFromInline
52
+ internal let _group : Builtin . RawPointer
53
+
54
+ // No public initializers
55
+ @inlinable
56
+ init ( group: Builtin . RawPointer ) {
57
+ self . _group = group
58
+ }
59
+
60
+ /// Await all the remaining tasks on this group.
61
+ ///
62
+ /// - Throws: The first error that was encountered by this group.
63
+ @usableFromInline
64
+ internal mutating func awaitAllRemainingTasks( ) async throws {
65
+ let _: Void ? = try await _taskGroupWaitAll ( group: _group)
66
+ }
67
+
68
+ @_alwaysEmitIntoClient
69
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
70
+ @available ( * , unavailable, message: " Unavailable in task-to-thread concurrency model " , renamed: " addTask(operation:) " )
71
+ #endif
72
+ public mutating func addTask(
73
+ priority: TaskPriority ? = nil ,
74
+ operation: __owned @Sendable @escaping ( ) async -> Void
75
+ ) {
76
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
77
+ let flags = taskCreateFlags (
78
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
79
+ inheritContext: false , enqueueJob: false ,
80
+ addPendingGroupTaskUnconditionally: true
81
+ )
82
+ #else
83
+ let flags = taskCreateFlags (
84
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
85
+ inheritContext: false , enqueueJob: true ,
86
+ addPendingGroupTaskUnconditionally: true
87
+ )
88
+ #endif
89
+
90
+ // Create the task in this group.
91
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
92
+ }
93
+
94
+ @_alwaysEmitIntoClient
95
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
96
+ @available ( * , unavailable, message: " Unavailable in task-to-thread concurrency model " , renamed: " addTask(operation:) " )
97
+ #endif
98
+ public mutating func addTaskUnlessCancelled(
99
+ priority: TaskPriority ? = nil ,
100
+ operation: __owned @Sendable @escaping ( ) async -> Void
101
+ ) -> Bool {
102
+ let canAdd = _taskGroupAddPendingTask ( group: _group, unconditionally: false )
103
+
104
+ guard canAdd else {
105
+ // the group is cancelled and is not accepting any new work
106
+ return false
107
+ }
108
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
109
+ let flags = taskCreateFlags (
110
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
111
+ inheritContext: false , enqueueJob: false ,
112
+ addPendingGroupTaskUnconditionally: false
113
+ )
114
+ #else
115
+ let flags = taskCreateFlags (
116
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
117
+ inheritContext: false , enqueueJob: true ,
118
+ addPendingGroupTaskUnconditionally: false
119
+ )
120
+ #endif
121
+
122
+ // Create the task in this group.
123
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
124
+
125
+ return true
126
+ }
127
+
128
+ @_alwaysEmitIntoClient
129
+ public mutating func addTask(
130
+ operation: __owned @Sendable @escaping ( ) async -> Void
131
+ ) {
132
+ let flags = taskCreateFlags (
133
+ priority: nil , isChildTask: true , copyTaskLocals: false ,
134
+ inheritContext: false , enqueueJob: true ,
135
+ addPendingGroupTaskUnconditionally: true
136
+ )
137
+
138
+ // Create the task in this group.
139
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
140
+ }
141
+
142
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
143
+ @available ( * , unavailable, message: " Unavailable in task-to-thread concurrency model " , renamed: " addTaskUnlessCancelled(operation:) " )
144
+ #endif
145
+ @_alwaysEmitIntoClient
146
+ public mutating func addTaskUnlessCancelled(
147
+ operation: __owned @Sendable @escaping ( ) async -> Void
148
+ ) -> Bool {
149
+ #if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
150
+ let canAdd = _taskGroupAddPendingTask ( group: _group, unconditionally: false )
151
+
152
+ guard canAdd else {
153
+ // the group is cancelled and is not accepting any new work
154
+ return false
155
+ }
156
+
157
+ let flags = taskCreateFlags (
158
+ priority: nil , isChildTask: true , copyTaskLocals: false ,
159
+ inheritContext: false , enqueueJob: true ,
160
+ addPendingGroupTaskUnconditionally: false
161
+ )
162
+
163
+ // Create the task in this group.
164
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
165
+
166
+ return true
167
+ #else
168
+ fatalError ( " Unsupported Swift compiler " )
169
+ #endif
170
+ }
171
+
172
+ public var isEmpty : Bool {
173
+ _taskGroupIsEmpty ( _group)
174
+ }
175
+
176
+ public func cancelAll( ) {
177
+ _taskGroupCancelAll ( group: _group)
178
+ }
179
+
180
+ public var isCancelled : Bool {
181
+ return _taskGroupIsCancelled ( group: _group)
182
+ }
183
+ }
184
+
185
+ @available ( SwiftStdlib 5 . 8 , * )
186
+ @available ( * , unavailable)
187
+ extension DiscardingTaskGroup : Sendable { }
188
+
189
+ // ==== ThrowingDiscardingTaskGroup -------------------------------------------
190
+
191
+ @available ( SwiftStdlib 5 . 8 , * )
192
+ @inlinable
193
+ @_unsafeInheritExecutor
194
+ public func withThrowingDiscardingTaskGroup< GroupResult> (
195
+ returning returnType: GroupResult . Type = GroupResult . self,
196
+ body: ( inout ThrowingDiscardingTaskGroup < Error > ) async throws -> GroupResult
197
+ ) async throws -> GroupResult {
198
+ #if compiler(>=5.5) && $BuiltinTaskGroupWithArgument
199
+ let flags = taskGroupCreateFlags (
200
+ discardResults: true
201
+ )
202
+
203
+ let _group = Builtin . createTaskGroupWithFlags ( flags, GroupResult . self)
204
+ var group = ThrowingDiscardingTaskGroup < Error > ( group: _group)
205
+ defer { Builtin . destroyTaskGroup ( _group) }
206
+
207
+ let result : GroupResult
208
+ do {
209
+ result = try await body ( & group)
210
+ } catch {
211
+ group. cancelAll ( )
212
+
213
+ try await group. awaitAllRemainingTasks ( )
214
+
215
+ throw error
216
+ }
217
+
218
+ try await group. awaitAllRemainingTasks ( )
219
+
220
+ return result
221
+ #else
222
+ fatalError ( " Swift compiler is incompatible with this SDK version " )
223
+ #endif
224
+ }
225
+
226
+ @available ( SwiftStdlib 5 . 8 , * )
227
+ @frozen
228
+ public struct ThrowingDiscardingTaskGroup < Failure: Error > {
229
+
230
+ @usableFromInline
231
+ internal let _group : Builtin . RawPointer
232
+
233
+ // No public initializers
234
+ @inlinable
235
+ init ( group: Builtin . RawPointer ) {
236
+ self . _group = group
237
+ }
238
+
239
+ /// Await all the remaining tasks on this group.
240
+ @usableFromInline
241
+ internal mutating func awaitAllRemainingTasks( ) async throws {
242
+ let _: Void ? = try await _taskGroupWaitAll ( group: _group)
243
+ }
244
+
245
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
246
+ @available ( * , unavailable, message: " Unavailable in task-to-thread concurrency model " , renamed: " addTask(operation:) " )
247
+ #endif
248
+ @_alwaysEmitIntoClient
249
+ public mutating func addTask(
250
+ priority: TaskPriority ? = nil ,
251
+ operation: __owned @Sendable @escaping ( ) async throws -> Void
252
+ ) {
253
+ #if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
254
+ let flags = taskCreateFlags (
255
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
256
+ inheritContext: false , enqueueJob: true ,
257
+ addPendingGroupTaskUnconditionally: true
258
+ )
259
+
260
+ // Create the task in this group.
261
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
262
+ #else
263
+ fatalError ( " Unsupported Swift compiler " )
264
+ #endif
265
+ }
266
+
267
+ #if SWIFT_STDLIB_TASK_TO_THREAD_MODEL_CONCURRENCY
268
+ @available ( * , unavailable, message: " Unavailable in task-to-thread concurrency model " , renamed: " addTask(operation:) " )
269
+ #endif
270
+ @_alwaysEmitIntoClient
271
+ public mutating func addTaskUnlessCancelled(
272
+ priority: TaskPriority ? = nil ,
273
+ operation: __owned @Sendable @escaping ( ) async throws -> Void
274
+ ) -> Bool {
275
+ #if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
276
+ let canAdd = _taskGroupAddPendingTask ( group: _group, unconditionally: false )
277
+
278
+ guard canAdd else {
279
+ // the group is cancelled and is not accepting any new work
280
+ return false
281
+ }
282
+
283
+ let flags = taskCreateFlags (
284
+ priority: priority, isChildTask: true , copyTaskLocals: false ,
285
+ inheritContext: false , enqueueJob: true ,
286
+ addPendingGroupTaskUnconditionally: false
287
+ )
288
+
289
+ // Create the task in this group.
290
+ _ = Builtin . createAsyncTaskInGroup ( flags, _group, operation)
291
+
292
+ return true
293
+ #else
294
+ fatalError ( " Unsupported Swift compiler " )
295
+ #endif
296
+ }
297
+
298
+ public var isEmpty : Bool {
299
+ _taskGroupIsEmpty ( _group)
300
+ }
301
+
302
+ public func cancelAll( ) {
303
+ _taskGroupCancelAll ( group: _group)
304
+ }
305
+
306
+ public var isCancelled : Bool {
307
+ return _taskGroupIsCancelled ( group: _group)
308
+ }
309
+ }
310
+
311
+ @available ( SwiftStdlib 5 . 8 , * )
312
+ @available ( * , unavailable)
313
+ extension ThrowingDiscardingTaskGroup : Sendable { }
314
+
315
+ // ==== -----------------------------------------------------------------------
316
+ // MARK: Runtime functions
317
+
318
+ /// Always returns `nil`.
319
+ @available ( SwiftStdlib 5 . 8 , * )
320
+ @usableFromInline
321
+ @discardableResult
322
+ @_silgen_name ( " swift_taskGroup_waitAll " )
323
+ func _taskGroupWaitAll< T> (
324
+ group: Builtin . RawPointer
325
+ ) async throws -> T ?
326
+
327
+ @available ( SwiftStdlib 5 . 8 , * ) // FIXME: remove
328
+ @_silgen_name ( " swift_taskGroup_isDiscardingResults " )
329
+ func _taskGroupIsDiscardingResults( group: Builtin . RawPointer ) -> Bool
0 commit comments