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