Hello all,
Following the earlier discussion with @felipepiovezan in the Multicore Concurrency thread and his follow-up on swiftlang/swift#91047, I wanted to split Embedded Swift debugger support into a dedicated discussion.
The original question was how LLDB can determine which Swift task is executing on each thread. Since then, the Embedded Concurrency implementation has changed in a way that makes the question more general.
Embedded now builds Concurrency against the Embedded Threading backend. The runtime’s reserved TLS entries, including the current ActiveTask, go through Swift’s ThreadLocalStorage abstraction and ultimately through the swift_tls* platform hooks. The concrete storage behind those hooks is selected by the EmbeddedPlatform implementation linked into the final program.
That implementation might use:
- native pthread thread-specific storage
- dynamically allocated pthread keys
- RTOS-provided task-local storage
- a fixed per-core table
- a single global slot for a single-threaded system
or a completely unknown platform-specific alternative.
This creates a mismatch with the current debug ABI. _swift_concurrency_debug_internal_layout_version includes a _concurrency_current_task_storage_kind, which tells LLDB how the runtime stores the current task. The enum already recognizes that there are several possible storage strategies, but the Embedded Concurrency library cannot fully determine that strategy when it is built. It only knows that it will call the platform abstraction; the concrete representation is selected later at link time.
I think it is useful to separate this into two problems:
What is an execution context?
On a hosted platform this is usually an OS thread already represented by LLDB. On embedded targets it might instead be an RTOS task, a CPU core, or the only execution context in a single-threaded program. Some platforms may therefore require debugger or debug-server support before Swift can even answer questions about tasks.
Given an execution context, where is its current Swift task pointer?
Once LLDB has an appropriate thread or execution-context representation, it needs a fast and passive way to locate the corresponding ActiveTask storage.
In our earlier discussion, I suggested letting LLDB call a runtime or platform accessor. Felipe pointed out an important constraint:
This mapping of Threads -> Task has to be fast. It happens on every single stop [...] This is particularly important when communication between the debugger and the target is slower than local.
That makes an inferior call through _swift_tls_get unattractive as the general solution. It would require executing target code in the context of each thread, could perturb target state, and may not be available on bare-metal or remote targets.
Pausing here, hope this provides enough context to start a conversation.
Cheers.