How is the Cooperative Thread Pool integrated in Swift?

Hey everyone! I'm trying to learn more about how async/await's executors work in practice in Swift, and I'm struggling a bit to locate where and how exactly an executor's jobs are executed.

I understand from this post from John that the actual job execution mechanism / thread pool is implemented in libdispatch and is currently closed source, but I'm assuming that the eventual call to libdispatch is originating from the Swift runtime itself and that we can see it happening. I'm trying to find out where exactly this call happens.

By investigating the DefaultActor serial executor specifically I was able to trace the enqueueing logic all the way to swift_task_enqueueGlobal and swift_task_enqueueGlobalImpl, but I've hit a dead-end after that. Is what I'm looking for perhaps the hooks declared in GlobalExecutor.cpp? Or maybe I'm looking at the completely wrong place?

In other words, would someone be nice enough to give me an ELI5 of how Swift's executors and the actual thread pool are wired together, with some code pointers if possible? :blush:

Thanks in advance!

6 Likes

If you look at GlobalExecutor.cpp, you’ll see that we only pick the “cooperative” implementation when configured for it, which is not the default. The cooperative executor is a simple implementation that relies on the user donating a thread to the runtime. The primary implementation is in DispatchGlobalExecutor.inc.

2 Likes

Thanks John! Would it be correct to say then that what Apple calls "cooperative thread pool" and what Swift calls "cooperative global executor" are two entirely different things? With the former being a new feature of libdispatch that we use in DispatchGlobalExecutor.inc in order to build a libdispatch-based global executor, and the latter being a simpler alternative for platforms that can't/don't want to use the former?

1 Like

Yes, I think that’s a fair way of putting it.

2 Likes

Well, let me slightly amend that. Swift’s cooperative global executor is an alternative implementation available for targets that don’t want to use Dispatch at all, and which may or may not have general-purpose threads available. Dispatch is available on a number of targets, not just Apple’s; on Apple OSes, the Dispatch implementation is quite sophisticated (and even integrated with the kernel), and it behaves slightly differently (in a more “cooperative” way) for Swift jobs that it does for uses of e.g. dispatch_async.

4 Likes