Skip to content

Commit 96e965a

Browse files
committed
[Concurrency] Use dispatch cooperative queues when available.
These queues are better suited to the concurrency runtime.
1 parent af276b7 commit 96e965a

File tree

4 files changed

+37
-4
lines changed

4 files changed

+37
-4
lines changed

include/swift/Runtime/EnvironmentVariables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ extern swift::once_t initializeToken;
3636
}
3737
#include "../../../stdlib/public/runtime/EnvironmentVariables.def"
3838

39+
// Wrapper around SWIFT_DEBUG_CONCURRENCY_ENABLE_COOPERATIVE_QUEUES that the
40+
// Concurrency library can call.
41+
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableCooperativeQueues();
42+
3943
// Wrapper around SWIFT_ENABLE_ASYNC_JOB_DISPATCH_INTEGRATION that the
4044
// Concurrency library can call.
4145
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableJobDispatchIntegration();

stdlib/public/Concurrency/DispatchGlobalExecutor.inc

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ static constexpr size_t globalQueueCacheCount =
111111
static_cast<size_t>(JobPriority::UserInteractive) + 1;
112112
static std::atomic<dispatch_queue_t> globalQueueCache[globalQueueCacheCount];
113113

114+
static constexpr size_t dispatchQueueCooperativeFlag = 4;
115+
114116
#if defined(SWIFT_CONCURRENCY_BACK_DEPLOYMENT) || !defined(__APPLE__)
115117
extern "C" void dispatch_queue_set_width(dispatch_queue_t dq, long width);
116118
#endif
@@ -153,8 +155,14 @@ static dispatch_queue_t getGlobalQueue(JobPriority priority) {
153155
// If we don't have a queue cached for this priority, cache it now. This may
154156
// race with other threads doing this at the same time for this priority, but
155157
// that's OK, they'll all end up writing the same value.
156-
queue = dispatch_get_global_queue((dispatch_qos_class_t)priority,
157-
/*flags*/ 0);
158+
if (runtime::environment::concurrencyEnableCooperativeQueues())
159+
queue = dispatch_get_global_queue((dispatch_qos_class_t)priority,
160+
dispatchQueueCooperativeFlag);
161+
// If dispatch doesn't support dispatchQueueCooperativeFlag, it will return
162+
// NULL. Fall back to a standard global queue.
163+
if (!queue)
164+
queue = dispatch_get_global_queue((dispatch_qos_class_t)priority,
165+
/*flags*/ 0);
158166

159167
// Unconditionally store it back in the cache. If we raced with another
160168
// thread, we'll just overwrite the entry with the same value.
@@ -164,6 +172,18 @@ static dispatch_queue_t getGlobalQueue(JobPriority priority) {
164172
return queue;
165173
}
166174

175+
// Get a queue suitable for dispatch_after. Use the cooperative queues on OS
176+
// versions where they work with dispatch_after, and use a standard global
177+
// queue where cooperative queues don't work.
178+
static dispatch_queue_t getTimerQueue(JobPriority priority) {
179+
// On newer OSes, we can use the cooperative queues.
180+
if (__builtin_available(macOS 12.3, iOS 15.4, tvOS 15.4, watchOS 8.5, *))
181+
return getGlobalQueue(priority);
182+
183+
// On older OSes, use a standard global queue.
184+
return dispatch_get_global_queue((dispatch_qos_class_t)priority, /*flags*/ 0);
185+
}
186+
167187
SWIFT_CC(swift)
168188
static void swift_task_enqueueGlobalImpl(Job *job) {
169189
assert(job && "no job provided");
@@ -216,7 +236,7 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
216236

217237
JobPriority priority = job->getPriority();
218238

219-
auto queue = getGlobalQueue(priority);
239+
auto queue = getTimerQueue(priority);
220240

221241
job->SchedulerPrivate[Job::DispatchQueueIndex] =
222242
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
@@ -306,7 +326,7 @@ static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
306326

307327
JobPriority priority = job->getPriority();
308328

309-
auto queue = getGlobalQueue(priority);
329+
auto queue = getTimerQueue(priority);
310330

311331
job->SchedulerPrivate[Job::DispatchQueueIndex] =
312332
DISPATCH_QUEUE_GLOBAL_EXECUTOR;

stdlib/public/runtime/EnvironmentVariables.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ bool swift_COWChecksEnabled() {
242242
return runtime::environment::SWIFT_DEBUG_ENABLE_COW_CHECKS();
243243
}
244244

245+
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableCooperativeQueues() {
246+
return runtime::environment::
247+
SWIFT_DEBUG_CONCURRENCY_ENABLE_COOPERATIVE_QUEUES();
248+
}
249+
250+
245251
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableJobDispatchIntegration() {
246252
return runtime::environment::
247253
SWIFT_ENABLE_ASYNC_JOB_DISPATCH_INTEGRATION();

stdlib/public/runtime/EnvironmentVariables.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ VARIABLE(SWIFT_DEBUG_ENABLE_SHARED_CACHE_PROTOCOL_CONFORMANCES, bool, true,
6565

6666
#endif
6767

68+
VARIABLE(SWIFT_DEBUG_CONCURRENCY_ENABLE_COOPERATIVE_QUEUES, bool, true,
69+
"Enable dispatch cooperative queues in the global executor.")
70+
6871
#ifndef NDEBUG
6972

7073
VARIABLE(SWIFT_DEBUG_RUNTIME_EXCLUSIVITY_LOGGING, bool, false,

0 commit comments

Comments
 (0)