1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: David Wang <planetbeing@gmail.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef ZEND_GC_H
#define ZEND_GC_H
#include "zend_hrtime.h"
#ifndef GC_BENCH
# define GC_BENCH 0
#endif
BEGIN_EXTERN_C()
typedef struct _zend_gc_status {
bool active;
bool gc_protected;
bool full;
uint32_t runs;
uint32_t collected;
uint32_t threshold;
uint32_t buf_size;
uint32_t num_roots;
zend_hrtime_t application_time;
zend_hrtime_t collector_time;
zend_hrtime_t dtor_time;
zend_hrtime_t free_time;
} zend_gc_status;
ZEND_API extern int (*gc_collect_cycles)(void);
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref);
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref);
/* enable/disable automatic start of GC collection */
ZEND_API bool gc_enable(bool enable);
ZEND_API bool gc_enabled(void);
/* enable/disable possible root additions */
ZEND_API bool gc_protect(bool protect);
ZEND_API bool gc_protected(void);
#if GC_BENCH
void gc_bench_print(void);
#endif
/* The default implementation of the gc_collect_cycles callback. */
ZEND_API int zend_gc_collect_cycles(void);
ZEND_API void zend_gc_get_status(zend_gc_status *status);
void gc_init(void);
void gc_globals_ctor(void);
void gc_globals_dtor(void);
void gc_reset(void);
#ifdef ZTS
size_t zend_gc_globals_size(void);
#endif
#define GC_REMOVE_FROM_BUFFER(p) do { \
zend_refcounted *_p = (zend_refcounted*)(p); \
if (GC_TYPE_INFO(_p) & GC_INFO_MASK) { \
gc_remove_from_buffer(_p); \
} \
} while (0)
#define GC_MAY_LEAK(ref) \
((GC_TYPE_INFO(ref) & \
(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))) == 0)
static zend_always_inline void gc_check_possible_root(zend_refcounted *ref)
{
if (EXPECTED(GC_TYPE_INFO(ref) == GC_REFERENCE)) {
zval *zv = &((zend_reference*)ref)->val;
if (!Z_COLLECTABLE_P(zv)) {
return;
}
ref = Z_COUNTED_P(zv);
}
if (UNEXPECTED(GC_MAY_LEAK(ref))) {
gc_possible_root(ref);
}
}
static zend_always_inline void gc_check_possible_root_no_ref(zend_refcounted *ref)
{
ZEND_ASSERT(GC_TYPE_INFO(ref) != GC_REFERENCE);
if (UNEXPECTED(GC_MAY_LEAK(ref))) {
gc_possible_root(ref);
}
}
/* These APIs can be used to simplify object get_gc implementations
* over heterogeneous structures. See zend_generator_get_gc() for
* a usage example. */
typedef struct {
zval *cur;
zval *end;
zval *start;
} zend_get_gc_buffer;
ZEND_API zend_get_gc_buffer *zend_get_gc_buffer_create(void);
ZEND_API void zend_get_gc_buffer_grow(zend_get_gc_buffer *gc_buffer);
static zend_always_inline void zend_get_gc_buffer_add_zval(
zend_get_gc_buffer *gc_buffer, zval *zv) {
if (Z_REFCOUNTED_P(zv)) {
if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
zend_get_gc_buffer_grow(gc_buffer);
}
ZVAL_COPY_VALUE(gc_buffer->cur, zv);
gc_buffer->cur++;
}
}
static zend_always_inline void zend_get_gc_buffer_add_obj(
zend_get_gc_buffer *gc_buffer, zend_object *obj) {
if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
zend_get_gc_buffer_grow(gc_buffer);
}
ZVAL_OBJ(gc_buffer->cur, obj);
gc_buffer->cur++;
}
static zend_always_inline void zend_get_gc_buffer_add_ptr(
zend_get_gc_buffer *gc_buffer, void *ptr) {
if (UNEXPECTED(gc_buffer->cur == gc_buffer->end)) {
zend_get_gc_buffer_grow(gc_buffer);
}
ZVAL_PTR(gc_buffer->cur, ptr);
gc_buffer->cur++;
}
static zend_always_inline void zend_get_gc_buffer_use(
zend_get_gc_buffer *gc_buffer, zval **table, int *n) {
*table = gc_buffer->start;
*n = gc_buffer->cur - gc_buffer->start;
}
END_EXTERN_C()
#endif /* ZEND_GC_H */
|