Skip to content

Commit fdf1e73

Browse files
add gc and shutdown callbacks
1 parent fd47cd8 commit fdf1e73

12 files changed

+324
-20
lines changed

Zend/zend_alloc.c

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "zend_multiply.h"
5959
#include "zend_bitset.h"
6060
#include "zend_mmap.h"
61+
#include "zend_portability.h"
6162
#include <signal.h>
6263

6364
#ifdef HAVE_UNISTD_H
@@ -273,11 +274,15 @@ struct _zend_mm_heap {
273274
void *(*_malloc)(size_t);
274275
void (*_free)(void*);
275276
void *(*_realloc)(void*, size_t);
277+
size_t (*_gc)(void);
278+
void (*_shutdown)(bool full, bool silent);
276279
} std;
277280
struct {
278281
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
279282
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
280283
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
284+
size_t (*_gc)(void);
285+
void (*_shutdown)(bool full, bool silent);
281286
} debug;
282287
} custom_heap;
283288
HashTable *tracked_allocs;
@@ -1968,6 +1973,10 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
19681973

19691974
#if ZEND_MM_CUSTOM
19701975
if (heap->use_custom_heap) {
1976+
size_t (*gc)(void) = heap->custom_heap.std._gc;
1977+
if (gc) {
1978+
return gc();
1979+
}
19711980
return 0;
19721981
}
19731982
#endif
@@ -2262,10 +2271,10 @@ static void zend_mm_check_leaks(zend_mm_heap *heap)
22622271

22632272
#if ZEND_MM_CUSTOM
22642273
static void *tracked_malloc(size_t size);
2265-
static void tracked_free_all(void);
2274+
static void tracked_free_all(zend_mm_heap *heap);
22662275
#endif
22672276

2268-
void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
2277+
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22692278
{
22702279
zend_mm_chunk *p;
22712280
zend_mm_huge_list *list;
@@ -2274,7 +2283,7 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22742283
if (heap->use_custom_heap) {
22752284
if (heap->custom_heap.std._malloc == tracked_malloc) {
22762285
if (silent) {
2277-
tracked_free_all();
2286+
tracked_free_all(heap);
22782287
}
22792288
zend_hash_clean(heap->tracked_allocs);
22802289
if (full) {
@@ -2286,13 +2295,20 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
22862295
heap->size = 0;
22872296
}
22882297

2298+
void (*shutdown)(bool, bool) = heap->custom_heap.std._shutdown;
2299+
22892300
if (full) {
22902301
if (ZEND_DEBUG && heap->use_custom_heap == ZEND_MM_CUSTOM_HEAP_DEBUG) {
22912302
heap->custom_heap.debug._free(heap ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
22922303
} else {
22932304
heap->custom_heap.std._free(heap);
22942305
}
22952306
}
2307+
2308+
if (shutdown) {
2309+
shutdown(full, silent);
2310+
}
2311+
22962312
return;
22972313
}
22982314
#endif
@@ -2895,8 +2911,8 @@ static void *tracked_realloc(void *ptr, size_t new_size) {
28952911
return ptr;
28962912
}
28972913

2898-
static void tracked_free_all(void) {
2899-
HashTable *tracked_allocs = AG(mm_heap)->tracked_allocs;
2914+
static void tracked_free_all(zend_mm_heap *heap) {
2915+
HashTable *tracked_allocs = heap->tracked_allocs;
29002916
zend_ulong h;
29012917
ZEND_HASH_FOREACH_NUM_KEY(tracked_allocs, h) {
29022918
void *ptr = (void *) (uintptr_t) (h << ZEND_MM_ALIGNMENT_LOG2);
@@ -2980,6 +2996,16 @@ ZEND_API zend_mm_heap *zend_mm_get_heap(void)
29802996
return AG(mm_heap);
29812997
}
29822998

2999+
ZEND_API zend_mm_heap *zend_mm_heap_create(void)
3000+
{
3001+
return zend_mm_init();
3002+
}
3003+
3004+
ZEND_API void zend_mm_heap_free(zend_mm_heap *heap)
3005+
{
3006+
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
3007+
}
3008+
29833009
ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29843010
{
29853011
#if ZEND_MM_CUSTOM
@@ -2990,9 +3016,11 @@ ZEND_API bool zend_mm_is_custom_heap(zend_mm_heap *new_heap)
29903016
}
29913017

29923018
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))
3019+
void* (*_malloc)(size_t),
3020+
void (*_free)(void*),
3021+
void* (*_realloc)(void*, size_t),
3022+
size_t (*_gc)(void),
3023+
void (*_shutdown)(bool, bool))
29963024
{
29973025
#if ZEND_MM_CUSTOM
29983026
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3004,14 +3032,18 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
30043032
_heap->custom_heap.std._malloc = _malloc;
30053033
_heap->custom_heap.std._free = _free;
30063034
_heap->custom_heap.std._realloc = _realloc;
3035+
_heap->custom_heap.std._gc = _gc;
3036+
_heap->custom_heap.std._shutdown = _shutdown;
30073037
}
30083038
#endif
30093039
}
30103040

30113041
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))
3042+
void* (**_malloc)(size_t),
3043+
void (**_free)(void*),
3044+
void* (**_realloc)(void*, size_t),
3045+
size_t (**_gc)(void),
3046+
void (**_shutdown)(bool, bool))
30153047
{
30163048
#if ZEND_MM_CUSTOM
30173049
zend_mm_heap *_heap = (zend_mm_heap*)heap;
@@ -3020,15 +3052,29 @@ ZEND_API void zend_mm_get_custom_handlers(zend_mm_heap *heap,
30203052
*_malloc = _heap->custom_heap.std._malloc;
30213053
*_free = _heap->custom_heap.std._free;
30223054
*_realloc = _heap->custom_heap.std._realloc;
3055+
if (_gc != NULL) {
3056+
*_gc = _heap->custom_heap.std._gc;
3057+
}
3058+
if (_shutdown != NULL) {
3059+
*_shutdown = _heap->custom_heap.std._shutdown;
3060+
}
30233061
} else {
30243062
*_malloc = NULL;
30253063
*_free = NULL;
30263064
*_realloc = NULL;
3065+
if (_gc != NULL) {
3066+
*_gc = NULL;
3067+
}
3068+
if (_shutdown != NULL) {
3069+
*_shutdown = NULL;
3070+
}
30273071
}
30283072
#else
30293073
*_malloc = NULL;
30303074
*_free = NULL;
30313075
*_realloc = NULL;
3076+
*_gc = NULL;
3077+
*_shutdown = NULL;
30323078
#endif
30333079
}
30343080

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)