Skip to content

Commit a2783b2

Browse files
committed
[Concurrency] UnownedJob.priority and description for TaskPriority
1 parent f20eaac commit a2783b2

File tree

5 files changed

+141
-4
lines changed

5 files changed

+141
-4
lines changed

include/swift/Runtime/Concurrency.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,11 @@ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
560560
JobPriority
561561
swift_task_basePriority(AsyncTask *task);
562562

563+
/// Returns the priority of the job.
564+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
565+
JobPriority
566+
swift_concurrency_jobPriority(Job *job);
567+
563568
/// Create and add an cancellation record to the task.
564569
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
565570
CancellationNotificationStatusRecord*

stdlib/public/Concurrency/PartialAsyncTask.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,57 @@ internal func _swiftJobRun(_ job: UnownedJob,
2828
public struct UnownedJob: Sendable {
2929
private var context: Builtin.Job
3030

31+
/// The priority of this job.
32+
@available(SwiftStdlib 5.9, *)
33+
public var priority: JobPriority {
34+
let raw = _swift_concurrency_jobPriority(self)
35+
return JobPriority(rawValue: raw)
36+
}
37+
3138
@_alwaysEmitIntoClient
3239
@inlinable
40+
@available(*, deprecated, renamed: "runSynchronously")
3341
public func _runSynchronously(on executor: UnownedSerialExecutor) {
3442
_swiftJobRun(self, executor)
3543
}
44+
45+
@_alwaysEmitIntoClient
46+
@inlinable
47+
public func runSynchronously(on executor: UnownedSerialExecutor) {
48+
_swiftJobRun(self, executor)
49+
}
50+
}
51+
52+
/// The priority of this job.
53+
///
54+
/// The executor determines how priority information affects the way tasks are scheduled.
55+
/// The behavior varies depending on the executor currently being used.
56+
/// Typically, executors attempt to run tasks with a higher priority
57+
/// before tasks with a lower priority.
58+
/// However, the semantics of how priority is treated are left up to each
59+
/// platform and `Executor` implementation.
60+
///
61+
/// A Job's priority is roughly equivalent to a `TaskPriority`,
62+
/// however, since not all jobs are tasks, represented as separate type.
63+
///
64+
/// Conversions between the two priorities are available as initializers on the respective types.
65+
@available(SwiftStdlib 5.9, *)
66+
public struct JobPriority {
67+
public typealias RawValue = UInt8
68+
69+
/// The raw priority value.
70+
public var rawValue: RawValue
71+
}
72+
73+
@available(SwiftStdlib 5.9, *)
74+
extension TaskPriority {
75+
/// Convert a job priority to a task priority.
76+
///
77+
/// Most values are directly interchangeable, but this initializer reserves the right to fail for certain values.
78+
public init?(_ p: JobPriority) {
79+
// currently we always convert, but we could consider mapping over only recognized values etc.
80+
self = .init(rawValue: p.rawValue)
81+
}
3682
}
3783

3884
/// A mechanism to interface
@@ -291,3 +337,7 @@ public func withUnsafeThrowingContinuation<T>(
291337
public func _abiEnableAwaitContinuation() {
292338
fatalError("never use this function")
293339
}
340+
341+
@available(SwiftStdlib 5.9, *)
342+
@_silgen_name("swift_concurrency_jobPriority")
343+
internal func _swift_concurrency_jobPriority(_ job: UnownedJob) -> UInt8

stdlib/public/Concurrency/Task.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,20 +555,22 @@ const void *AsyncTask::getResumeFunctionForLogging() {
555555
return __ptrauth_swift_runtime_function_entry_strip(result);
556556
}
557557

558-
JobPriority swift::swift_task_currentPriority(AsyncTask *task)
559-
{
558+
JobPriority swift::swift_task_currentPriority(AsyncTask *task) {
560559
// This is racey but this is to be used in an API is inherently racey anyways.
561560
auto oldStatus = task->_private()._status().load(std::memory_order_relaxed);
562561
return oldStatus.getStoredPriority();
563562
}
564563

565-
JobPriority swift::swift_task_basePriority(AsyncTask *task)
566-
{
564+
JobPriority swift::swift_task_basePriority(AsyncTask *task) {
567565
JobPriority pri = task->_private().BasePriority;
568566
SWIFT_TASK_DEBUG_LOG("Task %p has base priority = %zu", task, pri);
569567
return pri;
570568
}
571569

570+
JobPriority swift::swift_concurrency_jobPriority(Job *job) {
571+
return job->getPriority();
572+
}
573+
572574
static inline bool isUnspecified(JobPriority priority) {
573575
return priority == JobPriority::Unspecified;
574576
}

stdlib/public/Concurrency/Task.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,26 @@ extension TaskPriority: Comparable {
273273
}
274274
}
275275

276+
277+
@available(SwiftStdlib 5.9, *)
278+
extension TaskPriority: CustomStringConvertible {
279+
@available(SwiftStdlib 5.9, *)
280+
public var description: String {
281+
switch self.rawValue {
282+
case Self.low.rawValue:
283+
return "\(Self.self).low"
284+
case Self.medium.rawValue:
285+
return "\(Self.self).medium"
286+
case Self.high.rawValue:
287+
return "\(Self.self).high"
288+
case Self.background.rawValue:
289+
return "\(Self.self).background"
290+
default:
291+
return "\(Self.self)(rawValue: \(self.rawValue))"
292+
}
293+
}
294+
}
295+
276296
@available(SwiftStdlib 5.1, *)
277297
extension TaskPriority: Codable { }
278298

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library) | %FileCheck %s
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: executable_test
5+
// UNSUPPORTED: freestanding
6+
7+
// UNSUPPORTED: back_deployment_runtime
8+
// REQUIRES: concurrency_runtime
9+
10+
final class InlineExecutor: SerialExecutor {
11+
public func enqueue(_ job: UnownedJob) {
12+
print("\(self): enqueue (priority: \(TaskPriority(job.priority)!))")
13+
job._runSynchronously(on: self.asUnownedSerialExecutor())
14+
}
15+
16+
public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
17+
return UnownedSerialExecutor(ordinary: self)
18+
}
19+
}
20+
21+
let inlineExecutor = InlineExecutor()
22+
23+
actor Custom {
24+
var count = 0
25+
26+
@available(SwiftStdlib 5.1, *)
27+
nonisolated var unownedExecutor: UnownedSerialExecutor {
28+
print("custom unownedExecutor")
29+
return inlineExecutor.asUnownedSerialExecutor()
30+
}
31+
32+
func report() async {
33+
print("custom.count == \(count)")
34+
count += 1
35+
}
36+
}
37+
38+
@available(SwiftStdlib 5.1, *)
39+
@main struct Main {
40+
static func main() async {
41+
print("begin")
42+
let actor = Custom()
43+
await Task(priority: .high) {
44+
await actor.report()
45+
}.value
46+
await Task() {
47+
await actor.report()
48+
}.value
49+
print("end")
50+
}
51+
}
52+
53+
// CHECK: begin
54+
// CHECK-NEXT: custom unownedExecutor
55+
// CHECK-NEXT: main.InlineExecutor: enqueue (priority: TaskPriority.high)
56+
// CHECK-NEXT: custom.count == 0
57+
// CHECK-NEXT: custom unownedExecutor
58+
// CHECK-NEXT: main.InlineExecutor: enqueue (priority: TaskPriority.medium)
59+
// CHECK-NEXT: custom.count == 1
60+
// CHECK-NEXT: end

0 commit comments

Comments
 (0)