@@ -111,6 +111,8 @@ static constexpr size_t globalQueueCacheCount =
111
111
static_cast <size_t >(JobPriority::UserInteractive) + 1;
112
112
static std::atomic<dispatch_queue_t > globalQueueCache[globalQueueCacheCount];
113
113
114
+ static constexpr size_t dispatchQueueCooperativeFlag = 4 ;
115
+
114
116
#if defined(SWIFT_CONCURRENCY_BACK_DEPLOYMENT) || !defined(__APPLE__)
115
117
extern " C" void dispatch_queue_set_width (dispatch_queue_t dq, long width);
116
118
#endif
@@ -153,8 +155,14 @@ static dispatch_queue_t getGlobalQueue(JobPriority priority) {
153
155
// If we don't have a queue cached for this priority, cache it now. This may
154
156
// race with other threads doing this at the same time for this priority, but
155
157
// 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 );
158
166
159
167
// Unconditionally store it back in the cache. If we raced with another
160
168
// thread, we'll just overwrite the entry with the same value.
@@ -164,6 +172,18 @@ static dispatch_queue_t getGlobalQueue(JobPriority priority) {
164
172
return queue;
165
173
}
166
174
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
+
167
187
SWIFT_CC (swift)
168
188
static void swift_task_enqueueGlobalImpl(Job *job) {
169
189
assert (job && " no job provided" );
@@ -216,7 +236,7 @@ static void swift_task_enqueueGlobalWithDelayImpl(JobDelay delay,
216
236
217
237
JobPriority priority = job->getPriority ();
218
238
219
- auto queue = getGlobalQueue (priority);
239
+ auto queue = getTimerQueue (priority);
220
240
221
241
job->SchedulerPrivate [Job::DispatchQueueIndex] =
222
242
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
@@ -306,7 +326,7 @@ static void swift_task_enqueueGlobalWithDeadlineImpl(long long sec,
306
326
307
327
JobPriority priority = job->getPriority ();
308
328
309
- auto queue = getGlobalQueue (priority);
329
+ auto queue = getTimerQueue (priority);
310
330
311
331
job->SchedulerPrivate [Job::DispatchQueueIndex] =
312
332
DISPATCH_QUEUE_GLOBAL_EXECUTOR;
0 commit comments