@@ -186,6 +186,33 @@ static void __swift_run_job_main_executor(void *_job) {
186
186
swift_job_run (job, ExecutorRef::mainExecutor ());
187
187
}
188
188
189
+ static constexpr size_t globalQueueCacheCount =
190
+ static_cast <size_t >(JobPriority::UserInteractive) + 1 ;
191
+ static std::atomic<dispatch_queue_t > globalQueueCache[globalQueueCacheCount];
192
+
193
+ static dispatch_queue_t getGlobalQueue (JobPriority priority) {
194
+ size_t numericPriority = static_cast <size_t >(priority);
195
+ if (numericPriority >= globalQueueCacheCount)
196
+ fatalError (0 , " invalid job priority %#zx" );
197
+
198
+ auto *ptr = &globalQueueCache[numericPriority];
199
+ auto queue = ptr->load (std::memory_order_relaxed);
200
+ if (SWIFT_LIKELY (queue))
201
+ return queue;
202
+
203
+ // If we don't have a queue cached for this priority, cache it now. This may
204
+ // race with other threads doing this at the same time for this priority, but
205
+ // that's OK, they'll all end up writing the same value.
206
+ queue = dispatch_get_global_queue ((dispatch_qos_class_t )priority,
207
+ /* flags*/ 0 );
208
+
209
+ // Unconditionally store it back in the cache. If we raced with another
210
+ // thread, we'll just overwrite the entry with the same value.
211
+ ptr->store (queue, std::memory_order_relaxed);
212
+
213
+ return queue;
214
+ }
215
+
189
216
#endif
190
217
191
218
void swift::swift_task_enqueueGlobal (Job *job) {
@@ -232,9 +259,7 @@ void swift::swift_task_enqueueGlobal(Job *job) {
232
259
233
260
JobPriority priority = job->getPriority ();
234
261
235
- // TODO: cache this to avoid the extra call
236
- auto queue = dispatch_get_global_queue ((dispatch_qos_class_t ) priority,
237
- /* flags*/ 0 );
262
+ auto queue = getGlobalQueue (priority);
238
263
239
264
dispatch_async_f (queue, dispatchContext, dispatchFunction);
240
265
#endif
@@ -256,9 +281,8 @@ void swift::swift_task_enqueueGlobalWithDelay(unsigned long long delay, Job *job
256
281
257
282
JobPriority priority = job->getPriority ();
258
283
259
- // TODO: cache this to avoid the extra call
260
- auto queue = dispatch_get_global_queue ((dispatch_qos_class_t ) priority,
261
- /* flags*/ 0 );
284
+ auto queue = getGlobalQueue (priority);
285
+
262
286
dispatch_time_t when = dispatch_time (DISPATCH_TIME_NOW, delay);
263
287
dispatch_after_f (when, queue, dispatchContext, dispatchFunction);
264
288
#endif
@@ -277,7 +301,7 @@ void swift::swift_task_enqueueMainExecutor(Job *job) {
277
301
dispatch_function_t dispatchFunction = &__swift_run_job_main_executor;
278
302
void *dispatchContext = job;
279
303
280
- // TODO: cache this to avoid the extra call
304
+ // This is an inline function that compiles down to a pointer to a global.
281
305
auto mainQueue = dispatch_get_main_queue ();
282
306
283
307
dispatch_async_f (mainQueue, dispatchContext, dispatchFunction);
0 commit comments