static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */
{
- OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
-
- if (GC_G(gc_enabled)) {
- gc_init();
+ zend_bool val;
+
+ 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)) {
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)
Returns status of the circular reference collector */
ZEND_FUNCTION(gc_enabled)
{
- RETURN_BOOL(GC_G(gc_enabled));
+ RETURN_BOOL(gc_enabled());
}
/* }}} */
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
#include "zend.h"
#include "zend_API.h"
+#ifndef GC_BENCH
+# define GC_BENCH 0
+#endif
+
+#ifndef ZEND_GC_DEBUG
+# define ZEND_GC_DEBUG 0
+#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)
-#ifndef ZEND_GC_DEBUG
-# define ZEND_GC_DEBUG 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
-ZEND_API int gc_globals_id;
+static int gc_globals_id;
+#define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v)
#else
-ZEND_API zend_gc_globals gc_globals;
+#define GC_G(v) (gc_globals.v)
+static zend_gc_globals gc_globals;
#endif
-ZEND_API int (*gc_collect_cycles)(void);
+#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__);
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)
#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);
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);
#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)
/* 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 */
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;