Skip to content

Commit 38d216e

Browse files
committed
Snapshot
1 parent da1e254 commit 38d216e

35 files changed

+886
-20
lines changed

Zend/zend_alloc.c

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,6 @@ typedef zend_mm_bitset zend_mm_page_map[ZEND_MM_PAGE_MAP_LEN]; /* 64B */
226226
typedef struct _zend_mm_page zend_mm_page;
227227
typedef struct _zend_mm_bin zend_mm_bin;
228228
typedef struct _zend_mm_free_slot zend_mm_free_slot;
229-
typedef struct _zend_mm_chunk zend_mm_chunk;
230229
typedef struct _zend_mm_huge_list zend_mm_huge_list;
231230

232231
static bool zend_mm_use_huge_pages = false;
@@ -322,6 +321,9 @@ struct _zend_mm_chunk {
322321
zend_mm_heap heap_slot; /* used only in main chunk */
323322
zend_mm_page_map free_map; /* 512 bits or 64 bytes */
324323
zend_mm_page_info map[ZEND_MM_PAGES]; /* 2 KB = 512 * 4 */
324+
bool preserve; /* Never free this chunk.
325+
Ensures the address space can
326+
not be re-used. */
325327
};
326328

327329
struct _zend_mm_page {
@@ -804,7 +806,7 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
804806
}
805807
}
806808

807-
static void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment)
809+
ZEND_API void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment)
808810
{
809811
#if ZEND_MM_STORAGE
810812
if (UNEXPECTED(heap->storage)) {
@@ -1172,11 +1174,15 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_
11721174
}
11731175
}
11741176
if (!heap->cached_chunks || chunk->num > heap->cached_chunks->num) {
1175-
zend_mm_chunk_free(heap, chunk, ZEND_MM_CHUNK_SIZE);
1177+
if (!chunk->preserve) {
1178+
zend_mm_chunk_free(heap, chunk, ZEND_MM_CHUNK_SIZE);
1179+
}
11761180
} else {
11771181
//TODO: select the best chunk to delete???
11781182
chunk->next = heap->cached_chunks->next;
1179-
zend_mm_chunk_free(heap, heap->cached_chunks, ZEND_MM_CHUNK_SIZE);
1183+
if (!heap->cached_chunks->preserve) {
1184+
zend_mm_chunk_free(heap, heap->cached_chunks, ZEND_MM_CHUNK_SIZE);
1185+
}
11801186
heap->cached_chunks = chunk;
11811187
}
11821188
}
@@ -2195,6 +2201,53 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap)
21952201
return collected * ZEND_MM_PAGE_SIZE;
21962202
}
21972203

2204+
ZEND_API zend_mm_chunk *zend_mm_get_chunk_list(zend_mm_heap *heap)
2205+
{
2206+
return heap->main_chunk;
2207+
}
2208+
2209+
ZEND_API int zend_mm_get_chunks_count(zend_mm_heap *heap)
2210+
{
2211+
return heap->chunks_count;
2212+
}
2213+
2214+
ZEND_API void *zend_mm_get_huge_list(zend_mm_heap *heap)
2215+
{
2216+
return heap->huge_list;
2217+
}
2218+
2219+
ZEND_API zend_mm_chunk *zend_mm_get_next_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk)
2220+
{
2221+
ZEND_ASSERT(chunk->heap == heap);
2222+
zend_mm_chunk *next = chunk->next;
2223+
if (next == heap->main_chunk) {
2224+
return NULL;
2225+
}
2226+
return next;
2227+
}
2228+
2229+
/* Adds the given chunk to the heap. The chunk is not initialized, and can have
2230+
* allocated slots and pages. */
2231+
ZEND_API void zend_mm_adopt_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk)
2232+
{
2233+
/* Do not import free lists, as the chunk may have been created with a
2234+
* different key. However, free pages can be allocated. */
2235+
chunk->heap = heap;
2236+
chunk->next = heap->main_chunk;
2237+
chunk->prev = heap->main_chunk->prev;
2238+
chunk->prev->next = chunk;
2239+
chunk->next->prev = chunk;
2240+
chunk->num = chunk->prev->num + 1;
2241+
heap->chunks_count++;
2242+
heap->peak_chunks_count++;
2243+
}
2244+
2245+
ZEND_API void zend_mm_preserve_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk)
2246+
{
2247+
ZEND_ASSERT(chunk->heap == heap);
2248+
chunk->preserve = true;
2249+
}
2250+
21982251
#if ZEND_DEBUG
21992252
/******************/
22002253
/* Leak detection */
@@ -2460,23 +2513,44 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent)
24602513
while (heap->cached_chunks) {
24612514
p = heap->cached_chunks;
24622515
heap->cached_chunks = p->next;
2463-
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
2516+
if (!p->preserve) {
2517+
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
2518+
}
24642519
}
24652520
/* free the first chunk */
2466-
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
2521+
if (!heap->main_chunk->preserve) {
2522+
zend_mm_chunk_free(heap, heap->main_chunk, ZEND_MM_CHUNK_SIZE);
2523+
}
24672524
} else {
2525+
/* unlink preserved chunks from the cache */
2526+
p = heap->cached_chunks;
2527+
while (p) {
2528+
zend_mm_chunk *q = p->next;
2529+
while (q && q->preserve) {
2530+
p->next = q = q->next;
2531+
heap->cached_chunks_count--;
2532+
}
2533+
p = q;
2534+
}
2535+
if (heap->cached_chunks && heap->cached_chunks->preserve) {
2536+
heap->cached_chunks_count--;
2537+
heap->cached_chunks = heap->cached_chunks->next;
2538+
}
2539+
24682540
/* free some cached chunks to keep average count */
24692541
heap->avg_chunks_count = (heap->avg_chunks_count + (double)heap->peak_chunks_count) / 2.0;
24702542
while ((double)heap->cached_chunks_count + 0.9 > heap->avg_chunks_count &&
24712543
heap->cached_chunks) {
24722544
p = heap->cached_chunks;
24732545
heap->cached_chunks = p->next;
2546+
ZEND_ASSERT(!p->preserve);
24742547
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
24752548
heap->cached_chunks_count--;
24762549
}
24772550
/* clear cached chunks */
24782551
p = heap->cached_chunks;
24792552
while (p != NULL) {
2553+
ZEND_ASSERT(!p->preserve);
24802554
zend_mm_chunk *q = p->next;
24812555
memset(p, 0, sizeof(zend_mm_chunk));
24822556
p->next = q;
@@ -2864,7 +2938,9 @@ ZEND_API zend_result zend_set_memory_limit(size_t memory_limit)
28642938
do {
28652939
zend_mm_chunk *p = heap->cached_chunks;
28662940
heap->cached_chunks = p->next;
2867-
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
2941+
if (!p->preserve) {
2942+
zend_mm_chunk_free(heap, p, ZEND_MM_CHUNK_SIZE);
2943+
}
28682944
heap->cached_chunks_count--;
28692945
heap->real_size -= ZEND_MM_CHUNK_SIZE;
28702946
} while (memory_limit < heap->real_size);
@@ -2919,8 +2995,22 @@ ZEND_API void zend_memory_reset_peak_usage(void)
29192995
#endif
29202996
}
29212997

2998+
static void alloc_globals_ctor(zend_alloc_globals *alloc_globals);
2999+
29223000
ZEND_API void shutdown_memory_manager(bool silent, bool full_shutdown)
29233001
{
3002+
if (!full_shutdown) {
3003+
zend_mm_heap *heap = AG(mm_heap);
3004+
if (heap->main_chunk->preserve) {
3005+
/* The main chunk is preserved, so we can not re-use it in the next
3006+
* request: We have to full shutdown and start a new heap.
3007+
* This happens when snapshot_state() was called during the request.
3008+
*/
3009+
zend_mm_shutdown(AG(mm_heap), 1, silent);
3010+
alloc_globals_ctor(&alloc_globals);
3011+
return;
3012+
}
3013+
}
29243014
zend_mm_shutdown(AG(mm_heap), full_shutdown, silent);
29253015
}
29263016

Zend/zend_alloc.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ ZEND_API void zend_memory_reset_peak_usage(void);
241241
efree_size_rel(ht, sizeof(HashTable))
242242

243243
/* Heap functions */
244-
typedef struct _zend_mm_heap zend_mm_heap;
244+
typedef struct _zend_mm_heap zend_mm_heap;
245+
typedef struct _zend_mm_chunk zend_mm_chunk;
245246

246247
ZEND_API zend_mm_heap *zend_mm_startup(void);
247248
ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, bool full_shutdown, bool silent);
@@ -316,6 +317,14 @@ struct _zend_mm_storage {
316317
ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap);
317318
ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void *data, size_t data_size);
318319

320+
ZEND_API zend_mm_chunk *zend_mm_get_chunk_list(zend_mm_heap *heap);
321+
ZEND_API zend_mm_chunk *zend_mm_get_next_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk);
322+
ZEND_API int zend_mm_get_chunks_count(zend_mm_heap *heap);
323+
ZEND_API void zend_mm_adopt_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk);
324+
ZEND_API void *zend_mm_chunk_alloc(zend_mm_heap *heap, size_t size, size_t alignment);
325+
ZEND_API void *zend_mm_get_huge_list(zend_mm_heap *heap);
326+
ZEND_API void zend_mm_preserve_chunk(zend_mm_heap *heap, zend_mm_chunk *chunk);
327+
319328
/*
320329
321330
// The following example shows how to use zend_mm_heap API with custom storage

0 commit comments

Comments
 (0)