Skip to content

Commit 45031f1

Browse files
committed
Make Swift task-creation entry points always-emit-into-client.
The `swift_task_create` entry point is our general runtime ABI for launching tasks. Make the various Swift APIs sitting on top of it always-emit-into-client to take them out of the ABI. This reduces the number of ABI entry points and allows us to make more ABI-compatible changes to the Swift side.
1 parent cd30a00 commit 45031f1

File tree

2 files changed

+79
-140
lines changed

2 files changed

+79
-140
lines changed

stdlib/public/Concurrency/Task.swift

Lines changed: 50 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ import Swift
6363
/// This reflects the fact that a task can be canceled for many reasons,
6464
/// and additional reasons can accrue during the cancellation process.
6565
@available(SwiftStdlib 5.5, *)
66+
@frozen
6667
public struct Task<Success, Failure: Error>: Sendable {
68+
@usableFromInline
6769
internal let _task: Builtin.NativeObject
6870

71+
@_alwaysEmitIntoClient
6972
internal init(_ task: Builtin.NativeObject) {
7073
self._task = task
7174
}
@@ -409,109 +412,32 @@ struct JobFlags {
409412

410413
// ==== Task Creation Flags --------------------------------------------------
411414

412-
/// Flags for schedulable jobs.
413-
///
414-
/// This is a port of the C++ FlagSet.
415+
/// Form task creation flags for use with the createAsyncTask builtins.
415416
@available(SwiftStdlib 5.5, *)
416-
struct TaskCreateFlags {
417-
/// The actual bit representation of these flags.
418-
var bits: Int = 0
419-
420-
/// The priority given to the job.
421-
var priority: TaskPriority? {
422-
get {
423-
let value = Int(bits) & 0xFF
424-
425-
if value == 0 {
426-
return nil
427-
}
428-
429-
return TaskPriority(rawValue: UInt8(value))
430-
}
431-
432-
set {
433-
bits = (bits & ~0xFF) | Int(newValue?.rawValue ?? 0)
434-
}
435-
}
436-
437-
/// Whether this is a child task.
438-
var isChildTask: Bool {
439-
get {
440-
(bits & (1 << 8)) != 0
441-
}
442-
443-
set {
444-
if newValue {
445-
bits = bits | 1 << 8
446-
} else {
447-
bits = (bits & ~(1 << 8))
448-
}
449-
}
417+
@_alwaysEmitIntoClient
418+
func taskCreateFlags(
419+
priority: TaskPriority?, isChildTask: Bool, copyTaskLocals: Bool,
420+
inheritContext: Bool, enqueueJob: Bool,
421+
addPendingGroupTaskUnconditionally: Bool
422+
) -> Int {
423+
var bits = 0
424+
bits |= (bits & ~0xFF) | Int(priority?.rawValue ?? 0)
425+
if isChildTask {
426+
bits |= 1 << 8
450427
}
451-
452-
/// Whether to copy thread locals from the currently-executing task into the
453-
/// newly-created task.
454-
var copyTaskLocals: Bool {
455-
get {
456-
(bits & (1 << 10)) != 0
457-
}
458-
459-
set {
460-
if newValue {
461-
bits = bits | 1 << 10
462-
} else {
463-
bits = (bits & ~(1 << 10))
464-
}
465-
}
428+
if copyTaskLocals {
429+
bits |= 1 << 10
466430
}
467-
468-
/// Whether this task should inherit as much context from the
469-
/// currently-executing task as it can.
470-
var inheritContext: Bool {
471-
get {
472-
(bits & (1 << 11)) != 0
473-
}
474-
475-
set {
476-
if newValue {
477-
bits = bits | 1 << 11
478-
} else {
479-
bits = (bits & ~(1 << 11))
480-
}
481-
}
431+
if inheritContext {
432+
bits |= 1 << 11
482433
}
483-
484-
/// Whether to enqueue the newly-created task on the given executor (if
485-
/// specified) or the global executor.
486-
var enqueueJob: Bool {
487-
get {
488-
(bits & (1 << 12)) != 0
489-
}
490-
491-
set {
492-
if newValue {
493-
bits = bits | 1 << 12
494-
} else {
495-
bits = (bits & ~(1 << 12))
496-
}
497-
}
434+
if enqueueJob {
435+
bits |= 1 << 12
498436
}
499-
500-
/// Whether to add a pending group task unconditionally as part of creating
501-
/// the task.
502-
var addPendingGroupTaskUnconditionally: Bool {
503-
get {
504-
(bits & (1 << 13)) != 0
505-
}
506-
507-
set {
508-
if newValue {
509-
bits = bits | 1 << 13
510-
} else {
511-
bits = (bits & ~(1 << 13))
512-
}
513-
}
437+
if addPendingGroupTaskUnconditionally {
438+
bits |= 1 << 13
514439
}
440+
return bits
515441
}
516442

517443
// ==== Task Creation ----------------------------------------------------------
@@ -534,20 +460,20 @@ extension Task where Failure == Never {
534460
/// Task.currentPriority.
535461
/// - operation: the operation to execute
536462
@discardableResult
463+
@_alwaysEmitIntoClient
537464
public init(
538465
priority: TaskPriority? = nil,
539466
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success
540467
) {
541468
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
542469
// Set up the job flags for a new task.
543-
var flags = TaskCreateFlags()
544-
flags.priority = priority
545-
flags.inheritContext = true
546-
flags.copyTaskLocals = true
547-
flags.enqueueJob = true
470+
let flags = taskCreateFlags(
471+
priority: priority, isChildTask: false, copyTaskLocals: true,
472+
inheritContext: true, enqueueJob: true,
473+
addPendingGroupTaskUnconditionally: false)
548474

549475
// Create the asynchronous task.
550-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
476+
let (task, _) = Builtin.createAsyncTask(flags, operation)
551477

552478
self._task = task
553479
#else
@@ -571,20 +497,21 @@ extension Task where Failure == Error {
571497
/// Task.currentPriority.
572498
/// - operation: the operation to execute
573499
@discardableResult
500+
@_alwaysEmitIntoClient
574501
public init(
575502
priority: TaskPriority? = nil,
576503
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> Success
577504
) {
578505
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
579-
// Set up the job flags for a new task.
580-
var flags = TaskCreateFlags()
581-
flags.priority = priority
582-
flags.inheritContext = true
583-
flags.copyTaskLocals = true
584-
flags.enqueueJob = true
506+
// Set up the task flags for a new task.
507+
let flags = taskCreateFlags(
508+
priority: priority, isChildTask: false, copyTaskLocals: true,
509+
inheritContext: true, enqueueJob: true,
510+
addPendingGroupTaskUnconditionally: false
511+
)
585512

586513
// Create the asynchronous task future.
587-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
514+
let (task, _) = Builtin.createAsyncTask(flags, operation)
588515

589516
self._task = task
590517
#else
@@ -627,18 +554,20 @@ extension Task where Failure == Never {
627554
/// tasks result or `cancel` it. If the operation fails the handle will
628555
/// throw the error the operation has thrown when awaited on.
629556
@discardableResult
557+
@_alwaysEmitIntoClient
630558
public static func detached(
631559
priority: TaskPriority? = nil,
632560
operation: __owned @Sendable @escaping () async -> Success
633561
) -> Task<Success, Failure> {
634562
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
635563
// Set up the job flags for a new task.
636-
var flags = TaskCreateFlags()
637-
flags.priority = priority
638-
flags.enqueueJob = true
564+
let flags = taskCreateFlags(
565+
priority: priority, isChildTask: false, copyTaskLocals: false,
566+
inheritContext: false, enqueueJob: true,
567+
addPendingGroupTaskUnconditionally: false)
639568

640569
// Create the asynchronous task future.
641-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
570+
let (task, _) = Builtin.createAsyncTask(flags, operation)
642571

643572
return Task(task)
644573
#else
@@ -682,18 +611,21 @@ extension Task where Failure == Error {
682611
/// tasks result or `cancel` it. If the operation fails the handle will
683612
/// throw the error the operation has thrown when awaited on.
684613
@discardableResult
614+
@_alwaysEmitIntoClient
685615
public static func detached(
686616
priority: TaskPriority? = nil,
687617
operation: __owned @Sendable @escaping () async throws -> Success
688618
) -> Task<Success, Failure> {
689619
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
690620
// Set up the job flags for a new task.
691-
var flags = TaskCreateFlags()
692-
flags.priority = priority
693-
flags.enqueueJob = true
621+
let flags = taskCreateFlags(
622+
priority: priority, isChildTask: false, copyTaskLocals: false,
623+
inheritContext: false, enqueueJob: true,
624+
addPendingGroupTaskUnconditionally: false
625+
)
694626

695627
// Create the asynchronous task future.
696-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
628+
let (task, _) = Builtin.createAsyncTask(flags, operation)
697629

698630
return Task(task)
699631
#else

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -235,19 +235,20 @@ public struct TaskGroup<ChildTaskResult> {
235235
/// - Returns:
236236
/// - `true` if the operation was added to the group successfully,
237237
/// `false` otherwise (e.g. because the group `isCancelled`)
238+
@_alwaysEmitIntoClient
238239
public mutating func async(
239240
priority: TaskPriority? = nil,
240241
operation: __owned @Sendable @escaping () async -> ChildTaskResult
241242
) {
242243
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
243-
var flags = TaskCreateFlags()
244-
flags.priority = priority
245-
flags.isChildTask = true
246-
flags.enqueueJob = true
247-
flags.addPendingGroupTaskUnconditionally = true
244+
let flags = taskCreateFlags(
245+
priority: priority, isChildTask: true, copyTaskLocals: false,
246+
inheritContext: false, enqueueJob: true,
247+
addPendingGroupTaskUnconditionally: true
248+
)
248249

249250
// Create the task in this group.
250-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
251+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
251252
#else
252253
fatalError("Unsupported Swift compiler")
253254
#endif
@@ -268,6 +269,7 @@ public struct TaskGroup<ChildTaskResult> {
268269
/// - Returns:
269270
/// - `true` if the operation was added to the group successfully,
270271
/// `false` otherwise (e.g. because the group `isCancelled`)
272+
@_alwaysEmitIntoClient
271273
public mutating func asyncUnlessCancelled(
272274
priority: TaskPriority? = nil,
273275
operation: __owned @Sendable @escaping () async -> ChildTaskResult
@@ -280,13 +282,14 @@ public struct TaskGroup<ChildTaskResult> {
280282
return false
281283
}
282284

283-
var flags = TaskCreateFlags()
284-
flags.priority = priority
285-
flags.isChildTask = true
286-
flags.enqueueJob = true
285+
let flags = taskCreateFlags(
286+
priority: priority, isChildTask: true, copyTaskLocals: false,
287+
inheritContext: false, enqueueJob: true,
288+
addPendingGroupTaskUnconditionally: false
289+
)
287290

288291
// Create the task in this group.
289-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
292+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
290293

291294
return true
292295
#else
@@ -456,19 +459,20 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
456459
/// - Returns:
457460
/// - `true` if the operation was added to the group successfully,
458461
/// `false` otherwise (e.g. because the group `isCancelled`)
462+
@_alwaysEmitIntoClient
459463
public mutating func async(
460464
priority: TaskPriority? = nil,
461465
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
462466
) {
463467
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
464-
var flags = TaskCreateFlags()
465-
flags.priority = priority
466-
flags.isChildTask = true
467-
flags.enqueueJob = true
468-
flags.addPendingGroupTaskUnconditionally = true
468+
let flags = taskCreateFlags(
469+
priority: priority, isChildTask: true, copyTaskLocals: false,
470+
inheritContext: false, enqueueJob: true,
471+
addPendingGroupTaskUnconditionally: true
472+
)
469473

470474
// Create the task in this group.
471-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
475+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
472476
#else
473477
fatalError("Unsupported Swift compiler")
474478
#endif
@@ -489,6 +493,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
489493
/// - Returns:
490494
/// - `true` if the operation was added to the group successfully,
491495
/// `false` otherwise (e.g. because the group `isCancelled`)
496+
@_alwaysEmitIntoClient
492497
public mutating func asyncUnlessCancelled(
493498
priority: TaskPriority? = nil,
494499
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
@@ -501,13 +506,14 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
501506
return false
502507
}
503508

504-
var flags = TaskCreateFlags()
505-
flags.priority = priority
506-
flags.isChildTask = true
507-
flags.enqueueJob = true
509+
let flags = taskCreateFlags(
510+
priority: priority, isChildTask: true, copyTaskLocals: false,
511+
inheritContext: false, enqueueJob: true,
512+
addPendingGroupTaskUnconditionally: false
513+
)
508514

509515
// Create the task in this group.
510-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
516+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
511517

512518
return true
513519
#else
@@ -820,6 +826,7 @@ func _taskGroupDestroy(group: __owned Builtin.RawPointer)
820826

821827
@available(SwiftStdlib 5.5, *)
822828
@_silgen_name("swift_taskGroup_addPending")
829+
@usableFromInline
823830
func _taskGroupAddPendingTask(
824831
group: Builtin.RawPointer,
825832
unconditionally: Bool

0 commit comments

Comments
 (0)