Skip to content

Commit e94adde

Browse files
committed
[Concurrency] manually adjust availability of task creation APIs with names
1 parent 4313f8f commit e94adde

File tree

6 files changed

+287
-375
lines changed

6 files changed

+287
-375
lines changed

stdlib/public/Concurrency/Task+TaskExecutor.swift

Lines changed: 180 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,10 @@ extension Task where Failure == Never {
202202
///
203203
/// Use this function when creating asynchronous work
204204
/// that operates on behalf of the synchronous function that calls it.
205-
/// Like `Task.detached(priority:operation:)`,
205+
/// Like `Task.detached(name:priority:operation:)`,
206206
/// this function creates a separate, top-level task.
207-
/// Unlike `Task.detached(priority:operation:)`,
208-
/// the task created by `Task.init(priority:operation:)`
207+
/// Unlike `Task.detached(name:priority:operation:)`,
208+
/// the task created by `Task.init(name:priority:operation:)`
209209
/// inherits the priority and actor context of the caller,
210210
/// so the operation is treated more like an asynchronous extension
211211
/// to the synchronous operation.
@@ -227,33 +227,58 @@ extension Task where Failure == Never {
227227
@discardableResult
228228
@_alwaysEmitIntoClient
229229
public init(
230-
executorPreference taskExecutor: consuming (any TaskExecutor)?,
230+
name: String? = nil,
231+
executorPreference taskExecutor: consuming (any TaskExecutor)? = nil,
231232
priority: TaskPriority? = nil,
232233
operation: sending @escaping () async -> Success
233234
) {
234235
guard let taskExecutor else {
235-
self = Self.init(priority: priority, operation: operation)
236+
self = Self.init(name: name, priority: priority, operation: operation)
236237
return
237238
}
239+
238240
// Set up the job flags for a new task.
239241
let flags = taskCreateFlags(
240-
priority: priority, isChildTask: false, copyTaskLocals: true,
241-
inheritContext: true, enqueueJob: true,
242+
priority: priority,
243+
isChildTask: false,
244+
copyTaskLocals: true,
245+
inheritContext: true,
246+
enqueueJob: true,
242247
addPendingGroupTaskUnconditionally: false,
243-
isDiscardingTask: false, isSynchronousStart: false)
244-
245-
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
246-
let (task, _) = Builtin.createTask(
247-
flags: flags,
248-
initialTaskExecutorConsuming: taskExecutor,
249-
operation: operation)
250-
#else
251-
let executorBuiltin: Builtin.Executor =
252-
taskExecutor.asUnownedTaskExecutor().executor
253-
let (task, _) = Builtin.createAsyncTaskWithExecutor(
254-
flags, executorBuiltin, operation)
255-
#endif
256-
self._task = task
248+
isDiscardingTask: false,
249+
isSynchronousStart: false)
250+
251+
var task: Builtin.NativeObject?
252+
#if $BuiltinCreateAsyncTaskName
253+
if let name {
254+
task =
255+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
256+
Builtin.createTask(
257+
flags: flags,
258+
initialTaskExecutorConsuming: taskExecutor,
259+
taskName: nameBytes.baseAddress!._rawValue,
260+
operation: operation).0
261+
}
262+
}
263+
#endif // $BuiltinCreateAsyncTaskName
264+
265+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
266+
if task == nil {
267+
task = Builtin.createTask(
268+
flags: flags,
269+
initialTaskExecutorConsuming: taskExecutor,
270+
operation: operation).0
271+
}
272+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
273+
274+
if task == nil {
275+
let executorBuiltin: Builtin.Executor =
276+
taskExecutor.asUnownedTaskExecutor().executor
277+
task = Builtin.createAsyncTaskWithExecutor(
278+
flags, executorBuiltin, operation).0
279+
}
280+
281+
self._task = task!
257282
}
258283
}
259284

@@ -265,10 +290,10 @@ extension Task where Failure == Error {
265290
///
266291
/// Use this function when creating asynchronous work
267292
/// that operates on behalf of the synchronous function that calls it.
268-
/// Like `Task.detached(priority:operation:)`,
293+
/// Like `Task.detached(name:priority:operation:)`,
269294
/// this function creates a separate, top-level task.
270295
/// Unlike `detach(priority:operation:)`,
271-
/// the task created by `Task.init(priority:operation:)`
296+
/// the task created by `Task.init(name:priority:operation:)`
272297
/// inherits the priority and actor context of the caller,
273298
/// so the operation is treated more like an asynchronous extension
274299
/// to the synchronous operation.
@@ -290,33 +315,58 @@ extension Task where Failure == Error {
290315
@discardableResult
291316
@_alwaysEmitIntoClient
292317
public init(
318+
name: String? = nil,
293319
executorPreference taskExecutor: consuming (any TaskExecutor)?,
294320
priority: TaskPriority? = nil,
295321
operation: sending @escaping () async throws -> Success
296322
) {
297323
guard let taskExecutor else {
298-
self = Self.init(priority: priority, operation: operation)
324+
self = Self.init(name: name, priority: priority, operation: operation)
299325
return
300326
}
327+
301328
// Set up the job flags for a new task.
302329
let flags = taskCreateFlags(
303-
priority: priority, isChildTask: false, copyTaskLocals: true,
304-
inheritContext: true, enqueueJob: true,
330+
priority: priority,
331+
isChildTask: false,
332+
copyTaskLocals: true,
333+
inheritContext: true,
334+
enqueueJob: true,
305335
addPendingGroupTaskUnconditionally: false,
306-
isDiscardingTask: false, isSynchronousStart: false)
307-
308-
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
309-
let (task, _) = Builtin.createTask(
310-
flags: flags,
311-
initialTaskExecutorConsuming: taskExecutor,
312-
operation: operation)
313-
#else
314-
let executorBuiltin: Builtin.Executor =
315-
taskExecutor.asUnownedTaskExecutor().executor
316-
let (task, _) = Builtin.createAsyncTaskWithExecutor(
317-
flags, executorBuiltin, operation)
318-
#endif
319-
self._task = task
336+
isDiscardingTask: false,
337+
isSynchronousStart: false)
338+
339+
var task: Builtin.NativeObject?
340+
#if $BuiltinCreateAsyncTaskName
341+
if let name {
342+
task =
343+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
344+
Builtin.createTask(
345+
flags: flags,
346+
initialTaskExecutorConsuming: taskExecutor,
347+
taskName: nameBytes.baseAddress!._rawValue,
348+
operation: operation).0
349+
}
350+
}
351+
#endif // $BuiltinCreateAsyncTaskName
352+
353+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
354+
if task == nil {
355+
task = Builtin.createTask(
356+
flags: flags,
357+
initialTaskExecutorConsuming: taskExecutor,
358+
operation: operation).0
359+
}
360+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
361+
362+
if task == nil {
363+
let executorBuiltin: Builtin.Executor =
364+
taskExecutor.asUnownedTaskExecutor().executor
365+
task = Builtin.createAsyncTaskWithExecutor(
366+
flags, executorBuiltin, operation).0
367+
}
368+
369+
self._task = task!
320370
}
321371
}
322372

@@ -352,32 +402,57 @@ extension Task where Failure == Never {
352402
@discardableResult
353403
@_alwaysEmitIntoClient
354404
public static func detached(
405+
name: String? = nil,
355406
executorPreference taskExecutor: (any TaskExecutor)?,
356407
priority: TaskPriority? = nil,
357408
operation: sending @escaping () async -> Success
358409
) -> Task<Success, Failure> {
359410
guard let taskExecutor else {
360-
return Self.detached(priority: priority, operation: operation)
411+
return Self.detached(name: name, priority: priority, operation: operation)
361412
}
413+
362414
// Set up the job flags for a new task.
363415
let flags = taskCreateFlags(
364-
priority: priority, isChildTask: false, copyTaskLocals: false,
365-
inheritContext: false, enqueueJob: true,
416+
priority: priority,
417+
isChildTask: false,
418+
copyTaskLocals: false,
419+
inheritContext: false,
420+
enqueueJob: true,
366421
addPendingGroupTaskUnconditionally: false,
367-
isDiscardingTask: false, isSynchronousStart: false)
368-
369-
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
370-
let (task, _) = Builtin.createTask(
371-
flags: flags,
372-
initialTaskExecutorConsuming: taskExecutor,
373-
operation: operation)
374-
#else
375-
let executorBuiltin: Builtin.Executor =
376-
taskExecutor.asUnownedTaskExecutor().executor
377-
let (task, _) = Builtin.createAsyncTaskWithExecutor(
378-
flags, executorBuiltin, operation)
379-
#endif
380-
return Task(task)
422+
isDiscardingTask: false,
423+
isSynchronousStart: false)
424+
425+
var task: Builtin.NativeObject?
426+
#if $BuiltinCreateAsyncTaskName
427+
if let name {
428+
task =
429+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
430+
Builtin.createTask(
431+
flags: flags,
432+
initialTaskExecutorConsuming: taskExecutor,
433+
taskName: nameBytes.baseAddress!._rawValue,
434+
operation: operation).0
435+
}
436+
}
437+
#endif // $BuiltinCreateAsyncTaskName
438+
439+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
440+
if task == nil {
441+
task = Builtin.createTask(
442+
flags: flags,
443+
initialTaskExecutorConsuming: taskExecutor,
444+
operation: operation).0
445+
}
446+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
447+
448+
if task == nil {
449+
let executorBuiltin: Builtin.Executor =
450+
taskExecutor.asUnownedTaskExecutor().executor
451+
task = Builtin.createAsyncTaskWithExecutor(
452+
flags, executorBuiltin, operation).0
453+
}
454+
455+
return Task(task!)
381456
}
382457
}
383458

@@ -413,32 +488,61 @@ extension Task where Failure == Error {
413488
@discardableResult
414489
@_alwaysEmitIntoClient
415490
public static func detached(
491+
name: String? = nil,
416492
executorPreference taskExecutor: (any TaskExecutor)?,
417493
priority: TaskPriority? = nil,
418494
operation: sending @escaping () async throws -> Success
419495
) -> Task<Success, Failure> {
420-
guard let taskExecutor else {
421-
return Self.detached(priority: priority, operation: operation)
422-
}
423496
// Set up the job flags for a new task.
424497
let flags = taskCreateFlags(
425-
priority: priority, isChildTask: false, copyTaskLocals: false,
426-
inheritContext: false, enqueueJob: true,
498+
priority: priority,
499+
isChildTask: false,
500+
copyTaskLocals: false,
501+
inheritContext: false,
502+
enqueueJob: true,
427503
addPendingGroupTaskUnconditionally: false,
428-
isDiscardingTask: false, isSynchronousStart: false)
429-
430-
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
431-
let (task, _) = Builtin.createTask(
432-
flags: flags,
433-
initialTaskExecutorConsuming: taskExecutor,
434-
operation: operation)
435-
#else
436-
let executorBuiltin: Builtin.Executor =
437-
taskExecutor.asUnownedTaskExecutor().executor
438-
let (task, _) = Builtin.createAsyncTaskWithExecutor(
439-
flags, executorBuiltin, operation)
440-
#endif
441-
return Task(task)
504+
isDiscardingTask: false,
505+
isSynchronousStart: false)
506+
507+
var task: Builtin.NativeObject?
508+
#if $BuiltinCreateAsyncTaskName
509+
if let name {
510+
task =
511+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
512+
Builtin.createTask(
513+
flags: flags,
514+
initialTaskExecutorConsuming: taskExecutor,
515+
taskName: nameBytes.baseAddress!._rawValue,
516+
operation: operation).0
517+
}
518+
}
519+
#endif // $BuiltinCreateAsyncTaskName
520+
521+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
522+
if task == nil {
523+
task = Builtin.createTask(
524+
flags: flags,
525+
initialTaskExecutorConsuming: taskExecutor,
526+
operation: operation).0
527+
}
528+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
529+
530+
if task == nil {
531+
if let taskExecutor {
532+
let executorBuiltin: Builtin.Executor =
533+
taskExecutor.asUnownedTaskExecutor().executor
534+
task = Builtin.createAsyncTaskWithExecutor(
535+
flags, executorBuiltin, operation).0
536+
} else {
537+
assert(taskExecutor == nil)
538+
task = Builtin.createTask(
539+
flags: flags,
540+
// no initialSerialExecutor since not isolated(any)
541+
operation: operation).0
542+
}
543+
}
544+
545+
return Task(task!)
442546
}
443547
}
444548

0 commit comments

Comments
 (0)