Skip to content

Commit b1705ae

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

File tree

6 files changed

+299
-380
lines changed

6 files changed

+299
-380
lines changed

stdlib/public/Concurrency/Task+TaskExecutor.swift

Lines changed: 192 additions & 81 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,61 @@ 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
) {
297-
guard let taskExecutor else {
298-
self = Self.init(priority: priority, operation: operation)
299-
return
300-
}
301323
// Set up the job flags for a new task.
302324
let flags = taskCreateFlags(
303-
priority: priority, isChildTask: false, copyTaskLocals: true,
304-
inheritContext: true, enqueueJob: true,
325+
priority: priority,
326+
isChildTask: false,
327+
copyTaskLocals: true,
328+
inheritContext: true,
329+
enqueueJob: true,
305330
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
331+
isDiscardingTask: false,
332+
isSynchronousStart: false)
333+
334+
var task: Builtin.NativeObject?
335+
#if $BuiltinCreateAsyncTaskName
336+
if let name {
337+
task =
338+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
339+
Builtin.createTask(
340+
flags: flags,
341+
initialTaskExecutorConsuming: taskExecutor,
342+
taskName: nameBytes.baseAddress!._rawValue,
343+
operation: operation).0
344+
}
345+
}
346+
#endif // $BuiltinCreateAsyncTaskName
347+
348+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
349+
if task == nil {
350+
task = Builtin.createTask(
351+
flags: flags,
352+
initialTaskExecutorConsuming: taskExecutor,
353+
operation: operation).0
354+
}
355+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
356+
357+
if task == nil {
358+
if let taskExecutor {
359+
let executorBuiltin: Builtin.Executor =
360+
taskExecutor.asUnownedTaskExecutor().executor
361+
task = Builtin.createAsyncTaskWithExecutor(
362+
flags, executorBuiltin, operation).0
363+
} else {
364+
assert(taskExecutor == nil)
365+
task = Builtin.createTask(
366+
flags: flags,
367+
// no initialSerialExecutor since not isolated(any)
368+
operation: operation).0
369+
}
370+
}
371+
372+
self._task = task!
320373
}
321374
}
322375

@@ -352,32 +405,61 @@ extension Task where Failure == Never {
352405
@discardableResult
353406
@_alwaysEmitIntoClient
354407
public static func detached(
408+
name: String? = nil,
355409
executorPreference taskExecutor: (any TaskExecutor)?,
356410
priority: TaskPriority? = nil,
357411
operation: sending @escaping () async -> Success
358412
) -> Task<Success, Failure> {
359-
guard let taskExecutor else {
360-
return Self.detached(priority: priority, operation: operation)
361-
}
362413
// Set up the job flags for a new task.
363414
let flags = taskCreateFlags(
364-
priority: priority, isChildTask: false, copyTaskLocals: false,
365-
inheritContext: false, enqueueJob: true,
415+
priority: priority,
416+
isChildTask: false,
417+
copyTaskLocals: false,
418+
inheritContext: false,
419+
enqueueJob: true,
366420
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)
421+
isDiscardingTask: false,
422+
isSynchronousStart: false)
423+
424+
var task: Builtin.NativeObject?
425+
#if $BuiltinCreateAsyncTaskName
426+
if let name {
427+
task =
428+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
429+
Builtin.createTask(
430+
flags: flags,
431+
initialTaskExecutorConsuming: taskExecutor,
432+
taskName: nameBytes.baseAddress!._rawValue,
433+
operation: operation).0
434+
}
435+
}
436+
#endif // $BuiltinCreateAsyncTaskName
437+
438+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
439+
if task == nil {
440+
task = Builtin.createTask(
441+
flags: flags,
442+
initialTaskExecutorConsuming: taskExecutor,
443+
operation: operation).0
444+
}
445+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
446+
447+
if task == nil {
448+
if let taskExecutor {
449+
let executorBuiltin: Builtin.Executor =
450+
taskExecutor.asUnownedTaskExecutor().executor
451+
task = Builtin.createAsyncTaskWithExecutor(
452+
flags, executorBuiltin, operation).0
453+
} else {
454+
assert(taskExecutor == nil)
455+
task = Builtin.createTask(
456+
flags: flags,
457+
// no initialSerialExecutor since not isolated(any)
458+
operation: operation).0
459+
}
460+
}
461+
462+
return Task(task!)
381463
}
382464
}
383465

@@ -413,32 +495,61 @@ extension Task where Failure == Error {
413495
@discardableResult
414496
@_alwaysEmitIntoClient
415497
public static func detached(
498+
name: String? = nil,
416499
executorPreference taskExecutor: (any TaskExecutor)?,
417500
priority: TaskPriority? = nil,
418501
operation: sending @escaping () async throws -> Success
419502
) -> Task<Success, Failure> {
420-
guard let taskExecutor else {
421-
return Self.detached(priority: priority, operation: operation)
422-
}
423503
// Set up the job flags for a new task.
424504
let flags = taskCreateFlags(
425-
priority: priority, isChildTask: false, copyTaskLocals: false,
426-
inheritContext: false, enqueueJob: true,
505+
priority: priority,
506+
isChildTask: false,
507+
copyTaskLocals: false,
508+
inheritContext: false,
509+
enqueueJob: true,
427510
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)
511+
isDiscardingTask: false,
512+
isSynchronousStart: false)
513+
514+
var task: Builtin.NativeObject?
515+
#if $BuiltinCreateAsyncTaskName
516+
if let name {
517+
task =
518+
unsafe name.utf8CString.withUnsafeBufferPointer { nameBytes in
519+
Builtin.createTask(
520+
flags: flags,
521+
initialTaskExecutorConsuming: taskExecutor,
522+
taskName: nameBytes.baseAddress!._rawValue,
523+
operation: operation).0
524+
}
525+
}
526+
#endif // $BuiltinCreateAsyncTaskName
527+
528+
#if $BuiltinCreateAsyncTaskOwnedTaskExecutor
529+
if task == nil {
530+
task = Builtin.createTask(
531+
flags: flags,
532+
initialTaskExecutorConsuming: taskExecutor,
533+
operation: operation).0
534+
}
535+
#endif // $BuiltinCreateAsyncTaskOwnedTaskExecutor
536+
537+
if task == nil {
538+
if let taskExecutor {
539+
let executorBuiltin: Builtin.Executor =
540+
taskExecutor.asUnownedTaskExecutor().executor
541+
task = Builtin.createAsyncTaskWithExecutor(
542+
flags, executorBuiltin, operation).0
543+
} else {
544+
assert(taskExecutor == nil)
545+
task = Builtin.createTask(
546+
flags: flags,
547+
// no initialSerialExecutor since not isolated(any)
548+
operation: operation).0
549+
}
550+
}
551+
552+
return Task(task!)
442553
}
443554
}
444555

0 commit comments

Comments
 (0)