My thinking is that we would extend this header to cover the entire set of potential platform dependencies for Embedded Swift. That way, to bring up Embedded Swift on any given platform, you would go through and implement each function from that one header, and you'd be done.
Yes, this definitely sounds like the right direction, not just for threading but for all platform-dependent code. I’m glad this experiment aligns with that direction!
For your pull request, that means I'd prefer the contents of ThreadDeferImpl.h to go into the EmbeddedPlatform.h where we document each entrypoint clearly for folks doing the porting. What do you think of that direction?
That makes sense. I’ve updated the PR in that direction: the hook surface now lives in `EmbeddedPlatform.h`, using `_swift_*` names, and `ThreadEmbeddedImpl.h` is just the adapter from Swift’s internal threading abstraction to those platform hooks
I debated this for the header I was working on, and took a bit of a different direction. I added an EmbeddedPlatformPOSIX library that folks could link in to implement the header definitions in terms of the same underlying POSIX functions we've already required (e.g., posix_memalign, putchar) to make it easier to make the move. For concurrency, we'd likely want different "single threaded" and "multi-threaded" implementations with different implementations on top of POSIX. I'm not opposed to providing weak definitions, but I wonder if being explicit is better for folks, so long as it is very well documented what they need to do.
That's really nice! Let me play this back to make sure I’m interpreting the model correctly.
Today, the Swift threading package is effectively selected as a build-time choice for the stdlib/runtime. For Embedded, the direction would be to move more of that decision to link time through the selected EmbeddedPlatform implementation. For example, there could be multiple implementations of the same EmbeddedPlatform.h hook surface:
- a single-threaded implementation
- a multithreaded POSIX/pthreads implementation
- possibly target-specific implementations provided by board/platform packages
The consumer would choose which implementation to link, and the Swift libraries would just depend on the documented _swift_* platform hooks. For convenience, the toolchain could provide a conservative single-threaded implementation, while platforms that need multicore scheduling would link a stronger/threaded implementation.
Is that the shape you have in mind?
If so, I can take a look at how to materialize this in the PR. One possible approach would be to provide multiple EmbeddedPlatform implementation libraries with the same library name and the same hook surface, but different behavior, for example single-threaded and POSIX-threaded variants. Then the consumer could select the implementation by putting the desired library earlier in the linker search path, or provide its own same-named implementation library. Does that match the model you’re thinking of?
Do we actually need the swift_threading_defer_lazy_mutex_* and swift_threading_defer_recursive_mutex_* entrypoints for the concurrency library? We shouldn't be using recursive mutexes, for sure.
void *swift_threading_defer_tls_get(uintptr_t key);
void swift_threading_defer_tls_set(uintptr_t key, void *value);
I kept the recursive and lazy mutex hooks because they preserve the current Threading contract. I agree we should reduce the required surface over time, especially if Concurrency should not rely on recursive mutexes, but as it does rely on them at the moment I think removing those assumptions could be a separate cleanup. In the meantime, single-threaded/default implementations can make those hooks cheap aliases, while platforms that need to honor the full current contract still can.
For TLS, I also moved toward making allocation explicit rather than treating it as optional, because the existing abstraction does have dynamic TLS keys. The embedded implementation can still reserve fixed keys for known runtime/stdlib uses, but if the abstraction exposes dynamic allocation, the platform layer should probably model that directly.
This is an excellent direction for Embedded Swift, let's refine it and get it landed!
Thank you for taking the time to review this, and for all the context and insight! I can take another pass over the PR once we’re aligned on the specifics.