Skip to content

Commit 1dd8a0e

Browse files
authored
Merge pull request swiftlang#38709 from DougGregor/actor-scheduling-without-priorities
Actor scheduling without priorities
2 parents 1e6b758 + cd81a50 commit 1dd8a0e

File tree

8 files changed

+34
-33
lines changed

8 files changed

+34
-33
lines changed

stdlib/public/Concurrency/Actor.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,8 +1050,7 @@ static void wakeOverrides(ProcessOverrideJob *nextOverride,
10501050
nextOverride = cur->NextJob.getAsPreprocessedOverride();
10511051

10521052
if (hasAlreadyActivated ||
1053-
!targetPriority ||
1054-
cur->getPriority() != *targetPriority)
1053+
!targetPriority)
10551054
cur->wakeAndAbandon();
10561055
else
10571056
hasAlreadyActivated = cur->wakeAndActivate();
@@ -1214,8 +1213,7 @@ void DefaultActorImpl::giveUpThread(RunningJobInfo runner) {
12141213
}
12151214

12161215
bool hasMoreJobs = (bool) newState.FirstJob;
1217-
bool hasOverrideAtNewPriority =
1218-
(runner.Priority < oldState.Flags.getMaxPriority());
1216+
bool hasOverrideAtNewPriority = false;
12191217
bool hasActiveInlineJob = newState.Flags.hasActiveInlineJob();
12201218
bool needsNewProcessJob = hasMoreJobs && !hasOverrideAtNewPriority;
12211219

@@ -1316,8 +1314,7 @@ Job *DefaultActorImpl::claimNextJobOrGiveUp(bool actorIsOwned,
13161314

13171315
// If the actor is out of work, or its priority doesn't match our
13181316
// priority, don't try to take over the actor.
1319-
if (!oldState.FirstJob ||
1320-
oldState.Flags.getMaxPriority() != runner.Priority) {
1317+
if (!oldState.FirstJob) {
13211318

13221319
// The only change we need here is inline-runner bookkeeping.
13231320
if (!tryUpdateForInlineRunner())
@@ -1399,8 +1396,7 @@ Job *DefaultActorImpl::claimNextJobOrGiveUp(bool actorIsOwned,
13991396
// FIXME: should this be an exact match in priority instead of
14001397
// potentially running jobs with too high a priority?
14011398
Job *jobToRun;
1402-
if (oldState.Flags.getMaxPriority() <= runner.Priority &&
1403-
newFirstJob) {
1399+
if (newFirstJob) {
14041400
jobToRun = newFirstJob;
14051401
newState.FirstJob = getNextJobInQueue(newFirstJob);
14061402
newState.Flags.setStatus(Status::Running);
@@ -1646,7 +1642,7 @@ void DefaultActorImpl::enqueue(Job *job) {
16461642

16471643
// If we need an override job, create it (if necessary) and
16481644
// register it with the queue.
1649-
bool needsOverride = !wasIdle && newPriority != oldPriority;
1645+
bool needsOverride = false;
16501646
if (needsOverride) {
16511647
overrideJob.addToState(this, newState);
16521648
} else {

stdlib/public/Concurrency/Task.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -496,15 +496,18 @@ static AsyncTaskAndContext swift_task_create_commonImpl(
496496

497497
if (currentTask)
498498
jobFlags.setPriority(currentTask->getPriority());
499-
else
500-
// FIXME: Ideally, this should be setting priority based on
501-
// swift_task_getCurrentThreadPriority(). However, that creates
502-
// priority differences which lead to different kinds of hangs
503-
// Temporarily use Unspecified to work around that.
504-
// See also: PR #37939.
505-
jobFlags.setPriority(JobPriority::Unspecified);
499+
else if (taskCreateFlags.inheritContext())
500+
jobFlags.setPriority(swift_task_getCurrentThreadPriority());
506501
}
507502

503+
// Adjust user-interactive priorities down to user-initiated.
504+
if (jobFlags.getPriority() == JobPriority::UserInteractive)
505+
jobFlags.setPriority(JobPriority::UserInitiated);
506+
507+
// If there is still no job priority, use the default priority.
508+
if (jobFlags.getPriority() == JobPriority::Unspecified)
509+
jobFlags.setPriority(JobPriority::Default);
510+
508511
// Figure out the size of the header.
509512
size_t headerSize = sizeof(AsyncTask);
510513
if (parent) {

stdlib/public/Concurrency/Task.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ extension Task where Success == Never, Failure == Never {
269269
}
270270

271271
// Otherwise, query the system.
272-
return TaskPriority(rawValue: UInt8(0))
272+
return TaskPriority(rawValue: UInt8(_getCurrentThreadPriority()))
273273
}
274274
}
275275
}
@@ -632,11 +632,10 @@ extension Task where Success == Never, Failure == Never {
632632
/// As such,
633633
/// this method isn't necessarily a way to avoid resource starvation.
634634
public static func yield() async {
635-
let currentTask = Builtin.getCurrentAsyncTask()
636-
let priority = getJobFlags(currentTask).priority ?? Task.currentPriority._downgradeUserInteractive
637-
638635
return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in
639-
let job = _taskCreateNullaryContinuationJob(priority: Int(priority.rawValue), continuation: continuation)
636+
let job = _taskCreateNullaryContinuationJob(
637+
priority: Int(Task.currentPriority.rawValue),
638+
continuation: continuation)
640639
_enqueueJobGlobal(job)
641640
}
642641
}
@@ -708,7 +707,8 @@ public struct UnsafeCurrentTask {
708707
/// - SeeAlso: `TaskPriority`
709708
/// - SeeAlso: `Task.currentPriority`
710709
public var priority: TaskPriority {
711-
getJobFlags(_task).priority ?? .unspecified
710+
getJobFlags(_task).priority ?? TaskPriority(
711+
rawValue: UInt8(_getCurrentThreadPriority()))
712712
}
713713

714714
/// Cancel the current task.

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ class alignas(sizeof(void*) * 2) ActiveTaskStatus {
236236
ActiveTaskStatus withEscalatedPriority(JobPriority priority) const {
237237
assert(priority > getStoredPriority());
238238
return ActiveTaskStatus(Record,
239-
(Flags & PriorityMask)
239+
(Flags & ~PriorityMask)
240240
| IsEscalated | uintptr_t(priority));
241241
}
242242
ActiveTaskStatus withoutStoredPriorityEscalation() const {

stdlib/public/Concurrency/TaskSleep.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@ extension Task where Success == Never, Failure == Never {
1919
///
2020
/// This function does _not_ block the underlying thread.
2121
public static func sleep(_ duration: UInt64) async {
22-
let currentTask = Builtin.getCurrentAsyncTask()
23-
let priority = getJobFlags(currentTask).priority ?? Task.currentPriority._downgradeUserInteractive
24-
2522
return await Builtin.withUnsafeContinuation { (continuation: Builtin.RawUnsafeContinuation) -> Void in
26-
let job = _taskCreateNullaryContinuationJob(priority: Int(priority.rawValue), continuation: continuation)
23+
let job = _taskCreateNullaryContinuationJob(
24+
priority: Int(Task.currentPriority.rawValue),
25+
continuation: continuation)
2726
_enqueueJobGlobalWithDelay(duration, job)
2827
}
2928
}

test/Concurrency/Runtime/actor_counters.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ actor Counter {
3636
}
3737
}
3838

39+
// Produce a random priority.
40+
nonisolated var randomPriority: TaskPriority? {
41+
let priorities: [TaskPriority?] = [ .background, .low, .medium, .high, nil ]
42+
return priorities.randomElement()!
43+
}
3944

4045
@available(SwiftStdlib 5.5, *)
4146
func worker(identity: Int, counters: [Counter], numIterations: Int) async {
@@ -59,8 +64,8 @@ func runTest(numCounters: Int, numWorkers: Int, numIterations: Int) async {
5964
var workers: [Task.Handle<Void, Error>] = []
6065
for i in 0..<numWorkers {
6166
workers.append(
62-
detach { [counters] in
63-
await Task.sleep(UInt64.random(in: 0..<100) * 1_000_000)
67+
Task.detached(priority: randomPriority) { [counters] in
68+
await try! Task.sleep(nanoseconds: UInt64.random(in: 0..<100) * 1_000_000)
6469
await worker(identity: i, counters: counters, numIterations: numIterations)
6570
}
6671
)

test/Concurrency/Runtime/async.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// REQUIRES: rdar79670222
21
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch)
32

43
// REQUIRES: executable_test
54
// REQUIRES: concurrency
65
// REQUIRES: libdispatch
76

8-
// rdar://76038845
97
// UNSUPPORTED: use_os_stdlib
108

119
import Dispatch

test/Concurrency/Runtime/async_task_priority_current.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Dispatch
1313
@available(SwiftStdlib 5.5, *)
1414
func test_detach() async {
1515
let a1 = Task.currentPriority
16-
print("a1: \(a1)") // CHECK: TaskPriority(rawValue: 0)
16+
print("a1: \(a1)") // CHECK: TaskPriority(rawValue: 21)
1717

1818
// Note: remember to detach using a higher priority, otherwise a lower one
1919
// might be escalated by the get() and we could see `default` in the detached
@@ -24,7 +24,7 @@ func test_detach() async {
2424
}.get()
2525

2626
let a3 = Task.currentPriority
27-
print("a3: \(a3)") // CHECK: a3: TaskPriority(rawValue: 0)
27+
print("a3: \(a3)") // CHECK: a3: TaskPriority(rawValue: 21)
2828
}
2929

3030
@available(SwiftStdlib 5.5, *)

0 commit comments

Comments
 (0)