Skip to content

Commit 819615e

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 ba0644c commit 819615e

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
@@ -36,9 +36,12 @@ import Swift
3636
/// individually schedulable as jobs. Jobs are generally not interacted
3737
/// with by end-users directly, unless implementing a scheduler.
3838
@available(SwiftStdlib 5.5, *)
39+
@frozen
3940
public struct Task<Success, Failure: Error>: Sendable {
41+
@usableFromInline
4042
internal let _task: Builtin.NativeObject
4143

44+
@_alwaysEmitIntoClient
4245
internal init(_ task: Builtin.NativeObject) {
4346
self._task = task
4447
}
@@ -381,109 +384,32 @@ struct JobFlags {
381384

382385
// ==== Task Creation Flags --------------------------------------------------
383386

384-
/// Flags for schedulable jobs.
385-
///
386-
/// This is a port of the C++ FlagSet.
387+
/// Form task creation flags for use with the createAsyncTask builtins.
387388
@available(SwiftStdlib 5.5, *)
388-
struct TaskCreateFlags {
389-
/// The actual bit representation of these flags.
390-
var bits: Int = 0
391-
392-
/// The priority given to the job.
393-
var priority: TaskPriority? {
394-
get {
395-
let value = Int(bits) & 0xFF
396-
397-
if value == 0 {
398-
return nil
399-
}
400-
401-
return TaskPriority(rawValue: UInt8(value))
402-
}
403-
404-
set {
405-
bits = (bits & ~0xFF) | Int(newValue?.rawValue ?? 0)
406-
}
407-
}
408-
409-
/// Whether this is a child task.
410-
var isChildTask: Bool {
411-
get {
412-
(bits & (1 << 8)) != 0
413-
}
414-
415-
set {
416-
if newValue {
417-
bits = bits | 1 << 8
418-
} else {
419-
bits = (bits & ~(1 << 8))
420-
}
421-
}
389+
@_alwaysEmitIntoClient
390+
func taskCreateFlags(
391+
priority: TaskPriority?, isChildTask: Bool, copyTaskLocals: Bool,
392+
inheritContext: Bool, enqueueJob: Bool,
393+
addPendingGroupTaskUnconditionally: Bool
394+
) -> Int {
395+
var bits = 0
396+
bits |= (bits & ~0xFF) | Int(priority?.rawValue ?? 0)
397+
if isChildTask {
398+
bits |= 1 << 8
422399
}
423-
424-
/// Whether to copy thread locals from the currently-executing task into the
425-
/// newly-created task.
426-
var copyTaskLocals: Bool {
427-
get {
428-
(bits & (1 << 10)) != 0
429-
}
430-
431-
set {
432-
if newValue {
433-
bits = bits | 1 << 10
434-
} else {
435-
bits = (bits & ~(1 << 10))
436-
}
437-
}
400+
if copyTaskLocals {
401+
bits |= 1 << 10
438402
}
439-
440-
/// Whether this task should inherit as much context from the
441-
/// currently-executing task as it can.
442-
var inheritContext: Bool {
443-
get {
444-
(bits & (1 << 11)) != 0
445-
}
446-
447-
set {
448-
if newValue {
449-
bits = bits | 1 << 11
450-
} else {
451-
bits = (bits & ~(1 << 11))
452-
}
453-
}
403+
if inheritContext {
404+
bits |= 1 << 11
454405
}
455-
456-
/// Whether to enqueue the newly-created task on the given executor (if
457-
/// specified) or the global executor.
458-
var enqueueJob: Bool {
459-
get {
460-
(bits & (1 << 12)) != 0
461-
}
462-
463-
set {
464-
if newValue {
465-
bits = bits | 1 << 12
466-
} else {
467-
bits = (bits & ~(1 << 12))
468-
}
469-
}
406+
if enqueueJob {
407+
bits |= 1 << 12
470408
}
471-
472-
/// Whether to add a pending group task unconditionally as part of creating
473-
/// the task.
474-
var addPendingGroupTaskUnconditionally: Bool {
475-
get {
476-
(bits & (1 << 13)) != 0
477-
}
478-
479-
set {
480-
if newValue {
481-
bits = bits | 1 << 13
482-
} else {
483-
bits = (bits & ~(1 << 13))
484-
}
485-
}
409+
if addPendingGroupTaskUnconditionally {
410+
bits |= 1 << 13
486411
}
412+
return bits
487413
}
488414

489415
// ==== Task Creation ----------------------------------------------------------
@@ -506,20 +432,20 @@ extension Task where Failure == Never {
506432
/// Task.currentPriority.
507433
/// - operation: the operation to execute
508434
@discardableResult
435+
@_alwaysEmitIntoClient
509436
public init(
510437
priority: TaskPriority? = nil,
511438
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success
512439
) {
513440
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
514441
// Set up the job flags for a new task.
515-
var flags = TaskCreateFlags()
516-
flags.priority = priority
517-
flags.inheritContext = true
518-
flags.copyTaskLocals = true
519-
flags.enqueueJob = true
442+
let flags = taskCreateFlags(
443+
priority: priority, isChildTask: false, copyTaskLocals: true,
444+
inheritContext: true, enqueueJob: true,
445+
addPendingGroupTaskUnconditionally: false)
520446

521447
// Create the asynchronous task.
522-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
448+
let (task, _) = Builtin.createAsyncTask(flags, operation)
523449

524450
self._task = task
525451
#else
@@ -543,20 +469,21 @@ extension Task where Failure == Error {
543469
/// Task.currentPriority.
544470
/// - operation: the operation to execute
545471
@discardableResult
472+
@_alwaysEmitIntoClient
546473
public init(
547474
priority: TaskPriority? = nil,
548475
@_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async throws -> Success
549476
) {
550477
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
551-
// Set up the job flags for a new task.
552-
var flags = TaskCreateFlags()
553-
flags.priority = priority
554-
flags.inheritContext = true
555-
flags.copyTaskLocals = true
556-
flags.enqueueJob = true
478+
// Set up the task flags for a new task.
479+
let flags = taskCreateFlags(
480+
priority: priority, isChildTask: false, copyTaskLocals: true,
481+
inheritContext: true, enqueueJob: true,
482+
addPendingGroupTaskUnconditionally: false
483+
)
557484

558485
// Create the asynchronous task future.
559-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
486+
let (task, _) = Builtin.createAsyncTask(flags, operation)
560487

561488
self._task = task
562489
#else
@@ -599,18 +526,20 @@ extension Task where Failure == Never {
599526
/// tasks result or `cancel` it. If the operation fails the handle will
600527
/// throw the error the operation has thrown when awaited on.
601528
@discardableResult
529+
@_alwaysEmitIntoClient
602530
public static func detached(
603531
priority: TaskPriority? = nil,
604532
operation: __owned @Sendable @escaping () async -> Success
605533
) -> Task<Success, Failure> {
606534
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
607535
// Set up the job flags for a new task.
608-
var flags = TaskCreateFlags()
609-
flags.priority = priority
610-
flags.enqueueJob = true
536+
let flags = taskCreateFlags(
537+
priority: priority, isChildTask: false, copyTaskLocals: false,
538+
inheritContext: false, enqueueJob: true,
539+
addPendingGroupTaskUnconditionally: false)
611540

612541
// Create the asynchronous task future.
613-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
542+
let (task, _) = Builtin.createAsyncTask(flags, operation)
614543

615544
return Task(task)
616545
#else
@@ -654,18 +583,21 @@ extension Task where Failure == Error {
654583
/// tasks result or `cancel` it. If the operation fails the handle will
655584
/// throw the error the operation has thrown when awaited on.
656585
@discardableResult
586+
@_alwaysEmitIntoClient
657587
public static func detached(
658588
priority: TaskPriority? = nil,
659589
operation: __owned @Sendable @escaping () async throws -> Success
660590
) -> Task<Success, Failure> {
661591
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
662592
// Set up the job flags for a new task.
663-
var flags = TaskCreateFlags()
664-
flags.priority = priority
665-
flags.enqueueJob = true
593+
let flags = taskCreateFlags(
594+
priority: priority, isChildTask: false, copyTaskLocals: false,
595+
inheritContext: false, enqueueJob: true,
596+
addPendingGroupTaskUnconditionally: false
597+
)
666598

667599
// Create the asynchronous task future.
668-
let (task, _) = Builtin.createAsyncTask(Int(flags.bits), operation)
600+
let (task, _) = Builtin.createAsyncTask(flags, operation)
669601

670602
return Task(task)
671603
#else

stdlib/public/Concurrency/TaskGroup.swift

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -207,19 +207,20 @@ public struct TaskGroup<ChildTaskResult> {
207207
/// - Returns:
208208
/// - `true` if the operation was added to the group successfully,
209209
/// `false` otherwise (e.g. because the group `isCancelled`)
210+
@_alwaysEmitIntoClient
210211
public mutating func async(
211212
priority: TaskPriority? = nil,
212213
operation: __owned @Sendable @escaping () async -> ChildTaskResult
213214
) {
214215
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
215-
var flags = TaskCreateFlags()
216-
flags.priority = priority
217-
flags.isChildTask = true
218-
flags.enqueueJob = true
219-
flags.addPendingGroupTaskUnconditionally = true
216+
let flags = taskCreateFlags(
217+
priority: priority, isChildTask: true, copyTaskLocals: false,
218+
inheritContext: false, enqueueJob: true,
219+
addPendingGroupTaskUnconditionally: true
220+
)
220221

221222
// Create the task in this group.
222-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
223+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
223224
#else
224225
fatalError("Unsupported Swift compiler")
225226
#endif
@@ -240,6 +241,7 @@ public struct TaskGroup<ChildTaskResult> {
240241
/// - Returns:
241242
/// - `true` if the operation was added to the group successfully,
242243
/// `false` otherwise (e.g. because the group `isCancelled`)
244+
@_alwaysEmitIntoClient
243245
public mutating func asyncUnlessCancelled(
244246
priority: TaskPriority? = nil,
245247
operation: __owned @Sendable @escaping () async -> ChildTaskResult
@@ -252,13 +254,14 @@ public struct TaskGroup<ChildTaskResult> {
252254
return false
253255
}
254256

255-
var flags = TaskCreateFlags()
256-
flags.priority = priority
257-
flags.isChildTask = true
258-
flags.enqueueJob = true
257+
let flags = taskCreateFlags(
258+
priority: priority, isChildTask: true, copyTaskLocals: false,
259+
inheritContext: false, enqueueJob: true,
260+
addPendingGroupTaskUnconditionally: false
261+
)
259262

260263
// Create the task in this group.
261-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
264+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
262265

263266
return true
264267
#else
@@ -436,19 +439,20 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
436439
/// - Returns:
437440
/// - `true` if the operation was added to the group successfully,
438441
/// `false` otherwise (e.g. because the group `isCancelled`)
442+
@_alwaysEmitIntoClient
439443
public mutating func async(
440444
priority: TaskPriority? = nil,
441445
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
442446
) {
443447
#if compiler(>=5.5) && $BuiltinCreateAsyncTaskInGroup
444-
var flags = TaskCreateFlags()
445-
flags.priority = priority
446-
flags.isChildTask = true
447-
flags.enqueueJob = true
448-
flags.addPendingGroupTaskUnconditionally = true
448+
let flags = taskCreateFlags(
449+
priority: priority, isChildTask: true, copyTaskLocals: false,
450+
inheritContext: false, enqueueJob: true,
451+
addPendingGroupTaskUnconditionally: true
452+
)
449453

450454
// Create the task in this group.
451-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
455+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
452456
#else
453457
fatalError("Unsupported Swift compiler")
454458
#endif
@@ -469,6 +473,7 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
469473
/// - Returns:
470474
/// - `true` if the operation was added to the group successfully,
471475
/// `false` otherwise (e.g. because the group `isCancelled`)
476+
@_alwaysEmitIntoClient
472477
public mutating func asyncUnlessCancelled(
473478
priority: TaskPriority? = nil,
474479
operation: __owned @Sendable @escaping () async throws -> ChildTaskResult
@@ -481,13 +486,14 @@ public struct ThrowingTaskGroup<ChildTaskResult, Failure: Error> {
481486
return false
482487
}
483488

484-
var flags = TaskCreateFlags()
485-
flags.priority = priority
486-
flags.isChildTask = true
487-
flags.enqueueJob = true
489+
let flags = taskCreateFlags(
490+
priority: priority, isChildTask: true, copyTaskLocals: false,
491+
inheritContext: false, enqueueJob: true,
492+
addPendingGroupTaskUnconditionally: false
493+
)
488494

489495
// Create the task in this group.
490-
_ = Builtin.createAsyncTaskInGroup(flags.bits, _group, operation)
496+
_ = Builtin.createAsyncTaskInGroup(flags, _group, operation)
491497

492498
return true
493499
#else
@@ -725,6 +731,7 @@ func _taskGroupDestroy(group: __owned Builtin.RawPointer)
725731

726732
@available(SwiftStdlib 5.5, *)
727733
@_silgen_name("swift_taskGroup_addPending")
734+
@usableFromInline
728735
func _taskGroupAddPendingTask(
729736
group: Builtin.RawPointer,
730737
unconditionally: Bool

0 commit comments

Comments
 (0)