Skip to content

Commit d476664

Browse files
add gc and shutdown callbacks
1 parent 14873dd commit d476664

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
@@ -272,6 +272,8 @@ struct _zend_mm_heap {
272272
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
273273
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
274274
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
275+
size_t (*_gc)(void);
276+
void (*_shutdown)(bool full, bool silent);
275277
} custom_heap;
276278
HashTable *tracked_allocs;
277279
#endif
@@ -1961,6 +1963,10 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
19611963

19621964
#if ZEND_MM_CUSTOM
19631965
if (heap->use_custom_heap) {
1966+
size_t (*gc)(void) = heap->custom_heap._gc;
1967+
if (gc) {
1968+
return gc();
1969+
}
19641970
return 0;
19651971
}
19661972
#endif
@@ -2255,10 +2261,10 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
22552261

22562262
#if ZEND_MM_CUSTOM
22572263
static void *tracked_malloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
2258-
static void tracked_free_all(void);
2264+
static void tracked_free_all(zend_mm_heap *heap);
22592265
#endif
22602266

2261-
void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2267+
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22622268
{
22632269
zend_mm_chunk *p;
22642270
zend_mm_huge_list *list;
@@ -2267,7 +2273,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22672273
if (heap->use_custom_heap) {
22682274
if (heap->custom_heap._malloc == tracked_malloc) {
22692275
if (silent) {
2270-
tracked_free_all();
2276+
tracked_free_all(heap);
22712277
}
22722278
zend_hash_clean(heap->tracked_allocs);
22732279
if (full) {
@@ -2279,9 +2285,16 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22792285
heap->size = 0;
22802286
}
22812287

2288+
void (*shutdown)(bool, bool) = heap->custom_heap._shutdown;
2289+
22822290
if (full) {
22832291
heap->custom_heap._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
22842292
}
2293+
2294+
if (shutdown) {
2295+
shutdown(full, silent);
2296+
}
2297+
22852298
return;
22862299
}
22872300
#endif
@@ -2854,8 +2867,8 @@ static void *tracked_realloc(void *ptr, size_t new_size ZEND_FILE_LINE_DC ZEND_F
28542867
return ptr;
28552868
}
28562869

2857-
static void tracked_free_all(void) {
2858-
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
2870+
static void tracked_free_all(zend_mm_heap *heap) {
2871+
HashTable *tracked_allocs = heap->tracked_allocs;
28592872
zend_ulong h;
28602873
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
28612874
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
@@ -2939,6 +2952,16 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void)
29392952
return AG(mm_heap);
29402953
}
29412954

2955+
ZEND_API zend_mm_heap *zend_mm_heap_create(void)
2956+
{
2957+
return zend_mm_init();
2958+
}
2959+
2960+
ZEND_API void zend_mm_heap_free(zend_mm_heap *heap)
2961+
{
2962+
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
2963+
}
2964+
29422965
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29432966
{
29442967
#if ZEND_MM_CUSTOM
@@ -2951,7 +2974,9 @@ ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29512974
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
29522975
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
29532976
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
2954-
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
2977+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
2978+
size_t (*_gc)(void),
2979+
void (*_shutdown)(bool, bool))
29552980
{
29562981
#if ZEND_MM_CUSTOM
29572982
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -2963,14 +2988,18 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
29632988
_heap->custom_heap._malloc = _malloc;
29642989
_heap->custom_heap._free = _free;
29652990
_heap->custom_heap._realloc = _realloc;
2991+
_heap->custom_heap._gc = _gc;
2992+
_heap->custom_heap._shutdown = _shutdown;
29662993
}
29672994
#endif
29682995
}
29692996

29702997
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
29712998
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
29722999
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
2973-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC))
3000+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
3001+
size_t (**_gc)(void),
3002+
void (**_shutdown)(bool, bool))
29743003
{
29753004
#if ZEND_MM_CUSTOM
29763005
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -2979,15 +3008,29 @@ ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
29793008
*_malloc = _heap->custom_heap._malloc;
29803009
*_free = _heap->custom_heap._free;
29813010
*_realloc = _heap->custom_heap._realloc;
3011+
if (_gc != NULL) {
3012+
*_gc = _heap->custom_heap._gc;
3013+
}
3014+
if (_shutdown != NULL) {
3015+
*_shutdown = _heap->custom_heap._shutdown;
3016+
}
29823017
} else {
29833018
*_malloc = NULL;
29843019
*_free = NULL;
29853020
*_realloc = NULL;
3021+
if (_gc != NULL) {
3022+
*_gc = NULL;
3023+
}
3024+
if (_shutdown != NULL) {
3025+
*_shutdown = NULL;
3026+
}
29863027
}
29873028
#else
29883029
*_malloc = NULL;
29893030
*_free = NULL;
29903031
*_realloc = NULL;
3032+
*_gc = NULL;
3033+
*_shutdown = NULL;
29913034
#endif
29923035
}
29933036

Zend/zend_alloc.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ ZEND_API size_t ZEND_FASTCALL _zend_mm_block_size(zend_mm_heap *heap, void *p ZE
262262
#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)
263263
#define zend_mm_block_size_rel(heap, p) _zend_mm_block_size((heap), (p) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
264264

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

@@ -273,13 +275,17 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap);
273275

274276
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap);
275277
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
276-
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
277-
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
278-
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
278+
void* (*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
279+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
280+
void* (*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
281+
size_t (*_gc)(void),
282+
void (*_shutdown)(bool, bool));
279283
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
280-
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
281-
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
282-
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC));
284+
void* (**_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
285+
void (**_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
286+
void* (**_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC),
287+
size_t (**_gc)(void),
288+
void (**_shutdown)(bool, bool));
283289

284290
typedef struct _zend_mm_storage zend_mm_storage;
285291

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
@@ -684,7 +686,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
684686
ZT_G(zend_test_heap),
685687
zend_test_custom_malloc,
686688
zend_test_custom_free,
687-
zend_test_custom_realloc
689+
zend_test_custom_realloc,
690+
NULL,
691+
NULL
688692
);
689693
ZT_G(zend_orig_heap) = zend_mm_get_heap();
690694
zend_mm_set_heap(ZT_G(zend_test_heap));
@@ -1193,6 +1197,7 @@ PHP_MINIT_FUNCTION(zend_test)
11931197
}
11941198

11951199
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
1200+
zend_test_mm_custom_handlers_minit(INIT_FUNC_ARGS_PASSTHRU);
11961201
zend_test_fiber_init();
11971202
zend_test_iterators_init();
11981203
zend_test_object_handlers_init();
@@ -1221,6 +1226,7 @@ PHP_RINIT_FUNCTION(zend_test)
12211226
{
12221227
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
12231228
ZT_G(observer_nesting_depth) = 0;
1229+
zend_test_mm_custom_handlers_rinit();
12241230
return SUCCESS;
12251231
}
12261232

@@ -1238,6 +1244,7 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
12381244
zend_mm_set_heap(ZT_G(zend_orig_heap));
12391245
}
12401246

1247+
zend_test_mm_custom_handlers_rshutdown();
12411248
return SUCCESS;
12421249
}
12431250

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)