For this week’s challenge, we’ll be looking at macros from a couple decades ago. They’re from the source code of PHP 4, more specific its thread-safe resource management module.
When PHP was compiled to operate in a multi-thread environment, the macros are defined as follows:
#define TSRMLS_D void ***tsrm_ls
#define TSRMLS_DC , TSRMLS_D
#define TSRMLS_C tsrm_ls
#define TSRMLS_CC , TSRMLS_C
The “D” macros are used in function declaration, while the “C” macros are used in function calls.
When PHP was compiled for single-thread operation, the macros resolve to basically nothing:
#define TSRMLS_D void
#define TSRMLS_DC
#define TSRMLS_C
#define TSRMLS_CC
tsrm_ls
points to the thread’s local storage. It’s passed from function to function so that when some of them need to access this or that global structure, they wouldn’t need to query the operation system and thereby incurring a performance hit.
The following is a macro used to access the interpreter’s core settings:
#ifdef ZTS
# define PG(v) TSRMG(core_globals_id, php_core_globals *, v)
#else
# define PG(v) (core_globals.v)
#endif
As you can see, when thread-safety is off, it’s simply a reference to a field of a global struct. The address is known at comptime. Accessing the field requires zero indirection.
When thread-safety is on, the followng macros are used:
#define TSRM_UNSHUFFLE_RSRC_ID(rsrc_id) ((rsrc_id)-1)
/* ... */
#define TSRMG(id, type, element) (((type) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)
If I’m reading the code right, there’re two indirections.
How would we deal with the same scenario in Zig? What strategy should be employed to maximize performance for both configurations?