mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Completely hide GC implementation details into zend_gc.c
This commit is contained in:
parent
ef255c9f0f
commit
baa9890112
27
Zend/zend.c
27
Zend/zend.c
@ -101,16 +101,35 @@ static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */
|
||||
|
||||
static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */
|
||||
{
|
||||
OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
|
||||
zend_bool val;
|
||||
|
||||
if (GC_G(gc_enabled)) {
|
||||
gc_init();
|
||||
if (ZSTR_LEN(new_value) == 2 && strcasecmp("on", ZSTR_VAL(new_value)) == 0) {
|
||||
val = 1;
|
||||
} else if (ZSTR_LEN(new_value) == 3 && strcasecmp("yes", ZSTR_VAL(new_value)) == 0) {
|
||||
val = 1;
|
||||
}else if (ZSTR_LEN(new_value) == 4 && strcasecmp("true", ZSTR_VAL(new_value)) == 0) {
|
||||
val = 1;
|
||||
} else {
|
||||
val = (zend_bool) atoi(ZSTR_VAL(new_value));
|
||||
}
|
||||
|
||||
gc_set_enabled(val);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static ZEND_INI_DISP(zend_gc_enabled_displayer_cb) /* {{{ */
|
||||
{
|
||||
if (gc_enabled()) {
|
||||
ZEND_PUTS("On");
|
||||
} else {
|
||||
ZEND_PUTS("Off");
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */
|
||||
{
|
||||
if (!CG(multibyte)) {
|
||||
@ -154,7 +173,7 @@ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */
|
||||
ZEND_INI_BEGIN()
|
||||
ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting)
|
||||
STD_ZEND_INI_ENTRY("zend.assertions", "1", ZEND_INI_ALL, OnUpdateAssertions, assertions, zend_executor_globals, executor_globals)
|
||||
STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals)
|
||||
ZEND_INI_ENTRY3_EX("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, NULL, NULL, NULL, zend_gc_enabled_displayer_cb)
|
||||
STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals)
|
||||
ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding)
|
||||
STD_ZEND_INI_BOOLEAN("zend.detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals)
|
||||
|
@ -361,7 +361,7 @@ ZEND_FUNCTION(gc_collect_cycles)
|
||||
Returns status of the circular reference collector */
|
||||
ZEND_FUNCTION(gc_enabled)
|
||||
{
|
||||
RETURN_BOOL(GC_G(gc_enabled));
|
||||
RETURN_BOOL(gc_enabled());
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -302,7 +302,7 @@ void shutdown_executor(void) /* {{{ */
|
||||
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
|
||||
|
||||
#if ZEND_DEBUG
|
||||
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
|
||||
if (gc_enabled() && !CG(unclean_shutdown)) {
|
||||
gc_collect_cycles();
|
||||
}
|
||||
#endif
|
||||
|
118
Zend/zend_gc.c
118
Zend/zend_gc.c
@ -72,23 +72,111 @@
|
||||
#include "zend.h"
|
||||
#include "zend_API.h"
|
||||
|
||||
/* one (0) is reserved */
|
||||
#define GC_ROOT_BUFFER_MAX_ENTRIES 10001
|
||||
|
||||
#define GC_HAS_DESTRUCTORS (1<<0)
|
||||
#ifndef GC_BENCH
|
||||
# define GC_BENCH 0
|
||||
#endif
|
||||
|
||||
#ifndef ZEND_GC_DEBUG
|
||||
# define ZEND_GC_DEBUG 0
|
||||
#endif
|
||||
|
||||
#ifdef ZTS
|
||||
ZEND_API int gc_globals_id;
|
||||
#else
|
||||
ZEND_API zend_gc_globals gc_globals;
|
||||
#endif
|
||||
#define GC_COLOR 0xc000
|
||||
|
||||
#define GC_BLACK 0x0000 /* must be zero */
|
||||
#define GC_WHITE 0x8000
|
||||
#define GC_GREY 0x4000
|
||||
#define GC_PURPLE 0xc000
|
||||
|
||||
#define GC_ADDRESS(v) \
|
||||
((v) & ~GC_COLOR)
|
||||
#define GC_INFO_GET_COLOR(v) \
|
||||
(((zend_uintptr_t)(v)) & GC_COLOR)
|
||||
#define GC_INFO_SET_ADDRESS(v, a) \
|
||||
do {(v) = ((v) & GC_COLOR) | (a);} while (0)
|
||||
#define GC_INFO_SET_COLOR(v, c) \
|
||||
do {(v) = ((v) & ~GC_COLOR) | (c);} while (0)
|
||||
#define GC_INFO_SET_BLACK(v) \
|
||||
do {(v) = (v) & ~GC_COLOR;} while (0)
|
||||
#define GC_INFO_SET_PURPLE(v) \
|
||||
do {(v) = (v) | GC_COLOR;} while (0)
|
||||
|
||||
/* one (0) is reserved */
|
||||
#define GC_ROOT_BUFFER_MAX_ENTRIES 10001
|
||||
|
||||
#define GC_HAS_DESTRUCTORS (1<<0)
|
||||
|
||||
#define GC_NUM_ADDITIONAL_ENTRIES \
|
||||
((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
|
||||
|
||||
ZEND_API int (*gc_collect_cycles)(void);
|
||||
|
||||
typedef struct _gc_root_buffer {
|
||||
zend_refcounted *ref;
|
||||
struct _gc_root_buffer *next; /* double-linked list */
|
||||
struct _gc_root_buffer *prev;
|
||||
uint32_t refcount;
|
||||
} gc_root_buffer;
|
||||
|
||||
typedef struct _gc_additional_bufer gc_additional_buffer;
|
||||
|
||||
struct _gc_additional_bufer {
|
||||
uint32_t used;
|
||||
gc_additional_buffer *next;
|
||||
gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES];
|
||||
};
|
||||
|
||||
typedef struct _zend_gc_globals {
|
||||
zend_bool gc_enabled;
|
||||
zend_bool gc_active;
|
||||
zend_bool gc_full;
|
||||
|
||||
gc_root_buffer *buf; /* preallocated arrays of buffers */
|
||||
gc_root_buffer roots; /* list of possible roots of cycles */
|
||||
gc_root_buffer *unused; /* list of unused buffers */
|
||||
gc_root_buffer *first_unused; /* pointer to first unused buffer */
|
||||
gc_root_buffer *last_unused; /* pointer to last unused buffer */
|
||||
|
||||
gc_root_buffer to_free; /* list to free */
|
||||
gc_root_buffer *next_to_free;
|
||||
|
||||
uint32_t gc_runs;
|
||||
uint32_t collected;
|
||||
|
||||
#if GC_BENCH
|
||||
uint32_t root_buf_length;
|
||||
uint32_t root_buf_peak;
|
||||
uint32_t zval_possible_root;
|
||||
uint32_t zval_buffered;
|
||||
uint32_t zval_remove_from_buffer;
|
||||
uint32_t zval_marked_grey;
|
||||
#endif
|
||||
|
||||
gc_additional_buffer *additional_buffer;
|
||||
|
||||
} zend_gc_globals;
|
||||
|
||||
#ifdef ZTS
|
||||
static int gc_globals_id;
|
||||
#define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v)
|
||||
#else
|
||||
#define GC_G(v) (gc_globals.v)
|
||||
static zend_gc_globals gc_globals;
|
||||
#endif
|
||||
|
||||
#if GC_BENCH
|
||||
# define GC_BENCH_INC(counter) GC_G(counter)++
|
||||
# define GC_BENCH_DEC(counter) GC_G(counter)--
|
||||
# define GC_BENCH_PEAK(peak, counter) do { \
|
||||
if (GC_G(counter) > GC_G(peak)) { \
|
||||
GC_G(peak) = GC_G(counter); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define GC_BENCH_INC(counter)
|
||||
# define GC_BENCH_DEC(counter)
|
||||
# define GC_BENCH_PEAK(peak, counter)
|
||||
#endif
|
||||
|
||||
#if ZEND_GC_DEBUG > 1
|
||||
# define GC_TRACE(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__);
|
||||
# define GC_TRACE_REF(ref, format, ...) \
|
||||
@ -249,13 +337,21 @@ ZEND_API void gc_reset(void)
|
||||
GC_G(additional_buffer) = NULL;
|
||||
}
|
||||
|
||||
ZEND_API void gc_init(void)
|
||||
ZEND_API zend_bool gc_set_enabled(zend_bool enable)
|
||||
{
|
||||
if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
|
||||
zend_bool old_enabled = GC_G(gc_enabled);
|
||||
GC_G(gc_enabled) = enable;
|
||||
if (enable && !old_enabled && GC_G(buf) == NULL) {
|
||||
GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
|
||||
GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
|
||||
gc_reset();
|
||||
}
|
||||
return old_enabled;
|
||||
}
|
||||
|
||||
ZEND_API zend_bool gc_enabled(void)
|
||||
{
|
||||
return GC_G(gc_enabled);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
|
||||
|
101
Zend/zend_gc.h
101
Zend/zend_gc.h
@ -22,102 +22,6 @@
|
||||
#ifndef ZEND_GC_H
|
||||
#define ZEND_GC_H
|
||||
|
||||
#ifndef GC_BENCH
|
||||
# define GC_BENCH 0
|
||||
#endif
|
||||
|
||||
#if GC_BENCH
|
||||
# define GC_BENCH_INC(counter) GC_G(counter)++
|
||||
# define GC_BENCH_DEC(counter) GC_G(counter)--
|
||||
# define GC_BENCH_PEAK(peak, counter) do { \
|
||||
if (GC_G(counter) > GC_G(peak)) { \
|
||||
GC_G(peak) = GC_G(counter); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define GC_BENCH_INC(counter)
|
||||
# define GC_BENCH_DEC(counter)
|
||||
# define GC_BENCH_PEAK(peak, counter)
|
||||
#endif
|
||||
|
||||
#define GC_COLOR 0xc000
|
||||
|
||||
#define GC_BLACK 0x0000
|
||||
#define GC_WHITE 0x8000
|
||||
#define GC_GREY 0x4000
|
||||
#define GC_PURPLE 0xc000
|
||||
|
||||
#define GC_ADDRESS(v) \
|
||||
((v) & ~GC_COLOR)
|
||||
#define GC_INFO_GET_COLOR(v) \
|
||||
(((zend_uintptr_t)(v)) & GC_COLOR)
|
||||
#define GC_INFO_SET_ADDRESS(v, a) \
|
||||
do {(v) = ((v) & GC_COLOR) | (a);} while (0)
|
||||
#define GC_INFO_SET_COLOR(v, c) \
|
||||
do {(v) = ((v) & ~GC_COLOR) | (c);} while (0)
|
||||
#define GC_INFO_SET_BLACK(v) \
|
||||
do {(v) = (v) & ~GC_COLOR;} while (0)
|
||||
#define GC_INFO_SET_PURPLE(v) \
|
||||
do {(v) = (v) | GC_COLOR;} while (0)
|
||||
|
||||
typedef struct _gc_root_buffer {
|
||||
zend_refcounted *ref;
|
||||
struct _gc_root_buffer *next; /* double-linked list */
|
||||
struct _gc_root_buffer *prev;
|
||||
uint32_t refcount;
|
||||
} gc_root_buffer;
|
||||
|
||||
#define GC_NUM_ADDITIONAL_ENTRIES \
|
||||
((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
|
||||
|
||||
typedef struct _gc_additional_bufer gc_additional_buffer;
|
||||
|
||||
struct _gc_additional_bufer {
|
||||
uint32_t used;
|
||||
gc_additional_buffer *next;
|
||||
gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES];
|
||||
};
|
||||
|
||||
typedef struct _zend_gc_globals {
|
||||
zend_bool gc_enabled;
|
||||
zend_bool gc_active;
|
||||
zend_bool gc_full;
|
||||
|
||||
gc_root_buffer *buf; /* preallocated arrays of buffers */
|
||||
gc_root_buffer roots; /* list of possible roots of cycles */
|
||||
gc_root_buffer *unused; /* list of unused buffers */
|
||||
gc_root_buffer *first_unused; /* pointer to first unused buffer */
|
||||
gc_root_buffer *last_unused; /* pointer to last unused buffer */
|
||||
|
||||
gc_root_buffer to_free; /* list to free */
|
||||
gc_root_buffer *next_to_free;
|
||||
|
||||
uint32_t gc_runs;
|
||||
uint32_t collected;
|
||||
|
||||
#if GC_BENCH
|
||||
uint32_t root_buf_length;
|
||||
uint32_t root_buf_peak;
|
||||
uint32_t zval_possible_root;
|
||||
uint32_t zval_buffered;
|
||||
uint32_t zval_remove_from_buffer;
|
||||
uint32_t zval_marked_grey;
|
||||
#endif
|
||||
|
||||
gc_additional_buffer *additional_buffer;
|
||||
|
||||
} zend_gc_globals;
|
||||
|
||||
#ifdef ZTS
|
||||
BEGIN_EXTERN_C()
|
||||
ZEND_API extern int gc_globals_id;
|
||||
END_EXTERN_C()
|
||||
#define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v)
|
||||
#else
|
||||
#define GC_G(v) (gc_globals.v)
|
||||
extern ZEND_API zend_gc_globals gc_globals;
|
||||
#endif
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
ZEND_API extern int (*gc_collect_cycles)(void);
|
||||
|
||||
@ -125,8 +29,9 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref);
|
||||
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref);
|
||||
ZEND_API void gc_globals_ctor(void);
|
||||
ZEND_API void gc_globals_dtor(void);
|
||||
ZEND_API void gc_init(void);
|
||||
ZEND_API void gc_reset(void);
|
||||
ZEND_API zend_bool gc_set_enabled(zend_bool enable);
|
||||
ZEND_API zend_bool gc_enabled(void);
|
||||
|
||||
/* The default implementation of the gc_collect_cycles callback. */
|
||||
ZEND_API int zend_gc_collect_cycles(void);
|
||||
@ -134,7 +39,7 @@ END_EXTERN_C()
|
||||
|
||||
#define GC_REMOVE_FROM_BUFFER(p) do { \
|
||||
zend_refcounted *_p = (zend_refcounted*)(p); \
|
||||
if (GC_ADDRESS(GC_INFO(_p))) { \
|
||||
if (GC_INFO(_p)) { \
|
||||
gc_remove_from_buffer(_p); \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -1363,7 +1363,7 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
|
||||
|
||||
/* break possible cycles */
|
||||
GC_REMOVE_FROM_BUFFER(ht);
|
||||
GC_TYPE_INFO(ht) = IS_NULL | (GC_WHITE << 16);
|
||||
GC_TYPE_INFO(ht) = IS_NULL /*???| (GC_WHITE << 16)*/;
|
||||
|
||||
if (ht->nNumUsed) {
|
||||
/* In some rare cases destructors of regular arrays may be changed */
|
||||
|
@ -210,7 +210,7 @@ typedef struct _zend_refcounted_h {
|
||||
ZEND_ENDIAN_LOHI_3(
|
||||
zend_uchar type,
|
||||
zend_uchar flags, /* used for strings & objects */
|
||||
uint16_t gc_info) /* keeps GC root number (or 0) and color */
|
||||
uint16_t gc_info) /* keeps GC information, must be initialized by 0 */
|
||||
} v;
|
||||
uint32_t type_info;
|
||||
} u;
|
||||
|
Loading…
Reference in New Issue
Block a user