Skip to content

Commit 6287e33

Browse files
committed
move AG and SCNG into native __thread storage, replay of #22231
1 parent a437eab commit 6287e33

9 files changed

Lines changed: 87 additions & 35 deletions

File tree

TSRM/TSRM.c

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ typedef struct {
4141
ts_allocate_ctor ctor;
4242
ts_allocate_dtor dtor;
4343
ptrdiff_t fast_offset;
44+
/* When set, storage comes from __thread memory instead of being allocated by TSRM. */
45+
void *(*tls_addr)(void);
4446
int done;
4547
} tsrm_resource_type;
4648

@@ -164,14 +166,20 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
164166

165167
static void ts_free_resources(tsrm_tls_entry *thread_resources)
166168
{
169+
bool own_thread = thread_resources->thread_id == tsrm_thread_id();
170+
167171
/* Need to destroy in reverse order to respect dependencies. */
168172
for (int i = thread_resources->count - 1; i >= 0; i--) {
169173
if (!resource_types_table[i].done) {
174+
/* A __thread block of a foreign thread is inaccessible. */
175+
if (resource_types_table[i].tls_addr && !own_thread) {
176+
continue;
177+
}
170178
if (resource_types_table[i].dtor) {
171179
resource_types_table[i].dtor(thread_resources->storage[i]);
172180
}
173181

174-
if (!resource_types_table[i].fast_offset) {
182+
if (!resource_types_table[i].fast_offset && !resource_types_table[i].tls_addr) {
175183
free(thread_resources->storage[i]);
176184
}
177185
}
@@ -258,7 +266,10 @@ static void tsrm_update_active_threads(void)
258266

259267
p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
260268
for (j=p->count; j<id_count; j++) {
261-
if (resource_types_table[j].fast_offset) {
269+
if (resource_types_table[j].tls_addr) {
270+
TSRM_ASSERT(p->thread_id == tsrm_thread_id());
271+
p->storage[j] = resource_types_table[j].tls_addr();
272+
} else if (resource_types_table[j].fast_offset) {
262273
p->storage[j] = (void *) (((char*)p) + resource_types_table[j].fast_offset);
263274
} else {
264275
p->storage[j] = (void *) malloc(resource_types_table[j].size);
@@ -303,6 +314,7 @@ TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate
303314
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
304315
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
305316
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0;
317+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = NULL;
306318
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
307319

308320
tsrm_update_active_threads();
@@ -381,6 +393,7 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
381393
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
382394
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
383395
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = *offset;
396+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = NULL;
384397
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
385398

386399
tsrm_update_active_threads();
@@ -390,6 +403,41 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset,
390403
return *rsrc_id;
391404
}
392405

406+
/* allocates a resource id whose per-thread storage is a native __thread block */
407+
TSRM_API ts_rsrc_id ts_allocate_tls_id(ts_rsrc_id *rsrc_id, void *(*tls_addr)(void), size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
408+
{
409+
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new TLS resource id, %d bytes", size));
410+
411+
tsrm_mutex_lock(tsmm_mutex);
412+
413+
*rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
414+
415+
if (resource_types_table_size < id_count) {
416+
tsrm_resource_type *_tmp;
417+
_tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
418+
if (!_tmp) {
419+
TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
420+
*rsrc_id = 0;
421+
tsrm_mutex_unlock(tsmm_mutex);
422+
return 0;
423+
}
424+
resource_types_table = _tmp;
425+
resource_types_table_size = id_count;
426+
}
427+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
428+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
429+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
430+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0;
431+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].tls_addr = tls_addr;
432+
resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
433+
434+
tsrm_update_active_threads();
435+
tsrm_mutex_unlock(tsmm_mutex);
436+
437+
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new TLS resource id %d", *rsrc_id));
438+
return *rsrc_id;
439+
}
440+
393441
static void set_thread_local_storage_resource_to(tsrm_tls_entry *thread_resource)
394442
{
395443
tsrm_tls_set(thread_resource);
@@ -422,7 +470,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
422470
if (resource_types_table[i].done) {
423471
(*thread_resources_ptr)->storage[i] = NULL;
424472
} else {
425-
if (resource_types_table[i].fast_offset) {
473+
if (resource_types_table[i].tls_addr) {
474+
(*thread_resources_ptr)->storage[i] = resource_types_table[i].tls_addr();
475+
} else if (resource_types_table[i].fast_offset) {
426476
(*thread_resources_ptr)->storage[i] = (void *) (((char*)(*thread_resources_ptr)) + resource_types_table[i].fast_offset);
427477
} else {
428478
(*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
@@ -510,7 +560,9 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
510560
/* In case that extensions don't use the pointer passed from the dtor, but incorrectly
511561
* use the global pointer, we need to setup the global pointer temporarily here. */
512562
set_thread_local_storage_resource_to(thread_resources);
513-
/* Free up the old resource from the old thread instance */
563+
/* Dead thread with a recycled id: its __thread blocks are gone, and this
564+
* thread's blocks were never constructed, so keep tls dtors from running. */
565+
thread_resources->thread_id = 0;
514566
ts_free_resources(thread_resources);
515567
free((char *) thread_resources - tsrm_reserved_front);
516568
/* Allocate a new resource at the same point in the linked list, and relink the next pointer */
@@ -584,7 +636,7 @@ void ts_free_id(ts_rsrc_id id)
584636
if (resource_types_table[rsrc_id].dtor) {
585637
resource_types_table[rsrc_id].dtor(p->storage[rsrc_id]);
586638
}
587-
if (!resource_types_table[rsrc_id].fast_offset) {
639+
if (!resource_types_table[rsrc_id].fast_offset && !resource_types_table[rsrc_id].tls_addr) {
588640
free(p->storage[rsrc_id]);
589641
}
590642
}

TSRM/TSRM.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, siz
100100
TSRM_API void tsrm_reserve_fast_front(size_t size);
101101
TSRM_API ts_rsrc_id ts_allocate_fast_id_at(ts_rsrc_id *rsrc_id, size_t *offset, ptrdiff_t fixed_offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
102102

103+
/* Resource whose per-thread storage is a native __thread block.
104+
* Must be called at startup before any other thread exists. */
105+
TSRM_API ts_rsrc_id ts_allocate_tls_id(ts_rsrc_id *rsrc_id, void *(*tls_addr)(void), size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
106+
103107
/* fetches the requested resource for the current thread */
104108
TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id);
105109
#define ts_resource(id) ts_resource_ex(id, NULL)

Zend/zend.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ ZEND_API int compiler_globals_id;
5454
ZEND_API int executor_globals_id;
5555
ZEND_API size_t compiler_globals_offset;
5656
ZEND_API size_t executor_globals_offset;
57+
/* ts_allocate_tls_id takes a callback so each thread resolves its own block.
58+
* A plain &language_scanner_globals would capture only the registering thread's address. */
59+
static void *language_scanner_globals_tls_addr(void) { return &language_scanner_globals; }
5760
static HashTable *global_function_table = NULL;
5861
static HashTable *global_class_table = NULL;
5962
static HashTable *global_constants_table = NULL;
@@ -1021,10 +1024,9 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
10211024
#ifdef ZTS
10221025
ts_allocate_fast_id_at(&compiler_globals_id, &compiler_globals_offset, ZEND_CG_OFFSET, sizeof(zend_compiler_globals), (ts_allocate_ctor) compiler_globals_ctor, (ts_allocate_dtor) compiler_globals_dtor);
10231026
ts_allocate_fast_id_at(&executor_globals_id, &executor_globals_offset, ZEND_EG_OFFSET, sizeof(zend_executor_globals), (ts_allocate_ctor) executor_globals_ctor, (ts_allocate_dtor) executor_globals_dtor);
1024-
ts_allocate_fast_id_at(&language_scanner_globals_id, &language_scanner_globals_offset, ZEND_SCNG_OFFSET, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL);
1027+
ts_allocate_tls_id(&language_scanner_globals_id, language_scanner_globals_tls_addr, sizeof(zend_php_scanner_globals), (ts_allocate_ctor) php_scanner_globals_ctor, NULL);
10251028
ZEND_ASSERT(compiler_globals_offset == ZEND_CG_OFFSET);
10261029
ZEND_ASSERT(executor_globals_offset == ZEND_EG_OFFSET);
1027-
ZEND_ASSERT(language_scanner_globals_offset == ZEND_SCNG_OFFSET);
10281030
ts_allocate_fast_id(&ini_scanner_globals_id, &ini_scanner_globals_offset, sizeof(zend_ini_scanner_globals), (ts_allocate_ctor) ini_scanner_globals_ctor, NULL);
10291031
compiler_globals = ts_resource(compiler_globals_id);
10301032
executor_globals = ts_resource(executor_globals_id);

Zend/zend_alloc.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,13 +2613,12 @@ typedef struct _zend_alloc_globals {
26132613

26142614
#ifdef ZTS
26152615
static int alloc_globals_id;
2616-
static size_t alloc_globals_offset;
2617-
# define ZEND_AG_OFFSET (ZEND_SCNG_OFFSET - (ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_alloc_globals)))
2618-
# define AG(v) ZEND_TSRMG_FAST(ZEND_AG_OFFSET, zend_alloc_globals *, v)
2616+
static TSRM_TLS TSRM_TLS_MODEL_ATTR zend_alloc_globals alloc_globals;
2617+
static void *alloc_globals_tls_addr(void) { return &alloc_globals; }
26192618
#else
2620-
# define AG(v) (alloc_globals.v)
26212619
static zend_alloc_globals alloc_globals;
26222620
#endif
2621+
#define AG(v) (alloc_globals.v)
26232622

26242623
ZEND_API bool is_zend_mm(void)
26252624
{
@@ -3336,8 +3335,7 @@ ZEND_API void start_memory_manager(void)
33363335
# endif
33373336
#endif
33383337
#ifdef ZTS
3339-
ts_allocate_fast_id_at(&alloc_globals_id, &alloc_globals_offset, ZEND_AG_OFFSET, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
3340-
ZEND_ASSERT(alloc_globals_offset == ZEND_AG_OFFSET);
3338+
ts_allocate_tls_id(&alloc_globals_id, alloc_globals_tls_addr, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
33413339
#else
33423340
alloc_globals_ctor(&alloc_globals);
33433341
#endif
@@ -3583,9 +3581,3 @@ ZEND_API char * __zend_strdup(const char *s)
35833581
zend_out_of_memory();
35843582
}
35853583

3586-
#ifdef ZTS
3587-
size_t zend_mm_globals_size(void)
3588-
{
3589-
return sizeof(zend_alloc_globals);
3590-
}
3591-
#endif

Zend/zend_alloc.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,6 @@ static void apc_init_heap(void)
403403
404404
*/
405405

406-
#ifdef ZTS
407-
size_t zend_mm_globals_size(void);
408-
#endif
409-
410406
END_EXTERN_C()
411407

412408
#endif

Zend/zend_globals.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,9 @@ struct _zend_executor_globals {
330330
};
331331

332332
#ifdef ZTS
333-
/* Compile-time offsets of the hot globals, in a reserved region just before the
334-
* cache pointer. ZEND_AG_OFFSET is furthest, in zend_alloc.c. */
333+
/* Compile-time offsets of the hot globals, in a reserved region just before *_tsrm_ls_cache. */
335334
# define ZEND_CG_OFFSET (-(ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)))
336335
# define ZEND_EG_OFFSET (ZEND_CG_OFFSET - (ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)))
337-
# define ZEND_SCNG_OFFSET (ZEND_EG_OFFSET - (ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_php_scanner_globals)))
338336
#endif
339337

340338
#define EG_FLAGS_INITIAL (0)

Zend/zend_globals_macros.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,20 @@ extern ZEND_API zend_executor_globals executor_globals;
4848

4949
/* Language Scanner */
5050
#ifdef ZTS
51-
# define LANG_SCNG(v) ZEND_TSRMG_FAST(ZEND_SCNG_OFFSET, zend_php_scanner_globals *, v)
5251
extern ZEND_API ts_rsrc_id language_scanner_globals_id;
53-
extern ZEND_API size_t language_scanner_globals_offset;
52+
# if defined(ZEND_WIN32) && !defined(LIBZEND_EXPORTS)
53+
# define LANG_SCNG(v) TSRMG(language_scanner_globals_id, zend_php_scanner_globals *, v)
54+
# else
55+
# ifdef ZEND_WIN32
56+
extern TSRM_TLS zend_php_scanner_globals language_scanner_globals;
57+
# else
58+
extern ZEND_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_php_scanner_globals language_scanner_globals;
59+
# endif
60+
# define LANG_SCNG(v) (language_scanner_globals.v)
61+
# endif
5462
#else
55-
# define LANG_SCNG(v) (language_scanner_globals.v)
5663
extern ZEND_API zend_php_scanner_globals language_scanner_globals;
64+
# define LANG_SCNG(v) (language_scanner_globals.v)
5765
#endif
5866

5967

Zend/zend_language_scanner.l

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@
8484
#define SCNG LANG_SCNG
8585
#ifdef ZTS
8686
ZEND_API ts_rsrc_id language_scanner_globals_id;
87-
ZEND_API size_t language_scanner_globals_offset;
87+
# ifdef ZEND_WIN32
88+
TSRM_TLS zend_php_scanner_globals language_scanner_globals;
89+
# else
90+
ZEND_API TSRM_TLS TSRM_TLS_MODEL_ATTR zend_php_scanner_globals language_scanner_globals;
91+
# endif
8892
#else
8993
ZEND_API zend_php_scanner_globals language_scanner_globals;
9094
#endif

main/main.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,13 +2819,11 @@ PHPAPI void php_reserve_tsrm_memory(void)
28192819
tsrm_reserve(
28202820
TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
28212821
TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)) +
2822-
TSRM_ALIGNED_SIZE(sizeof(zend_php_scanner_globals)) +
28232822
TSRM_ALIGNED_SIZE(sizeof(zend_ini_scanner_globals)) +
28242823
TSRM_ALIGNED_SIZE(sizeof(virtual_cwd_globals)) +
28252824
#ifdef ZEND_SIGNALS
28262825
TSRM_ALIGNED_SIZE(sizeof(zend_signal_globals_t)) +
28272826
#endif
2828-
TSRM_ALIGNED_SIZE(zend_mm_globals_size()) +
28292827
TSRM_ALIGNED_SIZE(zend_gc_globals_size()) +
28302828
TSRM_ALIGNED_SIZE(sizeof(php_core_globals)) +
28312829
TSRM_ALIGNED_SIZE(sizeof(sapi_globals_struct)) +
@@ -2845,9 +2843,7 @@ PHPAPI bool php_tsrm_startup_ex(int expected_threads)
28452843
/* Must cover the total size of every ZEND_*_OFFSET global, or the furthest underflows the block. */
28462844
tsrm_reserve_fast_front(
28472845
TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)) +
2848-
TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)) +
2849-
TSRM_ALIGNED_SIZE(sizeof(zend_php_scanner_globals)) +
2850-
TSRM_ALIGNED_SIZE(zend_mm_globals_size())); // AG size, exposed through function call
2846+
TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)));
28512847
(void)ts_resource(0);
28522848
return ret;
28532849
}

0 commit comments

Comments
 (0)