Skip to content

Commit 07fe9e1

Browse files
add gc and shutdown callbacks
1 parent fd47cd8 commit 07fe9e1

12 files changed

+323
-20
lines changed

Zend/zend_alloc.c

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,15 @@ struct _zend_mm_heap {
273273
void *(*_malloc)(size_t);
274274
void (*_free)(void*);
275275
void *(*_realloc)(void*, size_t);
276+
size_t (*_gc)(void);
277+
void (*_shutdown)(bool full, bool silent);
276278
} std;
277279
struct {
278280
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
279281
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
280282
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
283+
size_t (*_gc)(void);
284+
void (*_shutdown)(bool full, bool silent);
281285
} debug;
282286
} custom_heap;
283287
HashTable *tracked_allocs;
@@ -1968,6 +1972,10 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
19681972

19691973
#if ZEND_MM_CUSTOM
19701974
if (heap->use_custom_heap) {
1975+
size_t (*gc)(void) = heap->custom_heap.std._gc;
1976+
if (gc) {
1977+
return gc();
1978+
}
19711979
return 0;
19721980
}
19731981
#endif
@@ -2262,10 +2270,10 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
22622270

22632271
#if ZEND_MM_CUSTOM
22642272
static void *tracked_malloc(size_t size);
2265-
static void tracked_free_all(void);
2273+
static void tracked_free_all(zend_mm_heap *heap);
22662274
#endif
22672275

2268-
void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2276+
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22692277
{
22702278
zend_mm_chunk *p;
22712279
zend_mm_huge_list *list;
@@ -2274,7 +2282,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22742282
if (heap->use_custom_heap) {
22752283
if (heap->custom_heap.std._malloc == tracked_malloc) {
22762284
if (silent) {
2277-
tracked_free_all();
2285+
tracked_free_all(heap);
22782286
}
22792287
zend_hash_clean(heap->tracked_allocs);
22802288
if (full) {
@@ -2286,13 +2294,20 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22862294
heap->size = 0;
22872295
}
22882296

2297+
void (*shutdown)(bool, bool) = heap->custom_heap.std._shutdown;
2298+
22892299
if (full) {
22902300
if (ZEND_DEBUG && heap->use_custom_heap == ZEND_MM_CUSTOM_HEAP_DEBUG) {
22912301
heap->custom_heap.debug._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
22922302
} else {
22932303
heap->custom_heap.std._free(heap);
22942304
}
22952305
}
2306+
2307+
if (shutdown) {
2308+
shutdown(full, silent);
2309+
}
2310+
22962311
return;
22972312
}
22982313
#endif
@@ -2895,8 +2910,8 @@ static void *tracked_realloc(void *ptr, size_t new_size) {
28952910
return ptr;
28962911
}
28972912

2898-
static void tracked_free_all(void) {
2899-
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
2913+
static void tracked_free_all(zend_mm_heap *heap) {
2914+
HashTable *tracked_allocs = heap->tracked_allocs;
29002915
zend_ulong h;
29012916
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
29022917
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
@@ -2980,6 +2995,16 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void)
29802995
return AG(mm_heap);
29812996
}
29822997

2998+
ZEND_API zend_mm_heap *zend_mm_heap_create(void)
2999+
{
3000+
return zend_mm_init();
3001+
}
3002+
3003+
ZEND_API void zend_mm_heap_free(zend_mm_heap *heap)
3004+
{
3005+
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
3006+
}
3007+
29833008
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29843009
{
29853010
#if ZEND_MM_CUSTOM
@@ -2990,9 +3015,11 @@ ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29903015
}
29913016

29923017
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
2993-
void* (*_malloc)(size_t),
2994-
void (*_free)(void*),
2995-
void* (*_realloc)(void*, size_t))
3018+
void* (*_malloc)(size_t),
3019+
void (*_free)(void*),
3020+
void* (*_realloc)(void*, size_t),
3021+
size_t (*_gc)(void),
3022+
void (*_shutdown)(bool, bool))
29963023
{
29973024
#if ZEND_MM_CUSTOM
29983025
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3004,14 +3031,18 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
30043031
_heap->custom_heap.std._malloc = _malloc;
30053032
_heap->custom_heap.std._free = _free;
30063033
_heap->custom_heap.std._realloc = _realloc;
3034+
_heap->custom_heap.std._gc = _gc;
3035+
_heap->custom_heap.std._shutdown = _shutdown;
30073036
}
30083037
#endif
30093038
}
30103039

30113040
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
3012-
void* (**_malloc)(size_t),
3013-
void (**_free)(void*),
3014-
void* (**_realloc)(void*, size_t))
3041+
void* (**_malloc)(size_t),
3042+
void (**_free)(void*),
3043+
void* (**_realloc)(void*, size_t),
3044+
size_t (**_gc)(void),
3045+
void (**_shutdown)(bool, bool))
30153046
{
30163047
#if ZEND_MM_CUSTOM
30173048
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3020,15 +3051,29 @@ ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
30203051
*_malloc = _heap->custom_heap.std._malloc;
30213052
*_free = _heap->custom_heap.std._free;
30223053
*_realloc = _heap->custom_heap.std._realloc;
3054+
if (_gc != NULL) {
3055+
*_gc = _heap->custom_heap.std._gc;
3056+
}
3057+
if (_shutdown != NULL) {
3058+
*_shutdown = _heap->custom_heap.std._shutdown;
3059+
}
30233060
} else {
30243061
*_malloc = NULL;
30253062
*_free = NULL;
30263063
*_realloc = NULL;
3064+
if (_gc != NULL) {
3065+
*_gc = NULL;
3066+
}
3067+
if (_shutdown != NULL) {
3068+
*_shutdown = NULL;
3069+
}
30273070
}
30283071
#else
30293072
*_malloc = NULL;
30303073
*_free = NULL;
30313074
*_realloc = NULL;
3075+
*_gc = NULL;
3076+
*_shutdown = NULL;
30323077
#endif
30333078
}
30343079

Zend/zend_alloc.h

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

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

@@ -274,11 +276,15 @@ ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap);
274276
ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
275277
void* (*_malloc)(size_t),
276278
void (*_free)(void*),
277-
void* (*_realloc)(void*, size_t));
279+
void* (*_realloc)(void*, size_t),
280+
size_t (*gc)(void),
281+
void (*shutdown)(bool full, bool silent));
278282
ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
279283
void* (**_malloc)(size_t),
280284
void (**_free)(void*),
281-
void* (**_realloc)(void*, size_t));
285+
void* (**_realloc)(void*, size_t),
286+
size_t (**gc)(void),
287+
void (**shutdown)(bool full, bool silent));
282288

283289
#if ZEND_DEBUG
284290
ZEND_API void zend_mm_set_custom_debug_handlers(zend_mm_heap *heap,

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);
71+
void (*custom_free)(void*);
72+
void* (*custom_realloc)(void *, size_t);
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
@@ -682,7 +684,9 @@ static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
682684
ZT_G(zend_test_heap),
683685
zend_test_custom_malloc,
684686
zend_test_custom_free,
685-
zend_test_custom_realloc
687+
zend_test_custom_realloc,
688+
NULL,
689+
NULL
686690
);
687691
ZT_G(zend_orig_heap) = zend_mm_get_heap();
688692
zend_mm_set_heap(ZT_G(zend_test_heap));
@@ -1189,6 +1193,7 @@ PHP_MINIT_FUNCTION(zend_test)
11891193
}
11901194

11911195
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
1196+
zend_test_mm_custom_handlers_minit(INIT_FUNC_ARGS_PASSTHRU);
11921197
zend_test_fiber_init();
11931198
zend_test_iterators_init();
11941199
zend_test_object_handlers_init();
@@ -1217,6 +1222,7 @@ PHP_RINIT_FUNCTION(zend_test)
12171222
{
12181223
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
12191224
ZT_G(observer_nesting_depth) = 0;
1225+
zend_test_mm_custom_handlers_rinit();
12201226
return SUCCESS;
12211227
}
12221228

@@ -1234,6 +1240,7 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
12341240
zend_mm_set_heap(ZT_G(zend_orig_heap));
12351241
}
12361242

1243+
zend_test_mm_custom_handlers_rshutdown();
12371244
return SUCCESS;
12381245
}
12391246

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)