Skip to content

Commit 8612b23

Browse files
add gc and shutdown callbacks
1 parent 7c32704 commit 8612b23

12 files changed

+322
-20
lines changed

Zend/zend_alloc.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ struct _zend_mm_heap {
334334
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
335335
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
336336
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
337+
size_t (*_gc)(void);
338+
void (*_shutdown)(bool full, bool silent);
337339
} custom_heap;
338340
HashTable *tracked_allocs;
339341
#endif
@@ -2119,6 +2121,10 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
21192121

21202122
#if ZEND_MM_CUSTOM
21212123
if (heap->use_custom_heap) {
2124+
size_t (*gc)(void) = heap->custom_heap._gc;
2125+
if (gc) {
2126+
return gc();
2127+
}
21222128
return 0;
21232129
}
21242130
#endif
@@ -2421,10 +2427,10 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
24212427

24222428
#if ZEND_MM_CUSTOM
24232429
static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
2424-
static void tracked_free_all(void);
2430+
static void tracked_free_all(zend_mm_heap *heap);
24252431
#endif
24262432

2427-
void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2433+
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24282434
{
24292435
zend_mm_chunk *p;
24302436
zend_mm_huge_list *list;
@@ -2433,7 +2439,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24332439
if (heap->use_custom_heap) {
24342440
if (heap->custom_heap._malloc == tracked_malloc) {
24352441
if (silent) {
2436-
tracked_free_all();
2442+
tracked_free_all(heap);
24372443
}
24382444
zend_hash_clean(heap->tracked_allocs);
24392445
if (full) {
@@ -2445,9 +2451,16 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24452451
heap->size = 0;
24462452
}
24472453

2454+
void (*shutdown)(bool, bool) = heap->custom_heap._shutdown;
2455+
24482456
if (full) {
24492457
heap->custom_heap._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
24502458
}
2459+
2460+
if (shutdown) {
2461+
shutdown(full, silent);
2462+
}
2463+
24512464
return;
24522465
}
24532466
#endif
@@ -3039,8 +3052,8 @@ static void *tracked_realloc(void *ptr, size_t new_size ZEND_FILE_LINE_DC ZEND_F
30393052
return ptr;
30403053
}
30413054

3042-
static void tracked_free_all(void) {
3043-
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
3055+
static void tracked_free_all(zend_mm_heap *heap) {
3056+
HashTable *tracked_allocs = heap->tracked_allocs;
30443057
zend_ulong h;
30453058
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
30463059
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
@@ -3124,6 +3137,16 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void)
31243137
return AG(mm_heap);
31253138
}
31263139

3140+
ZEND_API zend_mm_heap *zend_mm_heap_create(void)
3141+
{
3142+
return zend_mm_init();
3143+
}
3144+
3145+
ZEND_API void zend_mm_heap_free(zend_mm_heap *heap)
3146+
{
3147+
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
3148+
}
3149+
31273150
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
31283151
{
31293152
#if ZEND_MM_CUSTOM
@@ -3136,7 +3159,9 @@ ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
31363159
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31373160
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
31383161
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3139-
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
3162+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3163+
size_t (*_gc)(void),
3164+
void (*_shutdown)(bool, bool))
31403165
{
31413166
#if ZEND_MM_CUSTOM
31423167
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3148,14 +3173,18 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31483173
_heap->custom_heap._malloc = _malloc;
31493174
_heap->custom_heap._free = _free;
31503175
_heap->custom_heap._realloc = _realloc;
3176+
_heap->custom_heap._gc = _gc;
3177+
_heap->custom_heap._shutdown = _shutdown;
31513178
}
31523179
#endif
31533180
}
31543181

31553182
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
31563183
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
31573184
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3158-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
3185+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3186+
size_t (**_gc)(void),
3187+
void (**_shutdown)(bool, bool))
31593188
{
31603189
#if ZEND_MM_CUSTOM
31613190
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3164,15 +3193,29 @@ ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
31643193
*_malloc = _heap->custom_heap._malloc;
31653194
*_free = _heap->custom_heap._free;
31663195
*_realloc = _heap->custom_heap._realloc;
3196+
if (_gc != NULL) {
3197+
*_gc = _heap->custom_heap._gc;
3198+
}
3199+
if (_shutdown != NULL) {
3200+
*_shutdown = _heap->custom_heap._shutdown;
3201+
}
31673202
} else {
31683203
*_malloc = NULL;
31693204
*_free = NULL;
31703205
*_realloc = NULL;
3206+
if (_gc != NULL) {
3207+
*_gc = NULL;
3208+
}
3209+
if (_shutdown != NULL) {
3210+
*_shutdown = NULL;
3211+
}
31713212
}
31723213
#else
31733214
*_malloc = NULL;
31743215
*_free = NULL;
31753216
*_realloc = NULL;
3217+
*_gc = NULL;
3218+
*_shutdown = NULL;
31763219
#endif
31773220
}
31783221

Zend/zend_alloc.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ ZEND_API size_t ZEND_FASTCALL _zend_mm_block_size(zend_mm_heap *heap, void *p ZE
263263
#define zend_mm_realloc2_rel(heap, p, size, copy_size) _zend_mm_realloc2((heap), (p), (size), (copy_size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC)
264264
#define zend_mm_block_size_rel(heap, p) _zend_mm_block_size((heap), (p) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
265265

266+
ZEND_API zend_mm_heap *zend_mm_heap_create(void);
267+
ZEND_API void zend_mm_heap_free(zend_mm_heap* heap);
266268
ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap);
267269
ZEND_API zend_mm_heap *zend_mm_get_heap(void);
268270

@@ -274,13 +276,17 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap);
274276

275277
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap);
276278
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
277-
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
278-
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
279-
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
279+
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
280+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
281+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
282+
size_t (*_gc)(void),
283+
void (*_shutdown)(bool, bool));
280284
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
281-
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
282-
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
283-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
285+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
286+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
287+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
288+
size_t (**_gc)(void),
289+
void (**_shutdown)(bool, bool));
284290

285291
typedef struct _zend_mm_storage zend_mm_storage;
286292

ext/zend_test/config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
44
[Enable zend_test extension])])
55

66
if test "$PHP_ZEND_TEST" != "no"; then
7-
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c object_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
7+
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c object_handlers.c zend_mm_custom_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
88
fi

ext/zend_test/config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
44

55
if (PHP_ZEND_TEST != "no") {
6-
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
6+
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c zend_mm_custom_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
77
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
88
}

ext/zend_test/php_test.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
6262
zend_long quantity_value;
6363
zend_string *str_test;
6464
zend_string *not_empty_str_test;
65+
int zend_mm_custom_handlers_enabled;
66+
67+
// the previous heap that was found in ZendMM
68+
zend_mm_heap* original_heap;
69+
// the custom handlers that might have been found in the previous heap
70+
void* (*custom_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
71+
void (*custom_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
72+
void* (*custom_realloc)(void *, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
73+
size_t (*custom_gc)(void);
74+
void (*custom_shutdown)(bool, bool);
75+
// this is our heap that we install our custom handlers on and inject into
76+
// ZendMM
77+
zend_mm_heap* observed_heap;
6578
ZEND_END_MODULE_GLOBALS(zend_test)
6679

6780
extern ZEND_DECLARE_MODULE_GLOBALS(zend_test)

ext/zend_test/test.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
+----------------------------------------------------------------------+
1515
*/
1616

17+
#include "zend_modules.h"
1718
#ifdef HAVE_CONFIG_H
1819
# include "config.h"
1920
#endif
@@ -35,6 +36,7 @@
3536
#include "test_arginfo.h"
3637
#include "zend_call_stack.h"
3738
#include "zend_exceptions.h"
39+
#include "zend_mm_custom_handlers.h"
3840

3941
// `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
4042
// assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
@@ -707,7 +709,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
707709
ZT_G(zend_test_heap),
708710
zend_test_custom_malloc,
709711
zend_test_custom_free,
710-
zend_test_custom_realloc
712+
zend_test_custom_realloc,
713+
NULL,
714+
NULL
711715
);
712716
ZT_G(zend_orig_heap) = zend_mm_get_heap();
713717
zend_mm_set_heap(ZT_G(zend_test_heap));
@@ -1260,6 +1264,7 @@ PHP_MINIT_FUNCTION(zend_test)
12601264
}
12611265

12621266
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
1267+
zend_test_mm_custom_handlers_minit(INIT_FUNC_ARGS_PASSTHRU);
12631268
zend_test_fiber_init();
12641269
zend_test_iterators_init();
12651270
zend_test_object_handlers_init();
@@ -1288,6 +1293,7 @@ PHP_RINIT_FUNCTION(zend_test)
12881293
{
12891294
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
12901295
ZT_G(observer_nesting_depth) = 0;
1296+
zend_test_mm_custom_handlers_rinit();
12911297
return SUCCESS;
12921298
}
12931299

@@ -1305,6 +1311,7 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
13051311
zend_mm_set_heap(ZT_G(zend_orig_heap));
13061312
}
13071313

1314+
zend_test_mm_custom_handlers_rshutdown();
13081315
return SUCCESS;
13091316
}
13101317

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
8+
$string = str_repeat('String', rand(1,100));
9+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
10+
?>
11+
--EXPECTREGEX--
12+
.*Allocated \d+ bytes at.*
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
$string = str_repeat('String', rand(1,100));
8+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
9+
unset($string);
10+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
11+
?>
12+
--EXPECTREGEX--
13+
.*Freed memory at.*
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
ZendMM Custom Handlers: garbage collection
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 1);
8+
gc_mem_caches();
9+
ini_set('zend_test.zend_mm_custom_handlers.enabled', 0);
10+
?>
11+
--EXPECTREGEX--
12+
.*ZendMM GC freed \d+ bytes.*

0 commit comments

Comments
 (0)