[RFC] Embedding multiple PHP engines in a single thread

php.internals

Unnamed Person

4 years ago
Hello internals, As you know, the PHP codebase makes heavy use of global variables. In ZTS builds, access to these globals are cleverly mapped to thread local storage via macros. To my knowledge, the limitation here is that there's no way to run multiple PHP engines in a single thread. (Please let me know if I'm missing something.) Naturally this is an extremely slim corner case. It would however unlock some interesting things like user-land zend_extensions and SAPIs without spawning threads needlessly. It would also enable one to build a coroutine-based SAPI[1]. I'm curious if there's been any previous discussion around this, or if anyone has general feedback before I take a shot at this. My rough idea is to modify TSRM to support multiple `tsrm_tls_entry.storage` per thread, keyed by some caller-supplied id. Currently a thread-safe resource is accessed like `thread[thread_id].storage[resource_id]`. In my idea it would be `thread[thread_id].storage[storage_id][resource_id]` with some API function to push/pop `storage_id`. Any thoughts on that approach? Support for non-ZTS builds would be rad but would require much larger code changes. Feedback appreciated. Thank you, Adam [1] for example, to call into PHP concurrently from Go's green-threads (which may share a single OS thread)

Nikita Popov

4 years ago
On Tue, Feb 1, 2022 at 3:36 AM <as@php.net> wrote:
> Hello internals, > > As you know, the PHP codebase makes heavy use of global variables. In ZTS > builds, access to these globals are cleverly mapped to thread local storage > via macros. To my knowledge, the limitation here is that there's no way to > run multiple PHP engines in a single thread. (Please let me know if I'm > missing something.) > > Naturally this is an extremely slim corner case. It would however unlock > some interesting things like user-land zend_extensions and SAPIs without > spawning threads needlessly. It would also enable one to build a > coroutine-based SAPI[1]. > > I'm curious if there's been any previous discussion around this, or if > anyone has general feedback before I take a shot at this. > > My rough idea is to modify TSRM to support multiple > `tsrm_tls_entry.storage` per thread, keyed by some caller-supplied id. > Currently a thread-safe resource is accessed like > `thread[thread_id].storage[resource_id]`. In my idea it would be > `thread[thread_id].storage[storage_id][resource_id]` with some API function > to push/pop `storage_id`. Any thoughts on that approach? > > Support for non-ZTS builds would be rad but would require much larger code > changes. > > Feedback appreciated. > > Thank you, > > Adam > > [1] for example, to call into PHP concurrently from Go's green-threads > (which may share a single OS thread) >
In places we also use real thread-local storage (ZEND_TLS) -- actually, this is the preferred method to manage global state if it is possible. Nowadays TSRM exists essentially only to work around deficiencies in cross-DLL TLS support on Windows. I don't think your scheme could extend to those cases. I'm not really convinced that it's worthwhile to invest effort in this directly. Regards, Nikita