Use GCD instead of Detached Thread in Async Resolver when on MacOS/iOS

The advantage is that GCD maintains the internal thread pool and
spawns threads when needed. I would expect the behavior to be
almost identical to creating a thread using PlatformThread.

Bug: webrtc:13237
Change-Id: Ie4406b5d128c244f66a73830d5a27f2d8fd88549
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/234300
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Commit-Queue: Byoungchan Lee <daniel.l@hpcnt.com>
Cr-Commit-Position: refs/heads/main@{#35165}
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index 8fb8193..d9fe93e 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -542,7 +542,10 @@
 
 if (is_mac || is_ios) {
   rtc_library("rtc_task_queue_gcd") {
-    visibility = [ "../api/task_queue:default_task_queue_factory" ]
+    visibility = [
+      ":threading",
+      "../api/task_queue:default_task_queue_factory",
+    ]
     sources = [
       "task_queue_gcd.cc",
       "task_queue_gcd.h",
@@ -832,7 +835,10 @@
     deps += [ ":win32" ]
   }
   if (is_mac || is_ios) {
-    deps += [ "system:cocoa_threading" ]
+    deps += [
+      ":rtc_task_queue_gcd",
+      "system:cocoa_threading",
+    ]
   }
 }
 
diff --git a/rtc_base/async_resolver.cc b/rtc_base/async_resolver.cc
index 75efce5..231e4fa 100644
--- a/rtc_base/async_resolver.cc
+++ b/rtc_base/async_resolver.cc
@@ -40,6 +40,10 @@
 #include "rtc_base/task_utils/to_queued_task.h"
 #include "rtc_base/third_party/sigslot/sigslot.h"  // for signal_with_thread...
 
+#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+#include "rtc_base/task_queue_gcd.h"
+#endif
+
 namespace rtc {
 
 int ResolveHostname(const std::string& hostname,
@@ -123,7 +127,7 @@
   RTC_DCHECK_RUN_ON(&sequence_checker_);
   RTC_DCHECK(!destroy_called_);
   addr_ = addr;
-  PlatformThread::SpawnDetached(
+  auto thread_function =
       [this, addr, caller_task_queue = webrtc::TaskQueueBase::Current(),
        state = state_] {
         std::vector<IPAddress> addresses;
@@ -146,8 +150,13 @@
                 }
               }));
         }
-      },
-      "AsyncResolver");
+      };
+#if defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
+  webrtc::PostTaskToGlobalQueue(
+      webrtc::ToQueuedTask(std::move(thread_function)));
+#else
+  PlatformThread::SpawnDetached(std::move(thread_function), "AsyncResolver");
+#endif
 }
 
 bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const {
diff --git a/rtc_base/task_queue_gcd.cc b/rtc_base/task_queue_gcd.cc
index 2276f63..aefc207 100644
--- a/rtc_base/task_queue_gcd.cc
+++ b/rtc_base/task_queue_gcd.cc
@@ -145,10 +145,24 @@
   }
 };
 
+// static
+void GlobalGcdRunTask(void* context) {
+  std::unique_ptr<QueuedTask> task(static_cast<QueuedTask*>(context));
+  task->Run();
+}
+
 }  // namespace
 
 std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory() {
   return std::make_unique<TaskQueueGcdFactory>();
 }
 
+void PostTaskToGlobalQueue(std::unique_ptr<QueuedTask> task,
+                           TaskQueueFactory::Priority priority) {
+  dispatch_queue_global_t global_queue =
+      dispatch_get_global_queue(TaskQueuePriorityToGCD(priority), 0);
+  QueuedTask* context = task.release();
+  dispatch_async_f(global_queue, context, &GlobalGcdRunTask);
+}
+
 }  // namespace webrtc
diff --git a/rtc_base/task_queue_gcd.h b/rtc_base/task_queue_gcd.h
index dc6039e..898c2a3 100644
--- a/rtc_base/task_queue_gcd.h
+++ b/rtc_base/task_queue_gcd.h
@@ -19,6 +19,11 @@
 
 std::unique_ptr<TaskQueueFactory> CreateTaskQueueGcdFactory();
 
+// Post a task into the system-defined global concurrent queue.
+void PostTaskToGlobalQueue(
+    std::unique_ptr<QueuedTask> task,
+    TaskQueueFactory::Priority priority = TaskQueueFactory::Priority::NORMAL);
+
 }  // namespace webrtc
 
 #endif  // RTC_BASE_TASK_QUEUE_GCD_H_